diff --git a/.bazelignore b/.bazelignore index fe6b1f377a..e29a94b637 100644 --- a/.bazelignore +++ b/.bazelignore @@ -2,3 +2,4 @@ node_modules dist aio/node_modules aio/tools/examples/shared/node_modules +integration/bazel diff --git a/.bazelrc b/.bazelrc index df393c71dc..59fd7b8332 100644 --- a/.bazelrc +++ b/.bazelrc @@ -22,12 +22,18 @@ test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test # Filesystem interactions # ############################### -# Don't create symlinks like bazel-out in the project. -# These cause VSCode to traverse a massive tree, opening file handles and +# Create symlinks in the project: +# - dist/bin for outputs +# - dist/testlogs, dist/genfiles +# - bazel-out +# NB: bazel-out should be excluded from the editor configuration. +# The checked-in /.vscode/settings.json does this for VSCode. +# Other editors may require manual config to ignore this directory. +# In the past, we say a problem where VSCode traversed a massive tree, opening file handles and # eventually a surprising failure with auto-discovery of the C++ toolchain in # MacOS High Sierra. # See https://github.com/bazelbuild/bazel/issues/4603 -build --symlink_prefix=/ +build --symlink_prefix=dist/ # Performance: avoid stat'ing input files build --watchfs @@ -36,6 +42,16 @@ build --watchfs run --nolegacy_external_runfiles test --nolegacy_external_runfiles +# Turn on --incompatible_strict_action_env which was on by default +# in Bazel 0.21.0 but turned off again in 0.22.0. Follow +# https://github.com/bazelbuild/bazel/issues/7026 for more details. +# This flag is needed to so that the bazel cache is not invalidated +# when running bazel via `yarn bazel`. +# See https://github.com/angular/angular/issues/27514. +build --incompatible_strict_action_env +run --incompatible_strict_action_env +test --incompatible_strict_action_env + ############################### # Release support # # Turn on these settings with # @@ -43,7 +59,9 @@ test --nolegacy_external_runfiles ############################### # Releases should always be stamped with version control info -build:release --workspace_status_command=./tools/bazel_stamp_vars.sh +# This command assumes node on the path and is a workaround for +# https://github.com/bazelbuild/bazel/issues/4802 +build:release --workspace_status_command="node ./tools/bazel_stamp_vars.js" ############################### # Output # @@ -82,7 +100,9 @@ build --define=compile=legacy ############################### # Load default settings for Remote Build Execution -import %workspace%/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.20.0.bazelrc +# When updating, the URLs of bazel_toolchains in packages/bazel/package.bzl +# may also need to be updated (see https://github.com/angular/angular/pull/27935) +import %workspace%/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.21.0.bazelrc # Increase the default number of jobs by 50% because our build has lots of # parallelism diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 9b2abeb660..0000000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory" : "bower_components" -} diff --git a/.buildkite/provision-windows-buildkite.ps1 b/.buildkite/provision-windows-buildkite.ps1 index 56c84569b1..7af03b2319 100644 --- a/.buildkite/provision-windows-buildkite.ps1 +++ b/.buildkite/provision-windows-buildkite.ps1 @@ -5,9 +5,9 @@ # VM creation: # In Google Cloud Platform, create a Compute Engine instance. -# We recommend machine type n1-highcpu-16 (16 vCPUs, 14.4 GB memory). -# Use a windows boot disk with container support such as -# "Windows Server version 1803 Datacenter Core for Containers". +# We recommend machine type n1-standard-16 (16 vCPUs, 60 GB memory). +# Use a recent windows boot disk with container support such as +# "Windows Server version 1803 Datacenter Core for Containers", and add a 128GB SSD disk. # Give it a name, then click "Create". # VM setup: @@ -35,7 +35,7 @@ # Get the token and tags from arguments. param ( [Parameter(Mandatory=$true)][string]$token, - [string]$tags = "" + [string]$tags = "", [Int]$agents = 1 ) @@ -54,6 +54,8 @@ Write-Host "Installing Git for Windows." Invoke-WebRequest -Uri https://github.com/git-for-windows/git/releases/download/v2.19.1.windows.1/Git-2.19.1-64-bit.exe -OutFile git.exe .\git.exe /VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /COMPONENTS="icons,ext\reg\shellhere,assoc,assoc_sh" /DIR="C:\git" Add-Path "C:\git\bin" +# Sleep for 15s while git is installed. Trying to remove the git.exe before it finishes install causes an error. +Start-Sleep -s 15 Remove-Item git.exe # Download NSSM (https://nssm.cc/) to run the BuildKite agent as a service. diff --git a/.circleci/bazel.rc b/.circleci/bazel.rc index 754a970122..315c2667d0 100644 --- a/.circleci/bazel.rc +++ b/.circleci/bazel.rc @@ -2,6 +2,10 @@ # We do this by copying this file to /etc/bazel.bazelrc at the start of the build. # See documentation in /docs/BAZEL.md +# Save downloaded repositories in a location that can be cached by CircleCI. This helps us +# speeding up the analysis time significantly with Bazel managed node dependencies on the CI. +build --repository_cache=/home/circleci/bazel_repository_cache + # Don't be spammy in the logs # TODO(gmagolan): Hide progress again once build performance improves # Presently, CircleCI can timeout during bazel test ... with the following diff --git a/.circleci/config.yml b/.circleci/config.yml index 38928e8bbc..389949576d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,10 +11,22 @@ # needed for jobs that run tests without Bazel. Bazel runs tests with browsers that will be # fetched by the Webtesting rules. Therefore for jobs that run tests with Bazel, we don't need a # docker image with browsers pre-installed. -# **NOTE**: If you change the version of the docker images, also change the `cache_key` suffix. +# **NOTE 1**: If you change the version of the `*-browsers` docker image, make sure the +# `CI_CHROMEDRIVER_VERSION_ARG` env var (in `.circleci/env.sh`) points to a ChromeDriver +# version that is compatible with the Chrome version in the image. +# **NOTE 2**: If you change the version of the docker images, also change the `cache_key` suffix. var_1: &default_docker_image circleci/node:10.12 var_2: &browsers_docker_image circleci/node:10.12-browsers -var_3: &cache_key v2-angular-{{ .Branch }}-{{ checksum "yarn.lock" }}-node-10.12 +# We don't want to include the current branch name in the cache key because that would prevent +# PRs from being able to restore the cache since the branch names are always different for PRs. +# The cache key should only consist of dynamic values that change whenever something in the +# cache changes. For example: +# 1) yarn lock file changes --> cached "node_modules" are different. +# 2) bazel repository definitions change --> cached bazel repositories are different. +# **NOTE 1 **: If you change the cache key prefix, also sync the restore_cache fallback to match. +# **NOTE 2 **: Keep the static part of the cache key as prefix to enable correct fallbacks. +# See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI. +var_3: &cache_key v2-angular-node-10.12-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }} # Define common ENV vars var_4: &define_env_vars @@ -45,13 +57,35 @@ var_7: &post_checkout var_8: &yarn_install run: name: Running Yarn install - command: yarn install --frozen-lockfile --non-interactive + command: | + # Yarn's requests sometimes take more than 10mins to complete. + # Print something to stdout, to prevent CircleCI from failing due to not output. + while true; do sleep 60; echo "[`date`] Keeping alive..."; done & + KEEP_ALIVE_PID=$! + yarn install --frozen-lockfile --non-interactive + kill $KEEP_ALIVE_PID var_9: &setup_circleci_bazel_config run: name: Setting up CircleCI bazel configuration command: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc +# Sets up Yarn by downloading it and installing it globally. We don't use Yarn from the +# docker image because this means that we can only use the Yarn version that comes with +# a specific version of NodeJS. We want to be able to update Yarn without having to +# update the docker image that comes with NodeJS. +var_10: &download_yarn + run: + name: Downloading Yarn + command: curl -o- -L https://yarnpkg.com/install.sh | PROFILE=$BASH_ENV bash -s -- --version "$CI_YARN_VERSION" + +var_11: &restore_cache + restore_cache: + keys: + - *cache_key + # This fallback should be the cache_key without variables. + - v2-angular-node-10.12- + version: 2 jobs: lint: @@ -59,9 +93,9 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars + - *download_yarn - *yarn_install - run: 'yarn bazel:format -mode=check || @@ -78,11 +112,11 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars - - *setup_circleci_bazel_config + - *download_yarn - *yarn_install + - *setup_circleci_bazel_config # Setup remote execution and run RBE-compatible tests. - *setup_bazel_remote_execution @@ -91,12 +125,6 @@ jobs: - run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc - run: yarn bazel test //... --build_tag_filters=-ivy-only,local --test_tag_filters=-ivy-only,local - - save_cache: - key: *cache_key - paths: - - "node_modules" - - "~/bazel_repository_cache" - # Temporary job to test what will happen when we flip the Ivy flag to true test_ivy_aot: <<: *job_defaults @@ -104,11 +132,11 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars - - *setup_circleci_bazel_config + - *download_yarn - *yarn_install + - *setup_circleci_bazel_config - *setup_bazel_remote_execution # We need to explicitly specify the --symlink_prefix option because otherwise we would @@ -143,9 +171,9 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars + - *download_yarn # Build aio - run: yarn --cwd aio build --progress=false # Lint the code @@ -157,9 +185,9 @@ jobs: # (Run before unit and e2e tests, which destroy the `dist/` directory.) - run: yarn --cwd aio payload-size # Run unit tests - - run: yarn --cwd aio test --watch=false + - run: yarn --cwd aio test --progress=false --watch=false # Run e2e tests - - run: yarn --cwd aio e2e + - run: yarn --cwd aio e2e --configuration=ci # Run unit tests for Firebase redirects - run: yarn --cwd aio redirects-test @@ -171,9 +199,9 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars + - *download_yarn # 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: yarn --cwd aio deploy-production @@ -186,31 +214,44 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - attach_workspace: at: dist - *define_env_vars + - *download_yarn # Build aio (with local Angular packages) - run: yarn --cwd aio build-local --progress=false # Run PWA-score tests # (Run before unit and e2e tests, which destroy the `dist/` directory.) - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE # Run unit tests - - run: yarn --cwd aio test --watch=false + - run: yarn --cwd aio test --progress=false --watch=false # Run e2e tests - - run: yarn --cwd aio e2e + - run: yarn --cwd aio e2e --configuration=ci + + test_aio_local_ivy: + <<: *job_defaults + steps: + - checkout: + <<: *post_checkout + - *restore_cache + - attach_workspace: + at: dist + - *define_env_vars + - *download_yarn + # Build aio with Ivy (using local Angular packages) + - run: yarn --cwd aio build-with-ivy --progress=false test_aio_tools: <<: *job_defaults steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - attach_workspace: at: dist - *define_env_vars + - *download_yarn # Install - run: yarn --cwd aio install --frozen-lockfile --non-interactive - run: yarn --cwd aio extract-cli-command-docs @@ -218,45 +259,47 @@ jobs: - run: yarn --cwd aio tools-test - run: ./aio/aio-builds-setup/scripts/test.sh - test_docs_examples_0: + test_docs_examples: <<: *job_defaults docker: # Needed because the example e2e tests depend on Chrome. - image: *browsers_docker_image + parallelism: 3 steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - attach_workspace: at: dist - *define_env_vars - # Install root - - *yarn_install + - *download_yarn # Install aio - run: yarn --cwd aio install --frozen-lockfile --non-interactive - # Run examples tests - - run: yarn --cwd aio example-e2e --setup --local --shard=0/2 + # Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled. + # Since the parallelism is set to "3", there will be three parallel CircleCI containers + # with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument. + - run: yarn --cwd aio example-e2e --setup --local --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} - test_docs_examples_1: + test_docs_examples_ivy: <<: *job_defaults docker: # Needed because the example e2e tests depend on Chrome. - image: *browsers_docker_image + parallelism: 3 steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - attach_workspace: at: dist - *define_env_vars - # Install root - - *yarn_install + - *download_yarn # Install aio - run: yarn --cwd aio install --frozen-lockfile --non-interactive - # Run examples tests - - run: yarn --cwd aio example-e2e --setup --local --shard=1/2 + # Run examples tests with ivy. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled. + # Since the parallelism is set to "3", there will be three parallel CircleCI containers + # with either "0", "1" or "2" as node index. This can be passed to the "--shard" argument. + - run: yarn --cwd aio example-e2e --setup --local --ivy --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} # This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`. aio_preview: @@ -266,10 +309,9 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars - - *yarn_install + - *download_yarn - run: ./aio/scripts/build-artifacts.sh $AIO_SNAPSHOT_ARTIFACT_PATH $CI_PULL_REQUEST $CI_COMMIT - store_artifacts: path: *aio_preview_artifact_path @@ -287,32 +329,34 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars - - run: yarn install --cwd aio --frozen-lockfile --non-interactive + - *download_yarn + - run: yarn --cwd aio install --frozen-lockfile --non-interactive - run: name: Wait for preview and run tests command: node aio/scripts/test-preview.js $CI_PULL_REQUEST $CI_COMMIT $CI_AIO_MIN_PWA_SCORE - # This job exists only for backwards-compatibility with old scripts and tests - # that rely on the pre-Bazel dist/packages-dist layout. - # It duplicates some work with the job above: we build the bazel packages - # twice. Even though we have a remote cache, these jobs will typically run in - # parallel so up-to-date outputs will not be available at the time the build + + # The `build-npm-packages` tasks exist for backwards-compatibility with old scripts and + # tests that rely on the pre-Bazel `dist/packages-dist` output structure (build.sh). + # Having multiple jobs that independently build in this manner duplicates some work; we build + # the bazel packages more than once. Even though we have a remote cache, these jobs will + # typically run in parallel so up-to-date outputs will not be available at the time the build # starts. - # No new jobs should depend on this one. - build-packages-dist: + + # Build the view engine npm packages. No new jobs should depend on this. + build-npm-packages: <<: *job_defaults resource_class: xlarge steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars - - *setup_circleci_bazel_config + - *download_yarn - *yarn_install + - *setup_circleci_bazel_config - *setup_bazel_remote_execution - run: scripts/build-packages-dist.sh @@ -323,6 +367,35 @@ jobs: root: dist paths: - packages-dist + + - save_cache: + key: *cache_key + paths: + - "node_modules" + - "~/bazel_repository_cache" + + + # Build the ivy npm packages. + build-ivy-npm-packages: + <<: *job_defaults + resource_class: xlarge + steps: + - checkout: + <<: *post_checkout + - *restore_cache + - *define_env_vars + - *download_yarn + - *yarn_install + - *setup_circleci_bazel_config + - *setup_bazel_remote_execution + + - run: scripts/build-ivy-npm-packages.sh + + # Save the npm packages from //packages/... for other workflow jobs to read + # https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs + - persist_to_workspace: + root: dist + paths: - packages-dist-ivy-aot # We run the integration tests outside of Bazel for now. @@ -333,6 +406,7 @@ jobs: # See comments inside the integration/run_tests.sh script. integration_test: <<: *job_defaults + parallelism: 4 docker: # Needed because the integration tests expect Chrome to be installed (e.g cli-hello-world) - image: *browsers_docker_image @@ -343,12 +417,16 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - attach_workspace: at: dist - *define_env_vars - - run: ./integration/run_tests.sh + - *download_yarn + # Some integration tests get their dependencies from the root `node_modules/`. + - *yarn_install + # Runs the integration tests in parallel across multiple CircleCI container instances. The + # amount of container nodes for this job is controlled by the "parallelism" option. + - run: ./integration/run_tests.sh ${CIRCLE_NODE_INDEX} ${CIRCLE_NODE_TOTAL} # This job updates the content of repos like github.com/angular/core-builds # for every green build on angular/angular. @@ -388,17 +466,96 @@ jobs: steps: - checkout: <<: *post_checkout - - restore_cache: - key: *cache_key + - *restore_cache - *define_env_vars + - *download_yarn - run: name: Run tests against the deployed apps command: ./aio/scripts/test-production.sh $CI_AIO_MIN_PWA_SCORE - run: name: Notify caretaker about failure - 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:\"}" $CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL' + # `$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 + legacy-unit-tests-local: + <<: *job_defaults + docker: + - image: *browsers_docker_image + steps: + - checkout: + <<: *post_checkout + - *restore_cache + - *define_env_vars + - *download_yarn + - *yarn_install + - run: yarn tsc -p packages + - run: yarn tsc -p modules + - run: yarn karma start ./karma-js.conf.js --single-run --browsers=ChromeNoSandbox + + legacy-unit-tests-saucelabs: + <<: *job_defaults + # In order to avoid the bottleneck of having a slow host machine, we acquire a better + # container for this job. This is necessary because we launch a lot of browsers concurrently + # and therefore the tunnel and Karma need to process a lot of file requests and tests. + resource_class: xlarge + steps: + - checkout: + <<: *post_checkout + - *restore_cache + - *define_env_vars + - *download_yarn + - *yarn_install + - run: + name: Preparing environment for running tests on Saucelabs. + command: | + setPublicVar KARMA_JS_BROWSERS $(node -e 'console.log(require("./browser-providers.conf").sauceAliases.CI_REQUIRED.join(","))') + setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev) + - run: + name: Starting Saucelabs tunnel + command: ./scripts/saucelabs/start-tunnel.sh + background: true + - run: yarn tsc -p packages + - run: yarn tsc -p modules + # Waits for the Saucelabs tunnel to be ready. This ensures that we don't run tests + # too early without Saucelabs not being ready. + - run: ./scripts/saucelabs/wait-for-tunnel.sh + - run: yarn karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS} + - run: ./scripts/saucelabs/stop-tunnel.sh + + legacy-misc-tests: + <<: *job_defaults + steps: + - checkout: + <<: *post_checkout + - *restore_cache + - *define_env_vars + - *download_yarn + - *yarn_install + - attach_workspace: + at: dist + - run: yarn gulp check-cycle + # TODO: disabled because the Bazel packages-dist does not seem to have map files for + # the ESM5/ES2015 output. See: https://github.com/angular/angular/issues/27966 + # - run: yarn gulp source-map-test + + # Job to run unit tests from angular/material2. Needs a browser since all + # component unit tests assume they're running in the browser environment. + material-unit-tests: + <<: *job_defaults + resource_class: xlarge + docker: + - image: *browsers_docker_image + steps: + - checkout: + <<: *post_checkout + - *define_env_vars + - *download_yarn + - attach_workspace: + at: dist + - run: ./scripts/ci/run_angular_material_unit_tests.sh + workflows: version: 2 default_workflow: @@ -406,23 +563,32 @@ workflows: - lint - test - test_ivy_aot - - build-packages-dist + - build-npm-packages + - build-ivy-npm-packages - test_aio + - legacy-unit-tests-local + - legacy-unit-tests-saucelabs - deploy_aio: requires: - test_aio + - legacy-misc-tests: + requires: + - build-npm-packages - test_aio_local: requires: - - build-packages-dist + - build-npm-packages + - test_aio_local_ivy: + requires: + - build-npm-packages - test_aio_tools: requires: - - build-packages-dist - - test_docs_examples_0: + - build-npm-packages + - test_docs_examples: requires: - - build-packages-dist - - test_docs_examples_1: + - build-npm-packages + - test_docs_examples_ivy: requires: - - build-packages-dist + - build-npm-packages - aio_preview: # Only run on PR builds. (There can be no previews for non-PR builds.) filters: @@ -433,7 +599,7 @@ workflows: - aio_preview - integration_test: requires: - - build-packages-dist + - build-npm-packages - publish_snapshot: # Note: no filters on this job because we want it to run for all upstream branches # We'd really like to filter out pull requests here, but not yet available: @@ -446,11 +612,20 @@ workflows: - integration_test # Only publish if `aio`/`docs` tests using the locally built Angular packages pass - test_aio_local - - test_docs_examples_0 - - test_docs_examples_1 + - test_aio_local_ivy + - test_docs_examples + - test_docs_examples_ivy # Get the artifacts to publish from the build-packages-dist job # since the publishing script expects the legacy outputs layout. - - build-packages-dist + - build-npm-packages + - build-ivy-npm-packages + - legacy-misc-tests + - legacy-unit-tests-local + - legacy-unit-tests-saucelabs + - material-unit-tests: + requires: + - build-ivy-npm-packages + aio_monitoring: jobs: @@ -462,3 +637,9 @@ workflows: branches: only: - master + +# TODO: +# - don't build the g3 branch +# - verify that we are bootstrapping with the right yarn version coming from the docker image +# - check local chrome version pulled from docker image +# - remove /tools/ngcontainer diff --git a/.circleci/env-helpers.inc.sh b/.circleci/env-helpers.inc.sh index 3a745321ef..ff21eb9ea0 100644 --- a/.circleci/env-helpers.inc.sh +++ b/.circleci/env-helpers.inc.sh @@ -15,7 +15,7 @@ # # Usage: `setPublicVar ` function setPublicVar() { - setSecretVar $1 $2; + setSecretVar $1 "$2"; echo "$1=$2"; } diff --git a/.circleci/env.sh b/.circleci/env.sh index 9680eb6b1e..2df630329b 100755 --- a/.circleci/env.sh +++ b/.circleci/env.sh @@ -1,7 +1,10 @@ #!/usr/bin/env bash -# Load helpers and make them available everywhere (through `$BASH_ENV`). +# Variables readonly envHelpersPath="`dirname $0`/env-helpers.inc.sh"; +readonly getCommitRangePath="`dirname $0`/get-commit-range.js"; + +# Load helpers and make them available everywhere (through `$BASH_ENV`). source $envHelpersPath; echo "source $envHelpersPath;" >> $BASH_ENV; @@ -9,17 +12,26 @@ echo "source $envHelpersPath;" >> $BASH_ENV; #################################################################################################### # Define PUBLIC environment variables for CircleCI. #################################################################################################### +# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info. +#################################################################################################### setPublicVar PROJECT_ROOT "$(pwd)"; setPublicVar CI_AIO_MIN_PWA_SCORE "95"; # This is the branch being built; e.g. `pull/12345` for PR builds. setPublicVar CI_BRANCH "$CIRCLE_BRANCH"; +# ChromeDriver version compatible with the Chrome version included in the docker image used in +# `.circleci/config.yml`. See http://chromedriver.chromium.org/downloads for a list of versions. +# This variable is intended to be passed as an arg to the `webdriver-manager update` command (e.g. +# `"postinstall": "webdriver-manager update $CI_CHROMEDRIVER_VERSION_ARG"`). +setPublicVar CI_CHROMEDRIVER_VERSION_ARG "--versions.chrome 2.45"; setPublicVar CI_COMMIT "$CIRCLE_SHA1"; -# `CI_COMMIT_RANGE` will only be available when `CIRCLE_COMPARE_URL` is also available, -# i.e. on push builds (a.k.a. non-PR builds). That is fine, since we only need it in push builds. -setPublicVar CI_COMMIT_RANGE "$(sed -r 's|^.*/([0-9a-f]+\.\.\.[0-9a-f]+)$|\1|i' <<< ${CIRCLE_COMPARE_URL:-})"; +# `CI_COMMIT_RANGE` will only be available when `CIRCLE_COMPARE_URL` is also available (or can be +# retrieved via `get-compare-url.js`), i.e. on push builds (a.k.a. non-PR, non-scheduled builds and +# rerun workflows of such builds). That is fine, since we only need it in push builds. +setPublicVar CI_COMMIT_RANGE "`[[ ${CIRCLE_PR_NUMBER:-false} != false ]] && echo "" || node $getCommitRangePath "$CIRCLE_BUILD_NUM" "$CIRCLE_COMPARE_URL"`"; setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}"; setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME"; setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME"; +setPublicVar CI_YARN_VERSION "1.13.0"; #################################################################################################### @@ -27,8 +39,27 @@ setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME"; #################################################################################################### setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN"; setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN"; -# Defined in https://angular-team.slack.com/apps/A0F7VRE7N-circleci. -setSecretVar CI_SECRET_SLACK_CARETAKER_WEBHOOK_URL "$SLACK_CARETAKER_WEBHOOK_URL"; + + +#################################################################################################### +# Define SauceLabs environment variables for CircleCI. +#################################################################################################### +# In order to have a meaningful SauceLabs badge on the repo page, +# the angular2-ci account is used only when pushing commits to master; +# in all other cases, the regular angular-ci account is used. +if [ "${CI_PULL_REQUEST}" = "false" ] && [ "${CI_REPO_OWNER}" = "angular" ] && [ "${CI_BRANCH}" = "master" ]; then + setPublicVar SAUCE_USERNAME "angular2-ci"; + setSecretVar SAUCE_ACCESS_KEY "693ebc16208a-0b5b-1614-8d66-a2662f4e"; +else + setPublicVar SAUCE_USERNAME "angular-ci"; + setSecretVar SAUCE_ACCESS_KEY "9b988f434ff8-fbca-8aa4-4ae3-35442987"; +fi +setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock +setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock +setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}" +# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not +# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout. +setPublicVar SAUCE_READY_FILE_TIMEOUT 120 # Source `$BASH_ENV` to make the variables available immediately. diff --git a/.circleci/get-commit-range.js b/.circleci/get-commit-range.js new file mode 100644 index 0000000000..f8cd211213 --- /dev/null +++ b/.circleci/get-commit-range.js @@ -0,0 +1,159 @@ +#!/usr/bin/env node + +/** + * **Usage:** + * ``` + * node get-commit-range [ []] + * ``` + * + * Returns the value of the `CIRCLE_COMPARE_URL` environment variable (if defined) or, if this is + * not a PR build (i.e. `CIRCLE_PR_NUMBER` is not defined), retrieves the equivalent of + * `CIRCLE_COMPARE_URL` for jobs that are part of a rerun workflow. + * + * **Context:** + * CircleCI sets the `CIRCLE_COMPARE_URL` environment variable (from which we can extract the commit + * range) on push builds (a.k.a. non-PR, non-scheduled builds). Yet, when a workflow is rerun + * (either from the beginning or from failed jobs) - e.g. when a job flakes - CircleCI does not set + * the `CIRCLE_COMPARE_URL`. + * + * **Implementation details:** + * This script relies on the fact that all rerun workflows share the same CircleCI workspace and the + * (undocumented) fact that the workspace ID happens to be the same as the workflow ID that first + * created it. + * + * For example, for a job on push build workflow, the CircleCI API will return data that look like: + * ```js + * { + * compare: 'THE_COMPARE_URL_WE_ARE_LOOKING_FOR', + * //... + * previous: { + * // ... + * build_num: 12345, + * }, + * //... + * workflows: { + * //... + * workflow_id: 'SOME_ID_A', + * workspace_id: 'SOME_ID_A', // Same as `workflow_id`. + * } + * } + * ``` + * + * If the workflow is rerun, the data for jobs on the new workflow will look like: + * ```js + * { + * compare: null, // ¯\_(ツ)_/¯ + * //... + * previous: { + * // ... + * build_num: 23456, + * }, + * //... + * workflows: { + * //... + * workflow_id: 'SOME_ID_B', + * workspace_id: 'SOME_ID_A', // Different from current `workflow_id`. + * // Same as original `workflow_id`. \o/ + * } + * } + * ``` + * + * This script uses the `previous.build_num` (which points to the previous build number on the same + * branch) to traverse the jobs backwards, until it finds a job from the original workflow. Such a + * job (if found) should also contain the compare URL. + * + * **NOTE 1:** + * This is only useful on workflows which are created by rerunning a workflow for which + * `CIRCLE_COMPARE_URL` was defined. + * + * **NOTE 2:** + * The `circleToken` will be used for CircleCI API requests if provided, but it is not needed for + * accessing the read-only endpoints that we need (as long as the current project is FOSS and the + * corresponding setting is turned on in "Advanced Settings" in the project dashboard). + * + * --- + * Inspired by https://circleci.com/orbs/registry/orb/iynere/compare-url + * (source code: https://github.com/iynere/compare-url-orb). + * + * We are not using the `compare-url` orb for the following reasons: + * 1. (By looking at the code) it would only work if the rerun workflow is the latest workflow on + * the branch (which is not guaranteed to be true). + * 2. It is less efficient (e.g. makes unnecessary CircleCI API requests for builds on different + * branches, installs extra dependencies, persists files to the workspace (as a means of passing + * the result to the calling job), etc.). + * 3. It is slightly more complicated to setup and consume than our own script. + * 4. Its implementation is more complicated than needed for our usecase (e.g. handles different git + * providers, handles newly created branches, etc.). + */ + +// Imports +const {get: httpsGet} = require('https'); + +// Constants +const API_URL_BASE = 'https://circleci.com/api/v1.1/project/github/angular/angular'; +const COMPARE_URL_RE = /^.*\/([0-9a-f]+\.\.\.[0-9a-f]+)$/i; + +// Run +_main(process.argv.slice(2)); + +// Helpers +async function _main([buildNumber, compareUrl = '', circleToken = '']) { + try { + if (!buildNumber || isNaN(buildNumber)) { + throw new Error( + 'Missing or invalid arguments.\n' + + 'Expected: buildNumber (number), compareUrl? (string), circleToken? (string)'); + } + + if (!compareUrl) { + compareUrl = await getCompareUrl(buildNumber, circleToken); + } + + const commitRangeMatch = COMPARE_URL_RE.exec(compareUrl) + const commitRange = commitRangeMatch ? commitRangeMatch[1] : ''; + + console.log(commitRange); + } catch (err) { + console.error(err); + process.exit(1); + } +} + +function getBuildInfo(buildNumber, circleToken) { + console.error(`BUILD ${buildNumber}`); + const url = `${API_URL_BASE}/${buildNumber}?circle-token=${circleToken}`; + return getJson(url); +} + +async function getCompareUrl(buildNumber, circleToken) { + let info = await getBuildInfo(buildNumber, circleToken); + const targetWorkflowId = info.workflows.workspace_id; + + while (info.workflows.workflow_id !== targetWorkflowId) { + info = await getBuildInfo(info.previous.build_num, circleToken); + } + + return info.compare || ''; +} + +function getJson(url) { + return new Promise((resolve, reject) => { + const opts = {headers: {Accept: 'application/json'}}; + const onResponse = res => { + const statusCode = res.statusCode || -1; + const isSuccess = (200 <= statusCode) && (statusCode <= 400); + let responseText = ''; + + res. + on('error', reject). + on('data', d => responseText += d). + on('end', () => isSuccess ? + resolve(JSON.parse(responseText)) : + reject(`Error getting '${url}' (status ${statusCode}):\n${responseText}`)); + }; + + httpsGet(url, opts, onResponse). + on('error', reject). + end(); + }); +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..6e593be73a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,771 @@ +# ================================================================================== +# ================================================================================== +# Angular CODEOWNERS +# ================================================================================== +# ================================================================================== +# +# Configuration of code ownership and review approvals for the angular/angular repo. +# +# More info: https://help.github.com/articles/about-codeowners/ +# + + +# ================================================ +# General rules / philosophy +# ================================================ +# +# - we trust that people do the right thing and not approve changes they don't feel confident reviewing +# - we use github teams so that we funnel code reviews to the most appropriate reviewer, this is why the team structure is fine-grained +# - we enforce that only approved PRs get merged to ensure that unreviewed code doesn't get accidentally merged +# - we delegate approval rights as much as possible so that we can scale better +# - each group must have at least one person, but several people are preferable to avoid a single point of failure issues +# - most file groups have one or two global approvers groups as fallbacks: +# - @angular/fw-global-approvers: for approving minor changes, large-scale refactorings, and emergency situations. +# - @angular/fw-global-approvers-for-docs-only-changes: for approving minor documentation-only changes that don't require engineering review +# - a small number of file groups have very limited number of reviewers because incorrect changes to the files they guard would have serious consequences (e.g. security, public api) +# +# Configuration nuances: +# +# - This configuration works in conjunction with the protected branch settings that require all changes to be made via pull requests with at least one approval. +# - This approval can come from an appropriate codeowner, or any repo collaborator (person with write access) if the PR is authored by a codeowner. +# - Each codeowners team must have write access to the repo, otherwise their reviews won't count. +# +# In the case of emergency, the repo administrators which include angular-caretaker can bypass this requirement. + + + +# ================================================ +# GitHub username registry +# (just to make this file easier to understand) +# ================================================ + +# alexeagle - Alex Eagle +# alxhub - Alex Rickabaugh +# AndrewKushnir - Andrew Kushnir +# andrewseguin - Andrew Seguin +# benlesh - Ben Lesh +# brandonroberts - Brandon Roberts +# filipesilva - Filipe Silva +# gkalpak - George Kalpakas +# hansl - Hans Larsen +# IgorMinar - Igor Minar +# jasonaden - Jason Aden +# jenniferfell - Jennifer Fell +# kara - Kara Erickson +# kyliau - Keen Yee Liau +# matsko - Matias Niemelä +# mgechev - Minko Gechev +# mhevery - Misko Hevery +# ocombe - Olivier Combe +# petebacondarwin - Pete Bacon Darwin +# pkozlowski-opensource - Pawel Kozlowski +# robwormald - Rob Wormald +# stephenfluin - Stephen Fluin +# vikerman - Vikram Subramanian + + + +###################################################################################################### +# +# Team structure and memberships +# ------------------------------ +# +# This section is here just because the GitHub UI is too hard to navigate and audit. +# +# Any changes to team structure or memberships must first be made in this file and only then +# implemented in the GitHub UI. +####################################################################################################### + + +# =========================================================== +# @angular/framework-global-approvers +# =========================================================== +# Used for approving minor changes, large-scale refactorings, and emergency situations. +# (secret team to avoid review requests, it also doesn't inherit from @angular/framework because nested teams can't be secret) +# +# - IgorMinar +# - kara +# - mhevery + + +# =========================================================== +# @angular/framework-global-approvers-for-docs-only-changes +# =========================================================== +# Used for approving minor documentation-only changes that don't require engineering review. +# (secret team to avoid review requests, it also doesn't inherit from @angular/framework because nested teams can't be secret) +# +# - brandonroberts +# - gkalpak +# - jenniferfell +# - petebacondarwin + + +# =========================================================== +# @angular/fw-animations +# =========================================================== +# +# - matsko + + +# =========================================================== +# @angular/tools-bazel +# =========================================================== +# +# - alexeagle +# - kyliau +# - IgorMinar +# - mgechev + + +# =========================================================== +# @angular/tools-cli +# =========================================================== +# +# - alexeagle +# - filipesilva +# - hansl +# - mgechev + + +# =========================================================== +# @angular/fw-compiler +# =========================================================== +# +# - alxhub + + +# =========================================================== +# @angular/fw-ngcc +# =========================================================== +# +# - alxhub +# - gkalpak +# - petebacondarwin + + +# =========================================================== +# @angular/fw-core +# =========================================================== +# +# - alxhub +# - AndrewKushnir +# - kara +# - mhevery +# - pkozlowski-opensource + + +# =========================================================== +# @angular/fw-http +# =========================================================== +# +# - alxhub +# - IgorMinar + + +# =========================================================== +# @angular/fw-elements +# =========================================================== +# +# - andrewseguin +# - gkalpak +# - robwormald + + +# =========================================================== +# @angular/fw-forms +# =========================================================== +# +# - kara + + +# =========================================================== +# @angular/tools-language-service +# =========================================================== +# +# - kyliau + + +# =========================================================== +# @angular/fw-server +# =========================================================== +# +# - alxhub +# - vikerman + + +# =========================================================== +# @angular/fw-router +# =========================================================== +# +# - jasonaden + + +# =========================================================== +# @angular/fw-service-worker +# =========================================================== +# +# - alxhub +# - gkalpak +# - IgorMinar + + +# =========================================================== +# @angular/fw-upgrade +# =========================================================== +# +# - gkalpak +# - petebacondarwin + + +# =========================================================== +# @angular/fw-testing +# =========================================================== +# +# - vikerman + + +# =========================================================== +# @angular/fw-i18n +# =========================================================== +# +# - AndrewKushnir +# - mhevery +# - ocombe +# - vikerman + + +# =========================================================== +# @angular/fw-security +# =========================================================== +# +# - IgorMinar +# - mhevery + + +# =========================================================== +# @angular/tools-benchpress +# =========================================================== +# +# - alxhub + + +# =========================================================== +# @angular/fw-integration +# =========================================================== +# +# - alexeagle +# - IgorMinar +# - mhevery + + +# =========================================================== +# @angular/docs-infra +# =========================================================== +# +# - brandonroberts +# - gkalpak +# - IgorMinar +# - petebacondarwin + + +# =========================================================== +# @angular/fw-docs-intro +# =========================================================== +# +# - brandonroberts +# - IgorMinar +# - stephenfluin + + +# =========================================================== +# @angular/fw-docs-observables +# =========================================================== +# +# - benlesh +# - jasonaden + + +# =========================================================== +# @angular/fw-docs-packaging +# =========================================================== +# +# - alexeagle +# - IgorMinar + + +# =========================================================== +# @angular/fw-docs-marketing +# =========================================================== +# +# - IgorMinar +# - stephenfluin + + +# =========================================================== +# @angular/fw-public-api +# =========================================================== +# +# - IgorMinar + + +# =========================================================== +# @angular/fw-dev-infra +# =========================================================== +# +# - alexeagle +# - IgorMinar + + + + + +###################################################################################################### +# +# CODEOWNERS rules +# ----------------- +# +# All the following rules are applied in the order specified in this file. +# The last rule that matches wins! +# +# See https://git-scm.com/docs/gitignore#_pattern_format for pattern syntax docs. +# +###################################################################################################### + + +# ================================================ +# Default Owners +# (in case no pattern matches a path in a PR - this should be treated as a bug and result in adding the path to CODEOWNERS) +# ================================================ + +* @IgorMinar @angular/framework-global-approvers + + + +# ================================================ +# @angular/animations +# ================================================ + +/packages/animations/** @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/platform-browser/animations/** @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/animations.md @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/animations/** @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/animations/** @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/bazel +# ================================================ + +/packages/bazel/** @angular/tools-bazel @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/compiler +# @angular/compiler-cli +# ================================================ + +/packages/compiler/** @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/compiler-cli/** @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/aot-compiler.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# packages/compiler-cli/src/ngcc/ +# ================================================ + +/packages/compiler-cli/src/ngcc/** @angular/fw-ngcc @angular/framework-global-approvers + + + +# ================================================ +# @angular/compiler-cli/ngtools +# +# a rule to control API changes between @angular/compiler-cli and @angular/cli +# ================================================ + +/packages/compiler-cli/src/ngtools/** @angular/tools-cli @angular/framework-global-approvers + + + +# ================================================ +# @angular/core +# @angular/common (except @angular/common/http) +# @angular/platform-browser +# @angular/platform-browser-dynamic +# @angular/platform-webworker +# @angular/platform-webworker-dynamic +# ================================================ + +/packages/core/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/common/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/platform-browser/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/platform-browser-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/platform-webworker/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/platform-webworker-dynamic/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/attribute-directives.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/attribute-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/attribute-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/bootstrapping.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/bootstrapping/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/component-interaction.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/component-interaction/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/component-interaction/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/component-styles.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/component-styles/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/dependency-injection.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/dependency-injection/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/dependency-injection/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/dependency-injection-in-action.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/dependency-injection-in-action/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/dependency-injection-in-action/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/dependency-injection-pattern.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/dynamic-component-loader.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/dynamic-component-loader/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/dynamic-component-loader/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/entry-components.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/feature-modules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/feature-modules/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/feature-modules/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/frequent-ngmodules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/frequent-ngmodules/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/hierarchical-dependency-injection.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/hierarchical-dependency-injection/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/lazy-loading-ngmodules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/lazy-loading-ngmodules/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/lazy-loading-ngmodules/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/lifecycle-hooks.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/lifecycle-hooks/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/lifecycle-hooks/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/examples/ngcontainer/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/ngcontainer/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/ngmodules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/ngmodules/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/ngmodule/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/ngmodule/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/ngmodule-api.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/ngmodule-faq.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/ngmodule-faq/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/ngmodule-vs-jsmodule.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/module-types.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/template-syntax.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/template-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/pipes.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/pipes/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/pipes/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/providers.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/providers/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/singleton-services.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/set-document-title.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/set-document-title/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/set-document-title/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/sharing-ngmodules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + +/aio/content/guide/structural-directives.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/structural-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/structural-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/common/http +# @angular/http +# ================================================ + +/packages/common/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/http.md @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/http/** @angular/fw-http @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/elements +# ================================================ + +/packages/elements/** @angular/fw-elements @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/elements/** @angular/fw-elements @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/elements/** @angular/fw-elements @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/elements.md @angular/fw-elements @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + +# ================================================ +# @angular/forms +# ================================================ + +/packages/forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/forms.md @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/forms-overview.md @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/forms-overview/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/forms-overview/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/form-validation.md @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/form-validation/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/form-validation/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/dynamic-form.md @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/dynamic-form/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/dynamic-form/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/reactive-forms.md @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/reactive-forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/reactive-forms/** @angular/fw-forms @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/language-service +# ================================================ + +/packages/language-service/** @angular/tools-language-service @angular/framework-global-approvers +/aio/content/guide/language-service.md @angular/tools-language-service @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/language-service/** @angular/tools-language-service @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/platform-server +# ================================================ + +/packages/platform-server/** @angular/fw-server @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/universal.md @angular/fw-server @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/universal/** @angular/fw-server @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/router +# ================================================ + +/packages/router/** @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/router.md @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/router/** @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/router/** @angular/fw-router @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/service-worker +# ================================================ + +/packages/service-worker/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/service-worker-getting-started.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/service-worker-getting-started/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/service-worker-communications.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/service-worker-config.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/service-worker-devops.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/service-worker-intro.md @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/service-worker/** @angular/fw-service-worker @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/upgrade +# ================================================ + +/packages/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/examples/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/upgrade.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/upgrade-module/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/upgrade/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/upgrade-phonecat-1-typescript/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/upgrade-phonecat-2-hybrid/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/upgrade-phonecat-3-final/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/upgrade-performance.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/ajs-quick-reference.md @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/ajs-quick-reference/** @angular/fw-upgrade @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular/**/testing +# ================================================ + +testing/** @angular/fw-testing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/testing.md @angular/fw-testing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/testing/** @angular/fw-testing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/testing/** @angular/fw-testing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular i18n +# ================================================ + +/packages/core/src/i18n/** @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/core/src/render3/i18n.ts @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/core/src/render3/i18n.md @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/core/src/render3/interfaces/i18n.ts @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/common/locales/** @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/common/src/i18n/** @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/common/src/pipes/date_pipe.ts @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/common/src/pipes/i18n_plural_pipe.ts @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/common/src/pipes/i18n_select_pipe.ts @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/common/src/pipes/number_pipe.ts @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/compiler/src/i18n/** @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/compiler/src/render3/view/i18n/** @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/packages/compiler-cli/src/extract_i18n.ts @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/i18n.md @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/i18n/** @angular/fw-i18n @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# @angular security +# ================================================ + +/packages/core/src/sanitization/** @angular/fw-security +/packages/core/test/linker/security_integration_spec.ts @angular/fw-security +/packages/compiler/src/schema/** @angular/fw-security +/packages/platform-browser/src/security/** @angular/fw-security +/aio/content/guide/security.md @angular/fw-security @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/security/** @angular/fw-security @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# benchpress +# ================================================ + +/packages/benchpress/** @angular/tools-benchpress @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# /integration/* +# ================================================ + +/integration/** @angular/fw-integration @angular/framework-global-approvers + + + +# ================================================ +# docs-infra +# ================================================ + +/aio/* @angular/docs-infra @angular/framework-global-approvers +/aio/aio-builds-setup/** @angular/docs-infra @angular/framework-global-approvers +/aio/scripts/** @angular/docs-infra @angular/framework-global-approvers +/aio/src/** @angular/docs-infra @angular/framework-global-approvers +/aio/tests/** @angular/docs-infra @angular/framework-global-approvers +/aio/tools/** @angular/docs-infra @angular/framework-global-approvers + + + +# ================================================ +# Docs: getting started & tutorial +# ================================================ + +/aio/content/guide/quickstart.md @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/tutorial/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# Docs: observables +# ================================================ + +/aio/content/examples/observables/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/observables/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/observables.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/comparing-observables.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/observables-in-angular/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/guide/observables-in-angular/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/observables-in-angular.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/practical-observable-usage/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/practical-observable-usage.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/rx-library/** @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/rx-library.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# Docs: packaging, tooling, releasing +# ================================================ + +/aio/content/guide/npm-packages.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/browser-support.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/typescript-configuration.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/setup-systemjs-anatomy.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/setup.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/examples/setup/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/deployment.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/releases.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/updating.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# Docs: marketing +# ================================================ + +/aio/content/marketing/** @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/images/marketing/** @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/navigation.json @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/license.md @angular/fw-docs-marketing @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + + + +# ================================================ +# Build & CI Owners +# ================================================ + +/* @angular/fw-dev-infra +/.buildkite/** @angular/fw-dev-infra +/.circleci/** @angular/fw-dev-infra +/.github/** @angular/fw-dev-infra +/docs/BAZEL.md @angular/fw-dev-infra +/scripts/** @angular/fw-dev-infra +/third_party/** @angular/fw-dev-infra +/tools/** @angular/fw-dev-infra +*.bzl @angular/fw-dev-infra + +# ================================================ +# Material CI +# ================================================ + +/tools/material-ci/** @angular/fw-core @angular/fw-dev-infra + + +# ================================================ +# Public API +# ================================================ + +/tools/public_api_guard/** @angular/fw-public-api + + + +# ================================================ +# CODEOWNERS Owners owners ... +# ================================================ + +/.github/CODEOWNERS @IgorMinar @angular/framework-global-approvers diff --git a/.github/angular-robot.yml b/.github/angular-robot.yml index e71ae2023d..c79c984a40 100644 --- a/.github/angular-robot.yml +++ b/.github/angular-robot.yml @@ -41,6 +41,7 @@ merge: exclude: - "packages/*" - "packages/bazel/*" + - "packages/bazel/src/api-extractor/**" - "packages/bazel/src/builders/**" - "packages/bazel/src/ng_package/**" - "packages/bazel/src/protractor/**" @@ -58,7 +59,6 @@ merge: - "**/package.json" - "**/tsconfig-build.json" - "**/tsconfig.json" - - "**/rollup.config.js" - "**/BUILD.bazel" - "**/*.md" - "packages/**/integrationtest/**" @@ -81,7 +81,7 @@ merge: # require that the PR has reviews from all requested reviewers # # This enables us to request reviews from both eng and tech writers, or multiple eng folks, and prevents accidental merges. - # Rather than merging PRs with pending reviews, if all PullApprove requirements are satisfied and additional reviews are not needed pending reviewers should be removed via GitHub UI (this also leaves an audit trail behind these decisions). + # Rather than merging PRs with pending reviews, if all approvals are obtained and additional reviews are not needed, any pending reviewers should be removed via GitHub UI (this also leaves an audit trail behind these decisions). requireReviews: true, # whether the PR shouldn't have a conflict with the base branch @@ -101,10 +101,13 @@ merge: # list of PR statuses that need to be successful requiredStatuses: - - "continuous-integration/travis-ci/pr" - - "code-review/pullapprove" - "ci/circleci: build" - "ci/circleci: lint" + - "ci/circleci: publish_snapshot" + - "ci/angular: size" + - "cla/google" + - "google3" + # the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable # {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option diff --git a/.gitignore b/.gitignore index 038b705638..d457312e27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ .DS_STORE /dist/ -/bazel-* +/bazel-out /integration/bazel/bazel-* e2e_test.* node_modules -bower_components tools/gulp-tasks/cldr/cldr-data/ # Include when developing application packages. @@ -13,9 +12,9 @@ pubspec.lock .c9 .idea/ .settings/ +.vscode/launch.json *.swo modules/.settings -.vscode modules/.vscode # Don't check in secret files diff --git a/.nvmrc b/.nvmrc index fe6d2ac749..f9fb144f9a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -10.9.0 +10.15.0 diff --git a/.pullapprove.yml b/.pullapprove.yml deleted file mode 100644 index 4c6f2362ed..0000000000 --- a/.pullapprove.yml +++ /dev/null @@ -1,541 +0,0 @@ -# Configuration for pullapprove.com -# -# Approval access and primary role is determined by info in the project ownership spreadsheet: -# https://docs.google.com/spreadsheets/d/1-HIlzfbPYGsPr9KuYMe6bLfc4LXzPjpoALqtYRYTZB0/edit?pli=1#gid=0&vpid=A5 -# -# === GitHub username to Full name map === -# -# alexeagle - Alex Eagle -# alxhub - Alex Rickabaugh -# andrewseguin - Andrew Seguin -# benlesh - Ben Lesh -# brandonroberts - Brandon Roberts -# brocco - Mike Brocchi -# filipesilva - Filipe Silva -# gkalpak - George Kalpakas -# hansl - Hans Larsen -# IgorMinar - Igor Minar -# jasonaden - Jason Aden -# jenniferfell - Jennifer Fell -# kara - Kara Erickson -# kyliau - Keen Yee Liau -# matsko - Matias Niemelä -# mhevery - Misko Hevery -# petebacondarwin - Pete Bacon Darwin -# pkozlowski-opensource - Pawel Kozlowski -# robwormald - Rob Wormald -# vikerman - Vikram Subramanian - - -version: 2 - -group_defaults: - required: 1 - reset_on_reopened: - enabled: true - approve_by_comment: - enabled: false - # see http://docs.pullapprove.com/groups/author_approval/ - author_approval: - # If the author is a reviewer on the PR, they will automatically have an "approved" status. - auto: true - -groups: - # Require all PRs to have at least one approval from *someone* - all: - users: all - required: 1 - rejection_value: -999 - # In this group, your self-approval does not count - author_approval: - auto: false - ignored: true - files: - include: - - "*" - - root: - conditions: - files: - include: - - "*" - exclude: - - "WORKSPACE" - - "BUILD.bazel" - - ".circleci/*" - - "aio/*" - - "integration/*" - - "modules/*" - - "packages/*" - - "tools/*" - users: - - alexeagle - - IgorMinar - - mhevery - - public-api: - conditions: - files: - include: - - "tools/public_api_guard/*" - users: - - IgorMinar - - mhevery - - bazel: - conditions: - files: - include: - - "WORKSPACE" - - ".bazel*" - - "*.bazel" - - "*.bzl" - - "packages/bazel/*" - - "/docs/BAZEL.md" - users: - - alexeagle #primary - - kyliau - - IgorMinar #fallback - - mhevery - - vikerman #fallback - - kara - - build-and-ci: - conditions: - files: - include: - - "*.yml" - - "*.json" - - "*.lock" - - "tools/*" - exclude: - - "aio/*" - - "packages/core/test/bundling/*" - - "tools/public_api_guard/*" - users: - - IgorMinar #primary - - alexeagle - - jasonaden - - mhevery #fallback - - integration: - conditions: - files: - - "integration/*" - users: - - alexeagle - - mhevery - - IgorMinar #fallback - - core: - conditions: - files: - - "packages/core/*" - - "aio/content/guide/bootstrapping.md" - - "aio/content/examples/bootstrapping/*" - - "aio/content/guide/attribute-directives.md" - - "aio/content/examples/attribute-directives/*" - - "aio/content/images/guide/attribute-directives/*" - - "aio/content/guide/structural-directives.md" - - "aio/content/examples/structural-directives/*" - - "aio/content/images/guide/structural-directives/*" - - "aio/content/guide/dynamic-component-loader.md" - - "aio/content/examples/dynamic-component-loader/*" - - "aio/content/images/guide/dynamic-component-loader/*" - - "aio/content/guide/template-syntax.md" - - "aio/content/examples/template-syntax/*" - - "aio/content/images/guide/template-syntax/*" - - "aio/content/guide/dependency-injection.md" - - "aio/content/examples/dependency-injection/*" - - "aio/content/images/guide/dependency-injection/*" - - "aio/content/guide/dependency-injection-in-action.md" - - "aio/content/examples/dependency-injection-in-action/*" - - "aio/content/images/guide/dependency-injection-in-action/*" - - "aio/content/guide/hierarchical-dependency-injection.md" - - "aio/content/examples/hierarchical-dependency-injection/*" - - "aio/content/guide/singleton-services.md" - - "aio/content/guide/dependency-injection-pattern.md" - - "aio/content/guide/providers.md" - - "aio/content/examples/providers/*" - - "aio/content/guide/component-interaction.md" - - "aio/content/examples/component-interaction/*" - - "aio/content/images/guide/component-interaction/*" - - "aio/content/guide/component-styles.md" - - "aio/content/examples/component-styles/*" - - "aio/content/guide/lifecycle-hooks.md" - - "aio/content/examples/lifecycle-hooks/*" - - "aio/content/images/guide/lifecycle-hooks/*" - - "aio/content/examples/ngcontainer/*" - - "aio/content/images/guide/ngcontainer/*" - - "aio/content/guide/pipes.md" - - "aio/content/examples/pipes/*" - - "aio/content/images/guide/pipes/*" - - "aio/content/guide/entry-components.md" - - "aio/content/guide/set-document-title.md" - - "aio/content/examples/set-document-title/*" - - "aio/content/images/guide/set-document-title/*" - - "aio/content/guide/ngmodules.md" - - "aio/content/examples/ngmodules/*" - - "aio/content/examples/ngmodule/*" - - "aio/content/images/guide/ngmodule/*" - - "aio/content/guide/ngmodule-faq.md" - - "aio/content/examples/ngmodule-faq/*" - - "aio/content/guide/module-types.md" - - "aio/content/guide/sharing-ngmodules.md" - - "aio/content/guide/frequent-ngmodules.md" - - "aio/content/images/guide/frequent-ngmodules/*" - - "aio/content/guide/ngmodule-api.md" - - "aio/content/guide/ngmodule-vs-jsmodule.md" - - "aio/content/guide/feature-modules.md" - - "aio/content/examples/feature-modules/*" - - "aio/content/images/guide/feature-modules/*" - - "aio/content/guide/lazy-loading-ngmodules.md" - - "aio/content/examples/lazy-loading-ngmodules/*" - - "aio/content/images/guide/lazy-loading-ngmodules" - users: - - mhevery #primary - - jasonaden - - kara - - IgorMinar - - jenniferfell #docs only - - animations: - conditions: - files: - - "packages/animations/*" - - "packages/platform-browser/animations/*" - - "aio/content/guide/animations.md" - - "aio/content/examples/animations/*" - - "aio/content/images/guide/animations/*" - users: - - matsko #primary - - mhevery #fallback - - IgorMinar #fallback - - jenniferfell #docs only - - kara - - compiler/i18n: - conditions: - files: - - "packages/compiler/src/i18n/*" - - "aio/content/guide/i18n.md" - - "aio/content/examples/i18n/*" - users: - - alxhub #primary - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - kara - - compiler: - conditions: - files: - - "packages/compiler/*" - - "aio/content/guide/aot-compiler.md" - users: - - alxhub #primary - - mhevery - - IgorMinar #fallback - - jenniferfell #docs only - - kara - - compiler-cli/ngtools: - conditions: - files: - - "packages/compiler-cli/src/ngtools*" - users: - - hansl - - filipesilva #fallback - - IgorMinar #fallback - - kara - - compiler-cli: - conditions: - files: - include: - - "packages/compiler-cli/*" - exclude: - - "packages/compiler-cli/src/ngtools*" - users: - - alexeagle - - alxhub - - IgorMinar #fallback - - mhevery #fallback - - kara - - common: - conditions: - files: - include: - - "packages/common/*" - exclude: - - "packages/common/http/*" - users: - - pkozlowski-opensource #primary - - IgorMinar #fallback - - mhevery #fallback - - kara - - forms: - conditions: - files: - - "packages/forms/*" - - "aio/content/guide/forms.md" - - "aio/content/examples/forms/*" - - "aio/content/images/guide/forms/*" - - "aio/content/guide/forms-overview.md" - - "aio/content/examples/forms-overview/*" - - "aio/content/images/guide/forms-overview/*" - - "aio/content/guide/form-validation.md" - - "aio/content/examples/form-validation/*" - - "aio/content/images/guide/form-validation/*" - - "aio/content/guide/dynamic-form.md" - - "aio/content/examples/dynamic-form/*" - - "aio/content/images/guide/dynamic-form/*" - - "aio/content/guide/reactive-forms.md" - - "aio/content/examples/reactive-forms/*" - - "aio/content/images/guide/reactive-forms/*" - users: - - kara #primary - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - http: - conditions: - files: - - "packages/common/http/*" - - "packages/http/*" - - "aio/content/guide/http.md" - - "aio/content/examples/http/*" - - "aio/content/images/guide/http/*" - users: - - alxhub #primary - - IgorMinar - - mhevery #fallback - - jenniferfell #docs only - - language-service: - conditions: - files: - - "packages/language-service/*" - - "aio/content/guide/language-service.md" - - "aio/content/images/guide/language-service/*" - users: - - kyliau #primary - # needs secondary - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - router: - conditions: - files: - - "packages/router/*" - - "aio/content/guide/router.md" - - "aio/content/examples/router/*" - - "aio/content/images/guide/router/*" - users: - - jasonaden #primary - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - kara - - testing: - conditions: - files: - - "*/testing/*" - - "aio/content/guide/testing.md" - - "aio/content/examples/testing/*" - - "aio/content/images/guide/testing/*" - users: - - vikerman - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - upgrade: - conditions: - files: - - "packages/upgrade/*" - - "aio/content/guide/upgrade.md" - - "aio/content/examples/upgrade-module/*" - - "aio/content/images/guide/upgrade/*" - - "aio/content/examples/upgrade-phonecat-1-typescript/*" - - "aio/content/examples/upgrade-phonecat-2-hybrid/*" - - "aio/content/examples/upgrade-phonecat-3-final/*" - - "aio/content/guide/upgrade-performance.md" - - "aio/content/guide/ajs-quick-reference.md" - - "aio/content/examples/ajs-quick-reference/*" - users: - - petebacondarwin #primary - - gkalpak - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - kara - - platform-browser: - conditions: - files: - - "packages/platform-browser/*" - users: - - mhevery #primary - # needs secondary - - IgorMinar #fallback - - kara - - platform-server: - conditions: - files: - - "packages/platform-server/*" - - "aio/content/guide/universal.md" - - "aio/content/examples/universal/*" - users: - - vikerman #primary - - alxhub #secondary - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - platform-webworker: - conditions: - files: - - "packages/platform-webworker/*" - users: - - mhevery #primary - # needs secondary - - IgorMinar #fallback - - kara - - service-worker: - conditions: - files: - - "packages/service-worker/*" - - "aio/content/guide/service-worker-getting-started.md" - - "aio/content/examples/service-worker-getting-started/*" - - "aio/content/guide/service-worker-communications.md" - - "aio/content/guide/service-worker-config.md" - - "aio/content/guide/service-worker-devops.md" - - "aio/content/guide/service-worker-intro.md" - - "aio/content/images/guide/service-worker/*" - users: - - gkalpak #primary - - alxhub - - IgorMinar - - mhevery #fallback - - jenniferfell #docs only - - elements: - conditions: - files: - - "packages/elements/*" - - "aio/content/examples/elements/*" - - "aio/content/images/guide/elements/*" - - "aio/content/guide/elements.md" - users: - - andrewseguin #primary - - gkalpak - - robwormald - - IgorMinar #fallback - - mhevery #fallback - - jenniferfell #docs only - - kara - - benchpress: - conditions: - files: - - "packages/benchpress/*" - users: - - alxhub # primary - # needs secondary - - IgorMinar #fallback - - mhevery #fallback - - docs-infra: - conditions: - files: - include: - - "aio/*" - exclude: - - "aio/content/*" - users: - - petebacondarwin #primary - - IgorMinar - - gkalpak - - mhevery #fallback - - docs/guide-and-tutorial: - conditions: - files: - include: - - "aio/content/*" - exclude: - - "aio/content/marketing/*" - - "aio/content/navigation.json" - - "aio/content/license.md" - users: - - stephenfluin - - jenniferfell - - brandonroberts - - petebacondarwin - - gkalpak - - IgorMinar - - mhevery #fallback - - docs/marketing: - conditions: - files: - include: - - "aio/content/marketing/*" - - "aio/content/images/marketing/*" - - "aio/content/navigation.json" - - "aio/content/license.md" - users: - - stephenfluin - - petebacondarwin - - gkalpak - - IgorMinar - - robwormald - - mhevery #fallback - - docs/observables: - conditions: - files: - - "aio/content/examples/observables/*" - - "aio/content/images/guide/observables/*" - - "aio/content/guide/observables.md" - - "aio/content/guide/comparing-observables.md" - - "aio/content/examples/observables-in-angular/*" - - "aio/content/images/guide/observables-in-angular/*" - - "aio/content/guide/observables-in-angular.md" - - "aio/content/examples/practical-observable-usage/*" - - "aio/content/guide/practical-observable-usage.md" - - "aio/content/examples/rx-library/*" - - "aio/content/guide/rx-library.md" - users: - - jasonaden - - benlesh - - IgorMinar - - mhevery - - jenniferfell #docs only - - docs/packaging: - conditions: - files: - - "aio/content/guide/npm-packages.md" - - "aio/content/guide/browser-support.md" - - "aio/content/guide/typescript-configuration.md" - - "aio/content/guide/setup-systemjs-anatomy.md" - - "aio/content/examples/setup/*" - - "aio/content/guide/setup.md" - - "aio/content/guide/deployment.md" - - "aio/content/guide/releases.md" - - "aio/content/guide/updating.md" - users: - - IgorMinar #primary - - alexeagle - - hansl - - mhevery #fallback - - jenniferfell #docs only diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..0fa0d13829 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "editor.formatOnSave": true, + // Please install http://clang.llvm.org/docs/ClangFormat.html in VSCode to take advantage of clang-format + "clang-format.executable": "${workspaceRoot}/node_modules/.bin/clang-format", + "files.watcherExclude": { + "**/.git/objects/**": true, + "**/.git/subtree-cache/**": true, + "**/node_modules/**": true, + "**/bazel-out/**": true, + "**/dist/**": true, + }, + "search.exclude": { + "**/node_modules": true, + "**/bower_components": true, + "**/bazel-out": true, + "**/dist": true, + }, + "git.ignoreLimitWarning": true, +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b0367967f3..a0f3b5ad2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,280 @@ - -# [7.2.0-rc.0](https://github.com/angular/angular/compare/7.2.0-beta.2...7.2.0-rc.0) (2018-12-18) + +# [8.0.0-beta.4](https://github.com/angular/angular/compare/8.0.0-beta.3...8.0.0-beta.4) (2019-02-15) + + +### Bug Fixes + +* **bazel:** Install angular repo before yarn_install ([#28670](https://github.com/angular/angular/issues/28670)) ([49fb8c3](https://github.com/angular/angular/commit/49fb8c3)) +* **bazel:** Turn on strict action env ([#28675](https://github.com/angular/angular/issues/28675)) ([2ea030c](https://github.com/angular/angular/commit/2ea030c)) +* **compiler:** ensure that event handlers have the correct source spans ([#28055](https://github.com/angular/angular/issues/28055)) ([cffd862](https://github.com/angular/angular/commit/cffd862)) +* **compiler:** fix two existing expression transformer issues ([#28523](https://github.com/angular/angular/issues/28523)) ([09af7ea](https://github.com/angular/angular/commit/09af7ea)) +* **compiler:** markup lexer should not capture quotes in attribute value ([#28055](https://github.com/angular/angular/issues/28055)) ([c0dac18](https://github.com/angular/angular/commit/c0dac18)) +* **compiler:** support `sourceMappingURL` comments that have trailing lines ([#28055](https://github.com/angular/angular/issues/28055)) ([0d6fdec](https://github.com/angular/angular/commit/0d6fdec)) +* **compiler-cli:** don't throw when listing lazy routes for an entry route ([#28372](https://github.com/angular/angular/issues/28372)) ([2caa419](https://github.com/angular/angular/commit/2caa419)) +* **core:** improve global variable detection ([#28679](https://github.com/angular/angular/issues/28679)) ([77eee42](https://github.com/angular/angular/commit/77eee42)), closes [#16545](https://github.com/angular/angular/issues/16545) +* **core:** use the correct generated URL for JIT compiled components ([#28055](https://github.com/angular/angular/issues/28055)) ([4f46bfb](https://github.com/angular/angular/commit/4f46bfb)) +* **core:** use the correct template URL in render3 JIT compilation ([#28055](https://github.com/angular/angular/issues/28055)) ([a5ea55a](https://github.com/angular/angular/commit/a5ea55a)) +* **forms:** mark form as pristine before emitting value and status change events ([#28395](https://github.com/angular/angular/issues/28395)) ([1df3aef](https://github.com/angular/angular/commit/1df3aef)), closes [#28130](https://github.com/angular/angular/issues/28130) +* **router:** redirect to root url when returned as UrlTree from guard ([#28271](https://github.com/angular/angular/issues/28271)) ([50732e1](https://github.com/angular/angular/commit/50732e1)), closes [#27845](https://github.com/angular/angular/issues/27845) +* **router:** set href when routerLink is used on an 'area' element ([#28441](https://github.com/angular/angular/issues/28441)) ([ed0cf7e](https://github.com/angular/angular/commit/ed0cf7e)), closes [#28401](https://github.com/angular/angular/issues/28401) + + +### Features + +* optionally save complete performance log in chrome benchpress tests ([#27551](https://github.com/angular/angular/issues/27551)) ([d42f32c](https://github.com/angular/angular/commit/d42f32c)) +* **bazel:** add dts bundler as action to ng_module ([#28588](https://github.com/angular/angular/issues/28588)) ([3d39100](https://github.com/angular/angular/commit/3d39100)) +* **compiler:** support tokenizing a sub-section of an input string ([#28055](https://github.com/angular/angular/issues/28055)) ([eeb560a](https://github.com/angular/angular/commit/eeb560a)) +* **compiler:** support tokenizing escaped strings ([#28055](https://github.com/angular/angular/issues/28055)) ([2424184](https://github.com/angular/angular/commit/2424184)) +* **compiler-cli:** no longer re-export external symbols by default ([#28633](https://github.com/angular/angular/issues/28633)) ([91b7152](https://github.com/angular/angular/commit/91b7152)), closes [#28594](https://github.com/angular/angular/issues/28594) [#25644](https://github.com/angular/angular/issues/25644) [#25644](https://github.com/angular/angular/issues/25644) + + + + +## [7.2.5](https://github.com/angular/angular/compare/7.2.4...7.2.5) +(2019-02-15) + + +### Bug Fixes + +* **compiler-cli:** diagnostics should respect "newLine" compiler option + ([#28550](https://github.com/angular/angular/issues/28550)) + ([ce750e6](https://github.com/angular/angular/commit/ce750e6)) +* **router:** redirect to root url when returned as UrlTree from guard + ([#28271](https://github.com/angular/angular/issues/28271)) + ([1e58a21](https://github.com/angular/angular/commit/1e58a21)), closes + [#27845](https://github.com/angular/angular/issues/27845) +* **router:** set href when routerLink is used on an 'area' element + ([#28441](https://github.com/angular/angular/issues/28441)) + ([d491a20](https://github.com/angular/angular/commit/d491a20)), closes + [#28401](https://github.com/angular/angular/issues/28401) + + + + +# [8.0.0-beta.3](https://github.com/angular/angular/compare/8.0.0-beta.2...8.0.0-beta.3) (2019-02-06) + + +### Bug Fixes + +* **bazel:** Bazel builder resolves with require.resolve() ([#28478](https://github.com/angular/angular/issues/28478)) ([36902e2](https://github.com/angular/angular/commit/36902e2)) +* **bazel:** fix integration test for bazel-schematics ([#28460](https://github.com/angular/angular/issues/28460)) ([b1e099b](https://github.com/angular/angular/commit/b1e099b)) +* **compiler-cli:** base synthetic filepaths on input filepath ([#28453](https://github.com/angular/angular/issues/28453)) ([7219639](https://github.com/angular/angular/commit/7219639)) +* **compiler-cli:** diagnostics should respect "newLine" compiler option ([#28352](https://github.com/angular/angular/issues/28352)) ([4aa189d](https://github.com/angular/angular/commit/4aa189d)) +* **core:** remove createInjector() from public API ([#28509](https://github.com/angular/angular/issues/28509)) ([f2621db](https://github.com/angular/angular/commit/f2621db)) + + +### Performance Improvements + +* pngcrush all pngs ([#28479](https://github.com/angular/angular/issues/28479)) ([ec6e730](https://github.com/angular/angular/commit/ec6e730)), closes [#18243](https://github.com/angular/angular/issues/18243) + + + + +## [7.2.4](https://github.com/angular/angular/compare/7.2.3...7.2.4) (2019-02-06) + + +### Bug Fixes + +* **bazel:** Bazel builder resolves with require.resolve() ([#28478](https://github.com/angular/angular/issues/28478)) ([d85d396](https://github.com/angular/angular/commit/d85d396)) +* **bazel:** fix integration test for bazel-schematics ([#28460](https://github.com/angular/angular/issues/28460)) ([449da8c](https://github.com/angular/angular/commit/449da8c)) + + +### Performance Improvements + +* pngcrush all pngs ([#28479](https://github.com/angular/angular/issues/28479)) ([1a25144](https://github.com/angular/angular/commit/1a25144)), closes [#18243](https://github.com/angular/angular/issues/18243) + + + + +# [8.0.0-beta.2](https://github.com/angular/angular/compare/8.0.0-beta.1...8.0.0-beta.2) (2019-01-30) + + +### Bug Fixes + +* **bazel:** also pass afterDeclarations transformers to emitWithTsickle ([#28342](https://github.com/angular/angular/issues/28342)) ([70e426b](https://github.com/angular/angular/commit/70e426b)) +* **forms:** don't override form group's dirty state when disabling controls ([#24591](https://github.com/angular/angular/issues/24591)) ([ef67282](https://github.com/angular/angular/commit/ef67282)) + + +### Features + +* **compiler-cli:** expose ngtsc as a TscPlugin ([#28435](https://github.com/angular/angular/issues/28435)) ([a227c52](https://github.com/angular/angular/commit/a227c52)) + + +### Performance Improvements + +* **core:** be more consistent about typeof checks ([#28400](https://github.com/angular/angular/issues/28400)) ([9af18c2](https://github.com/angular/angular/commit/9af18c2)) + + + + +## [7.2.3](https://github.com/angular/angular/compare/7.2.2...7.2.3) (2019-01-30) + + +### Bug Fixes + +* **bazel:** add [@npm](https://github.com/npm)//tslib dep to e2e ts_library target in bazel-workspace schematic ([#28358](https://github.com/angular/angular/issues/28358)) ([8cee56e](https://github.com/angular/angular/commit/8cee56e)) +* **bazel:** Bazel-workspace schematics should run in ScopedTree ([#28349](https://github.com/angular/angular/issues/28349)) ([260ac20](https://github.com/angular/angular/commit/260ac20)) +* **bazel:** Builder should invoke local bazel/iblaze ([#28303](https://github.com/angular/angular/issues/28303)) ([12b8a6e](https://github.com/angular/angular/commit/12b8a6e)) +* **bazel:** ng-new should run yarn install ([#28381](https://github.com/angular/angular/issues/28381)) ([a9d46e4](https://github.com/angular/angular/commit/a9d46e4)) + + +### Performance Improvements + +* yarn version upgrade ([#28360](https://github.com/angular/angular/issues/28360)) ([cc1b2a5](https://github.com/angular/angular/commit/cc1b2a5)) + + + + +# [8.0.0-beta.1](https://github.com/angular/angular/compare/8.0.0-beta.0...8.0.0-beta.1) (2019-01-22) + + +### Bug Fixes + +* **bazel:** increase node memory limit for ng_module rule to prevent OOM for big modules ([#28237](https://github.com/angular/angular/issues/28237)) ([73616ab](https://github.com/angular/angular/commit/73616ab)) +* **router:** `skipLocationChange` with named outlets ([#28300](https://github.com/angular/angular/issues/28300)) ([50df897](https://github.com/angular/angular/commit/50df897)), closes [#27680](https://github.com/angular/angular/issues/27680) [#28200](https://github.com/angular/angular/issues/28200) + + +### Features + +* **bazel:** Add support for SASS ([#28167](https://github.com/angular/angular/issues/28167)) ([f59f18c](https://github.com/angular/angular/commit/f59f18c)) +* **compiler-cli:** resolve generated Sass/Less files to .css inputs ([#28166](https://github.com/angular/angular/issues/28166)) ([a58fd21](https://github.com/angular/angular/commit/a58fd21)) +* **forms:** add `markAllAsTouched()` to `AbstractControl` ([#26812](https://github.com/angular/angular/issues/26812)) ([45bf911](https://github.com/angular/angular/commit/45bf911)), closes [#19400](https://github.com/angular/angular/issues/19400) + + +### Reverts + +* "ci: use image based cache for windows BuildKite ([#27990](https://github.com/angular/angular/issues/27990))" ([#28160](https://github.com/angular/angular/issues/28160)) ([7bdf3fe](https://github.com/angular/angular/commit/7bdf3fe)) + + + + +## [7.2.2](https://github.com/angular/angular/compare/7.2.1...7.2.2) (2019-01-22) + + +### Bug Fixes + +* **bazel:** Fix integration test after v8 bump ([#28194](https://github.com/angular/angular/issues/28194)) ([7b772e9](https://github.com/angular/angular/commit/7b772e9)), closes [#28142](https://github.com/angular/angular/issues/28142) +* **router:** `skipLocationChange` with named outlets ([#28301](https://github.com/angular/angular/issues/28301)) ([32737a6](https://github.com/angular/angular/commit/32737a6)), closes [#27680](https://github.com/angular/angular/issues/27680) [#28200](https://github.com/angular/angular/issues/28200) + + +### Features + +* **bazel:** Add support for SASS ([#28167](https://github.com/angular/angular/issues/28167)) ([a4d9192](https://github.com/angular/angular/commit/a4d9192)) +* **compiler-cli:** resolve generated Sass/Less files to .css inputs ([#28166](https://github.com/angular/angular/issues/28166)) ([4c00059](https://github.com/angular/angular/commit/4c00059)) + + + + +# [8.0.0-beta.0](https://github.com/angular/angular/compare/7.2.0...8.0.0-beta.0) (2019-01-16) + + +### Bug Fixes + +* **bazel:** Add [@bazel](https://github.com/bazel)/bazel to dev deps ([#28032](https://github.com/angular/angular/issues/28032)) ([5a0deb8](https://github.com/angular/angular/commit/5a0deb8)) +* **bazel:** Add /bazel-out to .gitignore ([#27874](https://github.com/angular/angular/issues/27874)) ([b05baa5](https://github.com/angular/angular/commit/b05baa5)) +* **bazel:** Add ibazel to deps of Bazel project ([#28090](https://github.com/angular/angular/issues/28090)) ([605f450](https://github.com/angular/angular/commit/605f450)) +* **bazel:** Bazel schematics should add router package ([#28141](https://github.com/angular/angular/issues/28141)) ([06e5bf1](https://github.com/angular/angular/commit/06e5bf1)) +* **bazel:** flat module misses AMD module name on windows ([#27839](https://github.com/angular/angular/issues/27839)) ([935ce63](https://github.com/angular/angular/commit/935ce63)) +* **bazel:** incorrectly always uses ngc-wrapped from "npm" workspace ([#28137](https://github.com/angular/angular/issues/28137)) ([d12db4e](https://github.com/angular/angular/commit/d12db4e)) +* **bazel:** ng_package creates invalid typings reexport on windows ([#27829](https://github.com/angular/angular/issues/27829)) ([4caf654](https://github.com/angular/angular/commit/4caf654)) +* **bazel:** packager not properly removing amd directives on windows ([#27829](https://github.com/angular/angular/issues/27829)) ([8473d68](https://github.com/angular/angular/commit/8473d68)) +* **bazel:** protractor rule does not run spec files with underscore ([#28022](https://github.com/angular/angular/issues/28022)) ([65e72e9](https://github.com/angular/angular/commit/65e72e9)) +* **bazel:** protractor utils cannot start server on windows ([#27915](https://github.com/angular/angular/issues/27915)) ([9de9c8a](https://github.com/angular/angular/commit/9de9c8a)) +* **bazel:** replay compilation uses wrong compiler for building esm5 ([#28053](https://github.com/angular/angular/issues/28053)) ([cd04513](https://github.com/angular/angular/commit/cd04513)) +* **bazel:** ts_web_test_suite now properly includes init_browser_spec.js ([#27965](https://github.com/angular/angular/issues/27965)) ([ce51dfb](https://github.com/angular/angular/commit/ce51dfb)) +* **service-worker:** navigation urls backwards compatibility ([#27244](https://github.com/angular/angular/issues/27244)) ([d49d1e7](https://github.com/angular/angular/commit/d49d1e7)) + + +### Features + +* **forms:** export NumberValueAccessor & RangeValueAccessor directives ([#27743](https://github.com/angular/angular/issues/27743)) ([ac15717](https://github.com/angular/angular/commit/ac15717)) + + +### Performance Improvements + +* **platform-server:** use shared `DomElementSchemaRegistry` instance ([#28150](https://github.com/angular/angular/issues/28150)) ([#28151](https://github.com/angular/angular/issues/28151)) ([ce3a746](https://github.com/angular/angular/commit/ce3a746)) + + + + +## [7.2.1](https://github.com/angular/angular/compare/7.2.0...7.2.1) (2019-01-16) + + +### Bug Fixes + +* **bazel:** Add [@bazel](https://github.com/bazel)/bazel to dev deps ([#28032](https://github.com/angular/angular/issues/28032)) ([21093b9](https://github.com/angular/angular/commit/21093b9)) +* **bazel:** Add /bazel-out to .gitignore ([#27874](https://github.com/angular/angular/issues/27874)) ([e4fc8ba](https://github.com/angular/angular/commit/e4fc8ba)) +* **bazel:** Add ibazel to deps of Bazel project ([#28090](https://github.com/angular/angular/issues/28090)) ([28d34b6](https://github.com/angular/angular/commit/28d34b6)) +* **bazel:** Bazel schematics should add router package ([#28141](https://github.com/angular/angular/issues/28141)) ([02a852a](https://github.com/angular/angular/commit/02a852a)) +* **bazel:** flat module misses AMD module name on windows ([#27839](https://github.com/angular/angular/issues/27839)) ([c3d8e28](https://github.com/angular/angular/commit/c3d8e28)) +* **bazel:** incorrectly always uses ngc-wrapped from "npm" workspace ([#28137](https://github.com/angular/angular/issues/28137)) ([ca3965a](https://github.com/angular/angular/commit/ca3965a)) +* **bazel:** ng_package creates invalid typings reexport on windows ([#27829](https://github.com/angular/angular/issues/27829)) ([6b394f6](https://github.com/angular/angular/commit/6b394f6)) +* **bazel:** packager not properly removing amd directives on windows ([#27829](https://github.com/angular/angular/issues/27829)) ([fad4145](https://github.com/angular/angular/commit/fad4145)) +* **bazel:** protractor rule does not run spec files with underscore ([#28022](https://github.com/angular/angular/issues/28022)) ([f05c5f8](https://github.com/angular/angular/commit/f05c5f8)) +* **bazel:** protractor utils cannot start server on windows ([#27915](https://github.com/angular/angular/issues/27915)) ([0be8487](https://github.com/angular/angular/commit/0be8487)) +* **bazel:** replay compilation uses wrong compiler for building esm5 ([#28053](https://github.com/angular/angular/issues/28053)) ([fbbdaaa](https://github.com/angular/angular/commit/fbbdaaa)) +* **router:** ensure URL is updated after second redirect with UrlUpdateStrategy="eager" ([#27680](https://github.com/angular/angular/issues/27680)) ([6ae7aee](https://github.com/angular/angular/commit/6ae7aee)), closes [#27116](https://github.com/angular/angular/issues/27116) +* **service-worker:** navigation urls backwards compatibility ([#27244](https://github.com/angular/angular/issues/27244)) ([585e871](https://github.com/angular/angular/commit/585e871)) + + +### Performance Improvements + +* **platform-server:** use shared `DomElementSchemaRegistry` instance ([#28150](https://github.com/angular/angular/issues/28150)) ([#28151](https://github.com/angular/angular/issues/28151)) ([6851581](https://github.com/angular/angular/commit/6851581)) + + + + +# [7.2.0](https://github.com/angular/angular/compare/7.1.4...7.2.0) (2019-01-07) + +7.2.0 release also contains all the fixes released in 7.1.4. + +### Features + +* add support for typescript 3.2 ([#27536](https://github.com/angular/angular/issues/27536)) ([17e702b](https://github.com/angular/angular/commit/17e702b)) +* **bazel:** ng-new schematics with Bazel ([#27277](https://github.com/angular/angular/issues/27277)) ([06d4a0c](https://github.com/angular/angular/commit/06d4a0c)) +* **forms:** match getError and hasError to get method signature ([#20211](https://github.com/angular/angular/issues/20211)) ([1b0b36d](https://github.com/angular/angular/commit/1b0b36d)) +* **router:** add predicate function mode for runGuardsAndResolvers ([#27682](https://github.com/angular/angular/issues/27682)) ([12c3176](https://github.com/angular/angular/commit/12c3176)), closes [#26861](https://github.com/angular/angular/issues/26861) [#18253](https://github.com/angular/angular/issues/18253) [#27464](https://github.com/angular/angular/issues/27464) +* **router:** add a Navigation type available during navigation ([#27198](https://github.com/angular/angular/issues/27198)) ([d40af0c](https://github.com/angular/angular/commit/d40af0c)) +* **router:** add pathParamsOrQueryParamsChange mode for runGuardsAndResolvers ([#27464](https://github.com/angular/angular/issues/27464)) ([d70a7f3](https://github.com/angular/angular/commit/d70a7f3)), closes [#26861](https://github.com/angular/angular/issues/26861) [#18253](https://github.com/angular/angular/issues/18253) +* **router:** allow passing `state` to routerLink directives ([#27198](https://github.com/angular/angular/issues/27198)) ([73f6ed9](https://github.com/angular/angular/commit/73f6ed9)), closes [#24617](https://github.com/angular/angular/issues/24617) +* **router:** allow passing state to `NavigationExtras` ([#27198](https://github.com/angular/angular/issues/27198)) ([67f4a5d](https://github.com/angular/angular/commit/67f4a5d)) +* **router:** restore whole object when navigating back to a page managed by Angular router ([#27198](https://github.com/angular/angular/issues/27198)) ([2684249](https://github.com/angular/angular/commit/2684249)) ### Bug Fixes * **animations:** do not truncate decimals for delay ([#24455](https://github.com/angular/angular/issues/24455)) ([f1c9d6a](https://github.com/angular/angular/commit/f1c9d6a)) * **animations:** mark actual descendant node as disabled ([#26180](https://github.com/angular/angular/issues/26180)) ([df123e0](https://github.com/angular/angular/commit/df123e0)) +* **bazel:** unable to launch protractor test on windows ([#27850](https://github.com/angular/angular/issues/27850)) ([1e6c9be](https://github.com/angular/angular/commit/1e6c9be)) * **bazel:** devserver entry_module should have underscore name ([#27719](https://github.com/angular/angular/issues/27719)) ([f57916c](https://github.com/angular/angular/commit/f57916c)) * **bazel:** emit full node stack traces when Angular compilation crashes ([#27678](https://github.com/angular/angular/issues/27678)) ([522919a](https://github.com/angular/angular/commit/522919a)) * **bazel:** fix major/minor semver check between [@angular](https://github.com/angular)/bazel npm packager version and angular bazel repo version ([#27635](https://github.com/angular/angular/issues/27635)) ([1cc08b4](https://github.com/angular/angular/commit/1cc08b4)) * **bazel:** Load http_archive and rules_nodejs dependencies ([#27609](https://github.com/angular/angular/issues/27609)) ([8313ffc](https://github.com/angular/angular/commit/8313ffc)) * **bazel:** ng_package writes unrelevant definitions to bazel out ([#27519](https://github.com/angular/angular/issues/27519)) ([44dfa60](https://github.com/angular/angular/commit/44dfa60)), closes [/github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts#L105-L124](https://github.com//github.com/angular/angular/blob/4f9374951d67c75f67a31c110bd61ab72563db7d/packages/bazel/src/ng_package/packager.ts/issues/L105-L124) * **bazel:** Set module_name and enable ng test ([#27715](https://github.com/angular/angular/issues/27715)) ([85866de](https://github.com/angular/angular/commit/85866de)) +* **bazel:** fix TS errors in the `schematics/bazel-workspace` files ([#27600](https://github.com/angular/angular/issues/27600)) ([3290fc3](https://github.com/angular/angular/commit/3290fc3)) +* **bazel:** Read latest versions from latest-versions.ts & use semver check ([#27526](https://github.com/angular/angular/issues/27526)) ([30a3b49](https://github.com/angular/angular/commit/30a3b49)) +* **bazel:** tsickle dependency not working with typescript 3.1.x ([#27402](https://github.com/angular/angular/issues/27402)) ([f034114](https://github.com/angular/angular/commit/f034114)) +* **bazel:** do not throw error when writing tsickle externs ([#27200](https://github.com/angular/angular/issues/27200)) ([20a2bae](https://github.com/angular/angular/commit/20a2bae)) +* **bazel:** do not throw if ts compile action does not create esm5 outputs ([#27401](https://github.com/angular/angular/issues/27401)) ([c61a8b7](https://github.com/angular/angular/commit/c61a8b7)) +* **bazel:** ng_package cannot be run multiple times without clean ([#27200](https://github.com/angular/angular/issues/27200)) ([4f93749](https://github.com/angular/angular/commit/4f93749)) +* **bazel:** ng_package not generating UMD bundles on windows ([#27200](https://github.com/angular/angular/issues/27200)) ([7d59880](https://github.com/angular/angular/commit/7d59880)) +* **bazel:** ng_package should correctly map to source maps in secondary entry-points ([#27313](https://github.com/angular/angular/issues/27313)) ([eb17502](https://github.com/angular/angular/commit/eb17502)), closes [#25510](https://github.com/angular/angular/issues/25510) +* **bazel:** Respect existing angular installation ([#27495](https://github.com/angular/angular/issues/27495)) ([4da739a](https://github.com/angular/angular/commit/4da739a)) * **common:** KeyValuePipe should return empty array for empty objects ([#27258](https://github.com/angular/angular/issues/27258)) ([b39efdd](https://github.com/angular/angular/commit/b39efdd)) +* **common:** expose request url in network error ([#27143](https://github.com/angular/angular/issues/27143)) ([1db53da](https://github.com/angular/angular/commit/1db53da)), closes [#27029](https://github.com/angular/angular/issues/27029) * **compiler-cli:** create LiteralLikeNode for String and Number literal ([#27536](https://github.com/angular/angular/issues/27536)) ([2c9b6c0](https://github.com/angular/angular/commit/2c9b6c0)) +* **compiler-cli:** flatModuleIndex files not generated on windows with multiple input files ([#27200](https://github.com/angular/angular/issues/27200)) ([d3c08e7](https://github.com/angular/angular/commit/d3c08e7)) +* **core:** export a value for InjectFlags ([#27279](https://github.com/angular/angular/issues/27279)) ([23b06af](https://github.com/angular/angular/commit/23b06af)), closes [#27251](https://github.com/angular/angular/issues/27251) +* **core:** More precise return type for `InjectableDecorator` ([#27360](https://github.com/angular/angular/issues/27360)) ([4b9948c](https://github.com/angular/angular/commit/4b9948c)), closes [#26942](https://github.com/angular/angular/issues/26942) +* **forms:** typed argument for FormBuilder group ([#26985](https://github.com/angular/angular/issues/26985)) ([b0c7561](https://github.com/angular/angular/commit/b0c7561)) +* **platform-server:** add [@angular](https://github.com/angular)/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([32c5be9](https://github.com/angular/angular/commit/32c5be9)), closes [#26154](https://github.com/angular/angular/issues/26154) * **router:** ensure URL is updated after second redirect with UrlUpdateStrategy="eager" ([#27523](https://github.com/angular/angular/issues/27523)) ([ad26cd6](https://github.com/angular/angular/commit/ad26cd6)), closes [#27116](https://github.com/angular/angular/issues/27116) +* **router:** update URL after redirects when urlHandlingStrategy='eager' ([#27356](https://github.com/angular/angular/issues/27356)) ([11a8bd8](https://github.com/angular/angular/commit/11a8bd8)), closes [#27076](https://github.com/angular/angular/issues/27076) +* **upgrade:** allow nesting components from different downgraded modules ([#27217](https://github.com/angular/angular/issues/27217)) ([bc0ee01](https://github.com/angular/angular/commit/bc0ee01)) +* **upgrade:** correctly handle nested downgraded components with `downgradeModule()` ([#27217](https://github.com/angular/angular/issues/27217)) ([326b464](https://github.com/angular/angular/commit/326b464)), closes [#22581](https://github.com/angular/angular/issues/22581) [#22869](https://github.com/angular/angular/issues/22869) [#27083](https://github.com/angular/angular/issues/27083) * **upgrade:** upgrade Directive facade should not return different instance from constructor ([#27660](https://github.com/angular/angular/issues/27660)) ([c986d3d](https://github.com/angular/angular/commit/c986d3d)) - - -### Features - -* add support for typescript 3.2 ([#27536](https://github.com/angular/angular/issues/27536)) ([17e702b](https://github.com/angular/angular/commit/17e702b)) -* **router:** add predicate function mode for runGuardsAndResolvers ([#27682](https://github.com/angular/angular/issues/27682)) ([12c3176](https://github.com/angular/angular/commit/12c3176)), closes [#26861](https://github.com/angular/angular/issues/26861) [#18253](https://github.com/angular/angular/issues/18253) [#27464](https://github.com/angular/angular/issues/27464) +* **upgrade:** don't rely upon the runtime to resolve forward refs ([#27132](https://github.com/angular/angular/issues/27132)) ([a4462c2](https://github.com/angular/angular/commit/a4462c2)) @@ -44,19 +297,6 @@ - -# [7.2.0-beta.2](https://github.com/angular/angular/compare/7.2.0-beta.1...7.2.0-beta.2) (2018-12-11) - - -### Bug Fixes - -* **bazel:** fix TS errors in the `schematics/bazel-workspace` files ([#27600](https://github.com/angular/angular/issues/27600)) ([3290fc3](https://github.com/angular/angular/commit/3290fc3)) -* **bazel:** Read latest versions from latest-versions.ts & use semver check ([#27526](https://github.com/angular/angular/issues/27526)) ([30a3b49](https://github.com/angular/angular/commit/30a3b49)) -* **bazel:** tsickle dependency not working with typescript 3.1.x ([#27402](https://github.com/angular/angular/issues/27402)) ([f034114](https://github.com/angular/angular/commit/f034114)) -* **forms:** typed argument for FormBuilder group ([#26985](https://github.com/angular/angular/issues/26985)) ([b0c7561](https://github.com/angular/angular/commit/b0c7561)) - - - ## [7.1.3](https://github.com/angular/angular/compare/7.1.2...7.1.3) (2018-12-11) @@ -83,47 +323,6 @@ * **platform-server:** add [@angular](https://github.com/angular)/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([236ac06](https://github.com/angular/angular/commit/236ac06)), closes [#26154](https://github.com/angular/angular/issues/26154) - -# [7.2.0-beta.1](https://github.com/angular/angular/compare/7.1.0...7.2.0-beta.1) (2018-12-06) - - -### Bug Fixes - -* **bazel:** do not throw error when writing tsickle externs ([#27200](https://github.com/angular/angular/issues/27200)) ([20a2bae](https://github.com/angular/angular/commit/20a2bae)) -* **bazel:** do not throw if ts compile action does not create esm5 outputs ([#27401](https://github.com/angular/angular/issues/27401)) ([c61a8b7](https://github.com/angular/angular/commit/c61a8b7)) -* **bazel:** ng_package cannot be run multiple times without clean ([#27200](https://github.com/angular/angular/issues/27200)) ([4f93749](https://github.com/angular/angular/commit/4f93749)) -* **bazel:** ng_package not generating UMD bundles on windows ([#27200](https://github.com/angular/angular/issues/27200)) ([7d59880](https://github.com/angular/angular/commit/7d59880)) -* **bazel:** ng_package should correctly map to source maps in secondary entry-points ([#27313](https://github.com/angular/angular/issues/27313)) ([eb17502](https://github.com/angular/angular/commit/eb17502)), closes [#25510](https://github.com/angular/angular/issues/25510) -* **bazel:** Respect existing angular installation ([#27495](https://github.com/angular/angular/issues/27495)) ([4da739a](https://github.com/angular/angular/commit/4da739a)) -* **common:** expose request url in network error ([#27143](https://github.com/angular/angular/issues/27143)) ([1db53da](https://github.com/angular/angular/commit/1db53da)), closes [#27029](https://github.com/angular/angular/issues/27029) -* **compiler-cli:** flatModuleIndex files not generated on windows with multiple input files ([#27200](https://github.com/angular/angular/issues/27200)) ([d3c08e7](https://github.com/angular/angular/commit/d3c08e7)) -* **core:** export a value for InjectFlags ([#27279](https://github.com/angular/angular/issues/27279)) ([23b06af](https://github.com/angular/angular/commit/23b06af)), closes [#27251](https://github.com/angular/angular/issues/27251) -* **core:** More precise return type for `InjectableDecorator` ([#27360](https://github.com/angular/angular/issues/27360)) ([4b9948c](https://github.com/angular/angular/commit/4b9948c)), closes [#26942](https://github.com/angular/angular/issues/26942) -* **forms:** apply unicode flag to pattern attribute when supported ([#20819](https://github.com/angular/angular/issues/20819)) ([3c34b8b](https://github.com/angular/angular/commit/3c34b8b)) -* **platform-server:** add [@angular](https://github.com/angular)/http to the list of peerDependencies ([#27307](https://github.com/angular/angular/issues/27307)) ([32c5be9](https://github.com/angular/angular/commit/32c5be9)), closes [#26154](https://github.com/angular/angular/issues/26154) -* **router:** update URL after redirects when urlHandlingStrategy='eager' ([#27356](https://github.com/angular/angular/issues/27356)) ([11a8bd8](https://github.com/angular/angular/commit/11a8bd8)), closes [#27076](https://github.com/angular/angular/issues/27076) -* **upgrade:** don't rely upon the runtime to resolve forward refs ([#27132](https://github.com/angular/angular/issues/27132)) ([a4462c2](https://github.com/angular/angular/commit/a4462c2)) - - -### Features - -* **bazel:** ng-new schematics with Bazel ([#27277](https://github.com/angular/angular/issues/27277)) ([06d4a0c](https://github.com/angular/angular/commit/06d4a0c)) -* **router:** add a Navigation type available during navigation ([#27198](https://github.com/angular/angular/issues/27198)) ([d40af0c](https://github.com/angular/angular/commit/d40af0c)) -* **router:** add pathParamsOrQueryParamsChange mode for runGuardsAndResolvers ([#27464](https://github.com/angular/angular/issues/27464)) ([d70a7f3](https://github.com/angular/angular/commit/d70a7f3)), closes [#26861](https://github.com/angular/angular/issues/26861) [#18253](https://github.com/angular/angular/issues/18253) -* **router:** allow passing `state` to routerLink directives ([#27198](https://github.com/angular/angular/issues/27198)) ([73f6ed9](https://github.com/angular/angular/commit/73f6ed9)), closes [#24617](https://github.com/angular/angular/issues/24617) -* **router:** allow passing state to `NavigationExtras` ([#27198](https://github.com/angular/angular/issues/27198)) ([67f4a5d](https://github.com/angular/angular/commit/67f4a5d)) -* **router:** restore whole object when navigating back to a page managed by Angular router ([#27198](https://github.com/angular/angular/issues/27198)) ([2684249](https://github.com/angular/angular/commit/2684249)) - - -# [7.2.0-beta.0](https://github.com/angular/angular/compare/7.1.0...7.2.0-beta.0) (2018-11-28) - - -### Bug Fixes - -* **common:** expose request url in network error ([#27143](https://github.com/angular/angular/issues/27143)) ([1db53da](https://github.com/angular/angular/commit/1db53da)), closes [#27029](https://github.com/angular/angular/issues/27029) -* **upgrade:** don't rely upon the runtime to resolve forward refs ([#27132](https://github.com/angular/angular/issues/27132)) ([a4462c2](https://github.com/angular/angular/commit/a4462c2)) - - ## [7.1.1](https://github.com/angular/angular/compare/7.1.0...7.1.1) (2018-11-28) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 17f82cc495..c3d9fd3eab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -191,7 +191,7 @@ If the commit reverts a previous commit, it should begin with `revert: `, follow Must be one of the following: * **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) -* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) +* **ci**: Changes to our CI configuration files and scripts (example scopes: Circle, BrowserStack, SauceLabs) * **docs**: Documentation only changes * **feat**: A new feature * **fix**: A bug fix diff --git a/LICENSE b/LICENSE index f868eadca1..828d3633f7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2014-2018 Google, Inc. http://angular.io +Copyright (c) 2010-2019 Google LLC. http://angular.io/license Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 25798688ce..6693a4b272 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -[![Build Status](https://travis-ci.org/angular/angular.svg?branch=master)](https://travis-ci.org/angular/angular) -[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/angular/tree/master) +[![CircleCI](https://circleci.com/gh/angular/angular/tree/master.svg?style=shield)](https://circleci.com/gh/angular/workflows/angular/tree/master) [![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06)](https://www.browserstack.com/automate/public-build/LzF3RzBVVGt6VWE2S0hHaC9uYllOZz09LS1BVjNTclBKV0x4eVRlcjA4QVY1M0N3PT0=--eb4ce8c8dc2c1c5b2b5352d473ee12a73ac20e06) [![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![npm version](https://badge.fury.io/js/%40angular%2Fcore.svg)](https://www.npmjs.com/@angular/core) diff --git a/WORKSPACE b/WORKSPACE index 4257235643..6c70dcbfc9 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,17 +1,6 @@ workspace(name = "angular") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -load( - "//packages/bazel:package.bzl", - "rules_angular_dependencies", - "rules_angular_dev_dependencies", -) - -http_archive( - name = "io_bazel_rules_go", - sha256 = "b7a62250a3a73277ade0ce306d22f122365b513f5402222403e507f2f997d421", - url = "https://github.com/bazelbuild/rules_go/releases/download/0.16.3/rules_go-0.16.3.tar.gz", -) # Uncomment for local bazel rules development #local_repository( @@ -23,25 +12,15 @@ http_archive( # path = "../rules_typescript", #) -# Angular Bazel users will call this function -rules_angular_dependencies() +# Fetch rules_nodejs so we can install our npm dependencies +http_archive( + name = "build_bazel_rules_nodejs", + sha256 = "1416d03823fed624b49a0abbd9979f7c63bbedfd37890ddecedd2fe25cccebc6", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.18.6/rules_nodejs-0.18.6.tar.gz"], +) -# Install transitive deps of rules_nodejs -load("@build_bazel_rules_nodejs//:package.bzl", "rules_nodejs_dependencies") - -rules_nodejs_dependencies() - -# These are the dependencies only for us -rules_angular_dev_dependencies() - -# Install transitive deps of rules_typescript -load("@build_bazel_rules_typescript//:package.bzl", "rules_typescript_dependencies") - -rules_typescript_dependencies() - -# -# Point Bazel to WORKSPACEs that live in subdirectories -# +# Fetch the rxjs repository since we build rxjs from source +# TODO(gregmagolan): use rxjs bundles in the bazel build http_archive( name = "rxjs", sha256 = "72b0b4e517f43358f554c125e40e39f67688cd2738a8998b4a266981ed32f403", @@ -49,19 +28,23 @@ http_archive( url = "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz", ) -# Point to the integration test workspace just so that Bazel doesn't descend into it -# when expanding the //... pattern +# Use a mock @npm repository while we are building angular from source +# downstream. Angular will get its npm dependencies with in @ngdeps which +# is setup in ng_setup_workspace(). +# TODO(gregmagolan): remove @ngdeps once angular is no longer build from source +# downstream and have build use @npm for npm dependencies local_repository( - name = "bazel_integration_test", - path = "integration/bazel", + name = "npm", + path = "tools/npm_workspace", ) -# -# Load and install our dependencies downloaded above. -# -load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install") +# Check the bazel version and download npm dependencies +load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories") -check_bazel_version("0.20.0", """ +# Bazel version must be at least v0.21.0 because: +# - 0.21.0 Using --incompatible_strict_action_env flag fixes cache when running `yarn bazel` +# (see https://github.com/angular/angular/issues/27514#issuecomment-451438271) +check_bazel_version("0.21.0", """ You no longer need to install Bazel on your machine. Angular has a dependency on the @bazel/bazel package which supplies it. Try running `yarn bazel` instead. @@ -69,6 +52,7 @@ Try running `yarn bazel` instead. """) +# Setup the Node.js toolchain node_repositories( node_version = "10.9.0", package_json = ["//:package.json"], @@ -76,41 +60,48 @@ node_repositories( yarn_version = "1.12.1", ) -local_repository( - name = "npm", - path = "tools/npm_workspace", -) +# Setup the angular toolchain which installs npm dependencies into @ngdeps +load("//tools:ng_setup_workspace.bzl", "ng_setup_workspace") -load("@io_bazel_rules_go//go:def.bzl", "go_register_toolchains", "go_rules_dependencies") +ng_setup_workspace() -go_rules_dependencies() +# Install all bazel dependencies of the @ngdeps npm packages +load("@ngdeps//:install_bazel_dependencies.bzl", "install_bazel_dependencies") -go_register_toolchains() +install_bazel_dependencies() -load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories") +# Load angular dependencies +load("//packages/bazel:package.bzl", "rules_angular_dev_dependencies") + +rules_angular_dev_dependencies() + +# Load karma dependencies +load("@build_bazel_rules_karma//:package.bzl", "rules_karma_dependencies") + +rules_karma_dependencies() + +# Setup the rules_webtesting toolchain +load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories") web_test_repositories() -browser_repositories( - chromium = True, - firefox = True, -) +# Temporary work-around for https://github.com/angular/angular/issues/28681 +# TODO(gregmagolan): go back to @io_bazel_rules_webtesting browser_repositories +load("@angular//:browser_repositories.bzl", "browser_repositories") +browser_repositories() + +# Setup the rules_typescript tooolchain load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace") ts_setup_workspace() -load("@angular//:index.bzl", "ng_setup_workspace") - -ng_setup_workspace() - -################################## -# Skylark documentation generation - +# Setup the rules_sass toolchain load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories") sass_repositories() +# Setup the skydoc toolchain load("@io_bazel_skydoc//skylark:skylark.bzl", "skydoc_repositories") skydoc_repositories() diff --git a/aio/aio-builds-setup/dockerbuild/Dockerfile b/aio/aio-builds-setup/dockerbuild/Dockerfile index 1145c41b64..f5c137991f 100644 --- a/aio/aio-builds-setup/dockerbuild/Dockerfile +++ b/aio/aio-builds-setup/dockerbuild/Dockerfile @@ -26,8 +26,8 @@ ARG AIO_GITHUB_ORGANIZATION=angular ARG TEST_AIO_GITHUB_ORGANIZATION=test-org ARG AIO_GITHUB_REPO=angular ARG TEST_AIO_GITHUB_REPO=test-repo -ARG AIO_GITHUB_TEAM_SLUGS=team,aio-contributors -ARG TEST_AIO_GITHUB_TEAM_SLUGS=team,aio-contributors +ARG AIO_GITHUB_TEAM_SLUGS=aio-contributors +ARG TEST_AIO_GITHUB_TEAM_SLUGS=aio-contributors ARG AIO_NGINX_HOSTNAME=$AIO_DOMAIN_NAME ARG TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_DOMAIN_NAME ARG AIO_NGINX_PORT_HTTP=80 diff --git a/aio/angular.json b/aio/angular.json index d70909cf30..a5529b7931 100644 --- a/aio/angular.json +++ b/aio/angular.json @@ -105,6 +105,9 @@ }, "archive": { "browserTarget": "site:build:archive" + }, + "ci": { + "progress": false } } }, @@ -168,6 +171,11 @@ "options": { "protractorConfig": "tests/e2e/protractor.conf.js", "devServerTarget": "site:serve" + }, + "configurations": { + "ci": { + "devServerTarget": "site:serve:ci" + } } }, "lint": { diff --git a/aio/content/examples/.gitignore b/aio/content/examples/.gitignore index d40a958d04..6d03b437e2 100644 --- a/aio/content/examples/.gitignore +++ b/aio/content/examples/.gitignore @@ -57,7 +57,9 @@ dist/ # aot **/*.ngsummary.json +upgrade-module/tsconfig-aot.json !rollup-config.js +upgrade-module/rollup-config.js aot-compiler/**/*.d.ts aot-compiler/**/*.factory.d.ts upgrade-phonecat-2-hybrid/aot/**/* @@ -84,5 +86,9 @@ upgrade-phonecat-2-hybrid/aot/**/* *stackblitz.no-link.html # ngUpgrade testing +upgrade-phonecat-1-typescript/tsconfig-aot.json +upgrade-phonecat-1-typescript/rollup-config.js +upgrade-phonecat-3-final/tsconfig-aot.json +upgrade-phonecat-3-final/rollup-config.js !upgrade-phonecat-*/**/karma.conf.js !upgrade-phonecat-*/**/karma-test-shim.js diff --git a/aio/content/examples/ajs-quick-reference/src/app/app.component.ts b/aio/content/examples/ajs-quick-reference/src/app/app.component.ts index 6c5de8624e..de4b412cad 100644 --- a/aio/content/examples/ajs-quick-reference/src/app/app.component.ts +++ b/aio/content/examples/ajs-quick-reference/src/app/app.component.ts @@ -20,7 +20,7 @@ export class AppComponent { movies: IMovie[] = []; showImage = true; title = 'AngularJS to Angular Quick Ref Cookbook'; - toggleImage(event: UIEvent) { + toggleImage(event?: UIEvent) { this.showImage = !this.showImage; this.eventType = (event && event.type) || 'not provided'; } diff --git a/aio/content/examples/ajs-quick-reference/src/app/date.pipe.ts b/aio/content/examples/ajs-quick-reference/src/app/date.pipe.ts deleted file mode 100644 index e1421fa530..0000000000 --- a/aio/content/examples/ajs-quick-reference/src/app/date.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Injectable, Pipe, PipeTransform } from '@angular/core'; -import { DatePipe } from '@angular/common'; - -@Injectable() -// #docregion date-pipe -@Pipe({name: 'date', pure: true}) -export class StringSafeDatePipe extends DatePipe implements PipeTransform { - transform(value: any, format: string): string { - value = typeof value === 'string' ? - Date.parse(value) : value; - return super.transform(value, format); - } -} -// #enddocregion date-pipe diff --git a/aio/content/examples/animations/src/app/app.module.ts b/aio/content/examples/animations/src/app/app.module.ts index 8109d6269b..ae5c73f29f 100644 --- a/aio/content/examples/animations/src/app/app.module.ts +++ b/aio/content/examples/animations/src/app/app.module.ts @@ -19,6 +19,7 @@ import { HeroListAutoCalcPageComponent } from './hero-list-auto-page.component'; import { HeroListAutoComponent } from './hero-list-auto.component'; import { HomeComponent } from './home.component'; import { AboutComponent } from './about.component'; +import { InsertRemoveComponent } from './insert-remove.component'; @NgModule({ @@ -56,6 +57,7 @@ import { AboutComponent } from './about.component'; HeroListAutoCalcPageComponent, HeroListAutoComponent, HomeComponent, + InsertRemoveComponent, AboutComponent ], bootstrap: [AppComponent] diff --git a/aio/content/examples/component-interaction/example-config.json b/aio/content/examples/component-interaction/example-config.json index e69de29bb2..b93fc9e8da 100644 --- a/aio/content/examples/component-interaction/example-config.json +++ b/aio/content/examples/component-interaction/example-config.json @@ -0,0 +1,11 @@ +{ + "e2e": [ + { + "cmd": "yarn", + "args": [ + "e2e", + "--no-webdriver-update" + ] + } + ] +} \ No newline at end of file diff --git a/aio/content/examples/dependency-injection-in-action/src/app/parent-finder.component.ts b/aio/content/examples/dependency-injection-in-action/src/app/parent-finder.component.ts index 4cf6ea7acc..76d2c1b2b0 100644 --- a/aio/content/examples/dependency-injection-in-action/src/app/parent-finder.component.ts +++ b/aio/content/examples/dependency-injection-in-action/src/app/parent-finder.component.ts @@ -19,20 +19,20 @@ const DifferentParent = Parent; // #enddocregion provide-the-parent // The `parentType` defaults to `Parent` when omitting the second parameter. // #docregion provide-the-parent -const provideParent = +export function provideParent // #enddocregion provide-parent, provide-the-parent // #docregion provide-parent - (component: any, parentType?: any) => { + (component: any, parentType?: any) { return { provide: parentType || Parent, useExisting: forwardRef(() => component) }; - }; + } // #enddocregion provide-parent // Simpler syntax version that always provides the component in the name of `Parent`. -const provideTheParent = +export function provideTheParent // #docregion provide-the-parent - (component: any) => { + (component: any) { return { provide: Parent, useExisting: forwardRef(() => component) }; - }; + } // #enddocregion provide-the-parent diff --git a/aio/content/examples/dependency-injection/example-config.json b/aio/content/examples/dependency-injection/example-config.json index e69de29bb2..b93fc9e8da 100644 --- a/aio/content/examples/dependency-injection/example-config.json +++ b/aio/content/examples/dependency-injection/example-config.json @@ -0,0 +1,11 @@ +{ + "e2e": [ + { + "cmd": "yarn", + "args": [ + "e2e", + "--no-webdriver-update" + ] + } + ] +} \ No newline at end of file diff --git a/aio/content/examples/displaying-data/src/app/app-ctor.component.ts b/aio/content/examples/displaying-data/src/app/app-ctor.component.1.ts similarity index 100% rename from aio/content/examples/displaying-data/src/app/app-ctor.component.ts rename to aio/content/examples/displaying-data/src/app/app-ctor.component.1.ts diff --git a/aio/content/examples/event-binding/e2e/src/app.e2e-spec.ts b/aio/content/examples/event-binding/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000000..881a49f700 --- /dev/null +++ b/aio/content/examples/event-binding/e2e/src/app.e2e-spec.ts @@ -0,0 +1,71 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, protractor } from 'protractor'; + +describe('Event binding example', function () { + + beforeEach(function () { + browser.get(''); + }); + + let saveButton = element.all(by.css('button')).get(0); + let onSaveButton = element.all(by.css('button')).get(1); + let myClick = element.all(by.css('button')).get(2); + let deleteButton = element.all(by.css('button')).get(3); + let saveNoProp = element.all(by.css('button')).get(4); + let saveProp = element.all(by.css('button')).get(5); + + + it('should display Event Binding with Angular', function () { + expect(element(by.css('h1')).getText()).toEqual('Event Binding'); + }); + + it('should display 6 buttons', function() { + expect(saveButton.getText()).toBe('Save'); + expect(onSaveButton.getText()).toBe('on-click Save'); + expect(myClick.getText()).toBe('click with myClick'); + expect(deleteButton.getText()).toBe('Delete'); + expect(saveNoProp.getText()).toBe('Save, no propagation'); + expect(saveProp.getText()).toBe('Save with propagation'); + }); + + it('should support user input', function () { + let input = element(by.css('input')); + let bindingResult = element.all(by.css('h4')).get(1); + expect(bindingResult.getText()).toEqual('Result: teapot'); + input.sendKeys('abc'); + expect(bindingResult.getText()).toEqual('Result: teapotabc'); + }); + + it('should hide the item img', async () => { + let deleteButton = element.all(by.css('button')).get(3); + await deleteButton.click(); + browser.switchTo().alert().accept(); + expect(element.all(by.css('img')).get(0).getCssValue('display')).toEqual('none'); + }); + + it('should show two alerts', async () => { + let parentDiv = element.all(by.css('.parent-div')); + let childDiv = element.all(by.css('div > div')).get(1); + await parentDiv.click(); + browser.switchTo().alert().accept(); + expect(childDiv.getText()).toEqual('Click me too! (child)'); + await childDiv.click(); + expect(browser.switchTo().alert().getText()).toEqual('Click me. Event target class is child-div'); + browser.switchTo().alert().accept(); + }); + + it('should show 1 alert from Save, no prop, button', async () => { + await saveNoProp.click(); + expect(browser.switchTo().alert().getText()).toEqual('Saved. Event target is Save, no propagation'); + browser.switchTo().alert().accept(); + }); + + it('should show 2 alerts from Save w/prop button', async () => { + await saveProp.click(); + expect(browser.switchTo().alert().getText()).toEqual('Saved.'); + browser.switchTo().alert().accept(); + expect(browser.switchTo().alert().getText()).toEqual('Saved.'); + browser.switchTo().alert().accept(); + }); +}); diff --git a/aio/content/examples/quickstart/example-config.json b/aio/content/examples/event-binding/example-config.json similarity index 100% rename from aio/content/examples/quickstart/example-config.json rename to aio/content/examples/event-binding/example-config.json diff --git a/aio/content/examples/event-binding/src/app/app.component.css b/aio/content/examples/event-binding/src/app/app.component.css new file mode 100644 index 0000000000..a80480a914 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/app.component.css @@ -0,0 +1,25 @@ +.group { + background-color: #dae8f9; + padding: 1rem; + margin: 1rem 0; +} + +.parent-div { + background-color: #bdd1f7; + border: solid 1px rgb(25, 118, 210); + padding: 1rem; +} + +.parent-div:hover { + background-color: #8fb4f9; +} + +.child-div { + margin-top: 1rem; + background-color: #fff; + padding: 1rem; +} + +.child-div:hover { + background-color: #eee; +} diff --git a/aio/content/examples/event-binding/src/app/app.component.html b/aio/content/examples/event-binding/src/app/app.component.html new file mode 100644 index 0000000000..5edc3eaee2 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/app.component.html @@ -0,0 +1,53 @@ +

Event Binding

+ +
+

Target event

+ + + + + + + + + +

myClick is an event on the custom ClickDirective:

+ + {{clickMessage}} + + +
+ +
+

$event and event handling statements

+

Result: {{currentItem.name}}

+ + + + without NgModel + +
+ +
+

Binding to a nested component

+

Custom events with EventEmitter

+ + + + + +

Click to see event target class:

+
Click me (parent) +
Click me too! (child)
+
+ +

Saves only once:

+
+ +
+ +

Saves twice:

+
+ +
diff --git a/aio/content/examples/event-binding/src/app/app.component.spec.ts b/aio/content/examples/event-binding/src/app/app.component.spec.ts new file mode 100644 index 0000000000..852c902d87 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/app.component.spec.ts @@ -0,0 +1,27 @@ +import { TestBed, async } from '@angular/core/testing'; +import { AppComponent } from './app.component'; +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + it('should create the app', async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + it(`should have as title 'Featured product:'`, async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('Featured product:'); + })); + it('should render title in a p tag', async(() => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('p').textContent).toContain('Featured product:'); + })); +}); diff --git a/aio/content/examples/event-binding/src/app/app.component.ts b/aio/content/examples/event-binding/src/app/app.component.ts new file mode 100644 index 0000000000..69a76d6669 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/app.component.ts @@ -0,0 +1,29 @@ +import { Component } from '@angular/core'; +import { Item } from './item'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + + currentItem = { name: 'teapot'} ; + clickMessage = ''; + + onSave(event?: KeyboardEvent) { + const evtMsg = event ? ' Event target is ' + (event.target).textContent : ''; + alert('Saved.' + evtMsg); + if (event) { event.stopPropagation(); } + } + + deleteItem(item: Item) { + alert(`Delete the ${item}.`); + } + + onClickMe(event?: KeyboardEvent) { + const evtMsg = event ? ' Event target class is ' + (event.target).className : ''; + alert('Click me.' + evtMsg); + } + +} diff --git a/aio/content/examples/event-binding/src/app/app.module.ts b/aio/content/examples/event-binding/src/app/app.module.ts new file mode 100644 index 0000000000..d331a1d8fc --- /dev/null +++ b/aio/content/examples/event-binding/src/app/app.module.ts @@ -0,0 +1,22 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + + +import { AppComponent } from './app.component'; +import { ItemDetailComponent } from './item-detail/item-detail.component'; +import { ClickDirective } from './click.directive'; + + +@NgModule({ + declarations: [ + AppComponent, + ItemDetailComponent, + ClickDirective + ], + imports: [ + BrowserModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/aio/content/examples/event-binding/src/app/click.directive.ts b/aio/content/examples/event-binding/src/app/click.directive.ts new file mode 100644 index 0000000000..4e9e9085b1 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/click.directive.ts @@ -0,0 +1,18 @@ +/* tslint:disable use-output-property-decorator directive-class-suffix */ +import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'; + +@Directive({selector: '[myClick]'}) +export class ClickDirective { + @Output('myClick') clicks = new EventEmitter(); // @Output(alias) propertyName = ... + + toggle = false; + + constructor(el: ElementRef) { + el.nativeElement + .addEventListener('click', (event: Event) => { + this.toggle = !this.toggle; + this.clicks.emit(this.toggle ? 'Click!' : ''); + }); + } +} + diff --git a/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.css b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.css new file mode 100644 index 0000000000..38789a8947 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.css @@ -0,0 +1,11 @@ +.detail { + border: 1px solid rgb(25, 118, 210); + padding: 1rem; + margin: 1rem 0; +} + +img { + max-width: 100px; + display: block; + padding: 1rem 0; +} diff --git a/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.html b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.html new file mode 100644 index 0000000000..0cd2c19720 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.html @@ -0,0 +1,9 @@ +
+

This is the ItemDetailComponent

+ + + {{ item.name }} + + + +
diff --git a/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.spec.ts b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.spec.ts new file mode 100644 index 0000000000..7559cb65f6 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ItemDetailComponent } from './item-detail.component'; + +describe('ItemDetailComponent', () => { + let component: ItemDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ItemDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ItemDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.ts b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.ts new file mode 100644 index 0000000000..94ea032ce3 --- /dev/null +++ b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.ts @@ -0,0 +1,30 @@ +/* tslint:disable use-input-property-decorator use-output-property-decorator */ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +import { Item } from '../item'; + +@Component({ + selector: 'app-item-detail', + styleUrls: ['./item-detail.component.css'], + templateUrl: './item-detail.component.html' +}) +export class ItemDetailComponent { + + @Input() item; + itemImageUrl = 'assets/teapot.svg'; + lineThrough = ''; + displayNone = ''; + @Input() prefix = ''; + + // #docregion deleteRequest + // This component makes a request but it can't actually delete a hero. + @Output() deleteRequest = new EventEmitter(); + + delete() { + this.deleteRequest.emit(this.item.name); + this.displayNone = this.displayNone ? '' : 'none'; + this.lineThrough = this.lineThrough ? '' : 'line-through'; + } + // #enddocregion deleteRequest + +} diff --git a/aio/content/examples/event-binding/src/app/item.ts b/aio/content/examples/event-binding/src/app/item.ts new file mode 100644 index 0000000000..1a80527e1c --- /dev/null +++ b/aio/content/examples/event-binding/src/app/item.ts @@ -0,0 +1,4 @@ +export class Item { + name: ''; +} + diff --git a/aio/content/examples/event-binding/src/assets/teapot.svg b/aio/content/examples/event-binding/src/assets/teapot.svg new file mode 100644 index 0000000000..b5f51cf030 --- /dev/null +++ b/aio/content/examples/event-binding/src/assets/teapot.svg @@ -0,0 +1 @@ + diff --git a/integration/bazel-schematics/index.html b/aio/content/examples/event-binding/src/index.html similarity index 89% rename from integration/bazel-schematics/index.html rename to aio/content/examples/event-binding/src/index.html index 77e5ff2c6c..37a728cf33 100644 --- a/integration/bazel-schematics/index.html +++ b/aio/content/examples/event-binding/src/index.html @@ -2,7 +2,7 @@ - Demo + EventBinding diff --git a/integration/cli-hello-world-ivy/src/main.ts b/aio/content/examples/event-binding/src/main.ts similarity index 100% rename from integration/cli-hello-world-ivy/src/main.ts rename to aio/content/examples/event-binding/src/main.ts diff --git a/aio/content/examples/event-binding/stackblitz.json b/aio/content/examples/event-binding/stackblitz.json new file mode 100644 index 0000000000..765446194d --- /dev/null +++ b/aio/content/examples/event-binding/stackblitz.json @@ -0,0 +1,10 @@ +{ + "description": "Event Binding", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1,2].*" + ], + "file": "src/app/app.component.ts", + "tags": ["Event Binding"] +} diff --git a/aio/content/examples/http/e2e/src/app.e2e-spec.ts b/aio/content/examples/http/e2e/src/app.e2e-spec.ts index d0a77b5239..9baf2cdc65 100644 --- a/aio/content/examples/http/e2e/src/app.e2e-spec.ts +++ b/aio/content/examples/http/e2e/src/app.e2e-spec.ts @@ -28,10 +28,7 @@ let checkLogForMessage = (message: string) => { expect(page.logList.getText()).toContain(message); }; -// TODO(i): temorarily disable these tests because angular-in-memory-web-api is not compatible with rxjs v6 yet -// and we don't have the backwards compatibility package yet. -// Reenable after rxjs v6 compatibility package is out or angular-in-memory-web-api is compatible with rxjs v6 -xdescribe('Http Tests', function() { +describe('Http Tests', function() { beforeEach(() => { browser.get(''); }); diff --git a/aio/content/examples/i18n/example-config.json b/aio/content/examples/i18n/example-config.json index 1188a704a3..99b45f2c49 100644 --- a/aio/content/examples/i18n/example-config.json +++ b/aio/content/examples/i18n/example-config.json @@ -1,3 +1,12 @@ { - "projectType": "i18n" -} + "projectType": "i18n", + "e2e": [ + { + "cmd": "yarn", + "args": [ + "e2e", + "--no-webdriver-update" + ] + } + ] +} \ No newline at end of file diff --git a/aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts b/aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000000..06def93fc6 --- /dev/null +++ b/aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts @@ -0,0 +1,47 @@ +import { browser, element, by } from 'protractor'; + +describe('Interpolation e2e tests', () => { + + beforeEach(function () { + browser.get(''); + }); + + it('should display Interpolation and Template Expressions', function () { + expect(element(by.css('h1')).getText()).toEqual('Interpolation and Template Expressions'); + }); + + it('should display Current customer: Maria', function () { + expect(element.all(by.css('h3')).get(0).getText()).toBe(`Current customer: Maria`); + }); + + it('should display The sum of 1 + 1 is not 4.', function () { + expect(element.all(by.css('p:last-child')).get(0).getText()).toBe(`The sum of 1 + 1 is not 4.`); + }); + + it('should display Expression Context', function () { + expect(element.all(by.css('h2')).get(1).getText()).toBe(`Expression Context`); + }); + + it('should display a list of customers', function () { + expect(element.all(by.css('li')).get(0).getText()).toBe(`Maria`); + }); + + it('should display two pictures', function() { + let pottedPlant = element.all(by.css('img')).get(0); + let lamp = element.all(by.css('img')).get(1); + + expect(pottedPlant.getAttribute('src')).toContain('pottedPlant'); + expect(pottedPlant.isDisplayed()).toBe(true); + + expect(lamp.getAttribute('src')).toContain('lamp'); + expect(lamp.isDisplayed()).toBe(true); + }); + + it('should support user input', function () { + let input = element(by.css('input')); + let label = element(by.css('label')); + expect(label.getText()).toEqual('Type something:'); + input.sendKeys('abc'); + expect(label.getText()).toEqual('Type something: abc'); + }); +}); diff --git a/aio/content/examples/router/src/app/crisis-list/crisis-list.component.css b/aio/content/examples/interpolation/example-config.json similarity index 100% rename from aio/content/examples/router/src/app/crisis-list/crisis-list.component.css rename to aio/content/examples/interpolation/example-config.json diff --git a/integration/cli-hello-world-ivy/src/app/app.component.css b/aio/content/examples/interpolation/src/app/app.component.css similarity index 100% rename from integration/cli-hello-world-ivy/src/app/app.component.css rename to aio/content/examples/interpolation/src/app/app.component.css diff --git a/aio/content/examples/interpolation/src/app/app.component.html b/aio/content/examples/interpolation/src/app/app.component.html new file mode 100644 index 0000000000..992627d3a5 --- /dev/null +++ b/aio/content/examples/interpolation/src/app/app.component.html @@ -0,0 +1,59 @@ + +
+

Interpolation and Template Expressions

+
+ +
+

Interpolation

+ +

Current customer: {{ currentCustomer }}

+ + + +

{{title}}

+
+ + +

Evaluating template expressions

+

Simple evaluation (to a string):

+ + +

The sum of 1 + 1 is {{1 + 1}}.

+ + +

Evaluates using a method (also evaluates to a string):

+ + +

The sum of 1 + 1 is not {{1 + 1 + getVal()}}.

+ +
+ +
+

Expression Context

+ +
+

Component context, properties of app.component.ts:

+ +

{{recommended}}

+ + +
+ +
+

Template context, template input variables (let customer):

+ +
    +
  • {{customer.name}}
  • +
+ +
+ +
+

Template context: template reference variables (#customerInput):

+ + +
+ +
diff --git a/integration/cli-hello-world-ivy/src/app/app.component.spec.ts b/aio/content/examples/interpolation/src/app/app.component.spec.ts similarity index 75% rename from integration/cli-hello-world-ivy/src/app/app.component.spec.ts rename to aio/content/examples/interpolation/src/app/app.component.spec.ts index fc23152599..7fb8d406db 100644 --- a/integration/cli-hello-world-ivy/src/app/app.component.spec.ts +++ b/aio/content/examples/interpolation/src/app/app.component.spec.ts @@ -14,15 +14,15 @@ describe('AppComponent', () => { const app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); })); - it(`should have as title 'app'`, async(() => { + it(`should have as title 'Featured product:'`, async(() => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; - expect(app.title).toEqual('app'); + expect(app.title).toEqual('Featured product:'); })); - it('should render title in a h1 tag', async(() => { + it('should render title in a p tag', async(() => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); + expect(compiled.querySelector('p').textContent).toContain('Featured product:'); })); }); diff --git a/aio/content/examples/interpolation/src/app/app.component.ts b/aio/content/examples/interpolation/src/app/app.component.ts new file mode 100644 index 0000000000..06bb18afc0 --- /dev/null +++ b/aio/content/examples/interpolation/src/app/app.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; + +import { CUSTOMERS } from './customers'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + customers = CUSTOMERS; + + currentCustomer = 'Maria'; + title = 'Featured product:'; + itemImageUrl = '../assets/pottedPlant.png'; + + recommended = 'You might also like:'; + itemImageUrl2 = '../assets/lamp.png'; + + + + getVal(): number { return 2; } + + +} diff --git a/aio/content/examples/interpolation/src/app/app.module.ts b/aio/content/examples/interpolation/src/app/app.module.ts new file mode 100644 index 0000000000..926975afe8 --- /dev/null +++ b/aio/content/examples/interpolation/src/app/app.module.ts @@ -0,0 +1,18 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; + + +import { AppComponent } from './app.component'; + + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/aio/content/examples/interpolation/src/app/customer.ts b/aio/content/examples/interpolation/src/app/customer.ts new file mode 100644 index 0000000000..c191255efb --- /dev/null +++ b/aio/content/examples/interpolation/src/app/customer.ts @@ -0,0 +1,3 @@ +export class Customer { + name: string; +} diff --git a/aio/content/examples/interpolation/src/app/customers.ts b/aio/content/examples/interpolation/src/app/customers.ts new file mode 100644 index 0000000000..a1d25b93c9 --- /dev/null +++ b/aio/content/examples/interpolation/src/app/customers.ts @@ -0,0 +1,9 @@ +import { Customer } from './customer'; + +export const CUSTOMERS: Customer[] = [ + { name: 'Maria' }, + { name: 'Oliver' }, + { name: 'Walter' }, + { name: 'Lakshmi' }, + { name: 'Yasha' } +]; diff --git a/aio/content/examples/interpolation/src/assets/lamp.png b/aio/content/examples/interpolation/src/assets/lamp.png new file mode 100644 index 0000000000..24dce11901 Binary files /dev/null and b/aio/content/examples/interpolation/src/assets/lamp.png differ diff --git a/aio/content/examples/interpolation/src/assets/potted-plant.png b/aio/content/examples/interpolation/src/assets/potted-plant.png new file mode 100644 index 0000000000..9c40e4a54c Binary files /dev/null and b/aio/content/examples/interpolation/src/assets/potted-plant.png differ diff --git a/integration/cli-hello-world-ivy/src/index.html b/aio/content/examples/interpolation/src/index.html similarity index 77% rename from integration/cli-hello-world-ivy/src/index.html rename to aio/content/examples/interpolation/src/index.html index 8362f15b8f..92f30d0e84 100644 --- a/integration/cli-hello-world-ivy/src/index.html +++ b/aio/content/examples/interpolation/src/index.html @@ -2,12 +2,11 @@ - CliHelloWorld + Interpolation - diff --git a/aio/content/examples/interpolation/src/main.ts b/aio/content/examples/interpolation/src/main.ts new file mode 100644 index 0000000000..91ec6da5f0 --- /dev/null +++ b/aio/content/examples/interpolation/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.log(err)); diff --git a/aio/content/examples/interpolation/stackblitz.json b/aio/content/examples/interpolation/stackblitz.json new file mode 100644 index 0000000000..f33d39c88f --- /dev/null +++ b/aio/content/examples/interpolation/stackblitz.json @@ -0,0 +1,10 @@ +{ + "description": "Interpolation", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1,2].*" + ], + "file": "src/app/app.component.ts", + "tags": ["interpolation"] +} diff --git a/aio/content/examples/ngmodule-faq/src/app/app.module.3.ts b/aio/content/examples/ngmodule-faq/src/app/app.module.3.ts index 6fef183d9c..aace81b56f 100644 --- a/aio/content/examples/ngmodule-faq/src/app/app.module.3.ts +++ b/aio/content/examples/ngmodule-faq/src/app/app.module.3.ts @@ -13,8 +13,8 @@ import { AppComponent } from './app.component'; // #enddocregion */ // #docregion -import { HighlightDirective } from './highlight.directive'; -import { TitleComponent } from './title.component'; +import { HighlightDirective } from './highlight.directive.1'; +import { TitleComponent } from './title.component.1'; import { UserService } from './user.service'; /* Routing Module */ diff --git a/aio/content/examples/ngmodule-faq/src/app/contact/awesome.pipe.ts b/aio/content/examples/ngmodule-faq/src/app/contact/awesome.pipe.ts deleted file mode 100644 index d6dce99901..0000000000 --- a/aio/content/examples/ngmodule-faq/src/app/contact/awesome.pipe.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ name: 'awesome' }) -/** Precede the input string with the word "Awesome " */ -export class AwesomePipe implements PipeTransform { - transform(phrase: string) { - return phrase ? 'Awesome ' + phrase : ''; - } -} diff --git a/aio/content/examples/ngmodule-faq/src/app/contact/contact-highlight.directive.ts b/aio/content/examples/ngmodule-faq/src/app/contact/contact-highlight.directive.ts deleted file mode 100644 index a71dac6742..0000000000 --- a/aio/content/examples/ngmodule-faq/src/app/contact/contact-highlight.directive.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docplaster -// Same directive name and selector as -// HighlightDirective in parent AppModule -// It selects for both input boxes and 'highlight' attr -// and it highlights in blue instead of gold - -// #docregion -import { Directive, ElementRef } from '@angular/core'; - -// Highlight the host element or any InputElement in blue -@Directive({ selector: '[highlight], input' }) -export class ContactHighlightDirective { - constructor(el: ElementRef) { - el.nativeElement.style.backgroundColor = 'powderblue'; - // #enddocregion - console.log(`* Contact highlight called for ${el.nativeElement.tagName}`); - // #docregion - } -} -// #enddocregion diff --git a/aio/content/examples/ngmodule-faq/src/app/hero/highlight.directive.ts b/aio/content/examples/ngmodule-faq/src/app/hero/highlight.directive.ts deleted file mode 100644 index d7e39afd05..0000000000 --- a/aio/content/examples/ngmodule-faq/src/app/hero/highlight.directive.ts +++ /dev/null @@ -1,14 +0,0 @@ -// #docregion -import { Directive, ElementRef } from '@angular/core'; - -// Same directive name and selector as -// HighlightDirective in parent AppRootModule -// It selects for both input boxes and 'highlight' attr -// and it highlights in beige instead of yellow -@Directive({ selector: '[highlight]' }) -export class HighlightDirective { - constructor(el: ElementRef) { - el.nativeElement.style.backgroundColor = 'beige'; - console.log(`* Hero highlight called for ${el.nativeElement.tagName}`); - } -} diff --git a/aio/content/examples/ngmodule-faq/src/app/highlight.directive.ts b/aio/content/examples/ngmodule-faq/src/app/highlight.directive.1.ts similarity index 100% rename from aio/content/examples/ngmodule-faq/src/app/highlight.directive.ts rename to aio/content/examples/ngmodule-faq/src/app/highlight.directive.1.ts diff --git a/aio/content/examples/ngmodule-faq/src/app/title.component.html b/aio/content/examples/ngmodule-faq/src/app/title.component.1.html similarity index 100% rename from aio/content/examples/ngmodule-faq/src/app/title.component.html rename to aio/content/examples/ngmodule-faq/src/app/title.component.1.html diff --git a/aio/content/examples/ngmodule-faq/src/app/title.component.ts b/aio/content/examples/ngmodule-faq/src/app/title.component.1.ts similarity index 91% rename from aio/content/examples/ngmodule-faq/src/app/title.component.ts rename to aio/content/examples/ngmodule-faq/src/app/title.component.1.ts index b0761208a0..39e434e7e6 100644 --- a/aio/content/examples/ngmodule-faq/src/app/title.component.ts +++ b/aio/content/examples/ngmodule-faq/src/app/title.component.1.ts @@ -8,7 +8,7 @@ import { UserService } from './user.service'; @Component({ selector: 'app-title', - templateUrl: './title.component.html' + templateUrl: './title.component.1.html' }) export class TitleComponent { title = 'Angular Modules'; diff --git a/aio/content/examples/ngmodules/src/app/items/items.service.ts b/aio/content/examples/ngmodules/src/app/items/items.service.ts index 39968b452f..c764ad859e 100644 --- a/aio/content/examples/ngmodules/src/app/items/items.service.ts +++ b/aio/content/examples/ngmodules/src/app/items/items.service.ts @@ -16,7 +16,7 @@ const ITEMS: Item[] = [ const FETCH_LATENCY = 500; -/** Simulate a data service that retrieves crises from a server */ +/** Simulate a data service that retrieves items from a server */ @Injectable() export class ItemService implements OnDestroy { diff --git a/aio/content/examples/observables-in-angular/src/main.ts b/aio/content/examples/observables-in-angular/src/main.ts index c5e95560f5..f010819b4d 100644 --- a/aio/content/examples/observables-in-angular/src/main.ts +++ b/aio/content/examples/observables-in-angular/src/main.ts @@ -61,7 +61,7 @@ export class Routable1Component implements OnInit { navStart: Observable; constructor(private router: Router) { - // Create a new Observable the publishes only the NavigationStart event + // Create a new Observable that publishes only the NavigationStart event this.navStart = router.events.pipe( filter(evt => evt instanceof NavigationStart) ) as Observable; diff --git a/aio/content/examples/practical-observable-usage/src/backoff.ts b/aio/content/examples/practical-observable-usage/src/backoff.ts index 97b53845f1..e9e88e7cb2 100644 --- a/aio/content/examples/practical-observable-usage/src/backoff.ts +++ b/aio/content/examples/practical-observable-usage/src/backoff.ts @@ -5,10 +5,9 @@ import { retryWhen, map, mergeMap } from 'rxjs/operators'; function backoff(maxTries, ms) { return pipe( - retryWhen(attempts => range(1, maxTries) + retryWhen(attempts => zip(range(1, maxTries), attempts) .pipe( - zip(attempts, (i) => i), - map(i => i * i), + map(([i]) => i * i), mergeMap(i => timer(i * ms)) ) ) diff --git a/aio/content/examples/property-binding/src/app/app.component.ts b/aio/content/examples/property-binding/src/app/app.component.ts new file mode 100644 index 0000000000..1c52d44ebe --- /dev/null +++ b/aio/content/examples/property-binding/src/app/app.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; + + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + itemImageUrl = '../assets/lamp.png'; + isUnchanged = true; + classes = 'special'; + // #docregion parent-data-type + parentItem = 'bananas'; + // #enddocregion parent-data-type + + // #docregion pass-object + currentItem = [{ + id: 21, + name: 'peaches' + }]; + // #enddocregion pass-object + + interpolationTitle = 'Interpolation'; + propertyTitle = 'Property binding'; + + // #docregion malicious-content + evilTitle = 'Template Syntax'; + // #enddocregion malicious-content +} diff --git a/aio/content/examples/quickstart/bs-config.1.json b/aio/content/examples/quickstart/bs-config.1.json deleted file mode 100644 index 4e58595267..0000000000 --- a/aio/content/examples/quickstart/bs-config.1.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "server": { - "baseDir": "src", - "routes": { - "/node_modules": "node_modules" - } - } -} diff --git a/aio/content/examples/quickstart/src/app/app.component.ts b/aio/content/examples/quickstart/src/app/app.component.ts deleted file mode 100644 index 1ef28fc5c4..0000000000 --- a/aio/content/examples/quickstart/src/app/app.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -import { Component } from '@angular/core'; - -@Component({ - selector: 'my-app', - template: `

Hello {{name}}

` -}) -export class AppComponent { name = 'Angular'; } diff --git a/aio/content/examples/quickstart/src/app/app.module.ts b/aio/content/examples/quickstart/src/app/app.module.ts deleted file mode 100644 index 50a0e6eb47..0000000000 --- a/aio/content/examples/quickstart/src/app/app.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { AppComponent } from './app.component'; - -@NgModule({ - imports: [ BrowserModule ], - declarations: [ AppComponent ], - bootstrap: [ AppComponent ] -}) -export class AppModule { } diff --git a/aio/content/examples/quickstart/src/index.html b/aio/content/examples/quickstart/src/index.html deleted file mode 100644 index 21fb56edb9..0000000000 --- a/aio/content/examples/quickstart/src/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - Angular Quickstart - - - - - - - - - - - - - - - - - - - Loading AppComponent content here ... - - - - diff --git a/aio/content/examples/quickstart/src/main.ts b/aio/content/examples/quickstart/src/main.ts deleted file mode 100644 index 311c44b76d..0000000000 --- a/aio/content/examples/quickstart/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - -import { AppModule } from './app/app.module'; - -platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/aio/content/examples/quickstart/src/tsconfig.1.json b/aio/content/examples/quickstart/src/tsconfig.1.json deleted file mode 100644 index 2c7260d1bc..0000000000 --- a/aio/content/examples/quickstart/src/tsconfig.1.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "commonjs", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": [ "es2015", "dom" ], - "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true - } -} diff --git a/aio/content/examples/quickstart/stackblitz.json b/aio/content/examples/quickstart/stackblitz.json deleted file mode 100644 index fd606e2ab9..0000000000 --- a/aio/content/examples/quickstart/stackblitz.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "description": "QuickStart", - "files": [ - "src/app/app.component.ts", - "src/app/app.module.ts", - "src/main.ts", - "src/index.html" - ], - "file": "src/app/app.component.ts", - "tags": ["quickstart"] -} diff --git a/aio/content/examples/router/src/app/hero-list/hero-list.component.css b/aio/content/examples/router/src/app/crisis-list/crisis-list.component.1.css similarity index 100% rename from aio/content/examples/router/src/app/hero-list/hero-list.component.css rename to aio/content/examples/router/src/app/crisis-list/crisis-list.component.1.css diff --git a/aio/content/examples/router/src/app/crisis-list/crisis-list.component.html b/aio/content/examples/router/src/app/crisis-list/crisis-list.component.1.html similarity index 100% rename from aio/content/examples/router/src/app/crisis-list/crisis-list.component.html rename to aio/content/examples/router/src/app/crisis-list/crisis-list.component.1.html diff --git a/aio/content/examples/router/src/app/crisis-list/crisis-list.component.ts b/aio/content/examples/router/src/app/crisis-list/crisis-list.component.1.ts similarity index 63% rename from aio/content/examples/router/src/app/crisis-list/crisis-list.component.ts rename to aio/content/examples/router/src/app/crisis-list/crisis-list.component.1.ts index 2fa2e05e49..e8945db638 100644 --- a/aio/content/examples/router/src/app/crisis-list/crisis-list.component.ts +++ b/aio/content/examples/router/src/app/crisis-list/crisis-list.component.1.ts @@ -4,7 +4,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-crisis-list', - templateUrl: './crisis-list.component.html', - styleUrls: ['./crisis-list.component.css'] + templateUrl: './crisis-list.component.1.html', + styleUrls: ['./crisis-list.component.1.css'] }) export class CrisisListComponent { } diff --git a/integration/cli-hello-world-ivy/src/assets/.gitkeep b/aio/content/examples/router/src/app/hero-list/hero-list.component.1.css similarity index 100% rename from integration/cli-hello-world-ivy/src/assets/.gitkeep rename to aio/content/examples/router/src/app/hero-list/hero-list.component.1.css diff --git a/aio/content/examples/router/src/app/hero-list/hero-list.component.html b/aio/content/examples/router/src/app/hero-list/hero-list.component.1.html similarity index 100% rename from aio/content/examples/router/src/app/hero-list/hero-list.component.html rename to aio/content/examples/router/src/app/hero-list/hero-list.component.1.html diff --git a/aio/content/examples/router/src/app/hero-list/hero-list.component.ts b/aio/content/examples/router/src/app/hero-list/hero-list.component.1.ts similarity index 60% rename from aio/content/examples/router/src/app/hero-list/hero-list.component.ts rename to aio/content/examples/router/src/app/hero-list/hero-list.component.1.ts index 5ee06903c0..cbf2e54d99 100644 --- a/aio/content/examples/router/src/app/hero-list/hero-list.component.ts +++ b/aio/content/examples/router/src/app/hero-list/hero-list.component.1.ts @@ -4,7 +4,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'app-hero-list', - templateUrl: './hero-list.component.html', - styleUrls: ['./hero-list.component.css'] + templateUrl: './hero-list.component.1.html', + styleUrls: ['./hero-list.component.1.css'] }) export class HeroListComponent { } diff --git a/aio/content/examples/rx-library/src/simple-creation.ts b/aio/content/examples/rx-library/src/simple-creation.ts index 810e398e85..9c576ffca0 100644 --- a/aio/content/examples/rx-library/src/simple-creation.ts +++ b/aio/content/examples/rx-library/src/simple-creation.ts @@ -1,10 +1,10 @@ // #docregion promise -import { fromPromise } from 'rxjs'; +import { from } from 'rxjs'; // Create an Observable out of a promise -const data = fromPromise(fetch('/api/endpoint')); +const data = from(fetch('/api/endpoint')); // Subscribe to begin listening for async result data.subscribe({ next(response) { console.log(response); }, diff --git a/aio/content/examples/service-worker-getting-started/e2e/src/app.e2e-spec.ts b/aio/content/examples/service-worker-getting-started/e2e/src/app.e2e-spec.ts index 6d77937689..c221f0ebb6 100755 --- a/aio/content/examples/service-worker-getting-started/e2e/src/app.e2e-spec.ts +++ b/aio/content/examples/service-worker-getting-started/e2e/src/app.e2e-spec.ts @@ -34,8 +34,9 @@ describe('sw-example App', () => { expect(items[3].getText()).toBe('Angular blog'); }); }); - // Check for a rejected promise as the service worker is not enabled - it('SwUpdate.checkForUpdate() should return a rejected promise', () => { + + // Check for a rejected promise as the service worker is not enabled + it('SwUpdate.checkForUpdate() should return a rejected promise', () => { const button = element(by.css('button')); const rejectMessage = element(by.css('p')); button.click(); diff --git a/aio/content/examples/service-worker-getting-started/example-config.json b/aio/content/examples/service-worker-getting-started/example-config.json index e69de29bb2..b0e7e5672e 100644 --- a/aio/content/examples/service-worker-getting-started/example-config.json +++ b/aio/content/examples/service-worker-getting-started/example-config.json @@ -0,0 +1,10 @@ +{ + "projectType": "service-worker", + "e2e": [ + {"cmd": "yarn", "args": ["e2e", "--no-webdriver-update"]}, + {"cmd": "yarn", "args": ["build", "--prod"]}, + {"cmd": "node", "args": ["--eval", "assert(fs.existsSync('./dist/ngsw.json'), 'ngsw.json is missing')"]}, + {"cmd": "node", "args": ["--eval", "assert(fs.existsSync('./dist/ngsw-worker.js'), 'ngsw-worker.js is missing')"]}, + {"cmd": "node", "args": ["--eval", "assert(require('./package.json').dependencies['@angular/service-worker'], '@angular/service-worker is missing')"]} + ] +} diff --git a/aio/content/examples/service-worker-getting-started/src/ngsw-config.json b/aio/content/examples/service-worker-getting-started/ngsw-config.json old mode 100755 new mode 100644 similarity index 100% rename from aio/content/examples/service-worker-getting-started/src/ngsw-config.json rename to aio/content/examples/service-worker-getting-started/ngsw-config.json diff --git a/aio/content/examples/service-worker-getting-started/src/app/app.component.ts b/aio/content/examples/service-worker-getting-started/src/app/app.component.ts index 67cc894396..a2aa3028c5 100755 --- a/aio/content/examples/service-worker-getting-started/src/app/app.component.ts +++ b/aio/content/examples/service-worker-getting-started/src/app/app.component.ts @@ -12,9 +12,9 @@ export class AppComponent { constructor(private update: SwUpdate) {} updateCheck(): void { - this.update + this.update .checkForUpdate() .then(() => this.updateCheckText = 'resolved') .catch(err => this.updateCheckText = `rejected: ${err.message}`); - } + } } diff --git a/aio/content/examples/service-worker-getting-started/src/app/check-for-update.service.ts b/aio/content/examples/service-worker-getting-started/src/app/check-for-update.service.ts index 194b555ace..7375ac5bae 100755 --- a/aio/content/examples/service-worker-getting-started/src/app/check-for-update.service.ts +++ b/aio/content/examples/service-worker-getting-started/src/app/check-for-update.service.ts @@ -1,15 +1,17 @@ -import { Injectable } from '@angular/core'; +import { ApplicationRef, Injectable } from '@angular/core'; import { SwUpdate } from '@angular/service-worker'; - - -// #docregion sw-check-update -import { interval } from 'rxjs'; +import { concat, interval } from 'rxjs'; +import { first } from 'rxjs/operators'; @Injectable() export class CheckForUpdateService { - constructor(updates: SwUpdate) { - interval(6 * 60 * 60).subscribe(() => updates.checkForUpdate()); + constructor(appRef: ApplicationRef, updates: SwUpdate) { + // Allow the app to stabilize first, before starting polling for updates with `interval()`. + const appIsStable$ = appRef.isStable.pipe(first(isStable => isStable === true)); + const everySixHours$ = interval(6 * 60 * 60 * 1000); + const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$); + + everySixHoursOnceAppIsStable$.subscribe(() => updates.checkForUpdate()); } } -// #enddocregion sw-check-update diff --git a/aio/content/examples/setup/e2e-spec.ts b/aio/content/examples/setup/e2e-spec.ts deleted file mode 100644 index 73921707ee..0000000000 --- a/aio/content/examples/setup/e2e-spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; // necessary for es6 output in node - -import { browser, element, by } from 'protractor'; - -describe('QuickStart E2E Tests', function () { - - let expectedMsg = 'Hello Angular'; - - beforeEach(function () { - browser.get(''); - }); - - it(`should display: ${expectedMsg}`, function () { - expect(element(by.css('h1')).getText()).toEqual(expectedMsg); - }); - -}); diff --git a/aio/content/examples/quickstart/e2e-spec.ts b/aio/content/examples/setup/e2e/src/app.e2e-spec.ts similarity index 100% rename from aio/content/examples/quickstart/e2e-spec.ts rename to aio/content/examples/setup/e2e/src/app.e2e-spec.ts diff --git a/aio/content/examples/styleguide/src/03-06/app/core/spinner/index.ts b/aio/content/examples/styleguide/src/03-06/app/core/spinner/index.ts index 1d619300c0..19618714a5 100644 --- a/aio/content/examples/styleguide/src/03-06/app/core/spinner/index.ts +++ b/aio/content/examples/styleguide/src/03-06/app/core/spinner/index.ts @@ -1,3 +1,2 @@ // #docregion -export * from './spinner.component'; export * from './spinner.service'; diff --git a/aio/content/examples/styleguide/src/03-06/app/core/spinner/spinner.component.ts b/aio/content/examples/styleguide/src/03-06/app/core/spinner/spinner.component.ts deleted file mode 100644 index 1fd2a01500..0000000000 --- a/aio/content/examples/styleguide/src/03-06/app/core/spinner/spinner.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; - -import { SpinnerService } from './spinner.service'; - -@Component({ - selector: 'toh-spinner', - template: '
spinner
' -}) - -export class SpinnerComponent implements OnDestroy, OnInit { - constructor(private spinnerService: SpinnerService) { } - - ngOnInit() { } - - ngOnDestroy() { } -} diff --git a/aio/content/examples/styleguide/src/03-06/app/core/toast/index.ts b/aio/content/examples/styleguide/src/03-06/app/core/toast/index.ts index 01b41aff98..0a88fb952d 100644 --- a/aio/content/examples/styleguide/src/03-06/app/core/toast/index.ts +++ b/aio/content/examples/styleguide/src/03-06/app/core/toast/index.ts @@ -1,3 +1,2 @@ // #docregion -export * from './toast.component'; export * from './toast.service'; diff --git a/aio/content/examples/styleguide/src/03-06/app/core/toast/toast.component.ts b/aio/content/examples/styleguide/src/03-06/app/core/toast/toast.component.ts deleted file mode 100644 index dd0bba5eba..0000000000 --- a/aio/content/examples/styleguide/src/03-06/app/core/toast/toast.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { ToastService } from './toast.service'; - -@Component({ - selector: 'toh-toast', - template: '
toast
' -}) -export class ToastComponent implements OnInit { - constructor(toastService: ToastService) { } - - ngOnInit() { } -} diff --git a/aio/content/examples/styleguide/src/03-06/app/shared/toast/toast.component.ts b/aio/content/examples/styleguide/src/03-06/app/shared/toast/toast.component.ts deleted file mode 100644 index e1c1ae6665..0000000000 --- a/aio/content/examples/styleguide/src/03-06/app/shared/toast/toast.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -import { ToastService } from '../../core'; - -@Component({ - selector: 'toh-toast', - template: '
toast
' -}) -export class ToastComponent implements OnInit { - constructor(toastService: ToastService) { } - - ngOnInit() { } -} diff --git a/aio/content/examples/styleguide/src/05-13/app/app.component.ts b/aio/content/examples/styleguide/src/05-13/app/app.component.ts index 7c9f37919f..3b440ba42e 100644 --- a/aio/content/examples/styleguide/src/05-13/app/app.component.ts +++ b/aio/content/examples/styleguide/src/05-13/app/app.component.ts @@ -4,4 +4,7 @@ import { Component } from '@angular/core'; selector: 'sg-app', templateUrl: './app.component.html' }) -export class AppComponent { } +export class AppComponent { + + doSomething() {} +} diff --git a/aio/content/examples/styleguide/src/05-16/app/app.component.ts b/aio/content/examples/styleguide/src/05-16/app/app.component.ts index 7c9f37919f..4d549e7166 100644 --- a/aio/content/examples/styleguide/src/05-16/app/app.component.ts +++ b/aio/content/examples/styleguide/src/05-16/app/app.component.ts @@ -4,4 +4,7 @@ import { Component } from '@angular/core'; selector: 'sg-app', templateUrl: './app.component.html' }) -export class AppComponent { } +export class AppComponent { + + onSavedTheDay(event$: any) { } +} diff --git a/aio/content/examples/template-syntax/src/app/app.component.ts b/aio/content/examples/template-syntax/src/app/app.component.ts index b1d4e484df..0758ba6516 100644 --- a/aio/content/examples/template-syntax/src/app/app.component.ts +++ b/aio/content/examples/template-syntax/src/app/app.component.ts @@ -66,7 +66,7 @@ export class AppComponent implements AfterViewInit, OnInit { currentHero: Hero; - deleteHero(hero: Hero) { + deleteHero(hero?: Hero) { this.alert(`Delete ${hero ? hero.name : 'the hero'}.`); } @@ -105,18 +105,18 @@ export class AppComponent implements AfterViewInit, OnInit { get nullHero(): Hero { return null; } - onClickMe(event: KeyboardEvent) { + onClickMe(event?: KeyboardEvent) { let evtMsg = event ? ' Event target class is ' + (event.target).className : ''; this.alert('Click me.' + evtMsg); } - onSave(event: KeyboardEvent) { + onSave(event?: KeyboardEvent) { let evtMsg = event ? ' Event target is ' + (event.target).textContent : ''; this.alert('Saved.' + evtMsg); if (event) { event.stopPropagation(); } } - onSubmit() {/* referenced but not used */} + onSubmit(data: any) {/* referenced but not used */} product = { name: 'frimfram', diff --git a/aio/content/examples/testing/src/testing/router-link-directive-stub.ts b/aio/content/examples/testing/src/testing/router-link-directive-stub.ts index 761529d726..4da6f8fd04 100644 --- a/aio/content/examples/testing/src/testing/router-link-directive-stub.ts +++ b/aio/content/examples/testing/src/testing/router-link-directive-stub.ts @@ -1,4 +1,4 @@ -import { Directive, Input } from '@angular/core'; +import { Directive, Input, HostListener } from '@angular/core'; // export for convenience. export { RouterLink} from '@angular/router'; @@ -6,13 +6,13 @@ export { RouterLink} from '@angular/router'; /* tslint:disable:directive-class-suffix */ // #docregion router-link @Directive({ - selector: '[routerLink]', - host: { '(click)': 'onClick()' } + selector: '[routerLink]' }) export class RouterLinkDirectiveStub { @Input('routerLink') linkParams: any; navigatedTo: any = null; + @HostListener('click') onClick() { this.navigatedTo = this.linkParams; } diff --git a/aio/content/examples/toh-pt6/src/app/hero.service.ts b/aio/content/examples/toh-pt6/src/app/hero.service.ts index c1e0b4d094..65afef4474 100644 --- a/aio/content/examples/toh-pt6/src/app/hero.service.ts +++ b/aio/content/examples/toh-pt6/src/app/hero.service.ts @@ -42,7 +42,7 @@ export class HeroService { // #enddocregion getHeroes-2 tap(_ => this.log('fetched heroes')), // #docregion getHeroes-2 - catchError(this.handleError('getHeroes', [])) + catchError(this.handleError('getHeroes', [])) ); // #docregion getHeroes-1 } @@ -97,7 +97,7 @@ export class HeroService { /** POST: add a new hero to the server */ addHero (hero: Hero): Observable { return this.http.post(this.heroesUrl, hero, httpOptions).pipe( - tap((hero: Hero) => this.log(`added hero w/ id=${hero.id}`)), + tap((newHero: Hero) => this.log(`added hero w/ id=${newHero.id}`)), catchError(this.handleError('addHero')) ); } diff --git a/aio/content/examples/upgrade-phonecat-2-hybrid/karma.conf.js b/aio/content/examples/upgrade-phonecat-2-hybrid/karma.conf.js index 88ec4a1c1a..fe8a6bc8dc 100644 --- a/aio/content/examples/upgrade-phonecat-2-hybrid/karma.conf.js +++ b/aio/content/examples/upgrade-phonecat-2-hybrid/karma.conf.js @@ -23,15 +23,6 @@ module.exports = function(config) { clearContext: false // leave Jasmine Spec Runner output visible in browser }, - customLaunchers: { - // From the CLI. Not used here but interesting - // chrome setup for travis CI using chromium - Chrome_travis_ci: { - base: 'Chrome', - flags: ['--no-sandbox'] - } - }, - files: [ // System.js for module loading 'node_modules/systemjs/dist/system.src.js', diff --git a/aio/content/examples/upgrade-phonecat-3-final/karma.conf.js b/aio/content/examples/upgrade-phonecat-3-final/karma.conf.js index a4b4d9dda1..d290d6e61e 100644 --- a/aio/content/examples/upgrade-phonecat-3-final/karma.conf.js +++ b/aio/content/examples/upgrade-phonecat-3-final/karma.conf.js @@ -23,15 +23,6 @@ module.exports = function(config) { clearContext: false // leave Jasmine Spec Runner output visible in browser }, - customLaunchers: { - // From the CLI. Not used here but interesting - // chrome setup for travis CI using chromium - Chrome_travis_ci: { - base: 'Chrome', - flags: ['--no-sandbox'] - } - }, - files: [ // System.js for module loading 'node_modules/systemjs/dist/system.src.js', diff --git a/aio/content/guide/aot-compiler.md b/aio/content/guide/aot-compiler.md index 56793a6826..7bca7af585 100644 --- a/aio/content/guide/aot-compiler.md +++ b/aio/content/guide/aot-compiler.md @@ -1066,7 +1066,7 @@ The compiler can only reference _exported symbols_. 编译器只能引用*已导出的符号*。 -Decorated component class members must be public. You cannot make an `@Input()` property private or internal. +Decorated component class members must be public. You cannot make an `@Input()` property private or protected. 带有装饰器的类成员必须是公开的。你不可能制作一个私有或内部使用的 `@Input()` 属性。 @@ -2570,7 +2570,7 @@ done manually. When `true`, this option tells the compiler not to check the TypeScript version. The compiler will skip checking and will not error out when an unsupported version of TypeScript is used. -Setting this option to `true` is not recommended because unsupported versions of TypeScript might have undefined behaviour. +Setting this option to `true` is not recommended because unsupported versions of TypeScript might have undefined behavior. 当为 `true` 时,该选项告诉编译器不要检查 TypeScript 的版本。 当时用了不支持的 TypeScript 版本时,该选项将会跳过检查,并且不会报错。 diff --git a/aio/content/guide/architecture-modules.md b/aio/content/guide/architecture-modules.md index f18a55e227..5d73dea1a0 100644 --- a/aio/content/guide/architecture-modules.md +++ b/aio/content/guide/architecture-modules.md @@ -143,7 +143,7 @@ JavaScript 中,每个*文件*是一个模块,文件中定义的所有对象 Component -Angular loads as a collection of JavaScript modules. You can think of them as library modules. Each Angular library name begins with the `@angular` prefix. Install them with the `npm` package manager and import parts of them with JavaScript `import` statements. +Angular loads as a collection of JavaScript modules. You can think of them as library modules. Each Angular library name begins with the `@angular` prefix. Install them with the node package manager `npm` and import parts of them with JavaScript `import` statements. Angular 会作为一组 JavaScript 模块进行加载,你可以把它们看成库模块。每个 Angular 库的名称都带有 `@angular` 前缀。 使用 `npm` 包管理器安装 Angular 的库,并使用 JavaScript 的 `import` 语句导入其中的各个部分。 diff --git a/aio/content/guide/architecture.md b/aio/content/guide/architecture.md index 358df7c72a..d068362e57 100644 --- a/aio/content/guide/architecture.md +++ b/aio/content/guide/architecture.md @@ -146,7 +146,7 @@ Angular 为一些通用的转换提供了预定义管道,你还可以定义自 ## 服务与依赖注入 -For data or logic that isn't associated with a specific view, and that you want to share across components, you create a *service* class. A service class definition is immediately preceded by the `@Injectable()` decorator. The decorator provides the metadata that allows your service to be *injected* into client components as a dependency. +For data or logic that isn't associated with a specific view, and that you want to share across components, you create a *service* class. A service class definition is immediately preceded by the `@Injectable()` decorator. The decorator provides the metadata that allows other providers to be **injected** as dependencies into your class. 对于与特定视图无关并希望跨组件共享的数据或逻辑,可以创建*服务*类。 服务类的定义通常紧跟在 “@Injectable()” 装饰器之后。该装饰器提供的元数据可以让你的服务作为依赖*被注入到*客户组件中。 diff --git a/aio/content/guide/browser-support.md b/aio/content/guide/browser-support.md index 4c4321ccb2..3b290f7710 100644 --- a/aio/content/guide/browser-support.md +++ b/aio/content/guide/browser-support.md @@ -555,6 +555,27 @@ Here are the features which may require additional polyfills: + + + + + [Router](guide/router) + + when using [hash-based routing](guide/router#appendix-locationstrategy-and-browser-url-styles) + + + + + [ES7/array](guide/browser-support#core-es7-array) + + + + + IE 11 + + + + ### Suggested polyfills ## @@ -599,7 +620,7 @@ Below are the polyfills which are used to test the framework itself. They are a - ES7/reflect + ES7/reflect @@ -617,6 +638,24 @@ Below are the polyfills which are used to test the framework itself. They are a + + + + + ES7/array + + + + + MIT + + + + 0.1KB + + + + diff --git a/aio/content/guide/build.md b/aio/content/guide/build.md index e5ded3f11c..ff57876ee2 100644 --- a/aio/content/guide/build.md +++ b/aio/content/guide/build.md @@ -83,7 +83,7 @@ The following sets content sets default values for the production build target: ``` export const environment = { - production: true + production: true, apiUrl: 'http://my-prod-url' }; ``` @@ -346,7 +346,7 @@ Each budget entry is a JSON object with the following properties: baseline - An absolute baseline size for percentage values. + The baseline size for comparison. 一个表示基准大小的绝对值,用做比例值的基数。 @@ -356,7 +356,7 @@ Each budget entry is a JSON object with the following properties: maximumWarning - Warns when a size exceeds this threshold percentage of the baseline. + The maximum threshold for warning relative to the baseline. 当大小超过基线的这个阈值百分比时给出警告。 @@ -366,7 +366,7 @@ Each budget entry is a JSON object with the following properties: maximumError - Reports an error when the size exceeds this threshold percentage of the baseline. + The maximum threshold for error relative to the baseline. 当大小超过基线的这个阈值百分比时报错。 @@ -376,7 +376,7 @@ Each budget entry is a JSON object with the following properties: minimumWarning - Warns when the size reaches this threshold percentage of the baseline. + The minimum threshold for warning relative to the baseline. 当大小小于基线的这个阈值百分比时给出警告。 @@ -386,7 +386,7 @@ Each budget entry is a JSON object with the following properties: minimumError - Reports an error when the size reaches this threshold percentage of the baseline. + The minimum threshold for error relative to the baseline. 当大小小于基线的这个阈值百分比时报错。 @@ -396,7 +396,7 @@ Each budget entry is a JSON object with the following properties: warning - Warns when the size ??reaches or exceeds?? this threshold percentage of the baseline. + The threshold for warning relative to the baseline (min & max). 当大小达到或小于基线的这个阈值百分比时都给出警告。 @@ -406,7 +406,7 @@ Each budget entry is a JSON object with the following properties: error - Reports an error when the size ??reaches or exceeds?? this threshold percentage of the baseline. + The threshold for error relative to the baseline (min & max). 当大小达到或小于基线的这个阈值百分比时都报错。 @@ -429,8 +429,8 @@ CLI 使用 [Autoprefixer](https://github.com/postcss/autoprefixer) 来确保对 你会发现当你要从构建中针对特定的目标浏览器或排除指定的浏览器版本时,这是很有必要的。 Internally, Autoprefixer relies on a library called [Browserslist](https://github.com/browserslist/browserslist) to figure out which browsers to support with prefixing. -Browserlist looks for configuration options in a `browserlist` property of the package configuration file, or in a configuration file named `.browserslistrc`. -Autoprefixer looks for the Browserlist configuration when it prefixes your CSS. +Browserlist looks for configuration options in a `browserslist` property of the package configuration file, or in a configuration file named `.browserslistrc`. +Autoprefixer looks for the `browserslist` configuration when it prefixes your CSS. 在内部 Autoprefixer 依赖一个名叫 [Browserslist](https://github.com/browserslist/browserslist) 的库来指出需要为哪些浏览器加前缀。 Browserlist 会在 `package.json` 的 `browserlist` 属性中或一个名叫 `.browserslistrc` 的配置文件中来配置这些选项。 diff --git a/aio/content/guide/creating-libraries.md b/aio/content/guide/creating-libraries.md new file mode 100644 index 0000000000..5b54d3e8a8 --- /dev/null +++ b/aio/content/guide/creating-libraries.md @@ -0,0 +1,189 @@ +# Creating Libraries + +You can create and publish new libraries to extend Angular functionality. If you find that you need to solve the same problem in more than one app (or want to share your solution with other developers), you have a candidate for a library. + +An simple example might be a button that sends users to your company website, that would be included in all apps that your company builds. + +## Getting started + +Use the Angular CLI to generate a new library skeleton with the following command: + + + ng generate library my-lib + + +This creates the `projects/my-lib` folder in your workspace, which contains a component and a service inside an NgModule. +The workspace configuration file, `angular.json`, is updated with a project of type 'library'. + + +"projects": { + ... + "my-lib": { + "root": "projects/my-lib", + "sourceRoot": "projects/my-lib/src", + "projectType": "library", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + ... + + +You can build, test, and lint the project with CLI commands: + + + ng build my-lib + ng test my-lib + ng lint my-lib + + +Notice that the configured builder for the project is different from the default builder for app projects. +This builder, among other things, ensures that the library is always built with the [AoT compiler](guide/aot-compiler), without the need to specify the `--prod` flag. + +To make library code reusable you must define a public API for it. This "user layer" defines what is available to consumers of your library. A user of your library should be able to access public functionality (such as NgModules, service providers and general utility functions) through a single import path. + +The public API for your library is maintained in the `index.ts` file of your library folder. +Anything exported from this file is made public when your library is imported into an application. +Use an NgModule to expose services and components. + +Your library should supply documentation (typically a README file) for installation and maintenance. + +## Refactoring parts of an app into a library + +To make your solution reusable, you need to adjust it so that it does not depend on app-specific code. +Here are some things to consider in migrating application functionality to a library. + +* Declarations such as components and pipes should be designed as stateless, meaning they don’t rely on or alter external variables. If you do rely on state, you need to evaluate every case and decide whether it is application state or state that the library would manage. + +* Any observables that the components subscribe to internally should be cleaned up and disposed of during the lifecycle of those components. + +* Components should expose their interactions through inputs for providing context, and outputs for communicating events to other components. + +* Services should declare their own providers (rather than declaring providers in the NgModule or a component), so that they are *tree-shakable*. This allows the compiler to leave the service out of the bundle if it never gets injected into the application that imports the library. For more about this, see [Tree-shakable providers](guide/dependency-injection-providers#tree-shakable-providers). + +* If you register global service providers or share providers across multiple NgModules, use the [`forRoot()` and `forChild()` patterns](guide/singleton-services) provided by the [RouterModule](api/router/RouterModule). + +* Check all internal dependencies. + * For custom classes or interfaces used in components or service, check whether they depend on additional classes or interfaces that also need to be migrated. + * Similarly, if your library code depends on a service, that service needs to be migrated. + * If your library code or its templates depend on other libraries (such a Angular Material, for instance), you must configure your library with those dependencies. + +## Reusable code and schematics + +A library typically includes *reusable code* that defines components, services, and other Angular artifacts (pipes, directives, and so on) that you simply import into a project. +A library is packaged into an npm package for publishing and sharing, and this package can also include [schematics](guide/glossary#schematic) that provide instructions for generating or transforming code directly in your project, in the same way that the CLI creates a generic skeleton app with `ng generate component`. +A schematic that is combined with a library can, for example, provide the Angular CLI with the information it needs to generate a particular component defined in that library. + +What you include in your library is determined by the kind of task you are trying to accomplish. +For example, if you want a dropdown with some canned data to show how to add it to your app, your library could define a schematic to create it. +For a component like a dropdown that would contain different passed-in values each time, you could provide it as a component in a shared library. + +Suppose you want to read a configuration file and then generate a form based on that configuration. +If that form will need additional customization by the user, it might work best as a schematic. +However, if the forms will always be the same and not need much customization by developers, then you could create a dynamic component that takes the configuration and generates the form. +In general, the more complex the customization, the more useful the schematic approach. + +## Integrating with the CLI + +A library can include [schematics](guide/glossary#schematic) that allow it to integrate with the Angular CLI. + +* Include an installation schematic so that `ng add` can add your library to a project. + +* Include generation schematics in your library so that `ng generate` can scaffold your defined artifacts (components, services, tests, and so on) in a project. + +* Include an update schematic so that `ng update` can update your library’s dependencies and provide migrations for breaking changes in new releases. + +To learn more, see [Schematics — An Introduction](https://blog.angular.io/schematics-an-introduction-dc1dfbc2a2b2). + +## Publishing your library + +Use the Angular CLI and the npm package manager to build and publish your library as an npm package. +Libraries are built in [AoT mode](guide/aot-compiler) by default, so you do not need to specify the `-prod` flag when building for publication. + + +ng build my-lib +cd dist/my-lib +npm publish + + +If you've never published a package in npm before, you must create a user account. Read more in [Publishing npm Packages](https://docs.npmjs.com/getting-started/publishing-npm-packages). + +## Linked libraries + +While working on a published library, you can use [npm link](https://docs.npmjs.com/cli/link) to avoid reinstalling the library on every build. + +The library must be rebuilt on every change. +When linking a library, make sure that the build step runs in watch mode, and that the library's `package.json` configuration points at the correct entry points. +For example, `main` should point at a JavaScript file, not a TypeScript file. + +## Use TypeScript path mapping for peer dependencies + +Angular libraries should list all `@angular/*` dependencies as peer dependencies. +This insures that when modules ask for Angular, they all get the exact same module. +If a library lists `@angular/core` in `dependencies` instead of `peerDependencies`, it might get a different Angular module instead, which would cause your application to break. + +While developing a library, you must install all peer dependencies through `devDependencies` to ensure that the library compiles properly. +A linked library will then have its own set of Angular libraries that it uses for building, located in its `node_modules` folder. +However, this can cause problems while building or running your application. + +To get around this problem you can use TypeScript path mapping to tell TypeScript that it should load some modules from a specific location. +List all the peer dependencies that your library uses in the TypeScript configuration file `./tsconfig.json`, and point them at the local copy in the app's `node_modules` folder. + +``` +{ + "compilerOptions": { + // ... + // paths are relative to `baseUrl` path. + "paths": { + "@angular/*": [ + "../node_modules/@angular/*" + ] + } + } +} +``` + +This mapping ensures that your library always loads the local copies of the modules it needs. + +## Using your own library in apps + +You don't have to publish your library to the npm package manager in order to use it in your own apps, but you do have to build it first. + +To use your own library in an app: + +* Build the library. You cannot use a library before it is built. + + ng build my-lib + + +* In your apps, import from the library by name: + ``` + import { my-export } from 'my-lib'; + ``` + +### Building and rebuilding your library + +The build step is important if you haven't published your library as an npm package and then installed the package back into your app from npm. +For instance, if you clone your git repository and run `npm install`, your editor will show the `my-lib` imports as missing if you haven't yet built your library. + +
+ +When you import something from a library in an Angular app, Angular looks for a mapping between the library name and a location on disk. +When you install a library package, the mapping is in the `node_modules` folder. When you build your own library, it has to find the mapping in your `tsconfig` paths. + +Generating a library with the Angular CLI automatically adds its path to the `tsconfig` file. +The Angular CLI uses the `tsconfig` paths to tell the build system where to find the library. + +
+ +If you find that changes to your library are not reflected in your app, your app is probably using an old build of the library. + +You can rebuild your library whenever you make changes to it, but this extra step takes time. +*Incremental builds* functionality improves the library-development experience. +Every time a file is changed a partial build is performed that emits the amended files. + +Incremental builds can be run as a backround process in your dev environment. To take advantage of this feature add the `--watch` flag to the build command: + + +ng build my-lib --watch + diff --git a/aio/content/guide/dependency-injection-in-action.md b/aio/content/guide/dependency-injection-in-action.md index f4653094bf..937f4d91de 100644 --- a/aio/content/guide/dependency-injection-in-action.md +++ b/aio/content/guide/dependency-injection-in-action.md @@ -79,8 +79,8 @@ When all dependencies are in place, `AppComponent` displays the user information ## 把服务的范围限制到某个组件的子树下 -An Angular application has multiple injectors, arranged in a tree hierarchy that parallels the component tree. -Each injector creates a singleton instance of a dependency. +An Angular application has multiple injectors, arranged in a tree hierarchy that parallels the component tree. +Each injector creates a singleton instance of a dependency. That same instance is injected wherever that injector provides that service. A particular service can be provided and created at any level of the injector hierarchy, which means that there can be multiple instances of a service if it is provided by multiple injectors. @@ -89,10 +89,10 @@ Angular 应用程序有多个依赖注入器,组织成一个与组件树平行 每个注入器都会创建依赖的一个单例。在所有该注入器负责提供服务的地方,所提供的都是同一个实例。 可以在注入器树的任何层级提供和建立特定的服务。这意味着,如果在多个注入器中提供该服务,那么该服务也就会有多个实例。 -Dependencies provided by the root injector can be injected into *any* component *anywhere* in the application. -In some cases, you might want to restrict service availability to a particular region of the application. +Dependencies provided by the root injector can be injected into *any* component *anywhere* in the application. +In some cases, you might want to restrict service availability to a particular region of the application. For instance, you might want to let users explicitly opt in to use a service, -rather than letting the root injector provide it automatically. +rather than letting the root injector provide it automatically. 由根注入器提供的依赖可以注入到应用中任何地方的任何组件中。 但有时候你可能希望把服务的有效性限制到应用程序的一个特定区域。 @@ -211,14 +211,14 @@ and confirm that the three `HeroBioComponent` instances have their own cached he When a class requires a dependency, that dependency is added to the constructor as a parameter. When Angular needs to instantiate the class, it calls upon the DI framework to supply the dependency. By default, the DI framework searches for a provider in the injector hierarchy, -starting at the component's local injector of the component, and if necessary bubbling up +starting at the component's local injector of the component, and if necessary bubbling up through the injector tree until it reaches the root injector. 当类需要某个依赖项时,该依赖项就会作为参数添加到类的构造函数中。 当 Angular 需要实例化该类时,就会调用 DI 框架来提供该依赖。 默认情况下,DI 框架会在注入器树中查找一个提供商,从该组件的局部注入器开始,如果需要,则沿着注入器树向上冒泡,直到根注入器。 -* The first injector configured with a provider supplies the dependency (a service instance or value) to the constructor. +* The first injector configured with a provider supplies the dependency (a service instance or value) to the constructor. 第一个配置过该提供商的注入器就会把依赖(服务实例或值)提供给这个构造函数。 @@ -227,7 +227,7 @@ through the injector tree until it reaches the root injector. 如果在根注入器中也没有找到提供商,则 DI 框架将会给构造函数返回一个 null。 There are a number of options for modifying the default search behavior, using _parameter decorators_ -on the service-valued parameters of a class constructor. +on the service-valued parameters of a class constructor. 通过在类的构造函数中对服务参数使用*参数装饰器*,可以提供一些选项来修改默认的搜索行为。 @@ -237,9 +237,9 @@ on the service-valued parameters of a class constructor. ### 用 `@Optional` 来让依赖是可选的,以及使用 `@Host` 来限定搜索方式 -Dependencies can be registered at any level in the component hierarchy. -When a component requests a dependency, Angular starts with that component's injector -and walks up the injector tree until it finds the first suitable provider. +Dependencies can be registered at any level in the component hierarchy. +When a component requests a dependency, Angular starts with that component's injector +and walks up the injector tree until it finds the first suitable provider. Angular throws an error if it can't find the dependency during that walk. 依赖可以注册在组件树的任何层级上。 @@ -247,7 +247,7 @@ Angular throws an error if it can't find the dependency during that walk. In some cases, you need to limit the search or accommodate a missing dependency. You can modify Angular's search behavior with the `@Host` and `@Optional` qualifying -decorators on a service-valued parameter of the component's constructor. +decorators on a service-valued parameter of the component's constructor. 某些情况下,你需要限制搜索,或容忍依赖项的缺失。 你可以使用组件构造函数参数上的 `@Host` 和 `@Optional` 这两个限定装饰器来修改 Angular 的搜索行为。 @@ -256,9 +256,9 @@ decorators on a service-valued parameter of the component's constructor. `@Optional` 属性装饰器告诉 Angular 当找不到依赖时就返回 null。 -* The `@Host` property decorator stops the upward search at the *host component*. -The host component is typically the component requesting the dependency. -However, when this component is projected into a *parent* component, +* The `@Host` property decorator stops the upward search at the *host component*. +The host component is typically the component requesting the dependency. +However, when this component is projected into a *parent* component, that parent component becomes the host. The following example covers this second case. `@Host` 属性装饰器会禁止在*宿主组件*以上的搜索。宿主组件通常就是请求该依赖的那个组件。 @@ -346,8 +346,8 @@ Here's `HeroBiosAndContactsComponent` in action. If you comment out the `@Host()` decorator, Angular walks up the injector ancestor tree -until it finds the logger at the `AppComponent` level. -The logger logic kicks in and the hero display updates +until it finds the logger at the `AppComponent` level. +The logger logic kicks in and the hero display updates with the "!!!" marker to indicate that the logger was found. 如果注释掉 `@Host()` 装饰器,Angular 就会沿着注入器树往上走,直到在 `AppComponent` 中找到该日志服务。日志服务的逻辑加了进来,所显示的英雄信息增加了 "!!!" 标记,这表明确实找到了日志服务。 @@ -366,7 +366,7 @@ the app throws an exception when it cannot find the required logger at the host ### 使用 `@Inject` 指定自定义提供商 -Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`. +Using a custom provider allows you to provide a concrete implementation for implicit dependencies, such as built-in browser APIs. The following example uses an `InjectionToken` to provide the [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) browser API as a dependency in the `BrowserStorageService`. 自定义提供商让你可以为隐式依赖提供一个具体的实现,比如内置浏览器 API。下面的例子使用 `InjectionToken` 来提供 [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage),将其作为 `BrowserStorageService` 的依赖项。 @@ -378,6 +378,8 @@ The `factory` function returns the `localStorage` property that is attached to t `factory` 函数返回 window 对象上的 `localStorage` 属性。`Inject` 装饰器修饰一个构造函数参数,用于为某个依赖提供自定义提供商。现在,就可以在测试期间使用 `localStorage` 的 Mock API 来覆盖这个提供商了,而不必与真实的浏览器 API 进行交互。 +{@a skip} + ### Modify the provider search with `@Self` and `@SkipSelf` ### 使用 `@Self` 和 `@SkipSelf` 来修改提供商的搜索方式 @@ -422,7 +424,7 @@ DOM element to which the directive is applied. 当用户把鼠标移到 DOM 元素上时,指令将指令所在的元素的背景设置为一个高亮颜色。 Angular sets the constructor's `el` parameter to the injected `ElementRef`. -(An `ElementRef` is a wrapper around a DOM element, +(An `ElementRef` is a wrapper around a DOM element, whose `nativeElement` property exposes the DOM element for the directive to manipulate.) Angular 把构造函数参数 `el` 设置为注入的 `ElementRef`,该 `ElementRef` 代表了宿主的 DOM 元素, 它的 `nativeElement` 属性把该 DOM 元素暴露给了指令。 @@ -479,7 +481,7 @@ and assigns the returned value to the `logger` parameter. Angular 会要求注入器提供与 `LoggerService` 相关的服务,并把返回的值赋给 `logger` 参数。 If the injector has already cached an instance of the service associated with the token, -it provides that instance. +it provides that instance. If it doesn't, it needs to make one using the provider associated with the token. 如果注入器已经缓存了与该令牌相关的服务实例,那么它就会直接提供此实例。 @@ -498,7 +500,7 @@ If the search fails, the injector throws an error—unless the request was [ A new injector has no providers. Angular initializes the injectors it creates with a set of preferred providers. -You have to configure providers for your own app-specific dependencies. +You have to configure providers for your own app-specific dependencies. 新的注入器没有提供商。 Angular 会使用一组首选提供商来初始化它本身的注入器。 @@ -511,7 +513,7 @@ Angular 会使用一组首选提供商来初始化它本身的注入器。 ### 定义提供商 A dependency can't always be created by the default method of instantiating a class. -You learned about some other methods in [Dependency Providers](guide/dependency-injection-providers). +You learned about some other methods in [Dependency Providers](guide/dependency-injection-providers). The following `HeroOfTheMonthComponent` example demonstrates many of the alternatives and why you need them. It's visually simple: a few properties and the logs produced by a logger. @@ -561,7 +563,7 @@ The `HeroOfTheMonthComponent` example has two value providers. * The first provides an existing instance of the `Hero` class to use for the `Hero` token, rather than -requiring the injector to create a new instance with `new` or use its own cached instance. +requiring the injector to create a new instance with `new` or use its own cached instance. Here, the token is the class itself. 第一处提供了用于 `Hero` 令牌的 `Hero` 类的现有实例,而不是要求注入器使用 `new` 来创建一个新实例或使用它自己的缓存实例。这里令牌就是这个类本身。 @@ -569,7 +571,7 @@ Here, the token is the class itself. * The second specifies a literal string resource to use for the `TITLE` token. The `TITLE` provider token is *not* a class, but is instead a special kind of provider lookup key called an [injection token](guide/dependency-injection-in-action#injection-token), represented by -an `InjectionToken` instance. +an `InjectionToken` instance. 第二处为 `TITLE` 令牌指定了一个字符串字面量资源。 `TITLE` 提供商的令牌*不是一个类*,而是一个特别的提供商查询键,名叫[InjectionToken](guide/dependency-injection-in-action#injection-token),表示一个 `InjectionToken` 实例。 @@ -599,7 +601,7 @@ Other types of providers can create their values *lazily*; that is, when they're {@a useclass} -#### Class providers: `useClass` +#### Class providers: `useClass` #### 类提供商:`useClass` @@ -608,7 +610,7 @@ The `useClass` provider key lets you create and return a new instance of the spe `useClass` 提供的键让你可以创建并返回指定类的新实例。 You can use this type of provider to substitute an *alternative implementation* -for a common or default class. +for a common or default class. The alternative implementation could, for example, implement a different strategy, extend the default class, or emulate the behavior of the real class in a test case. @@ -717,7 +719,7 @@ This is illustrated in the following image, which displays the logging date. {@a usefactory} -#### Factory providers: `useFactory` +#### Factory providers: `useFactory` #### 工厂提供商:`useFactory` @@ -772,7 +774,6 @@ the string of names. * The function takes a winning `Hero` and a `HeroService` as arguments. 这个返回的函数需要一个 `Hero` 和一个 `HeroService` 参数。 - Angular supplies these arguments from injected values identified by the two *tokens* in the `deps` array. @@ -878,7 +879,7 @@ The `MinimalLogger` transpiles to this unoptimized, pre-minified JavaScript for Notice that it doesn't have any members. It never grows no matter how many members you add to the class, -as long as those members are typed but not implemented. Look again at the TypeScript `MinimalLogger` class to confirm that it has no implementation. +as long as those members are typed but not implemented.Look again at the TypeScript `MinimalLogger` class to confirm that it has no implementation. 注意,***只要不实现它***,不管添加多少成员,它永远不会增长大小,因为这些成员虽然是有类型的,但却没有实现。你可以再看看 TypeScript 的 `MinimalLogger` 类,确定一下它是没有实现的。 @@ -1057,7 +1058,7 @@ Break the circularity with `forwardRef`. - - diff --git a/aio/content/guide/dependency-injection.md b/aio/content/guide/dependency-injection.md index 32819adcf1..f51020bcae 100644 --- a/aio/content/guide/dependency-injection.md +++ b/aio/content/guide/dependency-injection.md @@ -250,7 +250,7 @@ Here's the revised component, making use of the injected service, side-by-side w -`HeroService` must provided in some parent injector. The code in `HeroListComponent` doesn't depend on where `HeroService` comes from. +`HeroService` must be provided in some parent injector. The code in `HeroListComponent` doesn't depend on where `HeroService` comes from. If you decided to provide `HeroService` in `AppModule`, `HeroListComponent` wouldn't change. 必须在某些父注入器中提供 `HeroService`。`HeroListComponent` 并不关心 `HeroService` 来自哪里。 diff --git a/aio/content/guide/deployment.md b/aio/content/guide/deployment.md index 1016ded1ea..355e06a7c0 100644 --- a/aio/content/guide/deployment.md +++ b/aio/content/guide/deployment.md @@ -61,7 +61,7 @@ Make a note of the user name and project name in GitHub. 使用 Angular CLI 命令 [`ng build`](cli/build) 来构建这个 GitHub 项目,选项如下: - ng build --prod --output-path docs --base-href + ng build --prod --output-path docs --base-href // 1. When the build is complete, make a copy of `docs/index.html` and name it `docs/404.html`. @@ -82,7 +82,7 @@ You can see your deployed page at `https://.github.io//
- Check out [angular-cli-ghpages](https://github.com/angular-buch/angular-cli-ghpages), a full featured package that does all this for you and has extra functionality. +Check out [angular-cli-ghpages](https://github.com/angular-buch/angular-cli-ghpages), a full featured package that does all this for you and has extra functionality. 参见 [angular-cli-ghpages](https://github.com/angular-buch/angular-cli-ghpages),这个包用到了全部这些特性,还提供了一些额外功能。 diff --git a/aio/content/guide/displaying-data.md b/aio/content/guide/displaying-data.md index 7962eff71b..424a1202ed 100644 --- a/aio/content/guide/displaying-data.md +++ b/aio/content/guide/displaying-data.md @@ -186,7 +186,7 @@ Although this example uses variable assignment to initialize the components, you 虽然这个例子使用了变量赋值的方式初始化组件,你还可以使用构造函数来声明和初始化属性。 - + diff --git a/aio/content/guide/elements.md b/aio/content/guide/elements.md index d7f6d8b621..a0213a1a7d 100644 --- a/aio/content/guide/elements.md +++ b/aio/content/guide/elements.md @@ -6,7 +6,7 @@ _Angular elements_ are Angular components packaged as _custom elements_, a web s *Angular 元素*就是打包成*自定义元素*的 Angular 组件。所谓自定义元素就是一套与具体框架无关的用于定义新 HTML 元素的 Web 标准。 -[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) are a Web Platform feature currently supported by Chrome, Opera, and Safari, and available in other browsers through polyfills (see [Browser Support](#browser-support)). +[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) are a Web Platform feature currently supported by Chrome, Firefox, Opera, and Safari, and available in other browsers through polyfills (see [Browser Support](#browser-support)). A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code. The browser maintains a `CustomElementRegistry` of defined custom elements (also called Web Components), which maps an instantiable JavaScript class to an HTML tag. diff --git a/aio/content/guide/file-structure.md b/aio/content/guide/file-structure.md index e8caa9b1c9..d4b902b4ef 100644 --- a/aio/content/guide/file-structure.md +++ b/aio/content/guide/file-structure.md @@ -105,7 +105,7 @@ Workspace-wide `node_modules` dependencies are visible to this project. | `assets/` | 包含图像文件和其它文件,当构建应用时会被原样复制到构建目标中。 | | `environments/` | Contains build configuration options for particular target environments. By default there is an unnamed standard development environment and a production ("prod") environment. You can define additional target environment configurations. | | `environments/` | 包含针对特定目标环境的配置选项。默认情况下有一个未命名的标准开发环境和一个名叫 "prod" 的产品环境。你可以定义一些额外的目标环境配置。 | -| `browserlist` | Configures sharing of target browsers and Node.js versions among various front-end tools. See [Browserlist on GitHub](https://github.com/browserslist/browserslist) for more information. | +| `browserslist` | Configures sharing of target browsers and Node.js versions among various front-end tools. See [Browserslist on GitHub](https://github.com/browserslist/browserslist) for more information. | | `browserlist` | 配置各个目标浏览器和 Node.js 版本之间的市场占有率,供各种前端工具使用。详情参见 [GitHub 上的 Browserlist](https://github.com/browserslist/browserslist)。 | | `favicon.ico` | An icon to use for this app in the bookmark bar. | | `favicon.ico` | 一个用在书签栏上的应用图标。 | diff --git a/aio/content/guide/glossary.md b/aio/content/guide/glossary.md index 22ab350048..42d60e7488 100644 --- a/aio/content/guide/glossary.md +++ b/aio/content/guide/glossary.md @@ -27,9 +27,9 @@ unexpected definitions. ## 预 (ahead-of-time, AOT) 编译 -The Angular ahead-of-time (AOT) compiler converts Angular HTML and TypeScript code -into efficient JavaScript code during the build phase, before the browser downloads -and runs that code. +The Angular ahead-of-time (AOT) compiler converts Angular HTML and TypeScript code +into efficient JavaScript code during the build phase, before the browser downloads +and runs that code. This is the best compilation mode for production environments, with decreased load time and increased performance compared to [just-in-time (JIT) compilation](guide/glossary#jit). Angular 的预先(AOT)编译器可以在编译期间把 Angular 的 HTML 代码和 TypeScript 代码转换成高效的 JavaScript 代码,这样浏览器就可以直接下载并运行它们。 @@ -39,13 +39,13 @@ By compiling your application using the `ngc` command-line tool, you can bootstr 使用命令行工具 `ngc` 来编译你的应用之后,就可以直接启动一个模块工厂,这意味着你不必再在 JavaScript 打包文件中包含 Angular 编译器。 -{@a angular-element} +{@a angular-element} ## Angular element ## Angular 元素(element) -An Angular [component](guide/glossary#component) packaged as a [custom element](guide/glossary#custom-element). +An Angular [component](guide/glossary#component) packaged as a [custom element](guide/glossary#custom-element). 被包装成[自定义元素](guide/glossary#custom-element)的 Angular [组件](guide/glossary#component)。 @@ -89,8 +89,8 @@ Learn more in [Attribute Directives](guide/attribute-directives). ## 绑定 (binding) -Generally, the practice of setting a variable or property to a data value. -Within Angular, typically refers to [data binding](guide/glossary#data-binding), +Generally, the practice of setting a variable or property to a data value. +Within Angular, typically refers to [data binding](guide/glossary#data-binding), which coordinates DOM object properties with data object properties. 广义上是指把变量或属性设置为某个数据值的一种实践。 @@ -112,7 +112,7 @@ A way to initialize and launch an app or system. 一种用来初始化和启动应用或系统的途径。 -In Angular, an app's root NgModule (`AppModule`) has a `bootstrap` property that identifies the app's top-level [components](guide/glossary#component). +In Angular, an app's root NgModule (`AppModule`) has a `bootstrap` property that identifies the app's top-level [components](guide/glossary#component). During the bootstrap process, Angular creates and inserts these components into the `index.html` host web page. You can bootstrap multiple apps in the same `index.html`. Each app contains its own components. @@ -138,7 +138,7 @@ Learn more in [Bootstrapping](guide/bootstrapping). ## 大小写类型(case types) -Angular uses capitalization conventions to distinguish the names of various types, as described in the [naming guidelines section](guide/styleguide#02-01) of the Style Guide. Here's a summary of the case types: +Angular uses capitalization conventions to distinguish the names of various types, as described in the [naming guidelines section](guide/styleguide#02-01) of the Style Guide. Here's a summary of the case types: Angular 使用大小写约定来区分多种名字,详见[风格指南中的 "命名" 一节](guide/styleguide#02-01)。下面是这些大小写类型的汇总表: @@ -201,10 +201,20 @@ The following decorators can declare Angular class types: ## 类字段装饰器(class field decorator) -A [decorator](guide/glossary#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`. +A [decorator](guide/glossary#decorator) statement immediately before a field in a class definition that declares the type of that field. Some examples are `@Input` and `@Output`. 出现在类定义中属性紧前方的[装饰器](guide/glossary#decorator)语句用来声明该字段的类型。比如 `@Input` 和 `@Output`。 +{@a collection} + +## collection + +## 集合(collection) + +In Angular, a set of related [schematics](#schematic) collected in an [npm package](#npm-package). + +在 Angular 中,是指收录在同一个 [npm 包](#npm-package) 中的[一组原理图(schematics)](#schematic)。 + {@a cli} ## command-line interface (CLI) @@ -224,6 +234,10 @@ CLI 支持开发周期中的所有阶段,比如构建、测试、打包和部 要了解 CLI 的全部功能,参见 [CLI 命令参考手册](cli)。 +See also [Schematics CLI](#schematics-cli). + +参见 [Schematics CLI](#schematics-cli)。 + {@a component} ## component @@ -235,7 +249,7 @@ A class with the `@Component()` [decorator](guide/glossary#decorator) that assoc 一个带有 `@Component()` [装饰器](guide/glossary#decorator)的类,和它的伴生[模板](guide/glossary#template)关联在一起。组件及其模板共同定义了一个[视图](guide/glossary#view)。 A component is a special type of [directive](guide/glossary#directive). -The `@Component()` decorator extends the `@Directive()` decorator with template-oriented features. +The `@Component()` decorator extends the `@Directive()` decorator with template-oriented features. 组件是[指令](guide/glossary#directive)的一种特例。`@Component()` 装饰器扩展了 `@Directive()` 装饰器,增加了一些与模板有关的特性。 @@ -253,7 +267,7 @@ Read more about components, templates, and views in [Architecture Overview](guid ## 自定义元素(Custom element) -A web platform feature, currently supported by most browsers and available in other browsers through polyfills (see [Browser support](guide/browser-support)). +A web platform feature, currently supported by most browsers and available in other browsers through polyfills (see [Browser support](guide/browser-support)). 一种 Web 平台的特性,目前已经被绝大多数浏览器支持,在其它浏览器中也可以通过腻子脚本获得支持(参见[浏览器支持](guide/browser-support))。 @@ -330,7 +344,7 @@ Read about the following forms of binding in [Template Syntax](guide/template-sy ## 可声明对象(declarable) -A class type that you can add to the `declarations` list of an [NgModule](guide/glossary#ngmodule). +A class type that you can add to the `declarations` list of an [NgModule](guide/glossary#ngmodule). You can declare [components](guide/glossary#component), [directives](guide/glossary#directive), and [pipes](guide/glossary#pipe). 类的一种类型,你可以把它们添加到 [NgModule](guide/glossary#ngmodule) 的 `declarations` 列表中。 @@ -368,18 +382,18 @@ Don't declare the following: ## 装饰器(decorator | decoration) -A function that modifies a class or property definition. Decorators (also called *annotations*) are an experimental (stage 2) [JavaScript language feature](https://github.com/wycats/javascript-decorators). +A function that modifies a class or property definition. Decorators (also called *annotations*) are an experimental (stage 2) [JavaScript language feature](https://github.com/wycats/javascript-decorators). TypeScript adds support for decorators. 一个函数,用来修饰紧随其后的类或属性定义。 装饰器(也叫注解)是 JavaScript 的一种语言[特性](https://github.com/wycats/javascript-decorators),是一项位于阶段2(stage 2)的试验特性。 Angular defines decorators that attach metadata to classes or properties -so that it knows what those classes or properties mean and how they should work. +so that it knows what those classes or properties mean and how they should work. Angular 定义了一些装饰器,用来为类或属性附加元数据,来让自己知道那些类或属性的含义,以及该如何处理它们。 -See [class decorator](guide/glossary#class-decorator), [class field decorator](guide/glossary#class-field-decorator). +See [class decorator](guide/glossary#class-decorator), [class field decorator](guide/glossary#class-field-decorator). 参见 [类装饰器](guide/glossary#class-decorator)、[类属性装饰器](guide/glossary#class-field-decorator)。 @@ -451,8 +465,8 @@ There are three categories of directive: [结构型指令](guide/glossary#structural-directive)修改 DOM 的结构。 -Angular supplies a number of built-in directives that begin with the `ng` prefix. -You can also create new directives to implement your own functionality. +Angular supplies a number of built-in directives that begin with the `ng` prefix. +You can also create new directives to implement your own functionality. You associate a *selector* (an HTML tag such as ``) with a custom directive, thereby extending the [template syntax](guide/template-syntax) that you can use in your apps. Angular 提供了一些以 `ng` 为前缀的内置指令。你也可以创建新的指令来实现自己的功能。 @@ -467,7 +481,6 @@ Angular 提供了一些以 `ng` 为前缀的内置指令。你也可以创建新 A special-purpose library or API; see [Domain-specific language](https://en.wikipedia.org/wiki/Domain-specific_language). 一种特殊用途的库或 API,参见[领域特定语言](https://en.wikipedia.org/wiki/Domain-specific_language)词条。 - Angular extends TypeScript with domain-specific languages for a number of domains relevant to Angular apps, defined in NgModules such as [animations](guide/animations), [forms](guide/forms), and [routing and navigation](guide/router). Angular 使用领域特定语言扩展了 TypeScript,用于与 Angular 应用相关的许多领域。这些 DSL 都定义在 NgModule 中,比如 [动画](guide/animations)、[表单](guide/forms)和[路由与导航](guide/router)。 @@ -511,7 +524,7 @@ The [official JavaScript language specification](https://en.wikipedia.org/wiki/E [官方 JavaScript 语言规范](https://en.wikipedia.org/wiki/ECMAScript) -Not all browsers support the latest ECMAScript standard, but you can use a [transpiler](guide/glossary#transpile) (like [TypeScript](guide/glossary#typescript)) to write code using the latest features, which will then be transpiled to code that runs on versions that are supported by browsers. +Not all browsers support the latest ECMAScript standard, but you can use a [transpiler](guide/glossary#transpile) (like [TypeScript](guide/glossary#typescript)) to write code using the latest features, which will then be transpiled to code that runs on versions that are supported by browsers. 并不是所有浏览器都支持最新的 ECMAScript 标准,不过你可以使用[转译器](guide/glossary#transpile)(比如[TypeScript](guide/glossary#typescript))来用最新特性写代码,然后它会被转译成可以在浏览器的其它版本上运行的代码。 @@ -525,8 +538,8 @@ To learn more, see [Browser Support](guide/browser-support). ## 元素(Element) -Angular defines an `ElementRef` class to wrap render-specific native UI elements. -In most cases, this allows you to use Angular templates and data binding to access DOM elements +Angular defines an `ElementRef` class to wrap render-specific native UI elements. +In most cases, this allows you to use Angular templates and data binding to access DOM elements without reference to the native element. Angular 定义了 `ElementRef` 类来包装与渲染有关的原生 UI 元素。这让你可以在大多数情况下使用 Angular 的模板和数据绑定机制来访问 DOM 元素,而不必再引用原生元素。 @@ -546,7 +559,7 @@ Compare to [custom element](guide/glossary#custom-element). ## 入口点(Entry Point) -A JavaScript symbol that makes parts of an [npm package](guide/npm-packages) available for import by other code. +A JavaScript symbol that makes parts of an [npm package](guide/npm-packages) available for import by other code. The Angular [scoped packages](guide/glossary#scoped-package) each have an entry point named `index`. JavaScript 的 ID 用来让这段代码成为 [npm 包](guide/npm-packages)的一部分,从而让其它代码能导入它。 @@ -638,7 +651,7 @@ Angular 中的类或其它概念使用[依赖注入](guide/glossary#di)机制来 An object in the Angular [dependency-injection](guide/glossary#dependency-injection) system that can find a named dependency in its cache or create a dependency -using a configured [provider](guide/glossary#provider). +using a configured [provider](guide/glossary#provider). Injectors are created for NgModules automatically as part of the bootstrap process and are inherited through the component hierarchy. @@ -668,7 +681,7 @@ Learn more about the injector hierarchy in [Hierarchical Dependency Injectors](g ## 输入属性 (input) -When defining a [directive](guide/glossary#directive), the `@Input()` decorator on a directive property +When defining a [directive](guide/glossary#directive), the `@Input()` decorator on a directive property makes that property available as a *target* of a [property binding](guide/template-syntax#property-binding). Data values flow into an input property from the data source identified in the [template expression](guide/glossary#template-expression) to the right of the equal sign. @@ -686,7 +699,7 @@ To learn more, see [input and output properties](guide/template-syntax#inputs-ou ## 插值表达式 (interpolation) -A form of property [data binding](guide/glossary#data-binding) in which a [template expression](guide/glossary#template-expression) between double-curly braces renders as text. +A form of property [data binding](guide/glossary#data-binding) in which a [template expression](guide/glossary#template-expression) between double-curly braces renders as text. That text can be concatenated with neighboring text before it is assigned to an element property or displayed between element tags, as in this example. @@ -718,13 +731,13 @@ See [ECMAScript](guide/glossary#ecma), [TypeScript](guide/glossary#typescript). ## 即时 (just-in-time, JIT) 编译 -The Angular just-in-time (JIT) compiler converts your Angular HTML and TypeScript code into +The Angular just-in-time (JIT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code at run time, as part of bootstrapping. 在启动期间,Angular 的即时编译器(JIT)会在运行期间把你的 Angular HTML 和 TypeScript 代码转换成高效的 JavaScript 代码。 -JIT compilation is the default (as opposed to AOT compilation) when you run Angular's `ng build` and `ng serve` CLI commands, and is a good choice during development. -JIT mode is strongly discouraged for production use +JIT compilation is the default (as opposed to AOT compilation) when you run Angular's `ng build` and `ng serve` CLI commands, and is a good choice during development. +JIT mode is strongly discouraged for production use because it results in large application payloads that hinder the bootstrap performance. 当你运行 Angular 的 CLI 命令 `ng build` 和 `ng serve` 时,JIT 编译是默认选项,而且是开发期间的最佳实践。但是强烈建议你不要在生产环境下使用 JIT 模式,因为它会导致巨大的应用负担,从而拖累启动时的性能。 @@ -743,13 +756,13 @@ Compare to [ahead-of-time (AOT) compilation](guide/glossary#aot). ## 惰性加载(Lazy loading) -A process that speeds up application load time by splitting the application into multiple bundles and loading them on demand. -For example, dependencies can be lazy loaded as needed—as opposed to [eager-loaded](guide/glossary#eager-loading) modules that are required by the root module and are thus loaded on launch. +A process that speeds up application load time by splitting the application into multiple bundles and loading them on demand. +For example, dependencies can be lazy loaded as needed—as opposed to [eager-loaded](guide/glossary#eager-loading) modules that are required by the root module and are thus loaded on launch. 惰性加载过程会把应用拆分成多个包并且按需加载它们,从而提高应用加载速度。 比如,一些依赖可以根据需要进行惰性加载,与之相对的是那些 [急性加载](guide/glossary#eager-loading) 的模块,它们是根模块所要用的,因此会在启动期间加载。 -The [router](guide/glossary#router) makes use of lazy loading to load child views only when the parent view is activated. +The [router](guide/glossary#router) makes use of lazy loading to load child views only when the parent view is activated. Similarly, you can build custom elements that can be loaded into an Angular app when needed. [路由器](guide/glossary#router)只有当父视图激活时才需要加载子视图。同样,你还可以构建一些自定义元素,它们也可以在需要时才加载进 Angular 应用。 @@ -760,16 +773,18 @@ Similarly, you can build custom elements that can be loaded into an Angular app ## 库(Library) -In Angular, a [project](guide/glossary#project) that provides functionality that can be included in other Angular apps. -A library isn't a complete Angular app and can't run independently. +In Angular, a [project](guide/glossary#project) that provides functionality that can be included in other Angular apps. +A library isn't a complete Angular app and can't run independently. 一种 Angular [项目](guide/glossary#project)。用来让其它 Angular 应用包含它,以提供各种功能。库不是一个完整的 Angular 应用,不能独立运行。 -* Library developers can use the [CLI](guide/glossary#cli) to `generate` scaffolding for a new library in an existing [workspace](guide/glossary#workspace), and can publish a library as an `npm` package. +* Library developers can use the [Angular CLI](guide/glossary#cli) to `generate` scaffolding for a new library in an existing [workspace](guide/glossary#workspace), and can publish a library as an `npm` package. 库的开发者可以使用 [CLI](guide/glossary#cli) 在现有的 [工作空间](guide/glossary#workspace) 中 `generate` 新库的脚手架,还能把库发布为 `npm` 包。 -* App developers can use the [CLI](guide/glossary#cli) to `add` a published library for use with an app in the same [workspace](guide/glossary#workspace). +* Application developers can use the [Angular CLI](guide/glossary#cli) to `add` a published library for use with an application in the same [workspace](guide/glossary#workspace). + +See also [schematic](#schematic). 应用开发者可以使用 [CLI](guide/glossary#cli) 来把一个已发布的库 `add` 进这个应用所在的[工作空间](guide/glossary#workspace)。 @@ -836,7 +851,7 @@ To learn more, see [Lifecycle Hooks](guide/lifecycle-hooks). ## 模块 (module) -In general, a module collects a block of code dedicated to a single purpose. Angular uses standard JavaScript modules and also defines an Angular module, `NgModule`. +In general, a module collects a block of code dedicated to a single purpose. Angular uses standard JavaScript modules and also defines an Angular module, `NgModule`. 通常,模块会收集一组专注于单一目的的代码块。Angular 既使用 JavaScript 的标准模块,也定义了 Angular 自己的模块,也就是 `NgModule`。 @@ -884,11 +899,11 @@ To learn more, see [NgModules](guide/ngmodules). {@a npm-package} -## npm package +## npm package ## npm 包 -The [npm package manager](https://docs.npmjs.com/getting-started/what-is-npm) is used to distribute and load Angular modules and libraries. +The [npm package manager](https://docs.npmjs.com/getting-started/what-is-npm) is used to distribute and load Angular modules and libraries. [npm 包管理器](https://docs.npmjs.com/getting-started/what-is-npm)用于分发与加载 Angular 的模块和库。 @@ -904,17 +919,17 @@ Learn more about how Angular uses [Npm Packages](guide/npm-packages). ## 可观察对象(Observable) -A producer of multiple values, which it pushes to [subscribers](guide/glossary#subscriber). Used for asynchronous event handling throughout Angular. You execute an observable by subscribing to it with its `subscribe()` method, passing callbacks for notifications of new values, errors, or completion. +A producer of multiple values, which it pushes to [subscribers](guide/glossary#subscriber). Used for asynchronous event handling throughout Angular. You execute an observable by subscribing to it with its `subscribe()` method, passing callbacks for notifications of new values, errors, or completion. 一个多值生成器,这些值会被推送给[订阅者](guide/glossary#subscriber)。 Angular 中到处都会用到异步事件处理。你要通过调用可观察对象的 `subscribe()` 方法来订阅它,从而让这个可观察对象得以执行,你还要给该方法传入一些回调函数来接收 "有新值"、"错误" 或 "完成" 等通知。 -Observables can deliver single or multiple values of any type to subscribers, either synchronously (as a function delivers a value to its caller) or on a schedule. A subscriber receives notification of new values as they are produced and notification of either normal completion or error completion. +Observables can deliver single or multiple values of any type to subscribers, either synchronously (as a function delivers a value to its caller) or on a schedule. A subscriber receives notification of new values as they are produced and notification of either normal completion or error completion. 可观察对象可以把任意类型的一个或多个值传给订阅者,无论是同步(就像函数把值返回给它的调用者一样)还是异步。 订阅者会在生成了新值时收到包含这个新值的通知,以及正常结束或错误结束时的通知。 -Angular uses a third-party library called [Reactive Extensions (RxJS)](http://reactivex.io/rxjs/). +Angular uses a third-party library called [Reactive Extensions (RxJS)](http://reactivex.io/rxjs/). Angular 使用一个名叫[响应式扩展 (RxJS)](http://reactivex.io/rxjs/)的第三方包来实现这些功能。 @@ -938,8 +953,8 @@ An object passed to the `subscribe()` method for an [observable](guide/glossary# ## 输出属性 (output) -When defining a [directive](guide/glossary#directive), the `@Output{}` decorator on a directive property -makes that property available as a *target* of [event binding](guide/template-syntax#event-binding). +When defining a [directive](guide/glossary#directive), the `@Output{}` decorator on a directive property +makes that property available as a *target* of [event binding](guide/template-syntax#event-binding). Events stream *out* of this property to the receiver identified in the [template expression](guide/glossary#template-expression) to the right of the equal sign. @@ -964,7 +979,6 @@ Angular defines various pipes, and you can define new pipes. 一个带有 `@Pipe` 装饰器的类,它定义了一个函数,用来把输入值转换成输出值,以显示在[视图](guide/glossary#view)中。 Angular 定义了很多管道,并且你还可可以自定义新的管道。 - To learn more, see [Pipes](guide/pipes). 要了解更多,参见[管道](guide/pipes)页。 @@ -973,8 +987,8 @@ To learn more, see [Pipes](guide/pipes). ## 腻子脚本(polyfill) -An [npm package](guide/npm-packages) that plugs gaps in a browser's JavaScript implementation. -See [Browser Support](guide/browser-support) for polyfills that support particular functionality for particular platforms. +An [npm package](guide/npm-packages) that plugs gaps in a browser's JavaScript implementation. +See [Browser Support](guide/browser-support) for polyfills that support particular functionality for particular platforms. 一个 [NPM 包](guide/npm-packages),它负责弥补浏览器 JavaScript 实现与最新标准之间的 "缝隙"。参见[浏览器支持](guide/browser-support)页,以了解要在特定平台支持特定功能时所需的腻子脚本。 @@ -985,7 +999,7 @@ See [Browser Support](guide/browser-support) for polyfills that support particul ## 项目(project) In Angular, a folder within a [workspace](guide/glossary#workspace) that contains an Angular app or [library](guide/glossary#library). -A workspace can contain multiple projects. +A workspace can contain multiple projects. All apps in a workspace can use libraries in the same workspace. 在 Angular 中,是指[工作空间](guide/glossary#workspace)中的一个文件夹,它包含 Angular 应用或[库](guide/glossary#library)。 @@ -1004,7 +1018,7 @@ for a class that requires it. 一个实现了 [`Provider`](api/core/Provider) 接口的对象。一个提供商对象定义了如何获取与 [DI 令牌(token)](guide/glossary#token) 相关联的可注入依赖。 [注入器](guide/glossary#injector)会使用这个提供商来创建它所依赖的那些类的实例。 -Angular registers its own providers with every injector, for services that Angular defines. +Angular registers its own providers with every injector, for services that Angular defines. You can register your own providers for services that your app needs. Angular 会为每个注入器注册一些 Angular 自己的服务。你也可以注册应用自己所需的服务提供商。 @@ -1075,7 +1089,6 @@ A tool that configures and implements navigation among states and [views](guide/ The `Router` module is an [NgModule](guide/glossary#ngmodule) that provides the necessary service providers and directives for navigating through application views. A [routing component](guide/glossary#routing-component) is one that imports the `Router` module and whose template contains a `RouterOutlet` element where it can display views produced by the router. `Router` 模块是一个 [NgModule](guide/glossary#ngmodule),它提供在应用视图间导航时需要的服务提供商和指令。[路由组件](guide/glossary#routing-component)是一种组件,它导入了 `Router` 模块,并且其模板中包含 `RouterOutlet` 元素,路由器生成的视图就会被显示在那里。 - The router defines navigation among views on a single page, as opposed to navigation among pages. It interprets URL-like links to determine which views to create or destroy, and which components to load or unload. It allows you to take advantage of [lazy loading](guide/glossary#lazy-load) in your Angular apps. 路由器定义了在单页面中的各个视图之间导航的方式,而不是在页面之间。它会解释类似 URL 的链接,以决定该创建或销毁哪些视图,以及要加载或卸载哪些组件。它让你可以在 Angular 应用中获得[惰性加载](guide/glossary#lazy-load)的好处。 @@ -1107,6 +1120,11 @@ An Angular [component](guide/glossary#component) with a `RouterOutlet` directive For more information, see [Routing and Navigation](guide/router). 要了解更多,参见[路由与导航](guide/router)。 +{@a rule} + +In [schematics](#schematic), a function that operates on a [file tree](#file-tree) to create, delete, or modify files in a specific manner, and returns a new `Tree` object. + +在 [schematics](#schematic) 中,是指一个在[文件树](#file-tree)上运行的函数,用于以指定方式创建、删除或修改文件,并返回一个新的 `Tree` 对象。 {@a S} @@ -1116,34 +1134,54 @@ For more information, see [Routing and Navigation](guide/router). ## 原理图(schematic) -A scaffolding library that defines how to generate or transform a programming project by creating, modifying, refactoring, or moving files and code. -The Angular [CLI](guide/glossary#cli) uses schematics to generate and modify [Angular projects](guide/glossary#project) and parts of projects. +A scaffolding library that defines how to generate or transform a programming project by creating, modifying, refactoring, or moving files and code. +A schematic defines [rules](#rule) that operate on a virtual file system called a [tree](#file-tree). +The [Angular CLI](guide/glossary#cli) uses schematics to generate and modify [Angular projects](guide/glossary#project) and parts of projects. 一种脚手架库,它会定义出要如何通过创建、修改、重构或移动文件和代码的方式生成或转换编程项目。 Angular [CLI](guide/glossary#cli) 使用原理图来生成和修改 [Angular 项目](guide/glossary#project)及其各个部件。 -* Angular provides a set of schematics for use with the CLI. See the [Angular CLI command reference](cli). The [`ng add`](cli/add) command runs schematics as part of adding a library to your project. The [`ng generate`](cli/generate) command runs schematics to create apps, libraries, and Angular code constructs. +* Angular provides a set of schematics for use with the CLI. See the [Angular CLI command reference](cli). The [`ng add`](cli/add) command runs schematics as part of adding a library to your project. The [`ng generate`](cli/generate) command runs schematics to create apps, libraries, and Angular code constructs. Angular 提供了一组用于 CLI 的原理图。参见 [Angular CLI 命令参考手册](cli)。当 [`ng add`](cli/add) 命令向项目中添加某个库时,就会运行原理图。[`ng generate`](cli/generate) 命令则会运行原理图,来创建应用、库和 Angular 代码块。 -* Library developers can create schematics that enable the CLI to generate their published libraries. -For more information, see [devkit documentation](https://www.npmjs.com/package/@angular-devkit/schematics). +* [Library](#library) developers can use the [Schematics CLI](#schematics-cli) to create schematics that enable the Angular CLI to add and update their published libraries, and to generate artifacts the library defines. + + For more information, see [devkit documentation](https://www.npmjs.com/package/@angular-devkit/schematics). 公共库的开发者可以创建原理图,来让 CLI 生成他们自己的发布的库。欲知详情,参见 [devkit 文档](https://www.npmjs.com/package/@angular-devkit/schematics)。 +{@a schematics-cli} + +## Schematics CLI + +Schematics come with their own command-line tool. +Using Node 6.9 or above, install the Schematics CLI globally: + +Schematics 自带了一个命令行工具。 +使用 Node 6.9 或更高版本,可以全局安装这个 Schematics CLI: + + +npm install -g @angular-devkit/schematics-cli + + +This installs the `schematics` executable, which you can use to create a new project, add a new schematic to an existing project, or extend an existing schematic. + +这会安装可执行文件 `schematics`,你可以用它来创建新工程、往现有工程中添加新的 schematic,或扩展某个现有的 schematic。 + {@a scoped-package} ## scoped package ## 范围化包 (scoped package) -A way to group related [npm packages](guide/npm-packages). +A way to group related [npm packages](guide/npm-packages). NgModules are delivered within scoped packages whose names begin with the Angular *scope name* `@angular`. For example, `@angular/core`, `@angular/common`, `@angular/forms`, and `@angular/router`. 一种把相关的 [npm 包](guide/npm-packages)分组到一起的方式。 Angular 的 NgModule 都是在一些以 `@angular` 为范围名的*范围化包*中发布的。比如 `@angular/core`、`@angular/common`、`@angular/forms` 和 `@angular/router`。 -Import a scoped package in the same way that you import a normal package. +Import a scoped package in the same way that you import a normal package. 和导入普通包相同的方式导入范围化包。 @@ -1157,14 +1195,14 @@ Import a scoped package in the same way that you import a normal package. ## 服务 (service) -In Angular, a class with the [@Injectable()](guide/glossary#injectable) decorator that encapsulates non-UI logic and code that can be reused across an application. +In Angular, a class with the [@Injectable()](guide/glossary#injectable) decorator that encapsulates non-UI logic and code that can be reused across an application. Angular distinguishes components from services to increase modularity and reusability. 在 Angular 中,服务就是一个带有 [@Injectable](guide/glossary#injectable) 装饰器的类,它封装了可以在应用程序中复用的非 UI 逻辑和代码。 Angular 把组件和服务分开,是为了增进模块化程度和可复用性。 -The `@Injectable()` metadata allows the service class to be used with the [dependency injection](guide/glossary#di) mechanism. -The injectable class is instantiated by a [provider](guide/glossary#provider). +The `@Injectable()` metadata allows the service class to be used with the [dependency injection](guide/glossary#di) mechanism. +The injectable class is instantiated by a [provider](guide/glossary#provider). [Injectors](guide/glossary#injector) maintain lists of providers and use them to provide service instances when they are required by components or other services. `@Injectable` 元数据让服务类能用于[依赖注入](guide/glossary#di)机制中。可注入的类是用[提供商](guide/glossary#provider)进行实例化的。 @@ -1227,12 +1265,12 @@ The `subscribe()` method takes a JavaScript object (called an [observer](guide/g ## 模板 (template) -Code associated with a component that defines how to render the component's [view](guide/glossary#view). +Code associated with a component that defines how to render the component's [view](guide/glossary#view). 模板是与组件相关的代码,用来定义如何在 HTML 中渲染组件的[视图](guide/glossary#view)。 -A template combines straight HTML with Angular [data-binding](guide/glossary#data-binding) syntax, [directives](guide/glossary#directive), -and [template expressions](guide/glossary#template-expression) (logical constructs). +A template combines straight HTML with Angular [data-binding](guide/glossary#data-binding) syntax, [directives](guide/glossary#directive), +and [template expressions](guide/glossary#template-expression) (logical constructs). The Angular elements insert or calculate values that modify the HTML elements before the page is displayed. 模板会把纯 HTML 和 Angular 的[数据绑定](guide/glossary#data-binding)语法、[指令](guide/glossary#directive)和[模板表达式](guide/glossary#template-expression)组合起来。Angular 的元素会插入或计算那些值,以便在页面显示出来之前修改 HTML 元素。 @@ -1314,21 +1352,30 @@ An opaque identifier used for efficient table lookup. In Angular, a [DI token](g The translation process that transforms one version of JavaScript to another version; for example, down-leveling ES2015 to the older ES5 version. 一种翻译过程,它会把一个版本的 JavaScript 转换成另一个版本,比如把下一版的 ES2015 转换成老版本的 ES5。 +{@a file-tree} + +## tree + +In [schematics](#schematic), a virtual file system represented by the `Tree` class. +Schematic [rules](#rule) take a tree object as input, operate on them, and return a new tree object. + +在 [schematics](#schematic) 中,一个用 `Tree` 类表示的虚拟文件系统。 +Schematic [规则](#rule)以一个 `tree` 对象作为输入,对它们进行操作,并且返回一个新的 `tree` 对象。 {@a typescript} ## TypeScript -A programming language based on JavaScript that is notable for its optional typing system. +A programming language based on JavaScript that is notable for its optional typing system. TypeScript provides compile-time type checking and strong tooling support (such as -code completion, refactoring, inline documentation, and intelligent search). +code completion, refactoring, inline documentation, and intelligent search). Many code editors and IDEs support TypeScript either natively or with plug-ins. TypeScript 是一种基于 JavaScript 的程序设计语言,以其可选类型系统著称。 TypeScript 提供了编译时类型检查和强大的工具支持(比如代码补齐、重构、内联文档和智能搜索等)。 许多代码编辑器和 IDE 都原生支持 TypeScript 或通过插件提供支持。 -TypeScript is the preferred language for Angular development. +TypeScript is the preferred language for Angular development. Read more about TypeScript at [typescriptlang.org](http://www.typescriptlang.org/). TypeScript 是 Angular 的首选语言。要了解更多,参见 [typescriptlang.org](http://www.typescriptlang.org/)。 @@ -1343,24 +1390,24 @@ TypeScript 是 Angular 的首选语言。要了解更多,参见 [typescriptlan ## 视图 (view) -The smallest grouping of display elements that can be created and destroyed together. +The smallest grouping of display elements that can be created and destroyed together. Angular renders a view under the control of one or more [directives](guide/glossary#directive), -especially [component](guide/glossary#component) directives and their companion [templates](guide/glossary#template). +especially [component](guide/glossary#component) directives and their companion [templates](guide/glossary#template). 视图是可显示元素的最小分组单位,它们会被同时创建和销毁。 Angular 在一个或多个[指令 (directive)](guide/glossary#directive) 的控制下渲染视图, 尤其是[组件 (component)](guide/glossary#component) 指令及其[模板 (template)](guide/glossary#template)。 -A view is specifically represented by a `ViewRef` instance associated with the component. -A view that belongs to a component is called a *host view*. -Views are typically collected into [view hierarchies](guide/glossary#view-tree). +A view is specifically represented by a `ViewRef` instance associated with the component. +A view that belongs to a component is called a *host view*. +Views are typically collected into [view hierarchies](guide/glossary#view-tree). 具体实现上,视图由一个与该组件相关的 `ViewRef` 实例表示。 属于某个组件的视图叫做*宿主视图*。 通常会把视图组织成一些[视图树(view hierarchies)](guide/glossary#view-tree)。 -Properties of elements in a view can change dynamically, in response to user actions; -the structure (number and order) of elements in a view can't. +Properties of elements in a view can change dynamically, in response to user actions; +the structure (number and order) of elements in a view can't. You can change the structure of elements by inserting, moving, or removing nested views within their view containers. 视图中各个元素的属性可以动态修改以响应用户的操作,而这些元素的结构(数量或顺序)则不能。你可以通过在它们的视图容器中插入、移动或移除内嵌视图来修改这些元素的结构。 @@ -1375,7 +1422,7 @@ View hierarchies can be loaded and unloaded dynamically as the user navigates th ## 视图树(View hierarchy) -A tree of related views that can be acted on as a unit. The root view is a component's *host view*. A host view can be the root of a tree of *embedded views*, collected in a *view container* (`ViewContainerRef`) attached to an anchor element in the hosting component. The view hierarchy is a key part of Angular change detection. +A tree of related views that can be acted on as a unit. The root view is a component's *host view*. A host view can be the root of a tree of *embedded views*, collected in a *view container* (`ViewContainerRef`) attached to an anchor element in the hosting component. The view hierarchy is a key part of Angular change detection. 一棵相关视图的树,它们可以作为一个整体行动。其根视图就是组件的*宿主视图*。宿主视图可以是*内嵌视图*树的根,它被收集到了宿主组件上的一个*视图容器(`ViewContainerRef`)*中。视图树是 Angular 变更检测的关键部件之一。 @@ -1401,8 +1448,8 @@ See [custom element](guide/glossary#custom-element). ## 工作空间(Workspace) In Angular, a folder that contains [projects](guide/glossary#project) (that is, apps and libraries). -The [CLI](guide/glossary#cli) `ng new` command creates a workspace to contain projects. -Commands that create or operate on apps and libraries (such as `add` and `generate`) must be executed from within a workspace folder. +The [CLI](guide/glossary#cli) `ng new` command creates a workspace to contain projects. +Commands that create or operate on apps and libraries (such as `add` and `generate`) must be executed from within a workspace folder. 在 Angular 中,是指一个包含[项目](guide/glossary#project)(即应用和库)的文件夹。 [CLI](guide/glossary#cli) 的 `ng new` 命令会创建一个包含项目的工作空间。而用来创建或操作应用和库的 `add` 和 `generate` 命令必须在工作空间目录下才能执行。 @@ -1426,7 +1473,7 @@ An Angular app runs in a zone where it can respond to asynchronous events by che Angular 应用会运行在一个 Zone 区域中,在这里,它可以对异步事件做出反应,可以通过检查数据变更、利用[数据绑定 (data bindings)](guide/glossary#data-binding) 来更新信息显示。 -A zone client can take action before and after an async operation completes. +A zone client can take action before and after an async operation completes. Zone 的使用方可以在异步操作完成之前或之后采取行动。 diff --git a/aio/content/guide/hierarchical-dependency-injection.md b/aio/content/guide/hierarchical-dependency-injection.md index 8be66c8319..81e6504c27 100644 --- a/aio/content/guide/hierarchical-dependency-injection.md +++ b/aio/content/guide/hierarchical-dependency-injection.md @@ -3,7 +3,7 @@ # 多级依赖注入器 The Angular dependency injection system is _hierarchical_. -There is a tree of injectors that parallel an app's component tree. +There is a tree of injectors that parallels an app's component tree. You can reconfigure the injectors at any level of that component tree. Angular 的依赖注入系统是*多级的*。 @@ -77,7 +77,7 @@ Learn more about dependency resolution through the injector hierarchy: *NgModule 级*的提供商可以在 `@NgModule()` `providers` 元数据中指定,也可以在 `@Injectable()` 的 `providedIn` 选项中指定某个模块类(但根模块 `AppModule` 除外)。 -Use the `@NgModule()` `provides` option if a module is [lazy loaded](guide/lazy-loading-ngmodules). The module's own injector is configured with the provider when that module is loaded, and Angular can inject the corresponding services in any class it creates in that module. If you use the `@Injectable()` option `providedIn: MyLazyloadModule`, the provider could be shaken out at compile time, if it is not used anywhere else in the app. +Use the `@NgModule()` `providers` option if a module is [lazy loaded](guide/lazy-loading-ngmodules). The module's own injector is configured with the provider when that module is loaded, and Angular can inject the corresponding services in any class it creates in that module. If you use the `@Injectable()` option `providedIn: MyLazyloadModule`, the provider could be shaken out at compile time, if it is not used anywhere else in the app. 如果某个模块是[惰性加载](guide/lazy-loading-ngmodules)的,那么请使用 `@NgModule()` 的 `provides` 选项。加载那个模块时,就会用这里的提供商来配置模块本身的注入器,而 Angular 会为该模块中创建的任何类注入相应的服务。如果你使用了 `@Injectable()` 中的 `providedIn: MyLazyloadModule` 选项,那么如果该提供商没有在别处用过,就可以在编译期间把它摇树优化掉。 diff --git a/aio/content/guide/libraries.md b/aio/content/guide/libraries.md new file mode 100644 index 0000000000..6e6b1901b4 --- /dev/null +++ b/aio/content/guide/libraries.md @@ -0,0 +1,30 @@ +# Overview of Angular Libraries + +Many applications need to solve the same general problems, such as presenting a unified user interface, presenting data, and allowing data entry. +Developers can create general solutions for particular domains that can be adapted for re-use in different apps. +Such a solution can be built as Angular *libraries* and these libraries can be published and shared as *npm packages*. + +An Angular library is an Angular [project](guide/glossary#project) that differs from an app in that it cannot run on its own. +A library must be imported and used in an app. + +Libraries extend Angular's base functionality. For example, to add [reactive forms](guide/reactive-forms) to an app, add the library package using `ng add @angular/forms`, then import the `ReactiveFormsModule` from the `@angular/forms` library in your application code. +Similarly, adding the [service worker](guide/service-worker-intro) library to an Angular application is one of the steps for turning an application into a [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) (PWA). +[Angular Material](https://material.angular.io/) is an example of a large, general-purpose library that provides sophisticated, reusable, and adaptable UI components. + +Any app developer can use these and other libraries that have been published as npm packages by the Angular team or by third parties. See [Using Published Libraries](guide/using-libraries). + +## Creating libraries + +If you have developed functionality that is suitable for reuse, you can create your own libraries. +These libraries can be used locally in your workspace, or you can publish them as [npm packages](guide/npm-packages) to share with other projects or other Angular developers. +These packages can be published to the npm registry, a private npm Enterprise registry, or a private package management system that supports npm packages. +See [Creating Libraries](guide/creating-libraries). + +Whether you decide to package functionality as a library is an architectural decision, similar to deciding whether a piece of functionality is a component or a service, or deciding on the scope of a component. + +Packaging functionality as a library forces the artifacts in the library to be decoupled from the application's business logic. +This can help to avoid various bad practices or architecture mistakes that can make it difficult to decouple and reuse code in the future. + +Putting code into a separate library is more complex than simply putting everything in one app. +It requires more of an investment in time and thought for managing, maintaining, and updating the library. +This complexity can pay off, however, when the library is being used in multiple apps. diff --git a/aio/content/guide/lifecycle-hooks.md b/aio/content/guide/lifecycle-hooks.md index e329e3f6cb..a4265681ad 100644 --- a/aio/content/guide/lifecycle-hooks.md +++ b/aio/content/guide/lifecycle-hooks.md @@ -224,7 +224,7 @@ calls the lifecycle hook methods in the following sequence at specific moments: 每当 Angular 做完组件视图和子视图的变更检测之后调用。 - Called after the `ngAfterViewInit` and every subsequent `ngAfterContentChecked()`. + Called after the `ngAfterViewInit()` and every subsequent `ngAfterContentChecked()`. `ngAfterViewInit()` 和每次 `ngAfterContentChecked()` 之后调用。 diff --git a/aio/content/guide/ngmodule-faq.md b/aio/content/guide/ngmodule-faq.md index de046844e6..a50d2ffb6d 100644 --- a/aio/content/guide/ngmodule-faq.md +++ b/aio/content/guide/ngmodule-faq.md @@ -168,7 +168,7 @@ components, directives, and pipes. 如果当前模块中的组件包含了*共享*模块和*特性*模块中的组件、指令和管道,就导入这些模块。 -Import only [BrowserModule](guide/ngmodule-faq#q-browser-vs-common-module) in the root `AppModule`. +Import [BrowserModule](guide/ngmodule-faq#q-browser-vs-common-module) only in the root `AppModule`. 只能在根模块 `AppModule` 中[导入_BrowserModule_](guide/ngmodule-faq#q-browser-vs-common-module)。 diff --git a/aio/content/guide/pipes.md b/aio/content/guide/pipes.md index f2a4caa72a..233c4c0cdf 100644 --- a/aio/content/guide/pipes.md +++ b/aio/content/guide/pipes.md @@ -418,7 +418,7 @@ code with checkbox switches and additional displays to help you experience these Replacing the array is an efficient way to signal Angular to update the display. -When do you replace the array? When the data change. +When do you replace the array? When the data changes. That's an easy rule to follow in *this* example where the only way to change the data is by adding a hero. @@ -426,7 +426,7 @@ where the only way to change the data is by adding a hero. 你该什么时候替换这个数组呢?当数据变化的时候。 在这个*玩具级*例子中,这是一个简单的规则,因为这里修改数据的唯一途径就是添加新英雄。 -More often, you don't know when the data have changed, +More often, you don't know when the data has changed, especially in applications that mutate data in many ways, perhaps in application locations far away. A component in such an application usually can't know about those changes. @@ -627,7 +627,7 @@ If you're not careful, this pipe will punish the server with requests. 时刻记住,非纯管道可能每隔几微秒就会被调用一次。 如果你不小心点,这个管道就会发起一大堆请求“攻击”服务器。 -In the following code, the pipe only calls the server when the request URL changes and it caches the server response. +In the following code, the pipe only calls the server when the requested URL changes and it caches the server response. The code uses the [Angular http](guide/http) client to retrieve data: 下面这个管道只有当所请求的 URL 发生变化时才会向服务器发起请求。它会缓存服务器的响应。 diff --git a/aio/content/guide/router.md b/aio/content/guide/router.md index b2474249b5..b84fe3672a 100644 --- a/aio/content/guide/router.md +++ b/aio/content/guide/router.md @@ -1353,11 +1353,11 @@ Replace the contents of each component with the sample HTML below. - + - + @@ -1466,7 +1466,7 @@ To test this feature, add a button with a `RouterLink` to the `HeroListComponent 要测试本特性,请往 `HeroListComponent` 的模板中添加一个带 `RouterLink` 的按钮,并且把它的链接设置为 `"/sidekicks"`。 - + @@ -1586,7 +1586,7 @@ Remember to restore the redirect to `pathMatch = 'full'`. 默认路由应该只有在*整个*URL 等于 `''` 时才重定向到 `HeroListComponent`,别忘了把重定向路由设置为 `pathMatch = 'full'`。 Learn more in Victor Savkin's -[post on redirects](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes). +[post on redirects](http://vsavkin.tumblr.com/post/146722301646/angular-router-empty-paths-componentless-routes). 要了解更多,参见 Victor Savkin 的帖子[关于重定向](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes)。 @@ -1818,11 +1818,11 @@ Here are the files discussed in this milestone. - + - + @@ -1916,7 +1916,7 @@ Create an `AppRouting` module in the `/app` folder to contain the routing config ng generate module app-routing --module app --flat -Import the `CrisisListComponent`, `HeroListComponent`, and `PageNotFoundCompponent` symbols +Import the `CrisisListComponent`, `HeroListComponent`, and `PageNotFoundComponent` symbols just like you did in the `app.module.ts`. Then move the `Router` imports and routing configuration, including `RouterModule.forRoot`, into this routing module. @@ -3145,12 +3145,12 @@ You could also create more transitions for other routes. This trigger is suffici 你还可以为其它路由组件用不同的转场效果创建更多触发器。现在这个触发器已经足够当前的里程碑用了。 -Back in the `AppComponent`, import the `RouterOutlet` token from the `@angular/router` package and the `slideInDownAnimation` from +Back in the `AppComponent`, import the `RouterOutlet` token from the `@angular/router` package and the `slideInAnimation` from `'./animations.ts`. 回到 `AppComponent`,从 `@angular/router` 中导入 `RouterOutlet` 令牌,并从 `'./animations.ts` 中导入 `slideInDownAnimation`。 -Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`. +Add an `animations` array to the `@Component` metadata's that contains the `slideInAnimation`. 把一个包含 `slideInDownAnimation` 的 `animations` 数组添加到 `@Component` 的元数据中。 @@ -4654,12 +4654,12 @@ Make the `AuthGuard` at least pretend to authenticate. 先让 `AuthGuard` 至少能“假装”进行认证。 -The `AuthGuard` should call an application service that can login a user and retain information about the current user. Generate a new `AuthService` in the `admin` folder: +The `AuthGuard` should call an application service that can login a user and retain information about the current user. Generate a new `AuthService` in the `auth` folder: `AuthGuard` 可以调用应用中的一项服务,该服务能让用户登录,并且保存当前用户的信息。在 `admin` 目录下生成一个新的 `AuthService`: - ng generate service admin/auth + ng generate service auth/auth Update the `AuthService` to log in the user: @@ -5177,7 +5177,7 @@ The relevant *Crisis Center* code for this milestone follows. - + diff --git a/aio/content/guide/rx-library.md b/aio/content/guide/rx-library.md index c38e3a94fc..8e842146ef 100644 --- a/aio/content/guide/rx-library.md +++ b/aio/content/guide/rx-library.md @@ -100,7 +100,7 @@ RxJS 提供了很多操作符,不过只有少数是常用的。 | Area | Operators | | :------------ | :---------- | | 类别 | 操作 | -| Creation | `from`, `fromPromise`,`fromEvent`, `of` | +| Creation | `from`,`fromEvent`, `of` | | 创建 | `from`, `fromPromise`,`fromEvent`, `of` | | Combination | `combineLatest`, `concat`, `merge`, `startWith` , `withLatestFrom`, `zip` | | 组合 | `combineLatest`, `concat`, `merge`, `startWith` , `withLatestFrom`, `zip` | @@ -173,4 +173,4 @@ For example: 比如: - \ No newline at end of file + diff --git a/aio/content/guide/service-worker-communications.md b/aio/content/guide/service-worker-communications.md index fde42d9a2b..ab3dd34a71 100644 --- a/aio/content/guide/service-worker-communications.md +++ b/aio/content/guide/service-worker-communications.md @@ -74,13 +74,34 @@ Do this with the `checkForUpdate()` method: 通过调用 `checkForUpdate()` 方法来实现: - + This method returns a `Promise` which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the `available` event will indicate availability of a new version of the app. 该方法返回一个用来表示检查更新已经成功完成的 `Promise`,不过它不会指出是否确实发现了一个更新。 即使找到了一个,Service Worker 还必须成功下载更新过的文件,而这可能会失败。如果成功了,就会通过一个 `available` 事件来表明当前应用有一个可用的新版本。 +
+ +In order to avoid negatively affecting the initial rendering, `ServiceWorkerModule` will by default +wait for the app to stabilize, before registering the ServiceWorker script. Constantly polling for +updates, e.g. with `interval()`, will prevent the app from stabilizing and the ServiceWorker +script will never be registered with the browser. + +为了避免影响页面的首次渲染,在注册 ServiceWorker 脚本之前,`ServiceWorkerModule` 默认会等待应用程序达到稳定态。如果不断轮询更新(比如调用 `interval()`)将阻止应用程序达到稳定态,也就永远不会往浏览器中注册 ServiceWorker 脚本。 + +You can avoid that by waiting for the app to stabilize first, before starting to poll for updates +(as shown in the example above). + +在开始轮询更新之前,你可以先等待应用程序达到稳定态,以避免这种情况(如上例所示)。 + +Note that this is true for any kind of polling done by your application. +Check the {@link ApplicationRef#isStable isStable} documentation for more information. + +请注意,应用中所执行的各种轮询都会阻止它达到稳定态。欲知详情,参见 {@link ApplicationRef#isStable isStable} 文档。 + +
+ ### Forcing update activation ### 强制激活更新 diff --git a/aio/content/guide/service-worker-config.md b/aio/content/guide/service-worker-config.md index fbc9b6cf38..5c644b5e3c 100644 --- a/aio/content/guide/service-worker-config.md +++ b/aio/content/guide/service-worker-config.md @@ -167,6 +167,10 @@ The `installMode` determines how these resources are initially cached. The `inst 这是一种按需缓存模式。永远不会请求的资源也永远不会被缓存。 这对于像为不同分辨率提供的图片之类的资源很有用,那样 Service Worker 就只会为特定的屏幕和设备方向缓存正确的资源。 +Defaults to `prefetch`. + +默认为 `prefetch`。 + ### `updateMode` For resources already in the cache, the `updateMode` determines the caching behavior when a new version of the app is discovered. Any resources in the group that have changed since the previous version are updated in accordance with `updateMode`. @@ -183,6 +187,10 @@ For resources already in the cache, the `updateMode` determines the caching beha `lazy` 告诉 Service Worker 不要缓存这些资源,而是先把它们看作未被请求的,等到它们再次被请求时才进行更新。 `lazy` 这个 `updateMode` 只有在 `installMode` 也同样是 `lazy` 时才有效。 +Defaults to the value `installMode` is set to. + +其默认值为 `installMode` 的值。 + ### `resources` This section describes the resources to cache, broken up into three groups. @@ -257,7 +265,7 @@ API 有时可能会以不向后兼容的方式更改格式。 `version` 提供了一种机制,用于指出这些被缓存的资源已经通过不向后兼容的方式进行了更新,并且旧的缓存条目(即来自以前版本的缓存条目)应该被丢弃。 -`version` is an integer field and defaults to `0`. +`version` is an integer field and defaults to `1`. `version` 是个整型字段,默认为 `0`。 diff --git a/aio/content/guide/service-worker-getting-started.md b/aio/content/guide/service-worker-getting-started.md index edfa4773aa..8ee07fae1d 100644 --- a/aio/content/guide/service-worker-getting-started.md +++ b/aio/content/guide/service-worker-getting-started.md @@ -184,6 +184,16 @@ Notice that all of the files the browser needs to render this application are ca 构建结果(JS 和 CSS 包)。 * Anything under `assets`. +* Images and fonts directly under the configured `outputPath` (by default `./dist//`) or `resourcesOutputPath`. See [`ng build`](cli/build) for more information about these options. + + +
+Pay attention to two key points: + +1. The generated `ngsw-config.json` includes a limited list of cachable fonts and images extentions. In some cases, you might want to modify the glob pattern to suit your needs. + +1. If `resourcesOutputPath` or `assets` paths are modified after the generation of configuration file, you need to change the paths manually in `ngsw-config.json`. +
`assets` 下的所有文件。 diff --git a/aio/content/guide/singleton-services.md b/aio/content/guide/singleton-services.md index f33370439b..7a4d5ce960 100644 --- a/aio/content/guide/singleton-services.md +++ b/aio/content/guide/singleton-services.md @@ -37,7 +37,7 @@ There are two ways to make a service a singleton in Angular: 把该服务包含在 `AppModule` 或某个只会被 `AppModule` 导入的模块中。 -Beginning with Angular 6.0, the preferred way to create a singleton services is to specify on the service that it should be provided in the application root. This is done by setting `providedIn` to `root` on the service's `@Injectable` decorator: +Beginning with Angular 6.0, the preferred way to create a singleton service is to specify on the service that it should be provided in the application root. This is done by setting `providedIn` to `root` on the service's `@Injectable` decorator: 从 Angular 6.0 开始,创建单例服务的首选方式是在那个服务类上指定它应该在应用的根上提供。只要在该服务的 `@Injectable` 装饰器上把 `providedIn` 设置为 `root` 就可以了: diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md index 12b853ba42..acf6c7eb6a 100644 --- a/aio/content/guide/template-syntax.md +++ b/aio/content/guide/template-syntax.md @@ -66,46 +66,64 @@ Begin with the first form of data binding—interpolation—to see how m {@a interpolation} -## Interpolation ( {{...}} ) +## Interpolation and Template Expressions -## 插值表达式 ( {{...}} ) +Interpolation allows you to incorporate calculated strings into the text +between HTML element tags and within attribute assignments. Template +expressions are what you use to calculate those strings. -You met the double-curly braces of interpolation, `{{` and `}}`, early in your Angular education. +The interpolation demonstrates all of +the syntax and code snippets described in this section. -在以前的 Angular 教程中,你遇到过由双花括号括起来的插值表达式,`{{` 和 `}}`。 +### Interpolation `{{...}}` - +### 插值表达式 `{{...}}` + +Interpolation refers to embedding expressions into marked up text. +By default, interpolation uses as its delimiter the double curly braces, `{{` and `}}`. + +所谓 "插值" 是指将表达式嵌入到标记文本中。 +默认情况下,插值表达式会用双花括号 `{{`和 `}}` 作为分隔符。 + +In the following snippet, `{{ currentCustomer }}` is an example of interpolation. + +在下面的代码片段中,`{{ currentCustomer }}` 就是插值表达式的例子。 + + -You use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments. +The text between the braces is often the name of a component +property. Angular replaces that name with the +string value of the corresponding component property. 插值表达式可以把计算后的字符串插入到 HTML 元素标签内的文本或对标签的属性进行赋值。 - + -The text between the braces is often the name of a component property. Angular replaces that name with the -string value of the corresponding component property. In the example above, Angular evaluates the `title` and `heroImageUrl` properties -and "fills in the blanks", first displaying a bold application title and then a heroic image. +In the example above, Angular evaluates the `title` and `itemImageUrl` properties +and fills in the blanks, first displaying some title text and then an image. 在括号之间的“素材”,通常是组件属性的名字。Angular 会用组件中相应属性的字符串值,替换这个名字。 上例中,Angular 计算 `title` 和 `heroImageUrl` 属性的值,并把它们填在空白处。 首先显示粗体的应用标题,然后显示英雄的图片。 -More generally, the text between the braces is a **template expression** that Angular first **evaluates** -and then **converts to a string**. The following interpolation illustrates the point by adding the two numbers: +More generally, the text between the braces is a **template expression** +that Angular first **evaluates** and then **converts to a string**. +The following interpolation illustrates the point by adding two numbers: 一般来说,括号间的素材是一个**模板表达式**,Angular 先**对它求值**,再把它**转换成字符串**。 下列插值表达式通过把括号中的两个数字相加说明了这一点: - + -The expression can invoke methods of the host component such as `getVal()`, seen here: +The expression can invoke methods of the host component such as `getVal()` in +the following example: 这个表达式可以调用宿主组件的方法,就像下面用的 `getVal()`: - + Angular evaluates all expressions in double curly braces, @@ -115,103 +133,115 @@ it assigns this composite interpolated result to an **element or directive prope Angular 对所有双花括号中的表达式求值,把求值的结果转换成字符串,并把它们跟相邻的字符串字面量连接起来。最后,把这个组合出来的插值结果赋给**元素或指令的属性**。 You appear to be inserting the result between element tags and assigning it to attributes. -It's convenient to think so, and you rarely suffer for this mistake. -Though this is not exactly true. Interpolation is a special syntax that Angular converts into a -[property binding](guide/template-syntax#property-binding), as is explained [below](guide/template-syntax#property-binding-or-interpolation). -表面上看,你在元素标签之间插入了结果和对标签的属性进行了赋值。 -这样思考起来很方便,并且这个误解很少给你带来麻烦。 -但严格来讲,这是不对的。插值表达式是一个特殊的语法,Angular 把它转换成了[属性绑定](guide/template-syntax#property-binding),[后面](guide/template-syntax#property-binding-or-interpolation)将会解释这一点。 +从表面上看,你就像是在元素标签之间插入了结果并对标签的属性进行了赋值。 -But first, let's take a closer look at template expressions and statements. +
-讲解属性绑定之前,先深入了解一下模板表达式和模板语句。 +However, interpolation is a special syntax that Angular converts into a +property binding. -
+但是,插值表达式其实是一个特殊语法,Angular 会把它转换为属性绑定。 -{@a template-expressions} +If you'd like to use something other than `{{` and `}}`, you can +configure the interpolation delimiter via the +[interpolation](api/core/Component#interpolation) +option in the `Component` metadata. -## Template expressions +如果你想用别的分隔符来代替 `{{` 和 `}}`,也可以通过 `Component` 元数据中的 [interpolation](api/core/Component#interpolation) 选项来配置插值分隔符。 -## 模板表达式 +
-A template **expression** produces a value. +### Template expressions + +### 模板表达式 + +a template **expression** produces a value and appears within the double +curly braces, `{{ }}`. Angular executes the expression and assigns it to a property of a binding target; -the target might be an HTML element, a component, or a directive. +the target could be an HTML element, a component, or a directive. -模板**表达式**产生一个值。 +模板**表达式**会产生一个值,并出现在双花括号 `{{ }}` 中。 Angular 执行这个表达式,并把它赋值给绑定目标的属性,这个绑定目标可能是 HTML 元素、组件或指令。 The interpolation braces in `{{1 + 1}}` surround the template expression `1 + 1`. -In the [property binding](guide/template-syntax#property-binding) section below, +In the property binding, a template expression appears in quotes to the right of the `=` symbol as in `[property]="expression"`. `{{1 + 1}}` 中所包含的模板表达式是 `1 + 1`。 - 在[属性绑定](guide/template-syntax#property-binding)中会再次看到模板表达式,它出现在 `=` 右侧的引号中,就像这样:`[property]="expression"`。 + 在属性绑定中会再次看到模板表达式,它出现在 `=` 右侧的引号中,就像这样:`[property]="expression"`。 -You write these template expressions in a language that looks like JavaScript. -Many JavaScript expressions are legal template expressions, but not all. +In terms of syntax, template expressions are similar to JavaScript. +Many JavaScript expressions are legal template expressions, with a few exceptions. -编写模板表达式所用的语言看起来很像 JavaScript。 - 很多 JavaScript 表达式也是合法的模板表达式,但不是全部。 +在语法上,模板表达式与 JavaScript 很像。很多 JavaScript 表达式都是合法的模板表达式,但也有一些例外。 -JavaScript expressions that have or promote side effects are prohibited, +You can't use JavaScript expressions that have or promote side effects, including: -JavaScript 中那些具有或可能引发副作用的表达式是被禁止的,包括: +你不能使用那些具有或可能引发副作用的 JavaScript 表达式,包括: -* assignments (`=`, `+=`, `-=`, ...) +* Assignments (`=`, `+=`, `-=`, `...`) - 赋值 (`=`, `+=`, `-=`, ...) + 赋值 (`=`, `+=`, `-=`, `...`) -* new +* Operators such as `new`, `typeof`, `instanceof`, etc. - `new` 运算符 + `new`、`typeof`、`instanceof` 等操作符。 -* chaining expressions with ; or , +* Chaining expressions with ; or , - 使用 `;` 或 `,` 的链式表达式 + 使用 ;, 串联起来的表达式 -* increment and decrement operators (`++` and `--`) +* The increment and decrement operators `++` and `--` - 自增和自减运算符:`++` 和 `--` + 自增和自减运算符:`++` 和 `--` + +* Some of the ES2015+ operators + + 一些 ES2015+ 版本的操作符 Other notable differences from JavaScript syntax include: -和 JavaScript 语 法的其它显著不同包括: +和 JavaScript 语法的其它显著差异包括: -* no support for the bitwise operators `|` and `&` +* No support for the bitwise operators such as `|` and `&` - 不支持位运算 `|` 和 `&` + 不支持位运算,比如 `|` 和 `&` -* new [template expression operators](guide/template-syntax#expression-operators), such as `|`, `?.` and `!`. +* New template expression operators, such as `|`, `?.` and `!` - 具有新的[模板表达式运算符](guide/template-syntax#expression-operators),比如 `|`、`?.` 和 `!`。 + 新的[模板表达式运算符](guide/template-syntax#expression-operators),比如 `|`、`?.` 和 `!`。 -{@a expression-context} + ### Expression context ### 表达式上下文 The *expression context* is typically the _component_ instance. -In the following snippets, the `title` within double-curly braces and the -`isUnchanged` in quotes refer to properties of the `AppComponent`. +In the following snippets, the `recommended` within double curly braces and the +`itemImageUrl2` in quotes refer to properties of the `AppComponent`. 典型的*表达式上下文*就是这个**组件实例**,它是各种绑定值的来源。 在下面的代码片段中,双花括号中的 `title` 和引号中的 `isUnchanged` 所引用的都是 `AppComponent` 中的属性。 - + An expression may also refer to properties of the _template's_ context -such as a [template input variable](guide/template-syntax#template-input-variable) (`let hero`) -or a [template reference variable](guide/template-syntax#ref-vars) (`#heroInput`). +such as a template input variable, + +`let customer`, or a template reference variable, `#customerInput`. + 表达式的上下文可以包括组件之外的对象。 比如[模板输入变量](guide/template-syntax#template-input-variable) (`let hero`)和[模板引用变量](guide/template-syntax#ref-vars)(`#heroInput`)就是备选的上下文对象之一。 - + + + + The context for terms in an expression is a blend of the _template variables_, @@ -223,34 +253,35 @@ and, lastly, the component's member names. 表达式中的上下文变量是由*模板变量*、指令的*上下文变量*(如果有)和组件的*成员*叠加而成的。 如果你要引用的变量名存在于一个以上的命名空间中,那么,模板变量是最优先的,其次是指令的上下文变量,最后是组件的成员。 -The previous example presents such a name collision. The component has a `hero` -property and the `*ngFor` defines a `hero` template variable. -The `hero` in `{{hero.name}}` +The previous example presents such a name collision. The component has a `customer` +property and the `*ngFor` defines a `customer` template variable. + +
+ +The `customer` in `{{customer.name}}` refers to the template input variable, not the component's property. 上一个例子中就体现了这种命名冲突。组件具有一个名叫 `hero` 的属性,而 `*ngFor` 声明了一个也叫 `hero` 的模板变量。 在 `{{hero.name}}` 表达式中的 `hero` 实际引用的是模板变量,而不是组件的属性。 Template expressions cannot refer to anything in -the global namespace (except `undefined`). They can't refer to `window` or `document`. They -can't call `console.log` or `Math.max`. They are restricted to referencing +the global namespace, except `undefined`. They can't refer to +`window` or `document`. Additionally, they +can't call `console.log()` or `Math.max()` and they are restricted to referencing members of the expression context. 模板表达式不能引用全局命名空间中的任何东西,比如 `window` 或 `document`。它们也不能调用 `console.log` 或 `Math.max`。 它们只能引用表达式上下文中的成员。 -{@a no-side-effects} - -{@a expression-guidelines} +
### Expression guidelines -### 表达式指南 +### 表达式使用指南 -Template expressions can make or break an application. -Please follow these guidelines: +When using template expressions follow these guidelines: -模板表达式能成就或毁掉一个应用。请遵循下列指南: +当使用模板表达式时,请遵循下列指南: * [No visible side effects](guide/template-syntax#no-visible-side-effects) @@ -264,15 +295,7 @@ Please follow these guidelines: [非常简单](guide/template-syntax#simplicity) -* [Idempotence](guide/template-syntax#idempotence) - - [幂等性](guide/template-syntax#idempotence) - -The only exceptions to these guidelines should be in specific circumstances that you thoroughly understand. - -超出上面指南外的情况应该只出现在那些你确信自己已经彻底理解的特定场景中。 - -#### No visible side effects +### No visible side effects #### 没有可见的副作用 @@ -289,13 +312,43 @@ The view should be stable throughout a single rendering pass. 永远不用担心读取组件值可能改变另外的显示值。 在一次单独的渲染过程中,视图应该总是稳定的。 -#### Quick execution +An [idempotent](https://en.wikipedia.org/wiki/Idempotence) expression is ideal because +it is free of side effects and improves Angular's change detection performance. -#### 执行迅速 +最好使用[幂等的](https://en.wikipedia.org/wiki/Idempotence)表达式,因为它没有副作用,并且能提升 Angular 变更检测的性能。 + +In Angular terms, an idempotent expression always returns +*exactly the same thing* until +one of its dependent values changes. + +在 Angular 的术语中,幂等的表达式应该总是返回*完全相同的东西*,直到某个依赖值发生改变。 + +Dependent values should not change during a single turn of the event loop. +If an idempotent expression returns a string or a number, it returns the same string or number when called twice in a row. If the expression returns an object, including an `array`, it returns the same object *reference* when called twice in a row. + +在单独的一次事件循环中,被依赖的值不应该改变。 + 如果幂等的表达式返回一个字符串或数字,连续调用它两次,也应该返回相同的字符串或数字。 + 如果幂等的表达式返回一个对象(包括 `Date` 或 `Array`),连续调用它两次,也应该返回同一个对象的*引用*。 + +
+ +There is one exception to this behavior that applies to `*ngFor`. `*ngFor` has `trackBy` functionality that can deal with referential inequality of objects that when iterating over them. + +当用于 `*ngFor` 时,这种行为有一个例外。`*ngFor` 具有一个 `trackBy` 功能,它可以在迭代时把两个引用不等的对象视作同一个。 + +For more information, see the [*ngFor with `trackBy`](guide/template-syntax#ngfor-with-trackby) section of this guide. + +欲知详情,参见[带 `trackBy` 的 *ngFor](guide/template-syntax#ngfor-with-trackby) 部分。 + +
+ +### Quick execution + +### 执行迅速 Angular executes template expressions after every change detection cycle. Change detection cycles are triggered by many asynchronous activities such as -promise resolutions, http results, timer events, keypresses and mouse moves. +promise resolutions, HTTP results, timer events, key presses and mouse moves. Angular 会在每个变更检测周期后执行模板表达式。 变更检测周期会被多种异步活动触发,比如 Promise 解析、HTTP 结果、定时器时间、按键或鼠标移动。 @@ -306,44 +359,23 @@ Consider caching values when their computation is expensive. 表达式应该快速结束,否则用户就会感到拖沓,特别是在较慢的设备上。 当计算代价较高时,应该考虑缓存那些从其它值计算得出的值。 -#### Simplicity +### Simplicity -#### 非常简单 +### 非常简单 -Although it's possible to write quite complex template expressions, you should avoid them. +Although it's possible to write complex template expressions, it's a better +practice to avoid them. -虽然也可以写出相当复杂的模板表达式,但不要那么写。 +虽然也可以写复杂的模板表达式,不过最好避免那样做。 -A property name or method call should be the norm. -An occasional Boolean negation (`!`) is OK. -Otherwise, confine application and business logic to the component itself, -where it will be easier to develop and test. +A property name or method call should be the norm, but an occasional Boolean negation, `!`, is OK. +Otherwise, confine application and business logic to the component, +where it is easier to develop and test. -常规是属性名或方法调用。偶尔的逻辑取反 (`!`) 也还凑合。 -其它情况下,应在组件中实现应用和业务逻辑,使开发和测试变得更容易。 +属性名或方法调用应该是常态,但偶然使用逻辑取反 `!` 也是可以的。 +其它情况下,应该把应用程序和业务逻辑限制在组件中,这样它才能更容易开发和测试。 -#### Idempotence - -#### 幂等性 - -An [idempotent](https://en.wikipedia.org/wiki/Idempotence) expression is ideal because -it is free of side effects and improves Angular's change detection performance. - -最好使用[幂等的](https://en.wikipedia.org/wiki/Idempotence)表达式,因为它没有副作用,并且能提升 Angular 变更检测的性能。 - -In Angular terms, an idempotent expression always returns *exactly the same thing* until -one of its dependent values changes. - -在 Angular 的术语中,幂等的表达式应该总是返回*完全相同的东西*,直到某个依赖值发生改变。 - -Dependent values should not change during a single turn of the event loop. -If an idempotent expression returns a string or a number, it returns the same string or number -when called twice in a row. If the expression returns an object (including an `array`), -it returns the same object *reference* when called twice in a row. - -在单独的一次事件循环中,被依赖的值不应该改变。 - 如果幂等的表达式返回一个字符串或数字,连续调用它两次,也应该返回相同的字符串或数字。 - 如果幂等的表达式返回一个对象(包括 `Date` 或 `Array`),连续调用它两次,也应该返回同一个对象的*引用*。 +
@@ -1350,7 +1382,6 @@ content harmlessly.
- {@a other-bindings} ## Attribute, class, and style bindings @@ -1585,57 +1616,45 @@ Note that a _style property_ name can be written in either {@a event-binding} -## Event binding ( (event) ) +## Event binding `(event)` -## 事件绑定 ( (事件名) ) +## 事件绑定 `(event)` -The bindings directives you've met so far flow data in one direction: **from a component to an element**. +Event binding allows you to listen for certain events such as +keystrokes, mouse movements, clicks, and touches. For an example +demonstrating all of the points in this section, see the event binding example. -前面遇到的绑定的数据流都是单向的:**从组件到元素**。 +事件绑定允许你侦听某些事件,比如按键、鼠标移动、点击和触屏。要查看本节中所有要点的演示,请参见事件绑定范例。 -Users don't just stare at the screen. They enter text into input boxes. They pick items from lists. -They click buttons. Such user actions may result in a flow of data in the opposite direction: -**from an element to a component**. - -但用户不会只盯着屏幕看。他们会在输入框中输入文本。他们会从列表中选取条目。 -他们会点击按钮。这类用户动作可能导致反向的数据流:*从元素到组件*。 - -The only way to know about a user action is to listen for certain events such as -keystrokes, mouse movements, clicks, and touches. -You declare your interest in user actions through Angular event binding. - -知道用户动作的唯一方式是监听某些事件,如按键、鼠标移动、点击和触摸屏幕。 -可以通过 Angular 事件绑定来声明对哪些用户动作感兴趣。 - -Event binding syntax consists of a **target event** name +Angular event binding syntax consists of a **target event** name within parentheses on the left of an equal sign, and a quoted -[template statement](guide/template-syntax#template-statements) on the right. +template statement on the right. The following event binding listens for the button's click events, calling the component's `onSave()` method whenever a click occurs: -事件绑定语法由等号左侧带圆括号的**目标事件**和右侧引号中的[模板语句](guide/template-syntax#template-statements)组成。 +Angular 的事件绑定语法由等号左侧带圆括号的**目标事件**和右侧引号中的[模板语句](guide/template-syntax#template-statements)组成。 下面事件绑定监听按钮的点击事件。每当点击发生时,都会调用组件的 `onSave()` 方法。 - - +
+ Syntax diagram +
### Target event ### 目标事件 -A **name between parentheses** — for example, `(click)` — -identifies the target event. In the following example, the target is the button's click event. +As above, the target is the button's click event. -**圆括号中的名称** —— 比如 `(click)` —— 标记出目标事件。在下面例子中,目标是按钮的 click 事件。 +如前所述,其目标就是此按钮的单击事件。 - + -Some people prefer the `on-` prefix alternative, known as the **canonical form**: +Alternatively, use the `on-` prefix, known as the canonical form: 有些人更喜欢带 `on-` 前缀的备选形式,称之为**规范形式**: - + Element events may be the more common targets, but Angular looks first to see if the name matches an event property @@ -1643,18 +1662,9 @@ of a known directive, as it does in the following example: 元素事件可能是更常见的目标,但 Angular 会先看这个名字是否能匹配上已知指令的事件属性,就像下面这个例子: - + -
- -The `myClick` directive is further described in the section -on [aliasing input/output properties](guide/template-syntax#aliasing-io). - -更多关于该 `myClick` 指令的解释,见[给输入/输出属性起别名](guide/template-syntax#aliasing-io)。 - -
- If the name fails to match an element event or an output property of a known directive, Angular reports an “unknown directive” error. @@ -1676,12 +1686,11 @@ into a model. 当事件发生时,这个处理器会执行模板语句。 典型的模板语句通常涉及到响应事件执行动作的接收器,例如从 HTML 控件中取得值,并存入模型。 -The binding conveys information about the event, including data values, through -an **event object named `$event`**. +The binding conveys information about the event. This information can include data values such as an event object, string, or number named `$event`. 绑定会通过**名叫 `$event` 的事件对象**传递关于此事件的信息(包括数据值)。 -The shape of the event object is determined by the target event. +The target event determines the shape of the `$event` object. If the target event is a native DOM element event, then `$event` is a [DOM event object](https://developer.mozilla.org/en-US/docs/Web/Events), with properties such as `target` and `target.value`. @@ -1693,11 +1702,12 @@ Consider this example: 考虑这个范例: - + -This code sets the input box `value` property by binding to the `name` property. -To listen for changes to the value, the code binds to the input box's `input` event. +This code sets the `` `value` property by binding to the `name` property. +To listen for changes to the value, the code binds to the `input` +event of the `` element. When the user makes changes, the `input` event is raised, and the binding executes the statement within a context that includes the DOM event object, `$event`. @@ -1709,18 +1719,14 @@ To update the `name` property, the changed text is retrieved by following the pa 要更新 `name` 属性,就要通过路径 `$event.target.value` 来获取更改后的值。 -If the event belongs to a directive (recall that components are directives), -`$event` has whatever shape the directive decides to produce. +If the event belongs to a directive—recall that components +are directives—`$event` has whatever shape the directive produces. 如果事件属于指令(回想一下,组件是指令的一种),那么 `$event` 具体是什么由指令决定。 -{@a eventemitter} +### Custom events with `EventEmitter` -{@a custom-event} - -### Custom events with EventEmitter - -### 使用 EventEmitter 实现自定义事件 +### 使用 `EventEmitter` 实现自定义事件 Directives typically raise custom events with an Angular [EventEmitter](api/core/EventEmitter). The directive creates an `EventEmitter` and exposes it as a property. @@ -1732,40 +1738,43 @@ Parent directives listen for the event by binding to this property and accessing 指令调用 `EventEmitter.emit(payload)` 来触发事件,可以传入任何东西作为消息载荷。 父指令通过绑定到这个属性来监听事件,并通过 `$event` 对象来访问载荷。 -Consider a `HeroDetailComponent` that presents hero information and responds to user actions. -Although the `HeroDetailComponent` has a delete button it doesn't know how to delete the hero itself. -The best it can do is raise an event reporting the user's delete request. +Consider an `ItemDetailComponent` that presents item information and responds to user actions. +Although the `ItemDetailComponent` has a delete button, it doesn't know how to delete the hero. It can only raise an event reporting the user's delete request. 假设 `HeroDetailComponent` 用于显示英雄的信息,并响应用户的动作。 虽然 `HeroDetailComponent` 包含删除按钮,但它自己并不知道该如何删除这个英雄。 最好的做法是触发事件来报告“删除用户”的请求。 -Here are the pertinent excerpts from that `HeroDetailComponent`: +Here are the pertinent excerpts from that `ItemDetailComponent`: + 下面的代码节选自 `HeroDetailComponent`: - + - + + The component defines a `deleteRequest` property that returns an `EventEmitter`. When the user clicks *delete*, the component invokes the `delete()` method, -telling the `EventEmitter` to emit a `Hero` object. +telling the `EventEmitter` to emit an `Item` object. 组件定义了 `deleteRequest` 属性,它是 `EventEmitter` 实例。 当用户点击*删除*时,组件会调用 `delete()` 方法,让 `EventEmitter` 发出一个 `Hero` 对象。 -Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event. +Now imagine a hosting parent component that binds to the `deleteRequest` event +of the `ItemDetailComponent`. 现在,假设有个宿主的父组件,它绑定了 `HeroDetailComponent` 的 `deleteRequest` 事件。 - + -When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method, -passing the *hero-to-delete* (emitted by `HeroDetail`) in the `$event` variable. +When the `deleteRequest` event fires, Angular calls the parent component's +`deleteItem()` method, passing the *item-to-delete* (emitted by `ItemDetail`) +in the `$event` variable. 当 `deleteRequest` 事件触发时,Angular 调用父组件的 `deleteHero` 方法, 在 `$event` 变量中传入*要删除的英雄*(来自 `HeroDetail`)。 @@ -1774,15 +1783,15 @@ passing the *hero-to-delete* (emitted by `HeroDetail`) in the `$event` variable. ### 模板语句有副作用 -The `deleteHero` method has a side effect: it deletes a hero. -Template statement side effects are not just OK, but expected. +Though [template expressions](guide/template-syntax#template-expressions) shouldn't have [side effects](guide/template-syntax#avoid-side-effects), template +statements usually do. The `deleteItem()` method does have +a side effect: it deletes an item. -`deleteHero` 方法有副作用:它删除了一个英雄。 -模板语句的副作用不仅没问题,反而正是所期望的。 +虽然[模板表达式](guide/template-syntax#template-expressions)不应该有[副作用](guide/template-syntax#avoid-side-effects),但是模板语句通常会有。这里的 `deleteItem()` 方法就有一个副作用:它删除了一个条目。 -Deleting the hero updates the model, perhaps triggering other changes -including queries and saves to a remote server. -These changes percolate through the system and are ultimately displayed in this and other views. +Deleting an item updates the model, and depending on your code, triggers +other changes including queries and saving to a remote server. +These changes propagate through the system and ultimately display in this and other views. 删除这个英雄会更新模型,还可能触发其它修改,包括向远端服务器的查询和保存。 这些变更通过系统进行扩散,并最终显示到当前以及其它视图中。 @@ -2772,7 +2781,6 @@ The following discussion refers to _components_ for brevity and because this topic is mostly a concern for component authors. 为简洁起见,以下讨论会涉及到**组件**,因为这个主题主要是组件作者所关心的问题。 -

Discussion

@@ -3247,7 +3255,7 @@ You'll need this template operator when you turn on strict null checks. It's opt {@a any-type-cast-function} -## The `$any` type cast function (`$any( )`) +## The `$any` type cast function (`$any( )`) ## 类型转换函数 `$any` ($any( <表达式> )) @@ -3260,7 +3268,7 @@ the expression to [the `any` type](http://www.typescriptlang.org/docs/handbook/b -In this example, when the Angular compiler turns your template into TypeScript code, +In this example, when the Angular compiler turns your template into TypeScript code, it prevents TypeScript from reporting that `marker` is not a member of the `Hero` interface. diff --git a/aio/content/guide/testing.md b/aio/content/guide/testing.md index 032ff06e1a..a28d694053 100644 --- a/aio/content/guide/testing.md +++ b/aio/content/guide/testing.md @@ -103,7 +103,7 @@ the `test.ts` files in the `src/` folder. 不过你也可以通过编辑 `src/` 目录下的 `karma.conf.js` 和 `test.ts` 文件来微调很多选项。 The `karma.conf.js` file is a partial karma configuration file. -The CLI constructs the full runtime configuration in memory,based on application structure specified in the `angular.json` file, supplemented by `karma.conf.js`. +The CLI constructs the full runtime configuration in memory, based on application structure specified in the `angular.json` file, supplemented by `karma.conf.js`. `karma.conf.js` 文件是 karma 配置文件的一部分。 CLI 会基于 `angular.json` 文件中指定的项目结构和 `karma.conf.js` 文件,来在内存中构建出完整的运行时配置。 @@ -171,7 +171,7 @@ Continuous integration (CI) servers let you set up your project repository so th There are paid CI services like Circle CI and Travis CI, and you can also host your own for free using Jenkins and others. Although Circle CI and Travis CI are paid services, they are provided free for open source projects. You can create a public project on GitHub and add these services without paying. -Contributions to the Angular repo are automatically run through a whole suite of Circle CI and Travis CI tests. +Contributions to the Angular repo are automatically run through a whole suite of Circle CI tests. 已经有一些像 Circle CI 和 Travis CI 这样的付费 CI 服务器,你还可以使用 Jenkins 或其它软件来搭建你自己的免费 CI 服务器。 虽然 Circle CI 和 Travis CI 是收费服务,但是它们也会为开源项目提供免费服务。 @@ -3334,7 +3334,7 @@ The URL bound to the `[routerLink]` attribute flows in to the directive's `linkP 这个 URL 被绑定到了 `[routerLink]` 属性,它的值流入了该指令的 `linkParams` 属性。 -The `host` metadata property wires the click event of the host element +The `HostListener` wires the click event of the host element (the `` anchor elements in `AppComponent`) to the stub directive's `onClick` method. 它的元数据中的 `host` 属性把宿主元素(即 `AppComponent` 中的 `` 元素)的 `click` 事件关联到了这个桩指令的 `onClick` 方法。 @@ -3626,7 +3626,7 @@ So when you call `createComponent()`, the `TestBed` compiles implicitly. That's not a problem when the source code is in memory. But the `BannerComponent` requires external files -that the compile must read from the file system, +that the compiler must read from the file system, an inherently _asynchronous_ operation. 当它的源码都在内存中的时候,这样做没问题。 @@ -4026,10 +4026,10 @@ The [override metadata object](#metadata-override-object) is a generic defined a [用于改写的元数据对象](#metadata-override-object)是一个泛型,其定义如下: - type MetadataOverride = { - add?: Partial; - remove?: Partial; - set?: Partial; + type MetadataOverride<T> = { + add?: Partial<T>; + remove?: Partial<T>; + set?: Partial<T>; }; @@ -4591,10 +4591,10 @@ appropriate to the method, that is, the parameter of an `@NgModule`, 每一个重载方法接受一个 `MetadataOverride`,这里 `T` 是适合这个方法的元数据类型,也就是 `@NgModule`、`@Component`、`@Directive` 或者 `@Pipe` 的参数。 - type MetadataOverride = { - add?: Partial; - remove?: Partial; - set?: Partial; + type MetadataOverride<T> = { + add?: Partial<T>; + remove?: Partial<T>; + set?: Partial<T>; }; diff --git a/aio/content/guide/typescript-configuration.md b/aio/content/guide/typescript-configuration.md index e9fc6e824e..e8064bc2b9 100644 --- a/aio/content/guide/typescript-configuration.md +++ b/aio/content/guide/typescript-configuration.md @@ -51,7 +51,21 @@ The [Setup](guide/setup) guide uses the following `tsconfig.json`: 在[搭建本地开发环境](guide/setup)中创建过如下的 `tsconfig.json`: - + + { + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + } + } + This file contains options and flags that are essential for Angular applications. diff --git a/aio/content/guide/universal.md b/aio/content/guide/universal.md index e0bdc9a341..48fc62bf85 100644 --- a/aio/content/guide/universal.md +++ b/aio/content/guide/universal.md @@ -114,7 +114,7 @@ Displaying the first page quickly can be critical for user engagement. 快速显示第一页对于吸引用户是至关重要的。 -[53percent of mobile site visits are abandoned](https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/) if pages take longer than 3 seconds to load. +[53percent of mobile site visits are abandoned](https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/) if pages take longer than 3 seconds to load. Your app may have to launch faster to engage these users before they decide to do something else. 如果页面加载超过了三秒钟,那么 [53% 的移动网站会被放弃](https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/)。 @@ -217,7 +217,6 @@ Before your app can be rendered on a server, you must make changes in the app it 1. Prepare your app by modifying both the app code and its configuration. 通过修改应用代码及其配置进行准备。 - 1. Add a build target, and build a Universal bundle using the CLI with the `@nguniversal/express-engine` schematic. 添加构建目标,并使用 CLI 中的 `@nguniversal/express-engine` 原理图来构建出 Universal 包。 @@ -274,13 +273,13 @@ Angular Universal 却没办法把这些凭证转发给独立的数据服务器 ## 步骤一:安装依赖 -Install `@angular/platform-server` into your project. Use the same version as the other `@angular` packages in your project. You also need `ts-loader` for your webpack build and `@nguniversal/module-map-ngfactory-loader` to handle lazy-loading in the context of a server-render. +Install `@angular/platform-server` into your project. Use the same version as the other `@angular` packages in your project. You also need `ts-loader`, `webpack-cli` for your webpack build and `@nguniversal/module-map-ngfactory-loader` to handle lazy-loading in the context of a server-render. 把 `@angular/platform-server` 安装到项目中。在项目中使用与其它 `@angular` 包相同的版本。你还需要 `ts-loader` 供 Webpack 构建时使用,还要安装 `@nguniversal/module-map-ngfactory-loader` 来处理服务端渲染环境下的惰性加载。 -``` -$ npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader -``` + +$ npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader webpack-cli + ## Step 2: Prepare your app @@ -514,6 +513,7 @@ import 'reflect-metadata'; import { renderModuleFactory } from '@angular/platform-server'; import { enableProdMode } from '@angular/core'; +import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; import * as express from 'express'; import { join } from 'path'; @@ -531,10 +531,8 @@ const DIST_FOLDER = join(process.cwd(), 'dist'); // Our index.html we'll use as our template const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString(); -// * NOTE :: leave this as require() since this file is built Dynamically from webpack -const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle'); +const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./server/main'); -const { provideModuleMap } = require('@nguniversal/module-map-ngfactory-loader'); app.engine('html', (_, options, callback) => { renderModuleFactory(AppServerModuleNgFactory, { @@ -638,26 +636,19 @@ node dist/server.js ### 创建一些脚本 Now let's create a few handy scripts to help us do all of this in the future. -You can add these in the `"server"` section of the Angular configuration file, `angular.json`. +You can add these in the `"scripts"` section of the `package.json`. 现在,来创建一些便利脚本,在以后帮助我们完成这些琐事。 你可以在 Angular 配置文件 `angular.json` 的 `"server"` 区添加这些脚本。 -"architect": { - "build": { ... } - "server": { - ... - "scripts": { - // Common scripts - "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server", - "serve:ssr": "node dist/server.js", - - // Helpers for the scripts - "build:client-and-server-bundles": "ng build --prod && ng build --prod --app 1 --output-hashing=false", - "webpack:server": "webpack --config webpack.server.config.js --progress --colors" - } - ... +"scripts": { + "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server", + "serve:ssr": "node dist/server.js", + "build:client-and-server-bundles": "ng build --prod && ng run my-project:server:production", + "webpack:server": "webpack --config webpack.server.config.js --progress --colors", + ... +} To run a production build of your app with Universal on your local system, use the following command. diff --git a/aio/content/guide/using-libraries.md b/aio/content/guide/using-libraries.md new file mode 100644 index 0000000000..dcf8098fab --- /dev/null +++ b/aio/content/guide/using-libraries.md @@ -0,0 +1,136 @@ +# Using Published Libraries + +When building Angular applications you can take advantage of sophisticated first-party libraries, such as [Angular Material](https://material.angular.io/), as well as rich ecosystem of third-party libraries. +See the [Angular Resources](https://angular.io/resources) page for links to the most popular ones. + +## Installing libraries + +Libraries are published as [npm packages](guide/npm-packages), usually together with schematics that integrate them with the Angular CLI. +To integrate reusable library code into an application, you need to install the package and import the provided functionality where you will use it. For most published Angular libraries, you can use the Angular CLI `ng add ` command. + +The `ng add` command uses the npm package manager or [yarn](https://yarnpkg.com/) to install the library package, and invokes schematics that are included in the package to other scaffolding within the project code, such as adding import statements, fonts, themes, and so on. + +A published library typically provides a README or other documentation on how to add that lib to your app. +For an example, see [Angular Material](https://material.angular.io/) docs. + +### Library typings + +Library packages often include typings in `.d.ts` files; see examples in `node_modules/@angular/material`. If your library's package does not include typings and your IDE complains, you may need to install the library's associated `@types/` package. + +For example, suppose you have a library named `d3`: + + +npm install d3 --save +npm install @types/d3 --save-dev + + +Types defined in a `@types/` package for a library installed into the workspace are automatically added to the TypeScript configuration for the project that uses that library. +TypeScript looks for types in the `node_modules/@types` folder by default, so you don't have to add each type package individually. + +If a library doesn't have typings available at `@types/`, you can still use it by manually adding typings for it. +To do this: + +1. Create a `typings.d.ts` file in your `src/` folder. This file is automatically included as global type definition. + +2. Add the following code in `src/typings.d.ts`. + +``` +declare module 'host' { + export interface Host { + protocol?: string; + hostname?: string; + pathname?: string; + } + export function parse(url: string, queryString?: string): Host; +} +``` + +3. In the component or file that uses the library, add the following code. + +``` +import * as host from 'host'; +const parsedUrl = host.parse('https://angular.io'); +console.log(parsedUrl.hostname); +``` + +You can define more typings as needed. + +## Updating libraries + +Libraries can be updated by their publishers, and also have their own dependencies which need to be kept current. +To check for updates to your installed libraries, use the [`ng update` command](cli/update). + +Use `ng update ` to update individual library versions. The Angular CLI checks the latest published release of the library, and if the latest version is newer than your installed version, downloads it and updates your `package.json` to match the latest version. + +When you update Angular to a new version, you need to make sure that any libraries you are using are current. If libraries have interdependencies, you might have to update them in a particular order. +See the [Angular Update Guide](https://update.angular.io/) for help. + +## Adding a library to the runtime global scope + +Legacy JavaScript libraries that are not imported into an app can be added to the runtime global scope and loaded as if they were in a script tag. +Configure the CLI to do this at build time using the "scripts" and "styles" options of the build target in the [CLI configuration file](guide/workspace-config), `angular.json`. + +For example, to use the [Bootstrap 4](https://getbootstrap.com/docs/4.0/getting-started/introduction/) library, first install the library and its dependencies using the npm package manager: + + +npm install jquery --save +npm install popper.js --save +npm install bootstrap --save + + +In the `angular.json` configuration file, add the associated script files to the "scripts" array: + +``` +"scripts": [ + "node_modules/jquery/dist/jquery.slim.js", + "node_modules/popper.js/dist/umd/popper.js", + "node_modules/bootstrap/dist/js/bootstrap.js" +], +``` + +Add the Bootstrap CSS file to the "styles" array: + +``` +"styles": [ + "node_modules/bootstrap/dist/css/bootstrap.css", + "src/styles.css" +], +``` + +Run or restart `ng serve` to see Bootstrap 4 working in your app. + +### Using runtime-global libraries inside your app + +Once you import a library using the "scripts" array, you should **not** import it using an import statement in your TypeScript code (such as `import * as $ from 'jquery';`). +If you do, you'll end up with two different copies of the library: one imported as a global library, and one imported as a module. +This is especially bad for libraries with plugins, like JQuery, because each copy will have different plugins. + +Instead, download typings for your library (`npm install @types/jquery`) and follow the library installation steps. This gives you access to the global variables exposed by that library. + +### Defining typings for runtime-global libraries + +If the global library you need to use does not have global typings, you can declare them manually as `any` in `src/typings.d.ts`. For example: + +``` +declare var libraryName: any; +``` + +Some scripts extend other libraries; for instance with JQuery plugins: + +``` +$('.test').myPlugin(); +``` + +In this case, the installed `@types/jquery` doesn't include `myPlugin`, so you need to add an interface in `src/typings.d.ts`. For example: + +``` +interface JQuery { + myPlugin(options?: any): any; +} +``` + +If don't add the interface for the script-defined extension, your IDE shows an error: + +``` +[TS][Error] Property 'myPlugin' does not exist on type 'JQuery' +``` diff --git a/aio/content/guide/workspace-config.md b/aio/content/guide/workspace-config.md index 2159c3a52e..be521bbb03 100644 --- a/aio/content/guide/workspace-config.md +++ b/aio/content/guide/workspace-config.md @@ -145,7 +145,7 @@ You can define and name additional alternate configurations (such as `stage`, fo The configurable options for a default or targeted build generally correspond to the options available for the [`ng build`](cli/build), [`ng serve`](cli/serve), and [`ng test`](cli/test) commands. For details of those options and their possible values, see the [CLI Reference](cli). -Some additional options (listed below) can only be set through the configuration file, either by direct editing or with the `ng config` command. +Some additional options (listed below) can only be set through the configuration file, either by direct editing or with the [`ng config`](cli/config) command. | OPTIONS PROPERTIES | DESCRIPTION | | :------------------------- | :---------------------------- | diff --git a/aio/content/images/bios/alainchautard.png b/aio/content/images/bios/alainchautard.png index 214cd836dc..0fce8607b8 100644 Binary files a/aio/content/images/bios/alainchautard.png and b/aio/content/images/bios/alainchautard.png differ diff --git a/aio/content/images/bios/jeff-cross.jpg b/aio/content/images/bios/jeff-cross.jpg index fec99139f3..6a3bcebfbf 100644 Binary files a/aio/content/images/bios/jeff-cross.jpg and b/aio/content/images/bios/jeff-cross.jpg differ diff --git a/aio/content/images/bios/mhartington.png b/aio/content/images/bios/mhartington.png index 4127ca3534..dfacd6d344 100644 Binary files a/aio/content/images/bios/mhartington.png and b/aio/content/images/bios/mhartington.png differ diff --git a/aio/content/images/guide/animations/keyframes-500.png b/aio/content/images/guide/animations/keyframes-500.png index 2f2ce86ed6..7cfdc92461 100644 Binary files a/aio/content/images/guide/animations/keyframes-500.png and b/aio/content/images/guide/animations/keyframes-500.png differ diff --git a/aio/content/images/guide/animations/keyframes-offset-500.png b/aio/content/images/guide/animations/keyframes-offset-500.png index adc2359133..89f630d5ed 100644 Binary files a/aio/content/images/guide/animations/keyframes-offset-500.png and b/aio/content/images/guide/animations/keyframes-offset-500.png differ diff --git a/aio/content/images/guide/animations/keyframes-pulsation.png b/aio/content/images/guide/animations/keyframes-pulsation.png index 2f5c1eb05b..577ce32d08 100644 Binary files a/aio/content/images/guide/animations/keyframes-pulsation.png and b/aio/content/images/guide/animations/keyframes-pulsation.png differ diff --git a/aio/content/images/guide/animations/open-closed.png b/aio/content/images/guide/animations/open-closed.png index fed1d588f5..7f4aff97da 100644 Binary files a/aio/content/images/guide/animations/open-closed.png and b/aio/content/images/guide/animations/open-closed.png differ diff --git a/aio/content/images/guide/animations/triggering-the-animation.png b/aio/content/images/guide/animations/triggering-the-animation.png index 72425d8159..cbaa7929e7 100644 Binary files a/aio/content/images/guide/animations/triggering-the-animation.png and b/aio/content/images/guide/animations/triggering-the-animation.png differ diff --git a/aio/content/images/guide/animations/wildcard-3-states.png b/aio/content/images/guide/animations/wildcard-3-states.png index 341a619fe7..d00fd24656 100644 Binary files a/aio/content/images/guide/animations/wildcard-3-states.png and b/aio/content/images/guide/animations/wildcard-3-states.png differ diff --git a/aio/content/images/guide/animations/wildcard-state-500.png b/aio/content/images/guide/animations/wildcard-state-500.png index 395e8e99fa..264e5aa691 100644 Binary files a/aio/content/images/guide/animations/wildcard-state-500.png and b/aio/content/images/guide/animations/wildcard-state-500.png differ diff --git a/aio/content/images/guide/architecture/compilation-context.png b/aio/content/images/guide/architecture/compilation-context.png index 1fdff50285..6fe602d3c6 100644 Binary files a/aio/content/images/guide/architecture/compilation-context.png and b/aio/content/images/guide/architecture/compilation-context.png differ diff --git a/aio/content/images/guide/architecture/view-hierarchy.png b/aio/content/images/guide/architecture/view-hierarchy.png index 1127e48f2e..0b8360a3d1 100644 Binary files a/aio/content/images/guide/architecture/view-hierarchy.png and b/aio/content/images/guide/architecture/view-hierarchy.png differ diff --git a/aio/content/images/guide/cli-quickstart/app-works.png b/aio/content/images/guide/cli-quickstart/app-works.png index 202e5fcbfc..1d339533f3 100644 Binary files a/aio/content/images/guide/cli-quickstart/app-works.png and b/aio/content/images/guide/cli-quickstart/app-works.png differ diff --git a/aio/content/images/guide/cli-quickstart/my-first-app.png b/aio/content/images/guide/cli-quickstart/my-first-app.png index b40f150d04..e2346a6111 100644 Binary files a/aio/content/images/guide/cli-quickstart/my-first-app.png and b/aio/content/images/guide/cli-quickstart/my-first-app.png differ diff --git a/aio/content/images/guide/elements/createElement.png b/aio/content/images/guide/elements/createElement.png index 1c1ea8d1ea..16328d7037 100644 Binary files a/aio/content/images/guide/elements/createElement.png and b/aio/content/images/guide/elements/createElement.png differ diff --git a/aio/content/images/guide/elements/customElement1.png b/aio/content/images/guide/elements/customElement1.png index 6be2f262a4..dcb1c0ab81 100644 Binary files a/aio/content/images/guide/elements/customElement1.png and b/aio/content/images/guide/elements/customElement1.png differ diff --git a/aio/content/images/guide/event-binding/syntax-diagram.svg b/aio/content/images/guide/event-binding/syntax-diagram.svg new file mode 100644 index 0000000000..03a1fbec6d --- /dev/null +++ b/aio/content/images/guide/event-binding/syntax-diagram.svg @@ -0,0 +1 @@ +<button(click)="onSave()">Save</button>target event nametemplate statement \ No newline at end of file diff --git a/aio/content/images/guide/feature-modules/feature-module.png b/aio/content/images/guide/feature-modules/feature-module.png index 9faec0e71d..91d6973d3a 100644 Binary files a/aio/content/images/guide/feature-modules/feature-module.png and b/aio/content/images/guide/feature-modules/feature-module.png differ diff --git a/aio/content/images/guide/forms-overview/dataflow-reactive-forms-mtv.png b/aio/content/images/guide/forms-overview/dataflow-reactive-forms-mtv.png old mode 100755 new mode 100644 index 8525831eb0..d769f73443 Binary files a/aio/content/images/guide/forms-overview/dataflow-reactive-forms-mtv.png and b/aio/content/images/guide/forms-overview/dataflow-reactive-forms-mtv.png differ diff --git a/aio/content/images/guide/forms-overview/dataflow-reactive-forms-vtm.png b/aio/content/images/guide/forms-overview/dataflow-reactive-forms-vtm.png old mode 100755 new mode 100644 index 9d001fced3..ce8ab26d49 Binary files a/aio/content/images/guide/forms-overview/dataflow-reactive-forms-vtm.png and b/aio/content/images/guide/forms-overview/dataflow-reactive-forms-vtm.png differ diff --git a/aio/content/images/guide/forms-overview/dataflow-td-forms-mtv.png b/aio/content/images/guide/forms-overview/dataflow-td-forms-mtv.png old mode 100755 new mode 100644 index c9c292f196..8f23589e3c Binary files a/aio/content/images/guide/forms-overview/dataflow-td-forms-mtv.png and b/aio/content/images/guide/forms-overview/dataflow-td-forms-mtv.png differ diff --git a/aio/content/images/guide/forms-overview/dataflow-td-forms-vtm.png b/aio/content/images/guide/forms-overview/dataflow-td-forms-vtm.png old mode 100755 new mode 100644 index 21087e5873..df0f4ce819 Binary files a/aio/content/images/guide/forms-overview/dataflow-td-forms-vtm.png and b/aio/content/images/guide/forms-overview/dataflow-td-forms-vtm.png differ diff --git a/aio/content/images/guide/forms-overview/key-diff-reactive-forms.png b/aio/content/images/guide/forms-overview/key-diff-reactive-forms.png old mode 100755 new mode 100644 index c09b26b408..a311eb1057 Binary files a/aio/content/images/guide/forms-overview/key-diff-reactive-forms.png and b/aio/content/images/guide/forms-overview/key-diff-reactive-forms.png differ diff --git a/aio/content/images/guide/forms-overview/key-diff-td-forms.png b/aio/content/images/guide/forms-overview/key-diff-td-forms.png old mode 100755 new mode 100644 index a66c383b3f..9aae675a0b Binary files a/aio/content/images/guide/forms-overview/key-diff-td-forms.png and b/aio/content/images/guide/forms-overview/key-diff-td-forms.png differ diff --git a/aio/content/images/guide/lazy-loading-ngmodules/chunk-arrow.png b/aio/content/images/guide/lazy-loading-ngmodules/chunk-arrow.png index d42dd1f6f4..b8d9d8632e 100644 Binary files a/aio/content/images/guide/lazy-loading-ngmodules/chunk-arrow.png and b/aio/content/images/guide/lazy-loading-ngmodules/chunk-arrow.png differ diff --git a/aio/content/images/guide/lazy-loading-ngmodules/chunk.png b/aio/content/images/guide/lazy-loading-ngmodules/chunk.png index f35bca8e0f..558d155f6f 100644 Binary files a/aio/content/images/guide/lazy-loading-ngmodules/chunk.png and b/aio/content/images/guide/lazy-loading-ngmodules/chunk.png differ diff --git a/aio/content/images/guide/lazy-loading-ngmodules/clear.png b/aio/content/images/guide/lazy-loading-ngmodules/clear.png index 70379ce1f8..df2bc89be5 100644 Binary files a/aio/content/images/guide/lazy-loading-ngmodules/clear.png and b/aio/content/images/guide/lazy-loading-ngmodules/clear.png differ diff --git a/aio/content/images/guide/lazy-loading-ngmodules/network-tab.png b/aio/content/images/guide/lazy-loading-ngmodules/network-tab.png index 29b13a9d87..439161cf93 100644 Binary files a/aio/content/images/guide/lazy-loading-ngmodules/network-tab.png and b/aio/content/images/guide/lazy-loading-ngmodules/network-tab.png differ diff --git a/aio/content/images/guide/lazy-loading-ngmodules/three-buttons.png b/aio/content/images/guide/lazy-loading-ngmodules/three-buttons.png index b44b0a8265..076ed234bf 100644 Binary files a/aio/content/images/guide/lazy-loading-ngmodules/three-buttons.png and b/aio/content/images/guide/lazy-loading-ngmodules/three-buttons.png differ diff --git a/aio/content/images/guide/reactive-forms/name-editor-1.png b/aio/content/images/guide/reactive-forms/name-editor-1.png index fd443e34c0..9806d5441a 100644 Binary files a/aio/content/images/guide/reactive-forms/name-editor-1.png and b/aio/content/images/guide/reactive-forms/name-editor-1.png differ diff --git a/aio/content/images/guide/reactive-forms/name-editor-2.png b/aio/content/images/guide/reactive-forms/name-editor-2.png index 57e18c56df..4a2b1de1b6 100644 Binary files a/aio/content/images/guide/reactive-forms/name-editor-2.png and b/aio/content/images/guide/reactive-forms/name-editor-2.png differ diff --git a/aio/content/images/guide/reactive-forms/profile-editor-1.png b/aio/content/images/guide/reactive-forms/profile-editor-1.png index ef7a9e56d2..e2740c36c3 100644 Binary files a/aio/content/images/guide/reactive-forms/profile-editor-1.png and b/aio/content/images/guide/reactive-forms/profile-editor-1.png differ diff --git a/aio/content/images/guide/reactive-forms/profile-editor-2.png b/aio/content/images/guide/reactive-forms/profile-editor-2.png index 06396d10de..e47e0934f9 100644 Binary files a/aio/content/images/guide/reactive-forms/profile-editor-2.png and b/aio/content/images/guide/reactive-forms/profile-editor-2.png differ diff --git a/aio/content/images/guide/reactive-forms/profile-editor-3.png b/aio/content/images/guide/reactive-forms/profile-editor-3.png index 55f995737e..5e202d3e10 100644 Binary files a/aio/content/images/guide/reactive-forms/profile-editor-3.png and b/aio/content/images/guide/reactive-forms/profile-editor-3.png differ diff --git a/aio/content/images/guide/reactive-forms/profile-editor-4.png b/aio/content/images/guide/reactive-forms/profile-editor-4.png index 9de5521146..39a79e37b1 100644 Binary files a/aio/content/images/guide/reactive-forms/profile-editor-4.png and b/aio/content/images/guide/reactive-forms/profile-editor-4.png differ diff --git a/aio/content/images/guide/security/binding-inner-html.png b/aio/content/images/guide/security/binding-inner-html.png index c28a31b5bb..6457a9fd72 100644 Binary files a/aio/content/images/guide/security/binding-inner-html.png and b/aio/content/images/guide/security/binding-inner-html.png differ diff --git a/aio/content/images/guide/service-worker/offline-checkbox.png b/aio/content/images/guide/service-worker/offline-checkbox.png index 8d960264e5..5f24784f86 100644 Binary files a/aio/content/images/guide/service-worker/offline-checkbox.png and b/aio/content/images/guide/service-worker/offline-checkbox.png differ diff --git a/aio/content/images/guide/service-worker/sw-active.png b/aio/content/images/guide/service-worker/sw-active.png index 4228bb810f..83ebc018cc 100644 Binary files a/aio/content/images/guide/service-worker/sw-active.png and b/aio/content/images/guide/service-worker/sw-active.png differ diff --git a/aio/content/images/guide/service-worker/welcome-msg-en.png b/aio/content/images/guide/service-worker/welcome-msg-en.png index c3bff71060..cc767e933f 100644 Binary files a/aio/content/images/guide/service-worker/welcome-msg-en.png and b/aio/content/images/guide/service-worker/welcome-msg-en.png differ diff --git a/aio/content/images/guide/service-worker/welcome-msg-fr.png b/aio/content/images/guide/service-worker/welcome-msg-fr.png index eb2b7e1581..7e01541792 100644 Binary files a/aio/content/images/guide/service-worker/welcome-msg-fr.png and b/aio/content/images/guide/service-worker/welcome-msg-fr.png differ diff --git a/aio/content/images/guide/structural-directives/template-rendering.png b/aio/content/images/guide/structural-directives/template-rendering.png old mode 100755 new mode 100644 diff --git a/aio/content/images/marketing/concept-icons/animations.png b/aio/content/images/marketing/concept-icons/animations.png index 85bec90225..ba915465c3 100644 Binary files a/aio/content/images/marketing/concept-icons/animations.png and b/aio/content/images/marketing/concept-icons/animations.png differ diff --git a/aio/content/images/marketing/concept-icons/augury.png b/aio/content/images/marketing/concept-icons/augury.png index d65dd38c3b..7e8c21c122 100644 Binary files a/aio/content/images/marketing/concept-icons/augury.png and b/aio/content/images/marketing/concept-icons/augury.png differ diff --git a/aio/content/images/marketing/concept-icons/cdk.png b/aio/content/images/marketing/concept-icons/cdk.png index 03003c5f55..f820997bc9 100644 Binary files a/aio/content/images/marketing/concept-icons/cdk.png and b/aio/content/images/marketing/concept-icons/cdk.png differ diff --git a/aio/content/images/marketing/concept-icons/cli.png b/aio/content/images/marketing/concept-icons/cli.png index e4d2b58452..2796871748 100644 Binary files a/aio/content/images/marketing/concept-icons/cli.png and b/aio/content/images/marketing/concept-icons/cli.png differ diff --git a/aio/content/images/marketing/concept-icons/compiler.png b/aio/content/images/marketing/concept-icons/compiler.png index 285031201a..a4544e050c 100644 Binary files a/aio/content/images/marketing/concept-icons/compiler.png and b/aio/content/images/marketing/concept-icons/compiler.png differ diff --git a/aio/content/images/marketing/concept-icons/components.png b/aio/content/images/marketing/concept-icons/components.png index 2e74e9e719..084ff499d0 100644 Binary files a/aio/content/images/marketing/concept-icons/components.png and b/aio/content/images/marketing/concept-icons/components.png differ diff --git a/aio/content/images/marketing/concept-icons/dependency-injection.png b/aio/content/images/marketing/concept-icons/dependency-injection.png index f1871cd3e9..9cbbfc4867 100644 Binary files a/aio/content/images/marketing/concept-icons/dependency-injection.png and b/aio/content/images/marketing/concept-icons/dependency-injection.png differ diff --git a/aio/content/images/marketing/concept-icons/forms.png b/aio/content/images/marketing/concept-icons/forms.png index 9324696aaf..1051ed9ec8 100644 Binary files a/aio/content/images/marketing/concept-icons/forms.png and b/aio/content/images/marketing/concept-icons/forms.png differ diff --git a/aio/content/images/marketing/concept-icons/http.png b/aio/content/images/marketing/concept-icons/http.png index ebbf122d6d..a6597e827a 100644 Binary files a/aio/content/images/marketing/concept-icons/http.png and b/aio/content/images/marketing/concept-icons/http.png differ diff --git a/aio/content/images/marketing/concept-icons/i18n.png b/aio/content/images/marketing/concept-icons/i18n.png index 4a6172420a..6c1c410b91 100644 Binary files a/aio/content/images/marketing/concept-icons/i18n.png and b/aio/content/images/marketing/concept-icons/i18n.png differ diff --git a/aio/content/images/marketing/concept-icons/karma.png b/aio/content/images/marketing/concept-icons/karma.png index 385a964297..81749c1da7 100644 Binary files a/aio/content/images/marketing/concept-icons/karma.png and b/aio/content/images/marketing/concept-icons/karma.png differ diff --git a/aio/content/images/marketing/concept-icons/labs.png b/aio/content/images/marketing/concept-icons/labs.png index 256cd5de4c..1acf0afdae 100644 Binary files a/aio/content/images/marketing/concept-icons/labs.png and b/aio/content/images/marketing/concept-icons/labs.png differ diff --git a/aio/content/images/marketing/concept-icons/language-services.png b/aio/content/images/marketing/concept-icons/language-services.png index be46eb8fd5..f2c4973bc0 100644 Binary files a/aio/content/images/marketing/concept-icons/language-services.png and b/aio/content/images/marketing/concept-icons/language-services.png differ diff --git a/aio/content/images/marketing/concept-icons/libraries.png b/aio/content/images/marketing/concept-icons/libraries.png index 036ed3ae86..60312c31cb 100644 Binary files a/aio/content/images/marketing/concept-icons/libraries.png and b/aio/content/images/marketing/concept-icons/libraries.png differ diff --git a/aio/content/images/marketing/concept-icons/material.png b/aio/content/images/marketing/concept-icons/material.png index 608ca6984b..31d7287314 100644 Binary files a/aio/content/images/marketing/concept-icons/material.png and b/aio/content/images/marketing/concept-icons/material.png differ diff --git a/aio/content/images/marketing/concept-icons/performance.png b/aio/content/images/marketing/concept-icons/performance.png index 01a9622b0c..3f059a6b36 100644 Binary files a/aio/content/images/marketing/concept-icons/performance.png and b/aio/content/images/marketing/concept-icons/performance.png differ diff --git a/aio/content/images/marketing/concept-icons/protractor.png b/aio/content/images/marketing/concept-icons/protractor.png index 79c32c91a3..8d6a687cdb 100644 Binary files a/aio/content/images/marketing/concept-icons/protractor.png and b/aio/content/images/marketing/concept-icons/protractor.png differ diff --git a/aio/content/images/marketing/concept-icons/pwa.png b/aio/content/images/marketing/concept-icons/pwa.png index c0e42c3fee..334e1c2b97 100644 Binary files a/aio/content/images/marketing/concept-icons/pwa.png and b/aio/content/images/marketing/concept-icons/pwa.png differ diff --git a/aio/content/images/marketing/concept-icons/router.png b/aio/content/images/marketing/concept-icons/router.png index 759c500261..67850bb4ff 100644 Binary files a/aio/content/images/marketing/concept-icons/router.png and b/aio/content/images/marketing/concept-icons/router.png differ diff --git a/aio/content/images/marketing/concept-icons/templates.png b/aio/content/images/marketing/concept-icons/templates.png index ba46271595..54128858f1 100644 Binary files a/aio/content/images/marketing/concept-icons/templates.png and b/aio/content/images/marketing/concept-icons/templates.png differ diff --git a/aio/content/images/marketing/concept-icons/universal.png b/aio/content/images/marketing/concept-icons/universal.png index 7450d9720e..163a314da5 100644 Binary files a/aio/content/images/marketing/concept-icons/universal.png and b/aio/content/images/marketing/concept-icons/universal.png differ diff --git a/aio/content/images/marketing/home/angular-connect.png b/aio/content/images/marketing/home/angular-connect.png index 43c21d9c2c..5b007b53df 100644 Binary files a/aio/content/images/marketing/home/angular-connect.png and b/aio/content/images/marketing/home/angular-connect.png differ diff --git a/aio/content/license.md b/aio/content/license.md index 35f5cedfba..8968896025 100644 --- a/aio/content/license.md +++ b/aio/content/license.md @@ -2,7 +2,7 @@ @description The MIT License -Copyright (c) 2014-2018 Google, Inc. +Copyright (c) 2010-2019 Google LLC. http://angular.io/license Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/aio/content/marketing/contributors.json b/aio/content/marketing/contributors.json index 3a491d4ae3..2a74a5edd8 100644 --- a/aio/content/marketing/contributors.json +++ b/aio/content/marketing/contributors.json @@ -698,5 +698,13 @@ "website": "https://brianflove.com", "bio": "Brian is a software engineer and GDE in Angular with a passion for learning, writing, speaking, teaching and mentoring. Brian has been building web applications for over 20 years and has long been a fanboy of JavaScript. When not in front of his Macbook Pro Brian is in the Rocky Mountains skiing or hiking.", "group": "GDE" + }, + "jeffbcross": { + "name": "Jeff Cross", + "picture": "jeff-cross.jpg", + "twitter": "jeffbcross", + "website": "https://nrwl.io/", + "bio": "Jeff is an Angular Consultant at nrwl.io where he helps enterprise teams succeed with Angular. Prior to founding Nrwl, Jeff was one of the earliest members of the Angular Core Team at Google, and contributed to many of the early state management and performance efforts of AngularJS and Angular.", + "group": "GDE" } } diff --git a/aio/content/marketing/docs.md b/aio/content/marketing/docs.md index da47ab07a2..4abad777f2 100644 --- a/aio/content/marketing/docs.md +++ b/aio/content/marketing/docs.md @@ -2,7 +2,7 @@

什么是 Angular?

-Angular is a platform that makes it easy to build applications with the web. Angular combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Angular empowers developers to build applications that live on the web, mobile, or the desktop +Angular is a platform that makes it easy to build applications with the web. Angular combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Angular empowers developers to build applications that live on the web, mobile, or the desktop. Angular 是一个开发平台。它能帮你更轻松的构建 Web 应用。Angular 集声明式模板、依赖注入、端到端工具和一些最佳实践于一身,为你解决开发方面的各种挑战。Angular 为开发者提升构建 Web、手机或桌面应用的能力。 diff --git a/aio/content/marketing/events.html b/aio/content/marketing/events.html index cad197c1d2..61f149a779 100755 --- a/aio/content/marketing/events.html +++ b/aio/content/marketing/events.html @@ -19,6 +19,12 @@ Atlanta, Georgia January 9 - 12, 2019 + + +
ng-India + Gurgaon, India + February 23, 2019 + diff --git a/aio/content/marketing/features.html b/aio/content/marketing/features.html index f20c0bb519..bc19270964 100755 --- a/aio/content/marketing/features.html +++ b/aio/content/marketing/features.html @@ -8,7 +8,7 @@
跨平台
- +
@@ -34,7 +34,7 @@
速度与性能
- +
@@ -65,7 +65,7 @@
生产率
- +
@@ -90,7 +90,7 @@
完整开发故事
- +
diff --git a/aio/content/marketing/index.html b/aio/content/marketing/index.html index c06ec3612c..54d59851d5 100755 --- a/aio/content/marketing/index.html +++ b/aio/content/marketing/index.html @@ -9,7 +9,7 @@ @@ -101,7 +101,7 @@
- + Angular quickstart
立即开始

开始构建你的 Angular 应用

diff --git a/aio/content/marketing/presskit.html b/aio/content/marketing/presskit.html index 0bfb1b977c..4ae5b7cca4 100644 --- a/aio/content/marketing/presskit.html +++ b/aio/content/marketing/presskit.html @@ -20,7 +20,7 @@
- Angular + Full color logo Angular

FULL COLOR LOGO

@@ -40,7 +40,7 @@
- + Black logo Angular
@@ -61,7 +61,7 @@
- + Transparent logo Angular
diff --git a/aio/content/marketing/resources.json b/aio/content/marketing/resources.json index e0ac578b71..6789c749b4 100644 --- a/aio/content/marketing/resources.json +++ b/aio/content/marketing/resources.json @@ -65,6 +65,13 @@ "title": "AngularAir", "url": "https://angularair.com/" }, + "sdlkfjsldfkz": { + "desc": "A weekly German podcast: Compact knowledge about Angular for take away", + "logo": "", + "rev": true, + "title": "Happy Angular Podcast", + "url": "https://happy-angular.de/" + }, "sldkfjsldjf": { "desc": "The live broadcast podcast all about JavaScript", "logo": "", @@ -459,6 +466,12 @@ "rev": true, "title": "Smart Web Components", "url": "https://www.htmlelements.com/angular/" + }, + "AlyleUI": { + "desc": "Minimal Design, a set of components for Angular.", + "rev": true, + "title": "Alyle UI", + "url": "https://alyle-ui.firebaseapp.com/" } } } diff --git a/aio/content/navigation.json b/aio/content/navigation.json index 18b46b385e..6bc27deacb 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -485,6 +485,27 @@ "tooltip": "学习如何把 AngularJS 的概念映射到 Angular 中。" } ] + }, + { + "title": "Angular Libraries", + "tooltip": "Extending Angular with shared libraries.", + "children": [ + { + "url": "guide/libraries", + "title": "Libraries Overview", + "tooltip": "Understand how and when to use or create libraries." + }, + { + "url": "guide/using-libraries", + "title": "Using Published Libraries", + "tooltip": "Integrate published libraries into an app." + }, + { + "url": "guide/creating-libraries", + "title": "Creating Libraries", + "tooltip": "Extend Angular by creating, publishing, and using your own libraries." + } + ] } ] }, @@ -818,6 +839,10 @@ { "title": "日本語版", "url": "https://angular.jp/" + }, + { + "title": "한국어", + "url": "https://angular.kr/" } ] } diff --git a/aio/content/tutorial/toh-pt0.md b/aio/content/tutorial/toh-pt0.md index 97fc64880d..e6d0797700 100644 --- a/aio/content/tutorial/toh-pt0.md +++ b/aio/content/tutorial/toh-pt0.md @@ -225,9 +225,9 @@ Put your application-wide styles there. 因此,CLI 会生成一个空白的 `styles.css` 文件。 你可以把全应用级别的样式放进去。 -Here's an excerpt from the `styles.css` for the _Tour of Heroes_ sample app. +Open `src/styles.css` and add the code below to the file. -下面是这个*英雄指南*范例应用中 `styles.css` 文件的片段。 +打开 `src/styles.css` 并把下列代码添加到此文件中。 diff --git a/aio/content/tutorial/toh-pt6.md b/aio/content/tutorial/toh-pt6.md index 9aa3d6e81c..4af601d0c4 100644 --- a/aio/content/tutorial/toh-pt6.md +++ b/aio/content/tutorial/toh-pt6.md @@ -178,7 +178,7 @@ Inject `HttpClient` into the constructor in a private property called `http`. Keep injecting the `MessageService`. You'll call it so frequently that -you'll wrap it in private `log` method. +you'll wrap it in a private `log()` method. 保留对 `MessageService` 的注入。你将会频繁调用它,因此请把它包裹进一个私有的 `log` 方法中。 @@ -560,7 +560,7 @@ Add the following `addHero()` method to the `HeroService` class. 它调用 `HttpClient.post()` 而不是 `put()`。 -* it expects the server to generates an id for the new hero, +* it expects the server to generate an id for the new hero, which it returns in the `Observable` to the caller. 它期待服务器为这个新的英雄生成一个 id,然后把它通过 `Observable` 返回给调用者。 diff --git a/aio/package.json b/aio/package.json index 0bc2d1ecd0..aa682d2954 100644 --- a/aio/package.json +++ b/aio/package.json @@ -14,12 +14,13 @@ "ng": "yarn check-env && ng", "start": "yarn check-env && ng serve --configuration=fast", "preview": "http-server-spa ./dist index.html 4200", - "build": "yarn build-for stable", - "prebuild-for": "yarn setup", - "build-for": "yarn ~~build --configuration", + "prebuild": "yarn setup", + "build": "yarn ~~build", "prebuild-local": "yarn setup-local", - "build-local": "yarn ~~build --configuration=stable", - "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 02d2ec250", + "build-local": "yarn ~~build", + "prebuild-with-ivy": "yarn setup-local && yarn ivy-ngcc", + "build-with-ivy": "node scripts/build-with-ivy", + "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 1631f7d62", "lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint", "test": "yarn check-env && ng test", "pree2e": "yarn check-env && yarn update-webdriver", @@ -57,15 +58,16 @@ "preserve-and-sync": "yarn docs", "serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"", "boilerplate:add": "node ./tools/examples/example-boilerplate add", + "boilerplate:add:ivy": "yarn boilerplate:add --ivy", "boilerplate:remove": "node ./tools/examples/example-boilerplate remove", "boilerplate:test": "node tools/examples/test.js", "generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz", "generate-zips": "node ./tools/example-zipper/generateZips", "build-404-page": "node scripts/build-404-page", - "update-webdriver": "webdriver-manager update --standalone false --gecko false $CHROMEDRIVER_VERSION_ARG", + "update-webdriver": "webdriver-manager update --standalone false --gecko false $CI_CHROMEDRIVER_VERSION_ARG", "~~check-env": "node scripts/check-environment", "~~clean-generated": "node --eval \"require('shelljs').rm('-rf', 'src/generated')\"", - "~~build": "ng build", + "~~build": "ng build --configuration=stable", "post~~build": "yarn build-404-page", "~~build-ie-polyfills": "webpack-cli src/ie-polyfills.js -o src/generated/ie-polyfills.min.js --mode production", "~~http-server": "http-server", @@ -75,7 +77,7 @@ }, "engines": { "node": ">=10.9.0 <11.0.0", - "yarn": ">=1.10.1 <1.13.0" + "yarn": ">=1.12.1 <=1.14.0" }, "private": true, "dependencies": { @@ -96,12 +98,11 @@ "core-js": "^2.4.1", "rxjs": "^6.3.0", "tslib": "^1.9.0", - "web-animations-js": "^2.2.5", "zone.js": "^0.8.26" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.10.0", - "@angular/cli": "7.2.0-beta.2", + "@angular-devkit/build-angular": "^0.12.1", + "@angular/cli": "7.2.1", "@angular/compiler": "^7.0.0", "@angular/compiler-cli": "^7.0.0", "@angular/language-service": "^7.0.0", @@ -110,16 +111,17 @@ "@types/jasminewd2": "^2.0.4", "@types/node": "~6.0.60", "@types/puppeteer": "^1.12.1", + "@yarnpkg/lockfile": "^1.1.0", "archiver": "^1.3.0", "canonical-path": "1.0.0", "chai": "^4.1.2", "chalk": "^2.1.0", "cjson": "^0.5.0", - "codelyzer": "~4.2.1", + "codelyzer": "~4.5.0", "cross-spawn": "^5.1.0", "css-selector-parser": "^1.3.0", "dgeni": "^0.4.11", - "dgeni-packages": "^0.27.0", + "dgeni-packages": "^0.27.1", "entities": "^1.1.1", "eslint": "^3.19.0", "eslint-plugin-jasmine": "^2.2.0", diff --git a/aio/scripts/build-404-page.js b/aio/scripts/build-404-page.js index a7147facbb..b44806f763 100644 --- a/aio/scripts/build-404-page.js +++ b/aio/scripts/build-404-page.js @@ -9,7 +9,7 @@ const SRC_DIR = resolve(__dirname, '../src'); const DIST_DIR = resolve(__dirname, '../dist'); // Run -_main(process.argv.slice(2)); +_main(); // Functions - Definitions function _main() { diff --git a/aio/scripts/build-with-ivy.js b/aio/scripts/build-with-ivy.js new file mode 100644 index 0000000000..8c159970f5 --- /dev/null +++ b/aio/scripts/build-with-ivy.js @@ -0,0 +1,46 @@ +#!/usr/bin/env node + +// Imports +const {extend, parse} = require('cjson'); +const {readFileSync, writeFileSync} = require('fs'); +const {join, resolve} = require('path'); +const {exec, set} = require('shelljs'); + +set('-e'); + +// Constants +const ROOT_DIR = resolve(__dirname, '..'); +const TS_CONFIG_PATH = join(ROOT_DIR, 'tsconfig.json'); +const NG_COMPILER_OPTS = { + angularCompilerOptions: { + // Related Jira issue: FW-737 + allowEmptyCodegenFiles: true, + enableIvy: 'ngtsc', + }, +}; + +// Run +_main(process.argv.slice(2)); + +// Functions - Definitions +function _main(buildArgs) { + console.log('\nModifying `tsconfig.json`...'); + const oldTsConfigStr = readFileSync(TS_CONFIG_PATH, 'utf8'); + const oldTsConfigObj = parse(oldTsConfigStr); + const newTsConfigObj = extend(true, oldTsConfigObj, NG_COMPILER_OPTS); + const newTsConfigStr = JSON.stringify(newTsConfigObj, null, 2); + writeFileSync(TS_CONFIG_PATH, newTsConfigStr); + console.log(newTsConfigStr); + + try { + const buildArgsStr = buildArgs.join(' '); + + console.log(`\nBuilding${buildArgsStr && ` with args \`${buildArgsStr}\``}...`); + exec(`yarn ~~build ${buildArgsStr}`, {cwd: ROOT_DIR}); + } finally { + console.log('\nRestoring `tsconfig.json`...'); + writeFileSync(TS_CONFIG_PATH, oldTsConfigStr); + } + + console.log('\nDone!'); +} diff --git a/aio/scripts/deploy-to-firebase.sh b/aio/scripts/deploy-to-firebase.sh index 9032c1ccc9..6000a311b8 100755 --- a/aio/scripts/deploy-to-firebase.sh +++ b/aio/scripts/deploy-to-firebase.sh @@ -93,7 +93,7 @@ fi cd "`dirname $0`/.." # Build the app - yarn build-for $deployEnv --progress=false + yarn build --configuration=$deployEnv --progress=false # Include any mode-specific files cp -rf src/extra-files/$deployEnv/. dist/ diff --git a/aio/scripts/test-pwa-score.js b/aio/scripts/test-pwa-score.js index 80d4601215..4b57939137 100644 --- a/aio/scripts/test-pwa-score.js +++ b/aio/scripts/test-pwa-score.js @@ -23,13 +23,6 @@ const LIGHTHOUSE_FLAGS = {logLevel: 'info'}; const SKIPPED_HTTPS_AUDITS = ['redirects-http']; const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/'; - -// Specify the path and flags for Chrome on Travis. -if (process.env.TRAVIS) { - process.env.LIGHTHOUSE_CHROMIUM_PATH = process.env.CHROME_BIN; - CHROME_LAUNCH_OPTS.chromeFlags = ['--no-sandbox']; -} - // Be less verbose on CI. if (process.env.CI) { LIGHTHOUSE_FLAGS.logLevel = 'error'; diff --git a/aio/src/404-body.html b/aio/src/404-body.html index 8b9185c228..1754328246 100644 --- a/aio/src/404-body.html +++ b/aio/src/404-body.html @@ -23,7 +23,7 @@ -
+
diff --git a/aio/src/app/app.component.html b/aio/src/app/app.component.html index fde39a7a93..0afe392477 100644 --- a/aio/src/app/app.component.html +++ b/aio/src/app/app.component.html @@ -7,14 +7,14 @@ - + - Version 6 of Angular Now Available! - Learn More + Help Angular by taking a 1 minute survey! + Go to survey @@ -52,7 +52,7 @@
-
+
- -
+ + diff --git a/aio/src/app/app.component.spec.ts b/aio/src/app/app.component.spec.ts index 2294324b0e..8685ef48b1 100644 --- a/aio/src/app/app.component.spec.ts +++ b/aio/src/app/app.component.spec.ts @@ -51,7 +51,7 @@ describe('AppComponent', () => { await newDocPromise; // Wait for the new document to be fetched. fixture.detectChanges(); // Propagate document change to the view (i.e to `DocViewer`). await docRenderedPromise; // Wait for the `docRendered` event. - }; + } function initializeTest(waitForDoc = true) { fixture = TestBed.createComponent(AppComponent); @@ -72,7 +72,7 @@ describe('AppComponent', () => { tocService = de.injector.get(TocService); return waitForDoc && awaitDocRendered(); - }; + } describe('with proper DocViewer', () => { @@ -460,11 +460,15 @@ describe('AppComponent', () => { let scrollService: ScrollService; let scrollSpy: jasmine.Spy; let scrollToTopSpy: jasmine.Spy; + let scrollAfterRenderSpy: jasmine.Spy; + let removeStoredScrollPositionSpy: jasmine.Spy; beforeEach(() => { scrollService = fixture.debugElement.injector.get(ScrollService); scrollSpy = spyOn(scrollService, 'scroll'); scrollToTopSpy = spyOn(scrollService, 'scrollToTop'); + scrollAfterRenderSpy = spyOn(scrollService, 'scrollAfterRender'); + removeStoredScrollPositionSpy = spyOn(scrollService, 'removeStoredScrollPosition'); }); it('should not scroll immediately when the docId (path) changes', () => { @@ -509,33 +513,24 @@ describe('AppComponent', () => { expect(scrollSpy).toHaveBeenCalledTimes(1); }); - it('should scroll to top when call `onDocRemoved` directly', () => { - scrollToTopSpy.calls.reset(); - + it('should call `removeStoredScrollPosition` when call `onDocRemoved` directly', () => { component.onDocRemoved(); - expect(scrollToTopSpy).toHaveBeenCalled(); + expect(removeStoredScrollPositionSpy).toHaveBeenCalled(); }); - it('should scroll after a delay when call `onDocInserted` directly', fakeAsync(() => { + it('should call `scrollAfterRender` when call `onDocInserted` directly', (() => { component.onDocInserted(); - expect(scrollSpy).not.toHaveBeenCalled(); - - tick(scrollDelay); - expect(scrollSpy).toHaveBeenCalled(); + expect(scrollAfterRenderSpy).toHaveBeenCalledWith(scrollDelay); })); - it('should scroll (via `onDocInserted`) when finish navigating to a new doc', fakeAsync(() => { - expect(scrollToTopSpy).not.toHaveBeenCalled(); - + it('should call `scrollAfterRender` (via `onDocInserted`) when navigate to a new Doc', fakeAsync(() => { locationService.go('guide/pipes'); - tick(1); // triggers the HTTP response for the document + tick(1); // triggers the HTTP response for the document fixture.detectChanges(); // triggers the event that calls `onDocInserted` - expect(scrollToTopSpy).toHaveBeenCalled(); - expect(scrollSpy).not.toHaveBeenCalled(); + expect(scrollAfterRenderSpy).toHaveBeenCalledWith(scrollDelay); - tick(scrollDelay); - expect(scrollSpy).toHaveBeenCalled(); + tick(500); // there are other outstanding timers in the AppComponent that are not relevant })); }); @@ -1070,7 +1065,7 @@ describe('AppComponent', () => { it('should set the id of the doc viewer container based on the current doc', () => { initializeTest(false); - const container = fixture.debugElement.query(By.css('section.sidenav-content')); + const container = fixture.debugElement.query(By.css('main.sidenav-content')); navigateTo('guide/pipes'); expect(component.pageId).toEqual('guide-pipes'); @@ -1087,7 +1082,7 @@ describe('AppComponent', () => { it('should not be affected by changes to the query', () => { initializeTest(false); - const container = fixture.debugElement.query(By.css('section.sidenav-content')); + const container = fixture.debugElement.query(By.css('main.sidenav-content')); navigateTo('guide/pipes'); navigateTo('guide/other?search=http'); diff --git a/aio/src/app/app.component.ts b/aio/src/app/app.component.ts index de4c95f0ba..e331ab12bd 100644 --- a/aio/src/app/app.component.ts +++ b/aio/src/app/app.component.ts @@ -135,7 +135,7 @@ export class AppComponent implements OnInit { } if (path === this.currentPath) { // scroll only if on same page (most likely a change to the hash) - this.autoScroll(); + this.scrollService.scroll(); } else { // don't scroll; leave that to `onDocRendered` this.currentPath = path; @@ -195,11 +195,6 @@ export class AppComponent implements OnInit { .subscribe(() => this.updateShell()); } - // Scroll to the anchor in the hash fragment or top of doc. - autoScroll() { - this.scrollService.scroll(); - } - onDocReady() { // About to transition to new view. this.isTransitioning = true; @@ -212,9 +207,7 @@ export class AppComponent implements OnInit { } onDocRemoved() { - // The previous document has been removed. - // Scroll to top to restore a clean visual state for the new document. - this.scrollService.scrollToTop(); + this.scrollService.removeStoredScrollPosition(); } onDocInserted() { @@ -224,9 +217,8 @@ export class AppComponent implements OnInit { // (e.g. sidenav, host classes) needs to happen asynchronously. setTimeout(() => this.updateShell()); - // Scroll 500ms after the new document has been inserted into the doc-viewer. - // The delay is to allow time for async layout to complete. - setTimeout(() => this.autoScroll(), 500); + // Scroll the good position depending on the context + this.scrollService.scrollAfterRender(500); } onDocRendered() { @@ -250,7 +242,7 @@ export class AppComponent implements OnInit { @HostListener('window:resize', ['$event.target.innerWidth']) onResize(width: number) { - this.isSideBySide = width > this.sideBySideWidth; + this.isSideBySide = width >= this.sideBySideWidth; this.showFloatingToc.next(width > this.showFloatingTocWidth); if (this.isSideBySide && !this.isSideNavDoc) { @@ -264,7 +256,6 @@ export class AppComponent implements OnInit { @HostListener('click', ['$event.target', '$event.button', '$event.ctrlKey', '$event.metaKey', '$event.altKey']) onClick(eventTarget: HTMLElement, button: number, ctrlKey: boolean, metaKey: boolean, altKey: boolean): boolean { - // Hide the search results if we clicked outside both the "search box" and the "search results" if (!this.searchElements.some(element => element.nativeElement.contains(eventTarget))) { this.hideSearchResults(); diff --git a/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.ts b/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.ts index 6698ec19bb..5ffa318e30 100644 --- a/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.ts +++ b/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.ts @@ -46,7 +46,7 @@ export interface Announcement { template: `
diff --git a/aio/src/app/custom-elements/api/api-list.component.ts b/aio/src/app/custom-elements/api/api-list.component.ts index 5f3b1247f3..bc9b89721d 100644 --- a/aio/src/app/custom-elements/api/api-list.component.ts +++ b/aio/src/app/custom-elements/api/api-list.component.ts @@ -14,6 +14,7 @@ import { LocationService } from 'app/shared/location.service'; import { ApiSection, ApiService } from './api.service'; import { Option } from 'app/shared/select/select.component'; +import { map } from 'rxjs/operators'; class SearchCriteria { query ? = ''; @@ -67,14 +68,17 @@ export class ApiListComponent implements OnInit { private locationService: LocationService) { } ngOnInit() { - this.filteredSections = combineLatest( - this.apiService.sections, - this.criteriaSubject, - (sections, criteria) => { - return sections - .map(section => ({ ...section, items: this.filterSection(section, criteria) })); - } - ); + this.filteredSections = + combineLatest( + this.apiService.sections, + this.criteriaSubject + ).pipe( + map( results => ({ sections: results[0], criteria: results[1]})), + map( results => ( + results.sections + .map(section => ({ ...section, items: this.filterSection(section, results.criteria) })) + )) + ); this.initializeSearchCriteria(); } @@ -121,7 +125,7 @@ export class ApiListComponent implements OnInit { return status === 'all' || status === item.stability || (status === 'security-risk' && item.securityRisk); - }; + } function matchesType() { return type === 'all' || type === item.docType; diff --git a/aio/src/app/custom-elements/api/api.service.ts b/aio/src/app/custom-elements/api/api.service.ts index fdfb54cfcf..39a8dfb0cf 100644 --- a/aio/src/app/custom-elements/api/api.service.ts +++ b/aio/src/app/custom-elements/api/api.service.ts @@ -54,7 +54,7 @@ export class ApiService implements OnDestroy { section.items.every(item => item.stability === 'deprecated'); }); })); - }; + } constructor(private http: HttpClient, private logger: Logger) { } diff --git a/aio/src/app/custom-elements/code/code-tabs.component.ts b/aio/src/app/custom-elements/code/code-tabs.component.ts index aaa6ad48dd..f0bb45e22a 100644 --- a/aio/src/app/custom-elements/code/code-tabs.component.ts +++ b/aio/src/app/custom-elements/code/code-tabs.component.ts @@ -46,7 +46,7 @@ export interface TabInfo { export class CodeTabsComponent implements OnInit, AfterViewInit { tabs: TabInfo[]; - @Input('linenums') linenums: string; + @Input() linenums: string; @ViewChild('content') content; diff --git a/aio/src/app/custom-elements/contributor/contributor-list.component.spec.ts b/aio/src/app/custom-elements/contributor/contributor-list.component.spec.ts index 4ecb04612c..6d7b8e40a0 100644 --- a/aio/src/app/custom-elements/contributor/contributor-list.component.spec.ts +++ b/aio/src/app/custom-elements/contributor/contributor-list.component.spec.ts @@ -79,7 +79,7 @@ describe('ContributorListComponent', () => { return comp; } - interface SearchResult { [index: string]: string; }; + interface SearchResult { [index: string]: string; } class TestLocationService { searchResult: SearchResult = {}; diff --git a/aio/src/app/custom-elements/elements-loader.spec.ts b/aio/src/app/custom-elements/elements-loader.spec.ts index 817dd71a57..a22304faac 100644 --- a/aio/src/app/custom-elements/elements-loader.spec.ts +++ b/aio/src/app/custom-elements/elements-loader.spec.ts @@ -245,7 +245,7 @@ class FakeComponentFactory extends ComponentFactory { rootSelectorOrNode?: string | any, ngModule?: NgModuleRef): ComponentRef { return jasmine.createSpy('ComponentRef') as any; - }; + } } class FakeComponentFactoryResolver extends ComponentFactoryResolver { diff --git a/aio/src/app/custom-elements/getting-started/ng-for/ng-for.component.spec.ts b/aio/src/app/custom-elements/getting-started/ng-for/ng-for.component.spec.ts index f5f5c8e9aa..3f7ba6d41b 100644 --- a/aio/src/app/custom-elements/getting-started/ng-for/ng-for.component.spec.ts +++ b/aio/src/app/custom-elements/getting-started/ng-for/ng-for.component.spec.ts @@ -37,6 +37,6 @@ describe('Getting Started NgFor Component', () => { component.parseError$.subscribe(error => { expect(error).toBeTruthy(); - }) + }); }); }); diff --git a/aio/src/app/custom-elements/getting-started/ng-if/ng-if.component.spec.ts b/aio/src/app/custom-elements/getting-started/ng-if/ng-if.component.spec.ts index c218e91278..09d297c5a7 100644 --- a/aio/src/app/custom-elements/getting-started/ng-if/ng-if.component.spec.ts +++ b/aio/src/app/custom-elements/getting-started/ng-if/ng-if.component.spec.ts @@ -46,6 +46,6 @@ describe('Getting Started NgIf Component', () => { component.parseError$.subscribe(error => { expect(error).toBeTruthy(); - }) + }); }); }); diff --git a/aio/src/app/custom-elements/resource/resource.service.ts b/aio/src/app/custom-elements/resource/resource.service.ts index 9fc921e092..ea0496f8bd 100644 --- a/aio/src/app/custom-elements/resource/resource.service.ts +++ b/aio/src/app/custom-elements/resource/resource.service.ts @@ -26,7 +26,7 @@ export class ResourceService { (categories as ConnectableObservable).connect(); return categories; - }; + } } // Extract sorted Category[] from resource JSON data diff --git a/aio/src/app/layout/doc-viewer/doc-viewer.component.ts b/aio/src/app/layout/doc-viewer/doc-viewer.component.ts index ee06e5ddce..e323b41cbb 100644 --- a/aio/src/app/layout/doc-viewer/doc-viewer.component.ts +++ b/aio/src/app/layout/doc-viewer/doc-viewer.component.ts @@ -98,9 +98,10 @@ export class DocViewerComponent implements OnDestroy { if (needsToc && !embeddedToc) { // Add an embedded ToC if it's needed and there isn't one in the content already. titleEl!.insertAdjacentHTML('afterend', ''); - } else if (!needsToc && embeddedToc) { + } else if (!needsToc && embeddedToc && embeddedToc.parentNode !== null) { // Remove the embedded Toc if it's there and not needed. - embeddedToc.remove(); + // We cannot use ChildNode.remove() because of IE11 + embeddedToc.parentNode.removeChild(embeddedToc); } return () => { diff --git a/aio/src/app/layout/doc-viewer/dt.component.ts b/aio/src/app/layout/doc-viewer/dt.component.ts index 41dc9397f5..23a40d0475 100644 --- a/aio/src/app/layout/doc-viewer/dt.component.ts +++ b/aio/src/app/layout/doc-viewer/dt.component.ts @@ -4,18 +4,17 @@ import { DocumentContents } from 'app/documents/document.service'; @Component({ selector: 'aio-dt', template: ` -
-
- -
- -
+
+
+ +
+ +
` }) export class DtComponent { - @Input() on = false; - @Input('doc') doc: DocumentContents; + @Input() doc: DocumentContents; @Output() docChange = new EventEmitter(); @ViewChild('dt', { read: ElementRef }) diff --git a/aio/src/app/layout/footer/footer.component.html b/aio/src/app/layout/footer/footer.component.html index 29ce3d0207..0820c09cba 100644 --- a/aio/src/app/layout/footer/footer.component.html +++ b/aio/src/app/layout/footer/footer.component.html @@ -11,11 +11,10 @@

- Powered by Google ©2010-2018. + Super-powered by Google ©2010-2019. 代码授权方式:MIT-style License. 文档授权方式:CC BY 4.0.

当前版本:{{versionInfo?.full}}.

- diff --git a/aio/src/app/navigation/navigation.service.ts b/aio/src/app/navigation/navigation.service.ts index ff08b2bf11..87bd602763 100644 --- a/aio/src/app/navigation/navigation.service.ts +++ b/aio/src/app/navigation/navigation.service.ts @@ -91,17 +91,19 @@ export class NavigationService { */ private getCurrentNodes(navigationViews: Observable): Observable { const currentNodes = combineLatest( - navigationViews.pipe(map(views => this.computeUrlToNavNodesMap(views))), - this.location.currentPath, - - (navMap, url) => { - const matchSpecialUrls = /^api/.exec(url); + navigationViews.pipe( + map(views => this.computeUrlToNavNodesMap(views))), + this.location.currentPath, + ).pipe( + map((result) => ({navMap: result[0] , url: result[1]})), + map((result) => { + const matchSpecialUrls = /^api/.exec(result.url); if (matchSpecialUrls) { - url = matchSpecialUrls[0]; + result.url = matchSpecialUrls[0]; } - return navMap.get(url) || { '' : { view: '', url: url, nodes: [] }}; - }) - .pipe(publishReplay(1)); + return result.navMap.get(result.url) || { '' : { view: '', url: result.url, nodes: [] }}; + }), + publishReplay(1)); (currentNodes as ConnectableObservable).connect(); return currentNodes; } diff --git a/aio/src/app/search/search.service.ts b/aio/src/app/search/search.service.ts index cd37900402..03a463eb5c 100644 --- a/aio/src/app/search/search.service.ts +++ b/aio/src/app/search/search.service.ts @@ -1,9 +1,3 @@ -/* -Copyright 2016 Google Inc. All Rights Reserved. -Use of this source code is governed by an MIT-style license that -can be found in the LICENSE file at http://angular.io/license -*/ - import { NgZone, Injectable } from '@angular/core'; import { ConnectableObservable, Observable, race, ReplaySubject, timer } from 'rxjs'; import { concatMap, first, publishReplay } from 'rxjs/operators'; diff --git a/aio/src/app/shared/deployment.service.ts b/aio/src/app/shared/deployment.service.ts index 6a3f0ee79a..3a77b91c93 100644 --- a/aio/src/app/shared/deployment.service.ts +++ b/aio/src/app/shared/deployment.service.ts @@ -14,4 +14,4 @@ export class Deployment { mode: string = this.location.search()['mode'] || environment.mode; constructor(private location: LocationService) {} -}; +} diff --git a/aio/src/app/shared/scroll-spy.service.spec.ts b/aio/src/app/shared/scroll-spy.service.spec.ts index 675d1190d3..c2d2ed7be7 100644 --- a/aio/src/app/shared/scroll-spy.service.spec.ts +++ b/aio/src/app/shared/scroll-spy.service.spec.ts @@ -1,6 +1,6 @@ import { Injector, ReflectiveInjector } from '@angular/core'; import { fakeAsync, tick } from '@angular/core/testing'; -import { DOCUMENT } from '@angular/platform-browser'; +import { DOCUMENT } from '@angular/common'; import { ScrollService } from 'app/shared/scroll.service'; import { ScrollItem, ScrollSpiedElement, ScrollSpiedElementGroup, ScrollSpyService } from 'app/shared/scroll-spy.service'; diff --git a/aio/src/app/shared/scroll.service.spec.ts b/aio/src/app/shared/scroll.service.spec.ts index 75dd14120b..5e0f72bb8a 100644 --- a/aio/src/app/shared/scroll.service.spec.ts +++ b/aio/src/app/shared/scroll.service.spec.ts @@ -1,6 +1,8 @@ import { ReflectiveInjector } from '@angular/core'; -import { PlatformLocation } from '@angular/common'; -import { DOCUMENT } from '@angular/platform-browser'; +import { Location, LocationStrategy, PlatformLocation, ViewportScroller } from '@angular/common'; +import { DOCUMENT } from '@angular/common'; +import { MockLocationStrategy, SpyLocation } from '@angular/common/testing'; +import { fakeAsync, tick } from '@angular/core/testing'; import { ScrollService, topMargin } from './scroll.service'; @@ -8,8 +10,9 @@ describe('ScrollService', () => { const topOfPageElem = {} as Element; let injector: ReflectiveInjector; let document: MockDocument; - let location: MockPlatformLocation; + let platformLocation: MockPlatformLocation; let scrollService: ScrollService; + let location: SpyLocation; class MockPlatformLocation { hash: string; @@ -27,19 +30,47 @@ describe('ScrollService', () => { scrollIntoView = jasmine.createSpy('Element scrollIntoView'); } - beforeEach(() => { - spyOn(window, 'scrollBy'); - }); + const viewportScrollerStub = jasmine.createSpyObj( + 'viewportScroller', + ['getScrollPosition', 'scrollToPosition']); beforeEach(() => { injector = ReflectiveInjector.resolveAndCreate([ ScrollService, + { provide: Location, useClass: SpyLocation }, { provide: DOCUMENT, useClass: MockDocument }, - { provide: PlatformLocation, useClass: MockPlatformLocation } + { provide: PlatformLocation, useClass: MockPlatformLocation }, + { provide: ViewportScroller, useValue: viewportScrollerStub }, + { provide: LocationStrategy, useClass: MockLocationStrategy } ]); - location = injector.get(PlatformLocation); + platformLocation = injector.get(PlatformLocation); document = injector.get(DOCUMENT); scrollService = injector.get(ScrollService); + location = injector.get(Location); + + spyOn(window, 'scrollBy'); + }); + + it('should debounce `updateScrollPositonInHistory()` after 500ms', fakeAsync(() => { + const updateScrollPositionInHistorySpy = spyOn(scrollService, 'updateScrollPositionInHistory'); + + window.dispatchEvent(new Event('scroll')); + tick(249); + window.dispatchEvent(new Event('scroll')); + tick(249); + window.dispatchEvent(new Event('scroll')); + tick(249); + expect(updateScrollPositionInHistorySpy).not.toHaveBeenCalled(); + tick(1); + expect(updateScrollPositionInHistorySpy).toHaveBeenCalledTimes(1); + })); + + it('should set `scrollRestoration` to `manual` if supported', () => { + if (scrollService.supportManualScrollRestoration) { + expect(window.history.scrollRestoration).toBe('manual'); + } else { + expect(window.history.scrollRestoration).toBeUndefined(); + } }); describe('#topOffset', () => { @@ -107,7 +138,7 @@ describe('ScrollService', () => { describe('#scroll', () => { it('should scroll to the top if there is no hash', () => { - location.hash = ''; + platformLocation.hash = ''; const topOfPage = new MockElement(); document.getElementById.and @@ -118,7 +149,7 @@ describe('ScrollService', () => { }); it('should not scroll if the hash does not match an element id', () => { - location.hash = 'not-found'; + platformLocation.hash = 'not-found'; document.getElementById.and.returnValue(null); scrollService.scroll(); @@ -128,7 +159,7 @@ describe('ScrollService', () => { it('should scroll to the element whose id matches the hash', () => { const element = new MockElement(); - location.hash = 'some-id'; + platformLocation.hash = 'some-id'; document.getElementById.and.returnValue(element); scrollService.scroll(); @@ -139,7 +170,7 @@ describe('ScrollService', () => { it('should scroll to the element whose id matches the hash with encoded characters', () => { const element = new MockElement(); - location.hash = '%F0%9F%91%8D'; // 👍 + platformLocation.hash = '%F0%9F%91%8D'; // 👍 document.getElementById.and.returnValue(element); scrollService.scroll(); @@ -210,4 +241,136 @@ describe('ScrollService', () => { }); }); + describe('#isLocationWithHash', () => { + it('should return true when the location has a hash', () => { + platformLocation.hash = 'anchor'; + expect(scrollService.isLocationWithHash()).toBe(true); + }); + + it('should return false when the location has no hash', () => { + platformLocation.hash = ''; + expect(scrollService.isLocationWithHash()).toBe(false); + }); + }); + + describe('#needToFixScrollPosition', async() => { + it('should return true when popState event was fired after a back navigation if the browser supports ' + + 'scrollRestoration`. Otherwise, needToFixScrollPosition() returns false', () => { + + if (scrollService.supportManualScrollRestoration) { + location.go('/initial-url1'); + // We simulate a scroll down + location.replaceState('/initial-url1', 'hack', {scrollPosition: [2000, 0]}); + location.go('/initial-url2'); + location.back(); + + expect(scrollService.popStateFired).toBe(true); + expect(scrollService.scrollPosition).toEqual([2000, 0]); + expect(scrollService.needToFixScrollPosition()).toBe(true); + } else { + location.go('/initial-url1'); + location.go('/initial-url2'); + location.back(); + + expect(scrollService.popStateFired).toBe(false); // popStateFired is always false + expect(scrollService.scrollPosition).toEqual([0, 0]); // scrollPosition always equals [0, 0] + expect(scrollService.needToFixScrollPosition()).toBe(false); + } + + }); + + it('should return true when popState event was fired after a forward navigation if the browser supports ' + + 'scrollRestoration`. Otherwise, needToFixScrollPosition() returns false', () => { + + if (scrollService.supportManualScrollRestoration) { + location.go('/initial-url1'); + location.go('/initial-url2'); + // We simulate a scroll down + location.replaceState('/initial-url1', 'hack', {scrollPosition: [2000, 0]}); + + location.back(); + scrollService.popStateFired = false; + scrollService.scrollPosition = [0, 0]; + location.forward(); + + expect(scrollService.popStateFired).toBe(true); + expect(scrollService.scrollPosition).toEqual([2000, 0]); + expect(scrollService.needToFixScrollPosition()).toBe(true); + } else { + location.go('/initial-url1'); + location.go('/initial-url2'); + location.back(); + location.forward(); + + expect(scrollService.popStateFired).toBe(false); // popStateFired is always false + expect(scrollService.scrollPosition).toEqual([0, 0]); // scrollPosition always equals [0, 0] + expect(scrollService.needToFixScrollPosition()).toBe(false); + } + + }); + }); + + describe('#scrollAfterRender', async() => { + + let scrollSpy: jasmine.Spy; + let scrollToTopSpy: jasmine.Spy; + let needToFixScrollPositionSpy: jasmine.Spy; + let scrollToPosition: jasmine.Spy; + let isLocationWithHashSpy: jasmine.Spy; + let getStoredScrollPositionSpy: jasmine.Spy; + const scrollDelay = 500; + + beforeEach(() => { + scrollSpy = spyOn(scrollService, 'scroll'); + scrollToTopSpy = spyOn(scrollService, 'scrollToTop'); + scrollToPosition = spyOn(scrollService, 'scrollToPosition'); + needToFixScrollPositionSpy = spyOn(scrollService, 'needToFixScrollPosition'); + getStoredScrollPositionSpy = spyOn(scrollService, 'getStoredScrollPosition'); + isLocationWithHashSpy = spyOn(scrollService, 'isLocationWithHash'); + }); + + + it('should call `scroll` when we navigate to a location with anchor', fakeAsync(() => { + needToFixScrollPositionSpy.and.returnValue(false); + getStoredScrollPositionSpy.and.returnValue(null); + isLocationWithHashSpy.and.returnValue(true); + + scrollService.scrollAfterRender(scrollDelay); + + expect(scrollSpy).not.toHaveBeenCalled(); + tick(scrollDelay); + expect(scrollSpy).toHaveBeenCalled(); + })); + + it('should call `scrollToTop` when we navigate to a location without anchor', fakeAsync(() => { + needToFixScrollPositionSpy.and.returnValue(false); + getStoredScrollPositionSpy.and.returnValue(null); + isLocationWithHashSpy.and.returnValue(false); + + scrollService.scrollAfterRender(scrollDelay); + + expect(scrollToTopSpy).toHaveBeenCalled(); + tick(scrollDelay); + expect(scrollSpy).not.toHaveBeenCalled(); + })); + + it('should call `viewportScroller.scrollToPosition` when we reload a page', fakeAsync(() => { + getStoredScrollPositionSpy.and.returnValue([0, 1000]); + + scrollService.scrollAfterRender(scrollDelay); + + expect(viewportScrollerStub.scrollToPosition).toHaveBeenCalled(); + expect(getStoredScrollPositionSpy).toHaveBeenCalled(); + })); + + it('should call `scrollToPosition` after a popState', fakeAsync(() => { + needToFixScrollPositionSpy.and.returnValue(true); + getStoredScrollPositionSpy.and.returnValue(null); + scrollService.scrollAfterRender(scrollDelay); + expect(scrollToPosition).toHaveBeenCalled(); + tick(scrollDelay); + expect(scrollSpy).not.toHaveBeenCalled(); + expect(scrollToTopSpy).not.toHaveBeenCalled(); + })); + }); }); diff --git a/aio/src/app/shared/scroll.service.ts b/aio/src/app/shared/scroll.service.ts index 764433b747..222c916f7c 100644 --- a/aio/src/app/shared/scroll.service.ts +++ b/aio/src/app/shared/scroll.service.ts @@ -1,7 +1,8 @@ import { Injectable, Inject } from '@angular/core'; -import { PlatformLocation } from '@angular/common'; -import { DOCUMENT } from '@angular/platform-browser'; +import { Location, PlatformLocation, ViewportScroller } from '@angular/common'; +import { DOCUMENT } from '@angular/common'; import { fromEvent } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; export const topMargin = 16; /** @@ -13,6 +14,13 @@ export class ScrollService { private _topOffset: number | null; private _topOfPageElement: Element; + // true when popState event has been fired. + popStateFired = false; + // scroll position which has to be restored after the popState event + scrollPosition: [number, number] = [0, 0]; + // true when the browser supports `scrollTo`, `scrollX`, `scrollY` and `scrollRestoration` + supportManualScrollRestoration: boolean; + // Offset from the top of the document to bottom of any static elements // at the top (e.g. toolbar) + some margin get topOffset() { @@ -32,9 +40,39 @@ export class ScrollService { constructor( @Inject(DOCUMENT) private document: any, - private location: PlatformLocation) { + private platformLocation: PlatformLocation, + private viewportScroller: ViewportScroller, + private location: Location) { // On resize, the toolbar might change height, so "invalidate" the top offset. fromEvent(window, 'resize').subscribe(() => this._topOffset = null); + + fromEvent(window, 'scroll') + .pipe(debounceTime(250)).subscribe(() => this.updateScrollPositionInHistory()); + + this.supportManualScrollRestoration = !!window && 'scrollTo' in window && 'scrollX' in window + && 'scrollY' in window && !!history && 'scrollRestoration' in history; + + // Change scroll restoration strategy to `manual` if it's supported + if (this.supportManualScrollRestoration) { + history.scrollRestoration = 'manual'; + // we have to detect forward and back navigation thanks to popState event + this.location.subscribe(event => { + // the type is `hashchange` when the fragment identifier of the URL has changed. It allows us to go to position + // just before a click on an anchor + if (event.type === 'hashchange') { + this.scrollToPosition(); + } else { + // Navigating with forward/back, we have to remove the position from the session storage in order to avoid a + // race-condition + this.removeStoredScrollPosition(); + // The popstate event is always triggered by doing a browser action such as a click on the back or forward button. + // It can be follow by a event of type `hashchange`. + this.popStateFired = true; + // we always should have a scrollPosition in our state history + this.scrollPosition = event.state ? event.state['scrollPosition'] : null; + } + }); + } } /** @@ -50,6 +88,44 @@ export class ScrollService { this.scrollToElement(element); } + /** + * test if the current location has a hash + */ + isLocationWithHash(): boolean { + return !!this.getCurrentHash(); + } + + /** + * When we load a document, we have to scroll to the correct position depending on whether this is a new location, + * a back/forward in the history, or a refresh + * @param delay before we scroll to the good position + */ + scrollAfterRender(delay: number) { + // If we do rendering following a refresh, we use the scroll position from the storage. + const storedScrollPosition = this.getStoredScrollPosition(); + if (storedScrollPosition) { + this.viewportScroller.scrollToPosition(storedScrollPosition); + } else { + if (this.needToFixScrollPosition()) { + // The document was reloaded following a popState `event` (called by the forward/back button), so we manage + // the scroll position + this.scrollToPosition(); + } else { + // The document was loaded either of the following cases: a direct navigation via typing the URL in the + // address bar or a click on a link. If the location contains a hash, we have to wait for async + // layout. + if (this.isLocationWithHash()) { + // Scroll 500ms after the new document has been inserted into the doc-viewer. + // The delay is to allow time for async layout to complete. + setTimeout(() => this.scroll(), delay); + } else { + // If the location doesn't contain a hash, we scroll to the top of the page. + this.scrollToTop(); + } + } + } + } + /** * Scroll to the element. * Don't scroll if no element. @@ -79,10 +155,42 @@ export class ScrollService { this.scrollToElement(this.topOfPageElement); } + scrollToPosition() { + this.viewportScroller.scrollToPosition(this.scrollPosition); + this.popStateFired = false; + } + + /** + * Update the state with scroll position into history. + */ + updateScrollPositionInHistory() { + if (this.supportManualScrollRestoration) { + const currentScrollPosition = this.viewportScroller.getScrollPosition(); + this.location.replaceState(this.location.path(true), undefined, {scrollPosition: currentScrollPosition}); + window.sessionStorage.setItem('scrollPosition', currentScrollPosition.toString()); + } + } + + getStoredScrollPosition(): [number, number] | null { + const position = window.sessionStorage.getItem('scrollPosition'); + return position ? JSON.parse('[' + position + ']') : null; + } + + removeStoredScrollPosition() { + window.sessionStorage.removeItem('scrollPosition'); + } + + /** + * Check if the scroll position need to be manually fixed after popState event + */ + needToFixScrollPosition(): boolean { + return this.popStateFired && this.scrollPosition && this.supportManualScrollRestoration; + } + /** * Return the hash fragment from the `PlatformLocation`, minus the leading `#`. */ private getCurrentHash() { - return decodeURIComponent(this.location.hash.replace(/^#/, '')); + return decodeURIComponent(this.platformLocation.hash.replace(/^#/, '')); } } diff --git a/aio/src/app/shared/toc.service.ts b/aio/src/app/shared/toc.service.ts index 7f08f9ee4e..da092af72c 100644 --- a/aio/src/app/shared/toc.service.ts +++ b/aio/src/app/shared/toc.service.ts @@ -68,7 +68,10 @@ export class TocService { } } // now remove the anchor - anchorLink.remove(); + if (anchorLink.parentNode !== null) { + // We cannot use ChildNode.remove() because of IE11 + anchorLink.parentNode.removeChild(anchorLink); + } } // security: the document element which provides this heading content // is always authored by the documentation team and is considered to be safe diff --git a/aio/src/app/shared/web-worker.ts b/aio/src/app/shared/web-worker.ts index 464e32fe07..07e545c5b6 100644 --- a/aio/src/app/shared/web-worker.ts +++ b/aio/src/app/shared/web-worker.ts @@ -1,9 +1,3 @@ -/* -Copyright 2016 Google Inc. All Rights Reserved. -Use of this source code is governed by an MIT-style license that -can be found in the LICENSE file at http://angular.io/license -*/ - import {NgZone} from '@angular/core'; import {Observable} from 'rxjs'; diff --git a/aio/src/assets/images/favicons/favicon-144x144.png b/aio/src/assets/images/favicons/favicon-144x144.png index 8488500f26..dffd78e090 100644 Binary files a/aio/src/assets/images/favicons/favicon-144x144.png and b/aio/src/assets/images/favicons/favicon-144x144.png differ diff --git a/aio/src/ie-polyfills.js b/aio/src/ie-polyfills.js index 83bd30af94..fd7bf38752 100644 --- a/aio/src/ie-polyfills.js +++ b/aio/src/ie-polyfills.js @@ -17,5 +17,5 @@ import 'core-js/es6/set'; /** IE10 and IE11 requires the following for NgClass support on SVG elements */ import 'classlist.js'; -/** IE10 and IE11 requires the following to support `@angular/animation`. */ -import 'web-animations-js'; +/** Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. */ +// import 'web-animations-js'; diff --git a/aio/src/index.html b/aio/src/index.html index cfb22bf415..96f2386203 100644 --- a/aio/src/index.html +++ b/aio/src/index.html @@ -87,7 +87,7 @@
一套框架,多种平台
移动 & 桌面
diff --git a/aio/src/karma.conf.js b/aio/src/karma.conf.js index 0d2fed3ee2..d925bf1f06 100644 --- a/aio/src/karma.conf.js +++ b/aio/src/karma.conf.js @@ -25,14 +25,8 @@ module.exports = function (config) { colors: true, logLevel: config.LOG_INFO, autoWatch: true, - browsers: ['CustomChrome'], + browsers: ['Chrome'], browserNoActivityTimeout: 60000, singleRun: false, - customLaunchers: { - CustomChrome: { - base: 'Chrome', - flags: process.env.TRAVIS && ['--no-sandbox'] - } - } }); }; diff --git a/aio/src/styles/0-base/_typography.scss b/aio/src/styles/0-base/_typography.scss index 3a9de4957e..0e6c90b13a 100755 --- a/aio/src/styles/0-base/_typography.scss +++ b/aio/src/styles/0-base/_typography.scss @@ -77,6 +77,14 @@ p, ol, ul, ol, li, input, a { } } +p { + margin: 14px 0 0; +} + +p + ul { + margin-top: 4px; +} + ol { li, p { margin: 4px 0; @@ -122,8 +130,13 @@ td { padding: 8px 30px; letter-spacing: 0.30px; - p:first-child, p:last-child { - margin: 0; + > p, ul { + &:first-child { + margin-top: 0; + } + &:last-child { + margin-bottom: 0; + } } } diff --git a/aio/src/styles/1-layouts/_marketing-layout.scss b/aio/src/styles/1-layouts/_marketing-layout.scss index f90c0ec4ec..2d15939a79 100644 --- a/aio/src/styles/1-layouts/_marketing-layout.scss +++ b/aio/src/styles/1-layouts/_marketing-layout.scss @@ -268,13 +268,13 @@ section#intro { aio-shell { &.page-resources, &.page-events, &.page-features, &.page-presskit, &.page-contribute { - section { + main { padding: 0rem 0rem 3rem; } } &.page-home { - section { + main { padding: 0; } } diff --git a/aio/src/styles/1-layouts/_top-menu.scss b/aio/src/styles/1-layouts/_top-menu.scss index 6f72ab3b29..4bb8820192 100644 --- a/aio/src/styles/1-layouts/_top-menu.scss +++ b/aio/src/styles/1-layouts/_top-menu.scss @@ -47,6 +47,7 @@ aio-shell.page-resources mat-toolbar.mat-toolbar { // DOCS PAGES OVERRIDE: HAMBURGER aio-shell.folder-api mat-toolbar.mat-toolbar, +aio-shell.folder-cli mat-toolbar.mat-toolbar, aio-shell.folder-docs mat-toolbar.mat-toolbar, aio-shell.folder-guide mat-toolbar.mat-toolbar, aio-shell.folder-tutorial mat-toolbar.mat-toolbar { diff --git a/aio/src/styles/2-modules/_api-pages.scss b/aio/src/styles/2-modules/_api-pages.scss index 6d7564d095..fc2ed6fc97 100644 --- a/aio/src/styles/2-modules/_api-pages.scss +++ b/aio/src/styles/2-modules/_api-pages.scss @@ -74,6 +74,12 @@ vertical-align: top; } } + + &.property-table { + td { + vertical-align: top; + } + } } .class-overview { @@ -87,19 +93,6 @@ .short-description { margin: 6px 0 0 10px; } - - .properties-table { - font-size: 14px; - - thead th { - &:nth-child(1) { - width: 20%; - } - &:nth-child(2) { - width: 20%; - } - } - } } .breadcrumb-container { diff --git a/aio/src/styles/2-modules/_cli-pages.scss b/aio/src/styles/2-modules/_cli-pages.scss index 18c869f739..03de07b761 100644 --- a/aio/src/styles/2-modules/_cli-pages.scss +++ b/aio/src/styles/2-modules/_cli-pages.scss @@ -7,4 +7,3 @@ .cli-option-syntax { white-space: pre; } - diff --git a/aio/src/styles/2-modules/_notification.scss b/aio/src/styles/2-modules/_notification.scss index 78a6cde583..35121b27d9 100644 --- a/aio/src/styles/2-modules/_notification.scss +++ b/aio/src/styles/2-modules/_notification.scss @@ -89,7 +89,7 @@ aio-notification { } &.page-home, &.page-resources, &.page-events, &.page-features, &.page-presskit, &.page-contribute { - section { + main { padding-top: $notificationHeight; } } diff --git a/aio/tests/deployment/e2e/protractor.conf.js b/aio/tests/deployment/e2e/protractor.conf.js index 6c9f1eba18..ff518f0c2f 100644 --- a/aio/tests/deployment/e2e/protractor.conf.js +++ b/aio/tests/deployment/e2e/protractor.conf.js @@ -10,11 +10,6 @@ exports.config = { suite: 'full', capabilities: { browserName: 'chrome', - // For Travis - chromeOptions: { - binary: process.env.CHROME_BIN, - args: ['--no-sandbox'] - } }, directConnect: true, framework: 'jasmine', diff --git a/aio/tests/deployment/e2e/redirection.e2e-spec.ts b/aio/tests/deployment/e2e/redirection.e2e-spec.ts index d6229e0fd6..bf292fdc94 100644 --- a/aio/tests/deployment/e2e/redirection.e2e-spec.ts +++ b/aio/tests/deployment/e2e/redirection.e2e-spec.ts @@ -7,10 +7,14 @@ describe(browser.baseUrl, () => { const stripQuery = (url: string) => url.replace(/\?.*$/, ''); const stripTrailingSlash = (url: string) => url.replace(/\/$/, ''); - beforeAll(done => page.init().then(done)); + beforeAll(() => page.init()); beforeEach(() => browser.waitForAngularEnabled(false)); - afterEach(() => browser.waitForAngularEnabled(true)); + + afterEach(async () => { + await page.unregisterSw(); + await browser.waitForAngularEnabled(true); + }); describe('(with sitemap URLs)', () => { page.sitemapUrls.forEach((path, i) => { @@ -30,11 +34,11 @@ describe(browser.baseUrl, () => { it(`should redirect '${fromUrl}' to '${toUrl}' (${i + 1}/${page.legacyUrls.length})`, async () => { await page.goTo(fromUrl); - const expectedUrl = stripTrailingSlash(/^http/.test(toUrl) ? toUrl : page.baseUrl + toUrl); + const expectedUrl = stripTrailingSlash(/^https?:/.test(toUrl) ? toUrl : page.baseUrl + toUrl); const actualUrl = await getCurrentUrl(); expect(actualUrl).toBe(expectedUrl); - }); + }, 120000); }); }); diff --git a/aio/tests/deployment/e2e/site.po.ts b/aio/tests/deployment/e2e/site.po.ts index 5933ee5cc7..4fba85022e 100644 --- a/aio/tests/deployment/e2e/site.po.ts +++ b/aio/tests/deployment/e2e/site.po.ts @@ -38,19 +38,14 @@ export class SitePage { } /** - * Navigate to a URL, disable animations, unregister the ServiceWorker, and wait for Angular. + * Navigate to a URL, disable animations, wait for Angular and unregister the ServiceWorker. * (The SW is unregistered to ensure that subsequent requests are passed through to the server.) */ async goTo(url: string) { - const unregisterServiceWorker = (cb: () => void) => navigator.serviceWorker - .getRegistrations() - .then(regs => Promise.all(regs.map(reg => reg.unregister()))) - .then(cb); - await browser.get(url || this.baseUrl); await browser.executeScript('document.body.classList.add(\'no-animations\')'); - await browser.executeAsyncScript(unregisterServiceWorker); await browser.waitForAngular(); + await this.unregisterSw(); }; /** @@ -60,4 +55,16 @@ export class SitePage { // Make an initial request to unregister the ServiceWorker. await this.goTo(''); } + + /** + * Unregister the ServiceWorker (if registered). + */ + async unregisterSw() { + const unregisterSwFn = (cb: () => void) => navigator.serviceWorker + .getRegistrations() + .then(regs => Promise.all(regs.map(reg => reg.unregister()))) + .then(cb); + + await browser.executeAsyncScript(unregisterSwFn); + } } diff --git a/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts b/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts index 5d05cebd91..2da958f390 100644 --- a/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts +++ b/aio/tests/deployment/e2e/smoke-tests.e2e-spec.ts @@ -4,10 +4,14 @@ import { SitePage } from './site.po'; describe(browser.baseUrl, () => { const page = new SitePage(); - beforeAll(done => page.init().then(done)); + beforeAll(() => page.init()); beforeEach(() => browser.waitForAngularEnabled(false)); - afterEach(() => browser.waitForAngularEnabled(true)); + + afterEach(async () => { + await page.unregisterSw(); + await browser.waitForAngularEnabled(true); + }); describe('(smoke tests)', () => { it('should show the home page', () => { diff --git a/aio/tests/e2e/protractor.conf.js b/aio/tests/e2e/protractor.conf.js index 2fbf107c8f..8001cc01f0 100644 --- a/aio/tests/e2e/protractor.conf.js +++ b/aio/tests/e2e/protractor.conf.js @@ -10,11 +10,6 @@ exports.config = { ], capabilities: { browserName: 'chrome', - // For Travis - chromeOptions: { - binary: process.env.CHROME_BIN, - args: ['--no-sandbox'] - } }, directConnect: true, baseUrl: 'http://localhost:4200/', diff --git a/aio/tools/README.md b/aio/tools/README.md index fa0d40b364..e44c358091 100644 --- a/aio/tools/README.md +++ b/aio/tools/README.md @@ -21,7 +21,7 @@ See the [README.md](cli-patches/README.md) for more details. Many of the documentation pages contain snippets of code examples. We extract these snippets from real working example applications, which are stored in subfolders of the `/aio/content/examples` folder. Each example can be built and run independently. Each example also provides e2e specs, which are run as part -of our Travis build tasks, to verify that the examples continue to work as expected, as changes are made +of our CI build tasks, to verify that the examples continue to work as expected, as changes are made to the core Angular libraries. In order to build, run and test these examples independently we need to install dependencies into their diff --git a/aio/tools/examples/README.md b/aio/tools/examples/README.md index ac85afeafb..4af058f6e0 100644 --- a/aio/tools/examples/README.md +++ b/aio/tools/examples/README.md @@ -3,8 +3,8 @@ Many of the documentation pages contain snippets of code examples. Extract these snippets from real working example applications, which are stored in subfolders of the `/aio/content/examples` folder. Each example can be built and run independently. Each example also provides e2e specs, which -are run as part of our Travis build tasks, to verify that the examples continue to work as expected, -as changes are made to the core Angular libraries. +are run as part of our CircleCI legacy build tasks, to verify that the examples continue to work as +expected, as changes are made to the core Angular libraries. In order to build, run and test these examples independently you need to install dependencies into their sub-folder. Also there are a number of common boilerplate files that are needed to configure diff --git a/aio/tools/examples/example-boilerplate.js b/aio/tools/examples/example-boilerplate.js index 773b37aea6..53fecd1d2a 100644 --- a/aio/tools/examples/example-boilerplate.js +++ b/aio/tools/examples/example-boilerplate.js @@ -61,6 +61,12 @@ BOILERPLATE_PATHS.i18n = [ 'package.json' ]; +BOILERPLATE_PATHS['service-worker'] = [ + ...cliRelativePath, + 'angular.json', + 'package.json' +]; + BOILERPLATE_PATHS.testing = [ ...cliRelativePath, 'angular.json' @@ -72,23 +78,38 @@ BOILERPLATE_PATHS.universal = [ 'package.json' ]; +BOILERPLATE_PATHS.ivy = { + systemjs: [ + 'rollup-config.js', + 'tsconfig-aot.json' + ], + cli: [ + 'src/tsconfig.app.json' + ] +}; + const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; class ExampleBoilerPlate { /** * Add boilerplate files to all the examples */ - add() { + add(ivy = false) { // Get all the examples folders, indicated by those that contain a `example-config.json` file const exampleFolders = this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules'); + + if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) { + throw new Error(`The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` + + `Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`); + } + + if (ivy) { + shelljs.exec(`yarn --cwd ${SHARED_PATH} ivy-ngcc`); + } + exampleFolders.forEach(exampleFolder => { const exampleConfig = this.loadJsonFile(path.resolve(exampleFolder, EXAMPLE_CONFIG_FILENAME)); - if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) { - throw new Error(`The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` + - `Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`); - } - // Link the node modules - requires admin access (on Windows) because it adds symlinks const destinationNodeModules = path.resolve(exampleFolder, 'node_modules'); fs.ensureSymlinkSync(SHARED_NODE_MODULES_PATH, destinationNodeModules); @@ -101,6 +122,12 @@ class ExampleBoilerPlate { // Copy the boilerplate common files BOILERPLATE_PATHS.common.forEach(filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath)); + + // Copy Ivy specific files + if (ivy && BOILERPLATE_PATHS.ivy[boilerPlateType]) { + const ivyBoilerPlateBasePath = path.resolve(BOILERPLATE_BASE_PATH, 'ivy', boilerPlateType); + BOILERPLATE_PATHS.ivy[boilerPlateType].forEach(filePath => this.copyFile(ivyBoilerPlateBasePath, exampleFolder, filePath)); + } }); } @@ -108,13 +135,13 @@ class ExampleBoilerPlate { * Remove all the boilerplate files from all the examples */ remove() { - shelljs.exec('git clean -xdfq', {cwd: EXAMPLES_BASE_PATH}); + shelljs.exec('git clean -xdfq', { cwd: EXAMPLES_BASE_PATH }); } main() { yargs .usage('$0 [args]') - .command('add', 'add the boilerplate to each example', () => this.add()) + .command('add', 'add the boilerplate to each example', (yrgs) => this.add(yrgs.argv.ivy)) .command('remove', 'remove the boilerplate from each example', () => this.remove()) .demandCommand(1, 'Please supply a command from the list above') .argv; @@ -138,7 +165,7 @@ class ExampleBoilerPlate { } loadJsonFile(filePath) { - return fs.readJsonSync(filePath, {throws: false}) || {}; + return fs.readJsonSync(filePath, { throws: false }) || {}; } normalizePath(filePath) { diff --git a/aio/tools/examples/run-example-e2e.js b/aio/tools/examples/run-example-e2e.js index 43c56b134a..4049a2b1f3 100644 --- a/aio/tools/examples/run-example-e2e.js +++ b/aio/tools/examples/run-example-e2e.js @@ -15,11 +15,25 @@ const PROTRACTOR_CONFIG_FILENAME = path.join(__dirname, './shared/protractor.con const SJS_SPEC_FILENAME = 'e2e-spec.ts'; const CLI_SPEC_FILENAME = 'e2e/src/app.e2e-spec.ts'; const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; -const IGNORED_EXAMPLES = [ // temporary ignores - 'quickstart', - 'setup', +const IGNORED_EXAMPLES = [ + // temporary ignores + ]; +const fixmeIvyExamples = [ + // fixmeIvy('unknown') failed content projection and applied styles + 'component-styles', + // fixmeIvy('unknown') ERROR Error: Unable to find context associated with [object + // HTMLInputElement] + 'http', + // fixmeIvy('unknown') app fails at runtime due to missing external service (goog is undefined) + 'i18n' +]; + +if (argv.ivy) { + IGNORED_EXAMPLES.push(...fixmeIvyExamples); +} + /** * Run Protractor End-to-End Tests for Doc Samples * @@ -44,30 +58,30 @@ function runE2e() { // Run setup. console.log('runE2e: setup boilerplate'); const installPackagesCommand = `example-use-${argv.local ? 'local' : 'npm'}`; - const addBoilerplateCommand = 'boilerplate:add'; - shelljs.exec(`yarn ${installPackagesCommand}`, { cwd: AIO_PATH }); - shelljs.exec(`yarn ${addBoilerplateCommand}`, { cwd: AIO_PATH }); + const addBoilerplateCommand = `boilerplate:add${argv.ivy ? ':ivy' : ''}`; + shelljs.exec(`yarn ${installPackagesCommand}`, {cwd: AIO_PATH}); + shelljs.exec(`yarn ${addBoilerplateCommand}`, {cwd: AIO_PATH}); } const outputFile = path.join(AIO_PATH, './protractor-results.txt'); return Promise.resolve() - .then(() => findAndRunE2eTests(argv.filter, outputFile, argv.shard)) - .then((status) => { - reportStatus(status, outputFile); - if (status.failed.length > 0) { - return Promise.reject('Some test suites failed'); - } - }).catch(function (e) { - console.log(e); - process.exitCode = 1; - }); + .then(() => findAndRunE2eTests(argv.filter, outputFile, argv.shard)) + .then((status) => { + reportStatus(status, outputFile); + if (status.failed.length > 0) { + return Promise.reject('Some test suites failed'); + } + }) + .catch(function(e) { + console.log(e); + process.exitCode = 1; + }); } // Finds all of the *e2e-spec.tests under the examples folder along with the corresponding apps // that they should run under. Then run each app/spec collection sequentially. function findAndRunE2eTests(filter, outputFile, shard) { - const shardParts = shard ? shard.split('/') : [0, 1]; const shardModulo = parseInt(shardParts[0], 10); const shardDivider = parseInt(shardParts[1], 10); @@ -79,45 +93,48 @@ function findAndRunE2eTests(filter, outputFile, shard) { fs.writeFileSync(outputFile, header); // Run the tests sequentially. - const status = { passed: [], failed: [] }; + const status = {passed: [], failed: []}; return getE2eSpecs(EXAMPLES_PATH, filter) - .then(e2eSpecPaths => { - console.log('All e2e specs:'); - logSpecs(e2eSpecPaths); + .then(e2eSpecPaths => { + console.log('All e2e specs:'); + logSpecs(e2eSpecPaths); - Object.keys(e2eSpecPaths).forEach(key => { - const value = e2eSpecPaths[key]; - e2eSpecPaths[key] = value.filter((p, index) => index % shardDivider === shardModulo); - }); - - console.log(`E2e specs for shard ${shardParts.join('/')}:`); - logSpecs(e2eSpecPaths); - - return e2eSpecPaths.systemjs.reduce((promise, specPath) => { - return promise.then(() => { - const examplePath = path.dirname(specPath); - return runE2eTestsSystemJS(examplePath, outputFile).then(ok => { - const arr = ok ? status.passed : status.failed; - arr.push(examplePath); - }); + Object.keys(e2eSpecPaths).forEach(key => { + const value = e2eSpecPaths[key]; + e2eSpecPaths[key] = value.filter((p, index) => index % shardDivider === shardModulo); }); - }, Promise.resolve()) - .then(() => { - return e2eSpecPaths.cli.reduce((promise, specPath) => { - return promise.then(() => { - return runE2eTestsCLI(specPath, outputFile).then(ok => { - const arr = ok ? status.passed : status.failed; - arr.push(specPath); + + console.log(`E2e specs for shard ${shardParts.join('/')}:`); + logSpecs(e2eSpecPaths); + + return e2eSpecPaths.systemjs + .reduce( + (promise, specPath) => { + return promise.then(() => { + const examplePath = path.dirname(specPath); + return runE2eTestsSystemJS(examplePath, outputFile).then(ok => { + const arr = ok ? status.passed : status.failed; + arr.push(examplePath); + }); + }); + }, + Promise.resolve()) + .then(() => { + return e2eSpecPaths.cli.reduce((promise, specPath) => { + return promise.then(() => { + return runE2eTestsCLI(specPath, outputFile).then(ok => { + const arr = ok ? status.passed : status.failed; + arr.push(specPath); + }); + }); + }, Promise.resolve()); }); - }); - }, Promise.resolve()); + }) + .then(() => { + const stopTime = new Date().getTime(); + status.elapsedTime = (stopTime - startTime) / 1000; + return status; }); - }) - .then(() => { - const stopTime = new Date().getTime(); - status.elapsedTime = (stopTime - startTime) / 1000; - return status; - }); } // Start the example in appDir; then run protractor with the specified @@ -127,8 +144,8 @@ function findAndRunE2eTests(filter, outputFile, shard) { function runE2eTestsSystemJS(appDir, outputFile) { const config = loadExampleConfig(appDir); - const appBuildSpawnInfo = spawnExt('yarn', [config.build], { cwd: appDir }); - const appRunSpawnInfo = spawnExt('yarn', [config.run, '-s'], { cwd: appDir }, true); + const appBuildSpawnInfo = spawnExt('yarn', [config.build], {cwd: appDir}); + const appRunSpawnInfo = spawnExt('yarn', [config.run, '-s'], {cwd: appDir}, true); let run = runProtractorSystemJS(appBuildSpawnInfo.promise, appDir, appRunSpawnInfo, outputFile); @@ -141,40 +158,40 @@ function runE2eTestsSystemJS(appDir, outputFile) { function runProtractorSystemJS(prepPromise, appDir, appRunSpawnInfo, outputFile) { const specFilename = path.resolve(`${appDir}/${SJS_SPEC_FILENAME}`); return prepPromise - .catch(function () { - const emsg = `Application at ${appDir} failed to transpile.\n\n`; - console.log(emsg); - fs.appendFileSync(outputFile, emsg); - return Promise.reject(emsg); - }) - .then(function () { - let transpileError = false; + .catch(function() { + const emsg = `Application at ${appDir} failed to transpile.\n\n`; + console.log(emsg); + fs.appendFileSync(outputFile, emsg); + return Promise.reject(emsg); + }) + .then(function() { + let transpileError = false; - // Start protractor. - console.log(`\n\n=========== Running aio example tests for: ${appDir}`); - const spawnInfo = spawnExt('yarn', ['protractor', - PROTRACTOR_CONFIG_FILENAME, - `--specs=${specFilename}`, - '--params.appDir=' + appDir, - '--params.outputFile=' + outputFile - ], { cwd: SHARED_PATH }); + // Start protractor. + console.log(`\n\n=========== Running aio example tests for: ${appDir}`); + const spawnInfo = spawnExt( + 'yarn', + [ + 'protractor', PROTRACTOR_CONFIG_FILENAME, `--specs=${specFilename}`, + '--params.appDir=' + appDir, '--params.outputFile=' + outputFile + ], + {cwd: SHARED_PATH}); - spawnInfo.proc.stderr.on('data', function (data) { - transpileError = transpileError || /npm ERR! Exit status 100/.test(data.toString()); - }); - return spawnInfo.promise.catch(function () { - if (transpileError) { - const emsg = `${specFilename} failed to transpile.\n\n`; - console.log(emsg); - fs.appendFileSync(outputFile, emsg); - } - return Promise.reject(); - }); - }) - .then( - function () { return finish(appRunSpawnInfo.proc.pid, true); }, - function () { return finish(appRunSpawnInfo.proc.pid, false); } - ); + spawnInfo.proc.stderr.on('data', function(data) { + transpileError = transpileError || /npm ERR! Exit status 100/.test(data.toString()); + }); + return spawnInfo.promise.catch(function() { + if (transpileError) { + const emsg = `${specFilename} failed to transpile.\n\n`; + console.log(emsg); + fs.appendFileSync(outputFile, emsg); + } + return Promise.reject(); + }); + }) + .then( + function() { return finish(appRunSpawnInfo.proc.pid, true); }, + function() { return finish(appRunSpawnInfo.proc.pid, false); }); } function finish(spawnProcId, ok) { @@ -187,14 +204,14 @@ function finish(spawnProcId, ok) { // Run e2e tests over the AOT build for projects that examples it. function runProtractorAoT(appDir, outputFile) { fs.appendFileSync(outputFile, '++ AoT version ++\n'); - const aotBuildSpawnInfo = spawnExt('yarn', ['build:aot'], { cwd: appDir }); + const aotBuildSpawnInfo = spawnExt('yarn', ['build:aot'], {cwd: appDir}); let promise = aotBuildSpawnInfo.promise; const copyFileCmd = 'copy-dist-files.js'; if (fs.existsSync(appDir + '/' + copyFileCmd)) { - promise = promise.then(() => spawnExt('node', [copyFileCmd], { cwd: appDir }).promise); + promise = promise.then(() => spawnExt('node', [copyFileCmd], {cwd: appDir}).promise); } - const aotRunSpawnInfo = spawnExt('yarn', ['serve:aot'], { cwd: appDir }, true); + const aotRunSpawnInfo = spawnExt('yarn', ['serve:aot'], {cwd: appDir}, true); return runProtractorSystemJS(promise, appDir, aotRunSpawnInfo, outputFile); } @@ -204,37 +221,53 @@ function runProtractorAoT(appDir, outputFile) { // CLI version function runE2eTestsCLI(appDir, outputFile) { console.log(`\n\n=========== Running aio example tests for: ${appDir}`); - // `--preserve-symlinks` is needed due the symlinked `node_modules/` in each example. // `--no-webdriver-update` is needed to preserve the ChromeDriver version already installed. - const args = ['e2e', '--no-webdriver-update']; - const e2eSpawn = spawnExt('yarn', args, { cwd: appDir }); - return e2eSpawn.promise.then( - function () { - fs.appendFileSync(outputFile, `Passed: ${appDir}\n\n`); - return finish(e2eSpawn.proc.pid, true); - }, - function () { - fs.appendFileSync(outputFile, `Failed: ${appDir}\n\n`); - return finish(e2eSpawn.proc.pid, false); - } - ); + const config = loadExampleConfig(appDir); + const commands = config.e2e || [{cmd: 'yarn', args: ['e2e', '--prod', '--no-webdriver-update']}]; + + const e2eSpawnPromise = commands.reduce((prevSpawnPromise, {cmd, args}) => { + return prevSpawnPromise.then(() => { + const currSpawn = spawnExt(cmd, args, {cwd: appDir}); + return currSpawn.promise.then( + () => Promise.resolve(finish(currSpawn.proc.pid, true)), + () => Promise.reject(finish(currSpawn.proc.pid, false))); + }); + }, Promise.resolve()); + + return e2eSpawnPromise.then( + () => { + fs.appendFileSync(outputFile, `Passed: ${appDir}\n\n`); + return true; + }, + () => { + fs.appendFileSync(outputFile, `Failed: ${appDir}\n\n`); + return false; + }); } // Report final status. function reportStatus(status, outputFile) { let log = ['']; + + log.push('Suites ignored due to legacy guides:'); + IGNORED_EXAMPLES.filter(example => !fixmeIvyExamples.find(ex => ex.startsWith(example))) + .forEach(function(val) { log.push(' ' + val); }); + + if (argv.ivy) { + log.push(''); + log.push('Suites ignored due to breakage with Ivy:'); + fixmeIvyExamples.forEach(function(val) { log.push(' ' + val); }); + } + + log.push(''); log.push('Suites passed:'); - status.passed.forEach(function (val) { - log.push(' ' + val); - }); + status.passed.forEach(function(val) { log.push(' ' + val); }); if (status.failed.length == 0) { log.push('All tests passed'); } else { log.push('Suites failed:'); - status.failed.forEach(function (val) { - log.push(' ' + val); - }); + status.failed.forEach(function(val) { log.push(' ' + val); }); } log.push('\nElapsed time: ' + status.elapsedTime + ' seconds'); log = log.join('\n'); @@ -253,68 +286,59 @@ function spawnExt(command, args, options, ignoreClose = false) { } catch (e) { console.log(e); reject(e); - return { proc: null, promise }; + return {proc: null, promise}; } - proc.stdout.on('data', function (data) { - process.stdout.write(data.toString()); - }); - proc.stderr.on('data', function (data) { - process.stdout.write(data.toString()); - }); - proc.on('close', function (returnCode) { + proc.stdout.on('data', function(data) { process.stdout.write(data.toString()); }); + proc.stderr.on('data', function(data) { process.stdout.write(data.toString()); }); + proc.on('close', function(returnCode) { console.log(`completed: ${descr} \n`); // Many tasks (e.g., tsc) complete but are actually errors; // Confirm return code is zero. returnCode === 0 || ignoreClose ? resolve(0) : reject(returnCode); }); - proc.on('error', function (data) { + proc.on('error', function(data) { console.log(`completed with error: ${descr} \n`); console.log(data.toString()); reject(data); }); }); - return { proc, promise }; + return {proc, promise}; } function getE2eSpecs(basePath, filter) { let specs = {}; - return getE2eSpecsFor(basePath, SJS_SPEC_FILENAME, filter).then(sjsPaths => { - specs.systemjs = sjsPaths; - }).then(() => { - return getE2eSpecsFor(basePath, CLI_SPEC_FILENAME, filter).then(cliPaths => { - return cliPaths.map(p => { - return p.replace(`${CLI_SPEC_FILENAME}`, ''); - }); - }); - }).then(cliPaths => { - specs.cli = cliPaths; - }).then(() => specs); + return getE2eSpecsFor(basePath, SJS_SPEC_FILENAME, filter) + .then(sjsPaths => { specs.systemjs = sjsPaths; }) + .then(() => { + return getE2eSpecsFor(basePath, CLI_SPEC_FILENAME, filter).then(cliPaths => { + return cliPaths.map(p => { return p.replace(`${CLI_SPEC_FILENAME}`, ''); }); + }); + }) + .then(cliPaths => { specs.cli = cliPaths; }) + .then(() => specs); } // Find all e2e specs in a given example folder. function getE2eSpecsFor(basePath, specFile, filter) { // Only get spec file at the example root. const e2eSpecGlob = `${filter ? `*${filter}*` : '*'}/${specFile}`; - return globby(e2eSpecGlob, { cwd: basePath, nodir: true }) - .then(paths => paths - .filter(file => !IGNORED_EXAMPLES.some(ignored => file.startsWith(ignored))) - .map(file => path.join(basePath, file)) - ); + return globby(e2eSpecGlob, {cwd: basePath, nodir: true}) + .then( + paths => paths.filter(file => !IGNORED_EXAMPLES.some(ignored => file.startsWith(ignored))) + .map(file => path.join(basePath, file))); } // Load configuration for an example. Used for SystemJS function loadExampleConfig(exampleFolder) { // Default config. - let config = { - build: 'build', - run: 'serve:e2e' - }; + let config = {build: 'build', run: 'serve:e2e'}; try { const exampleConfig = fs.readJsonSync(`${exampleFolder}/${EXAMPLE_CONFIG_FILENAME}`); Object.assign(config, exampleConfig); - } catch (e) { } + } catch (e) { + } return config; } diff --git a/aio/tools/examples/shared/boilerplate/cli/e2e/protractor.conf.js b/aio/tools/examples/shared/boilerplate/cli/e2e/protractor.conf.js index 6c78d28094..98b6d13e75 100644 --- a/aio/tools/examples/shared/boilerplate/cli/e2e/protractor.conf.js +++ b/aio/tools/examples/shared/boilerplate/cli/e2e/protractor.conf.js @@ -10,11 +10,6 @@ exports.config = { ], capabilities: { 'browserName': 'chrome', - // For Travis CI only - chromeOptions: { - binary: process.env.CHROME_BIN, - args: ['--no-sandbox'] - } }, directConnect: true, baseUrl: 'http://localhost:4200/', diff --git a/aio/tools/examples/shared/boilerplate/cli/src/tsconfig.app.json b/aio/tools/examples/shared/boilerplate/cli/src/tsconfig.app.json index 190fd300b6..dbbf994fa4 100644 --- a/aio/tools/examples/shared/boilerplate/cli/src/tsconfig.app.json +++ b/aio/tools/examples/shared/boilerplate/cli/src/tsconfig.app.json @@ -6,6 +6,16 @@ }, "exclude": [ "test.ts", - "**/*.spec.ts" + "**/*.spec.ts", + "**/*.avoid.ts", + "**/*.0.ts", + "**/*.1.ts", + "**/*.1b.ts", + "**/*.2.ts", + "**/*.3.ts", + "**/*.4.ts", + "**/*.5.ts", + "**/*.6.ts", + "**/*.7.ts" ] -} +} \ No newline at end of file diff --git a/aio/tools/examples/shared/boilerplate/ivy/cli/src/tsconfig.app.json b/aio/tools/examples/shared/boilerplate/ivy/cli/src/tsconfig.app.json new file mode 100644 index 0000000000..d4d4aad743 --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/ivy/cli/src/tsconfig.app.json @@ -0,0 +1,25 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts", + "**/*.avoid.ts", + "**/*.0.ts", + "**/*.1.ts", + "**/*.1b.ts", + "**/*.2.ts", + "**/*.3.ts", + "**/*.4.ts", + "**/*.5.ts", + "**/*.6.ts", + "**/*.7.ts" + ], + "angularCompilerOptions": { + "enableIvy": "ngtsc", + "allowEmptyCodegenFiles": true + } +} diff --git a/aio/tools/examples/shared/boilerplate/ivy/systemjs/rollup-config.js b/aio/tools/examples/shared/boilerplate/ivy/systemjs/rollup-config.js new file mode 100644 index 0000000000..c69cbcbc9a --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/ivy/systemjs/rollup-config.js @@ -0,0 +1,21 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +//paths are relative to the execution path +export default { + entry: 'app/main.js', + dest: 'aot/dist/build.js', // output a single application bundle + sourceMap: true, + sourceMapFile: 'aot/dist/build.js.map', + format: 'iife', + plugins: [ + nodeResolve({ jsnext: true, module: true }), + commonjs({ + include: ['node_modules/rxjs/**'] + }), + uglify() + ] +} diff --git a/aio/tools/examples/shared/boilerplate/ivy/systemjs/tsconfig-aot.json b/aio/tools/examples/shared/boilerplate/ivy/systemjs/tsconfig-aot.json new file mode 100644 index 0000000000..b113b6cade --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/ivy/systemjs/tsconfig-aot.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ + "es2015", + "dom" + ], + "removeComments": false, + "noImplicitAny": true, + "skipLibCheck": true, + "suppressImplicitAnyIndexErrors": true + }, + "files": [ + "app/app.module.ts", + "app/main.ts" + ], + "angularCompilerOptions": { + "skipMetadataEmit": true, + "enableIvy": "ngtsc" + } +} diff --git a/integration/bazel-schematics/angular.json.original b/aio/tools/examples/shared/boilerplate/service-worker/angular.json similarity index 87% rename from integration/bazel-schematics/angular.json.original rename to aio/tools/examples/shared/boilerplate/service-worker/angular.json index 9c70cea203..ba4dc645a4 100644 --- a/integration/bazel-schematics/angular.json.original +++ b/aio/tools/examples/shared/boilerplate/service-worker/angular.json @@ -3,7 +3,7 @@ "version": 1, "newProjectRoot": "projects", "projects": { - "demo": { + "angular.io-example": { "root": "", "sourceRoot": "src", "projectType": "application", @@ -13,7 +13,7 @@ "build": { "builder": "@angular-devkit/build-angular:browser", "options": { - "outputPath": "dist/demo", + "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", @@ -44,6 +44,7 @@ "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, + "serviceWorker": true, "budgets": [ { "type": "initial", @@ -57,18 +58,18 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "demo:build" + "browserTarget": "angular.io-example:build" }, "configurations": { "production": { - "browserTarget": "demo:build:production" + "browserTarget": "angular.io-example:build:production" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "demo:build" + "browserTarget": "angular.io-example:build" } }, "test": { @@ -102,7 +103,7 @@ } } }, - "demo-e2e": { + "angular.io-example-e2e": { "root": "e2e/", "projectType": "application", "prefix": "", @@ -111,11 +112,11 @@ "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", - "devServerTarget": "demo:serve" + "devServerTarget": "angular.io-example:serve" }, "configurations": { "production": { - "devServerTarget": "demo:serve:production" + "devServerTarget": "angular.io-example:serve:production" } } }, @@ -131,5 +132,5 @@ } } }, - "defaultProject": "demo" -} \ No newline at end of file + "defaultProject": "angular.io-example" +} diff --git a/aio/tools/examples/shared/boilerplate/service-worker/package.json b/aio/tools/examples/shared/boilerplate/service-worker/package.json new file mode 100644 index 0000000000..7de5334909 --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/service-worker/package.json @@ -0,0 +1,53 @@ +{ + "name": "angular.io-example", + "version": "0.0.0", + "license": "MIT", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "^7.0.0", + "@angular/common": "^7.0.0", + "@angular/compiler": "^7.0.0", + "@angular/core": "^7.0.0", + "@angular/forms": "^7.0.0", + "@angular/http": "^7.0.0", + "@angular/platform-browser": "^7.0.0", + "@angular/platform-browser-dynamic": "^7.0.0", + "@angular/router": "^7.0.0", + "@angular/service-worker": "^7.0.0", + "angular-in-memory-web-api": "^0.6.0", + "core-js": "^2.5.4", + "rxjs": "^6.3.0", + "web-animations-js": "^2.3.1", + "zone.js": "~0.8.26" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^0.10.0", + "@angular/cli": "^7.0.0", + "@angular/compiler-cli": "^7.0.0", + "@angular/language-service": "^7.0.0", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "@types/node": "~8.9.4", + "codelyzer": "~4.3.0", + "jasmine-core": "~2.99.1", + "jasmine-marbles": "^0.4.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~3.0.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~1.1.2", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tslint": "~5.11.0", + "typescript": "~3.1.1" + } +} diff --git a/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.build.js b/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.build.js index e1fbdf49b3..27547d8dbe 100644 --- a/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.build.js +++ b/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.build.js @@ -1,3 +1,10 @@ +/* +Copyright Google LLC. All Rights Reserved. +Use of this source code is governed by an MIT-style license that +can be found in the LICENSE file at http://angular.io/license +*/ + + /** * WEB VERSION FOR CURRENT ANGULAR BUILD * (based on systemjs.config.js in angular.io) @@ -94,9 +101,3 @@ }); })(this); - -/* -Copyright 2016 Google Inc. All Rights Reserved. -Use of this source code is governed by an MIT-style license that -can be found in the LICENSE file at http://angular.io/license -*/ diff --git a/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.js b/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.js index f8169ffa1a..d97df093d3 100644 --- a/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.js +++ b/aio/tools/examples/shared/boilerplate/systemjs/src/systemjs.config.web.js @@ -1,3 +1,9 @@ +/* +Copyright Google LLC. All Rights Reserved. +Use of this source code is governed by an MIT-style license that +can be found in the LICENSE file at http://angular.io/license +*/ + /** * WEB ANGULAR VERSION * (based on systemjs.config.js in angular.io) @@ -80,9 +86,3 @@ }); })(this); - -/* -Copyright 2016 Google Inc. All Rights Reserved. -Use of this source code is governed by an MIT-style license that -can be found in the LICENSE file at http://angular.io/license -*/ diff --git a/aio/tools/examples/shared/package.json b/aio/tools/examples/shared/package.json index 15a129fd37..5e47b1ccec 100644 --- a/aio/tools/examples/shared/package.json +++ b/aio/tools/examples/shared/package.json @@ -6,34 +6,34 @@ "scripts": { "http-server": "http-server", "protractor": "protractor", - "webdriver:update": "webdriver-manager update --standalone false --gecko false $CHROMEDRIVER_VERSION_ARG", + "webdriver:update": "webdriver-manager update --standalone false --gecko false $CI_CHROMEDRIVER_VERSION_ARG", "preinstall": "node ../../../../tools/yarn/check-yarn.js", "postinstall": "yarn webdriver:update" }, "engines": { "node": ">=10.9.0 <11.0.0", - "yarn": ">=1.10.1 <1.13.0" + "yarn": ">=1.10.1 <1.14.0" }, "keywords": [], "author": "", "license": "MIT", "dependencies": { - "@angular/animations": "^7.0.0", - "@angular/common": "^7.0.0", - "@angular/compiler": "^7.0.0", - "@angular/core": "^7.0.0", - "@angular/elements": "^7.0.0", - "@angular/forms": "^7.0.0", - "@angular/http": "^7.0.0", - "@angular/platform-browser": "^7.0.0", - "@angular/platform-browser-dynamic": "^7.0.0", - "@angular/router": "^7.0.0", - "@angular/service-worker": "^7.0.0", - "@angular/upgrade": "^7.0.0", - "@nguniversal/common": "^7.0.0", - "@nguniversal/express-engine": "^7.0.0", - "@nguniversal/module-map-ngfactory-loader": "^7.0.0", - "angular-in-memory-web-api": "^0.6.0", + "@angular/animations": "^7.1.0", + "@angular/common": "^7.1.0", + "@angular/compiler": "^7.1.0", + "@angular/core": "^7.1.0", + "@angular/elements": "^7.1.0", + "@angular/forms": "^7.1.0", + "@angular/http": "^7.1.0", + "@angular/platform-browser": "^7.1.0", + "@angular/platform-browser-dynamic": "^7.1.0", + "@angular/router": "^7.1.0", + "@angular/service-worker": "^7.1.0", + "@angular/upgrade": "^7.1.0", + "@nguniversal/common": "^7.1.0", + "@nguniversal/express-engine": "^7.1.0", + "@nguniversal/module-map-ngfactory-loader": "^7.1.0", + "angular-in-memory-web-api": "github:brandonroberts/in-memory-web-api-bazel#50a34d8", "core-js": "^2.5.4", "express": "^4.14.1", "rxjs": "^6.3.0", @@ -42,11 +42,11 @@ "zone.js": "~0.8.26" }, "devDependencies": { - "@angular-devkit/build-angular": "^0.10.0", - "@angular/cli": "^7.0.0", - "@angular/compiler-cli": "^7.0.0", - "@angular/language-service": "^7.0.0", - "@angular/platform-server": "^7.0.0", + "@angular-devkit/build-angular": "^0.11.0", + "@angular/cli": "^7.1.0", + "@angular/compiler-cli": "^7.1.0", + "@angular/language-service": "^7.1.0", + "@angular/platform-server": "^7.1.0", "@types/angular": "^1.6.47", "@types/angular-animate": "^1.5.10", "@types/angular-mocks": "^1.6.0", diff --git a/aio/tools/examples/shared/protractor.config.js b/aio/tools/examples/shared/protractor.config.js index 11c8d6d5fe..7a039e4111 100644 --- a/aio/tools/examples/shared/protractor.config.js +++ b/aio/tools/examples/shared/protractor.config.js @@ -21,11 +21,6 @@ exports.config = { // Capabilities to be passed to the webdriver instance. capabilities: { 'browserName': 'chrome', - // For Travis - chromeOptions: { - binary: process.env.CHROME_BIN, - args: ['--no-sandbox'] - } }, // Framework to use. Jasmine is recommended. diff --git a/aio/tools/examples/shared/yarn.lock b/aio/tools/examples/shared/yarn.lock index 45e2a1b691..6bed0fdac0 100644 --- a/aio/tools/examples/shared/yarn.lock +++ b/aio/tools/examples/shared/yarn.lock @@ -2,24 +2,34 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.10.3.tgz#6e4fd76ca41fbb3e5dc2a29f662ba3ee4d1ad086" +"@angular-devkit/architect@0.11.4": + version "0.11.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.11.4.tgz#f0cc3b4f1dd0128f6b41d3bb760bcf4c324cd063" + integrity sha512-2zi6S9tPlk52vyqN67IvFoeNgd0uxtrPlwl3TdvJ3wrH7sYGJnkQ+EzAE7cKUGWAV989BbNtx2YxhRDHnN21Fg== dependencies: - "@angular-devkit/core" "7.0.3" + "@angular-devkit/core" "7.1.4" rxjs "6.3.3" -"@angular-devkit/build-angular@^0.10.0": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.10.3.tgz#610a174efaa9d70b68e966d59a29369ac1781369" +"@angular-devkit/architect@0.13.1": + version "0.13.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.13.1.tgz#39597ce94f72d89bdd89ee567cb937cff4c13b98" + integrity sha512-QDmIbqde75ZZSEFbw6Q6kQWq4cY6C7D67yujXw6XTyubDNAs1tyXJyxTIB8vjSlEKwRizTTDd/B0ZXVcke3Mvw== dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/build-optimizer" "0.10.3" - "@angular-devkit/build-webpack" "0.10.3" - "@angular-devkit/core" "7.0.3" - "@ngtools/webpack" "7.0.3" + "@angular-devkit/core" "7.3.1" + rxjs "6.3.3" + +"@angular-devkit/build-angular@^0.11.0": + version "0.11.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.11.4.tgz#795084e29c66a71da15227cf2ac29794aa807c7c" + integrity sha512-5WQAQB4heDqAotqjU3Tl8Ons0S/e16dKwVkQFdqfKPyBgmu4CyUH35eTV+i6i7un1Elg65U5GnA4MiUtApqVyw== + dependencies: + "@angular-devkit/architect" "0.11.4" + "@angular-devkit/build-optimizer" "0.11.4" + "@angular-devkit/build-webpack" "0.11.4" + "@angular-devkit/core" "7.1.4" + "@ngtools/webpack" "7.1.4" ajv "6.5.3" - autoprefixer "9.1.5" + autoprefixer "9.3.1" circular-dependency-plugin "5.0.2" clean-css "4.2.1" copy-webpack-plugin "4.5.4" @@ -32,7 +42,7 @@ less-loader "4.1.0" license-webpack-plugin "2.0.2" loader-utils "1.1.0" - mini-css-extract-plugin "0.4.3" + mini-css-extract-plugin "0.4.4" minimatch "3.0.4" opn "5.3.0" parse5 "4.0.0" @@ -46,42 +56,45 @@ semver "5.5.1" source-map-loader "0.2.4" source-map-support "0.5.9" - speed-measure-webpack-plugin "^1.2.3" + speed-measure-webpack-plugin "1.2.3" stats-webpack-plugin "0.7.0" - style-loader "0.23.0" + style-loader "0.23.1" stylus "0.54.5" stylus-loader "3.0.2" terser-webpack-plugin "1.1.0" tree-kill "1.2.0" - webpack "4.19.1" - webpack-dev-middleware "3.3.0" - webpack-dev-server "3.1.8" + webpack "4.23.1" + webpack-dev-middleware "3.4.0" + webpack-dev-server "3.1.10" webpack-merge "4.1.4" - webpack-sources "1.2.0" + webpack-sources "1.3.0" webpack-subresource-integrity "1.1.0-rc.6" optionalDependencies: - node-sass "4.9.3" + node-sass "4.10.0" -"@angular-devkit/build-optimizer@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.10.3.tgz#e649b9d715edbb8eb4779a4f5772cc5cd842700f" +"@angular-devkit/build-optimizer@0.11.4": + version "0.11.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.11.4.tgz#d96b0e16a76f3825f173220a2de5f376fc5abaee" + integrity sha512-tAAWWFCcl918Q1JivlLvLFer8Qm4/THWbEneMwk5fQvG6/NgJLoa3itP/MCUq4qL6YHmp2DWkdWnWfRQCgHeFA== dependencies: loader-utils "1.1.0" source-map "0.5.6" - typescript "3.1.3" + typescript "3.1.6" webpack-sources "1.2.0" -"@angular-devkit/build-webpack@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.10.3.tgz#7bc42318f0d8cf71e52590a8a565b12d6fff67d0" +"@angular-devkit/build-webpack@0.11.4": + version "0.11.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.11.4.tgz#1397b21b6187eab0641830ece4c3b9faba00855e" + integrity sha512-4nEDXSbv3oDu27Rw5s2DMKmcOZYVAt76bryVF2SycSkDq3eAIiqmgw3G3CJJ4LTulXzDpaIpk02MvgbYkX+hvw== dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/core" "7.0.3" + "@angular-devkit/architect" "0.11.4" + "@angular-devkit/core" "7.1.4" rxjs "6.3.3" -"@angular-devkit/core@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.0.3.tgz#b9d0ef27f125e81dabfdac0813d310be1d8d40d2" +"@angular-devkit/core@7.1.4": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.1.4.tgz#4d903fd2ecc259b716ae76da19695d03993e583c" + integrity sha512-3cBVHjSQjMyE/mIyOX82ekdybNRQlN+kUfmdZS6oVW9aV48vdxcVbEGdl8t1H4enMf89u8kXiAAET9jFaqWopg== dependencies: ajv "6.5.3" chokidar "2.0.4" @@ -89,45 +102,64 @@ rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/schematics@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.0.3.tgz#4bd58115899d4c8db682cdacdf86a78fc5a559b2" +"@angular-devkit/core@7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.1.tgz#d92f6545796579cabdcfc29579a2c977f7a96c6c" + integrity sha512-56XDWWfIzOAkEk69lBLgmCYybPUA4yjunhmMlCk7vVdb7gbQUyzNjFD04Uj0GjlejatAQ5F76tRwygD9C+3RXQ== dependencies: - "@angular-devkit/core" "7.0.3" + ajv "6.7.0" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.1.tgz#7dc704005b966ea6c1ee62f380120183bb76eee6" + integrity sha512-cd7usiasfSgw75INz72/VssrLr9tiVRYfo1TEdvr9ww0GuQbuQpB33xbV8W135eAV8+wzQ3Ce8ohaDHibvj6Yg== + dependencies: + "@angular-devkit/core" "7.3.1" rxjs "6.3.3" -"@angular/animations@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.0.1.tgz#2df561c0959e156985297e69b7c30614537b4ffe" +"@angular/animations@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-7.2.4.tgz#4d0a0b9f14d6bfc38ca773613b61729d020435e6" + integrity sha512-Wx6cqU6koFOASlyl4aCygtbtROoehU6OKwV2EZTkfzHx6Eu/QyTiSa5kyoApVM5LMmCNeb8SxJMSAnKXztNl0A== dependencies: tslib "^1.9.0" -"@angular/cli@^7.0.0": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.0.3.tgz#fcc41f9eaae2ee15d86115804f3dbb2bdb63a8c2" +"@angular/cli@^7.1.0": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.3.1.tgz#a18acdec84deb03a1fae79cae415bbc8f9c87ffa" + integrity sha512-8EvXYRhTqTaTk5PKv7VZxIWJiyG51R9RC9gtpRFx4bbnurqBHdEUxGMmaRsGT8QDbfvVsWnuakE0eeW1CrfZAQ== dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - "@schematics/angular" "7.0.3" - "@schematics/update" "0.10.3" - inquirer "6.2.0" - opn "5.3.0" - rxjs "6.3.3" - semver "5.5.1" + "@angular-devkit/architect" "0.13.1" + "@angular-devkit/core" "7.3.1" + "@angular-devkit/schematics" "7.3.1" + "@schematics/angular" "7.3.1" + "@schematics/update" "0.13.1" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + inquirer "6.2.1" + npm-package-arg "6.1.0" + opn "5.4.0" + pacote "9.4.0" + semver "5.6.0" symbol-observable "1.2.0" -"@angular/common@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-7.0.1.tgz#55750879f08d5f4b6f247f7dce0b5ea2b3ec2059" +"@angular/common@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-7.2.4.tgz#9f1ed530e5dc7613a263e015c203ead390d50336" + integrity sha512-3/i8RtnLTx/90gJHk5maE8zwsSiHgHvLItaa0qVfNlWiU0eCId/PL6TgDkut5vN9SQYL0oxhxFaVd35HmwsmuQ== dependencies: tslib "^1.9.0" -"@angular/compiler-cli@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-7.0.1.tgz#bd21ebc950f65fb5848307a271e7bd9d049efc9c" +"@angular/compiler-cli@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-7.2.4.tgz#3de23fd5f558a859a444c58dab18f2981c9c2937" + integrity sha512-UhLosSeuwFIfaGqGcYOh9WSOuzEpeuhIRAOt81MeqOQEqkoreUjfxrQq8XWNkdqsPZHtiptF5ZwXlMBxlj9jJg== dependencies: - canonical-path "0.0.2" + canonical-path "1.0.0" chokidar "^1.4.2" convert-source-map "^1.5.1" dependency-graph "^0.7.2" @@ -136,77 +168,90 @@ reflect-metadata "^0.1.2" shelljs "^0.8.1" source-map "^0.6.1" + tslib "^1.9.0" yargs "9.0.1" -"@angular/compiler@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-7.0.1.tgz#29271bfdc9ac98f2f93c473a0cd82d6a043cf6e3" +"@angular/compiler@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-7.2.4.tgz#133eb97fc3169ec9ff84f134eb9e3497fa37537e" + integrity sha512-+zyMzPCL45ePEV9nrnYJvhAVgp2Y19bDaq0f0YdZAqAjgDqHzXGGR6wX8GueyJWmUYWx5vwK6Apla4HwDrYA1w== dependencies: tslib "^1.9.0" -"@angular/core@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.0.1.tgz#42f52bf04bf88759d4f4b9e03cb9b312508233a0" +"@angular/core@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.2.4.tgz#a6c84940c8edcfa37158f666a1f99c6e4a97bf95" + integrity sha512-kfAxhIxl89PmB7y81FR/RAv0yWRFcEYxEnTwV+o8jKGfemAXtQ0g/Vh+lJR0SD/TBgFilMxotN1mhwH4A8GShw== dependencies: tslib "^1.9.0" -"@angular/elements@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/elements/-/elements-7.0.1.tgz#d942e35dfb1ab0fe62724751c172c44a002caf31" +"@angular/elements@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/elements/-/elements-7.2.4.tgz#4b77cb0f815deb3fd83d8a3c9a807bcca11c2373" + integrity sha512-5V4kFmpncQTJEVdREaSBb4DVjZz88eLQBjzzvEUM3r7szhbQ1DYuubG7Sj2a1iIYSI/HTkPPvX57rQk3vq6AEw== dependencies: tslib "^1.9.0" -"@angular/forms@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.0.1.tgz#bece870353e12b821b572b7b447502bedfa9cc46" +"@angular/forms@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-7.2.4.tgz#be89cf83ad16fa3c813c12e4cff85da5409cf7a0" + integrity sha512-DAtOrdlTRsgvmZrsvczCAkY8dhTwZb5DXBmPuSXh0UR9lvEiCgNHGbwEiIiIkAHpw1wSeXZrq0qyy/oJRvf18g== dependencies: tslib "^1.9.0" -"@angular/http@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/http/-/http-7.0.1.tgz#54df0b7c6a5234d45a386bad81a64e0f1e85d666" +"@angular/http@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/http/-/http-7.2.4.tgz#fc151ac15c8c7542cb7242a430ad2319655c2ff5" + integrity sha512-kazJREm7MtSCYbE+9zU/CcUXI5Csu53PooeQlAp80/TOHqry6fVKIMHCI892Db9ScY2ds0SzbyTmrxEQo7PP1A== dependencies: tslib "^1.9.0" -"@angular/language-service@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-7.0.1.tgz#86eab29a979c2efd45617a3bff4dfb490f23dcc1" +"@angular/language-service@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-7.2.4.tgz#db72460040b070410cbff678410c142f4d682af8" + integrity sha512-A9Rud/27hHMSUUjpgn57nVeLsoYgdvFwJhtlZA/oCuSpmlD+LqqBsEpPhivwn++u44+DSrFXsic29jlFnsBotw== -"@angular/platform-browser-dynamic@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.0.1.tgz#bf50a90573bc49e00e4bb8c08f6dee888f553e04" +"@angular/platform-browser-dynamic@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.4.tgz#24dce1bb0d9dab541b3b1b3eda3084a732f11b64" + integrity sha512-J/xWlmaYOPUoCHZ5TiIRiyYa4uRMtCz3aGdBfY8k/NWtNo8SCYaS3aut7Sk4RS5rK8aAVi+aYFlY5YOrlW+Hbg== dependencies: tslib "^1.9.0" -"@angular/platform-browser@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-7.0.1.tgz#d9638cb6592543018b96355a0119fc826ab5e27e" +"@angular/platform-browser@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-7.2.4.tgz#2cf5305878d0620d6b8c02eff00ac3ca8dbc5970" + integrity sha512-Klt8aKR5SP9bqfMfpSY5vQOY7AQEs8JGuZOk5Bfc2dUtYT2IEIvK2IqO8v2rcFRVO13HOPUxl328efyHqLgI7g== dependencies: tslib "^1.9.0" -"@angular/platform-server@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-7.0.1.tgz#f284fbf90832a9fdefbba871faa50cec337822e2" +"@angular/platform-server@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-7.2.4.tgz#276803cc7cac8da54d1ad2f05e052e4f8af64a85" + integrity sha512-3KbLHw7xMbkxun93HeYX8pSiPmFWim3ftvKbfPlB01fjhdZvhHpf39Dn4T7iyT1vrZMccXL87psv4/lJkTf04A== dependencies: domino "^2.1.0" tslib "^1.9.0" xhr2 "^0.1.4" -"@angular/router@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-7.0.1.tgz#2085466c47a8efad576b4310db191c3e338cacef" +"@angular/router@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-7.2.4.tgz#83f1997c2a4e6acda93b991b8d7f3dad2b3f91f0" + integrity sha512-T8Uqf2H1SV1MQI38WwYJ4aa+4NNnvlp2Tp/rkfg6tKcp/cLkKqE6OOfiy9lmW+i/624v8tMgYoBMOUNBjAG23g== dependencies: tslib "^1.9.0" -"@angular/service-worker@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-7.0.1.tgz#773ad7e758e29a5ad8b5627636480a4c2d74568f" +"@angular/service-worker@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/service-worker/-/service-worker-7.2.4.tgz#d16d6d08c0d5c29c93e9f80cddc4013c9b8859fb" + integrity sha512-IYsHshkgCYYmWLwtP7wwk8tfwphE4IJrkUitEu+ST6x+er/K9LyLo09WQeEZHIwDaPm9icoqc3TJJdXI46mrmg== dependencies: tslib "^1.9.0" -"@angular/upgrade@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular/upgrade/-/upgrade-7.0.1.tgz#f790d9031754826b709c6f8b413e0fc9edad2762" +"@angular/upgrade@^7.1.0": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@angular/upgrade/-/upgrade-7.2.4.tgz#49ecce8f8a6c290599179d5d96d19812a496145a" + integrity sha512-sRDXl2Uy9fZrMROfe7eNZDWwb1fgoWYzJ8VrviUCRakTJf3ZQLuEf4ToTc3KY/KGxEubA4jiuI8LXbyTTmRMQw== dependencies: tslib "^1.9.0" @@ -288,45 +333,53 @@ lodash "^4.17.10" to-fast-properties "^2.0.0" -"@ngtools/webpack@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.0.3.tgz#96bc0d94e9a8ac84eb34cf81c59fdd21bfbd18e3" +"@ngtools/webpack@7.1.4": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.1.4.tgz#632ece6ed8e05fe743554cc935be36a653376f01" + integrity sha512-8A15TPJzg3g7yI70QvBzJ253P32WAgCVre9nMaDdd22UmlbvN8Ke4RuQY7vYVTECLL+bWpFJEFXL+ThzCRUgeA== dependencies: - "@angular-devkit/core" "7.0.3" + "@angular-devkit/core" "7.1.4" enhanced-resolve "4.1.0" rxjs "6.3.3" tree-kill "1.2.0" webpack-sources "1.2.0" -"@nguniversal/common@^7.0.0": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@nguniversal/common/-/common-7.0.2.tgz#86ccd25da0f02f7bd3285bcdce16fd26a1213326" +"@nguniversal/common@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@nguniversal/common/-/common-7.1.0.tgz#bd53e16a1dfce040413a6e3a3931fbc7ad2c8bb3" + integrity sha512-uEIJPzPk3u0MeOh2UhyDMsFlNemm1hHhvLaT5AJBBenoWcGkPRFuMilkZw7O12qStdthEZedfZYkOft2Fftpzg== -"@nguniversal/express-engine@^7.0.0": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@nguniversal/express-engine/-/express-engine-7.0.2.tgz#f7722828d7ec14951d0c24ad438772daf79583c8" +"@nguniversal/express-engine@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@nguniversal/express-engine/-/express-engine-7.1.0.tgz#d48b1a821036382d62e4d4b122b5e44790c41c3f" + integrity sha512-otOA3WTjb+XnEDiyhwkvP0hE1gC7PiJrDoDFs5Q77SQ0ZAjuGzAIIgpQrPE8B+v0zmVj2oucDNCSZlmYWb1P/Q== -"@nguniversal/module-map-ngfactory-loader@^7.0.0": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@nguniversal/module-map-ngfactory-loader/-/module-map-ngfactory-loader-7.0.2.tgz#2df0532f84d4f4e042adb294e3685fad28ed0622" +"@nguniversal/module-map-ngfactory-loader@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@nguniversal/module-map-ngfactory-loader/-/module-map-ngfactory-loader-7.1.0.tgz#70ea905c1b32c2edc484cb77aa7a3f3208069966" + integrity sha512-GYfb24OLJKBY58CgUsIsGgci5ceZAt4+GrVKh7RZRIHtZ/bjdGsvpIbfE9udqsnSowxIxHA5KzYHbC1x6AAB0A== -"@schematics/angular@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.0.3.tgz#7a43800cbf5b8971071cbab653b553b6c67b8809" +"@schematics/angular@7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.3.1.tgz#6fcd7004210fa9305310c3109c084df5c5521776" + integrity sha512-0Ne8APPlTAjKg5CSZqluwCuW/5yPjr3ALCWzqwPxN0suE745usThtasBmqrjw0RMIt8nRqRgtg54Z7lCPO9ZFg== dependencies: - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - typescript "3.1.3" + "@angular-devkit/core" "7.3.1" + "@angular-devkit/schematics" "7.3.1" + typescript "3.2.4" -"@schematics/update@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.10.3.tgz#4bb7580b3e2f6af0689861bd0628d65a3eb0cd75" +"@schematics/update@0.13.1": + version "0.13.1" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.13.1.tgz#481475aee18b4a9472a06512b2e4d6429af68231" + integrity sha512-EHOqolT/d/jRGuVTCUESLpk8JNpuaPlsVHfeK7Kdp/t0wSEnmtOelZX4+leS25lGXDaDUF3138ntjrZR4n6bGw== dependencies: - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - npm-registry-client "8.6.0" + "@angular-devkit/core" "7.3.1" + "@angular-devkit/schematics" "7.3.1" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + pacote "9.4.0" rxjs "6.3.3" - semver "5.5.1" + semver "5.6.0" semver-intersect "1.4.0" "@types/angular-animate@^1.5.10": @@ -427,133 +480,147 @@ "@types/express-serve-static-core" "*" "@types/mime" "*" -"@webassemblyjs/ast@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.6.tgz#3ef8c45b3e5e943a153a05281317474fef63e21e" +"@webassemblyjs/ast@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.10.tgz#0cfc61d61286240b72fc522cb755613699eea40a" + integrity sha512-wTUeaByYN2EA6qVqhbgavtGc7fLTOx0glG2IBsFlrFG51uXIGlYBTyIZMf4SPLo3v1bgV/7lBN3l7Z0R6Hswew== dependencies: - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" - mamacro "^0.0.3" + "@webassemblyjs/helper-module-context" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/wast-parser" "1.7.10" -"@webassemblyjs/floating-point-hex-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz#7cb37d51a05c3fe09b464ae7e711d1ab3837801f" +"@webassemblyjs/floating-point-hex-parser@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.10.tgz#ee63d729c6311a85863e369a473f9983f984e4d9" + integrity sha512-gMsGbI6I3p/P1xL2UxqhNh1ga2HCsx5VBB2i5VvJFAaqAjd2PBTRULc3BpTydabUQEGlaZCzEUQhLoLG7TvEYQ== -"@webassemblyjs/helper-api-error@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz#99b7e30e66f550a2638299a109dda84a622070ef" +"@webassemblyjs/helper-api-error@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.10.tgz#bfcb3bbe59775357475790a2ad7b289f09b2f198" + integrity sha512-DoYRlPWtuw3yd5BOr9XhtrmB6X1enYF0/54yNvQWGXZEPDF5PJVNI7zQ7gkcKfTESzp8bIBWailaFXEK/jjCsw== -"@webassemblyjs/helper-buffer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz#ba0648be12bbe560c25c997e175c2018df39ca3e" +"@webassemblyjs/helper-buffer@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.10.tgz#0a8c624c67ad0b214d2e003859921a1988cb151b" + integrity sha512-+RMU3dt/dPh4EpVX4u5jxsOlw22tp3zjqE0m3ftU2tsYxnPULb4cyHlgaNd2KoWuwasCQqn8Mhr+TTdbtj3LlA== -"@webassemblyjs/helper-code-frame@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz#5a94d21b0057b69a7403fca0c253c3aaca95b1a5" +"@webassemblyjs/helper-code-frame@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.10.tgz#0ab7e22fad0241a173178c73976fc0edf50832ce" + integrity sha512-UiytbpKAULOEab2hUZK2ywXen4gWJVrgxtwY3Kn+eZaaSWaRM8z/7dAXRSoamhKFiBh1uaqxzE/XD9BLlug3gw== dependencies: - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/wast-printer" "1.7.10" -"@webassemblyjs/helper-fsm@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz#ae1741c6f6121213c7a0b587fb964fac492d3e49" +"@webassemblyjs/helper-fsm@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.10.tgz#0915e7713fbbb735620a9d3e4fa3d7951f97ac64" + integrity sha512-w2vDtUK9xeSRtt5+RnnlRCI7wHEvLjF0XdnxJpgx+LJOvklTZPqWkuy/NhwHSLP19sm9H8dWxKeReMR7sCkGZA== -"@webassemblyjs/helper-module-context@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz#116d19a51a6cebc8900ad53ca34ff8269c668c23" +"@webassemblyjs/helper-module-context@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.10.tgz#9beb83f72740f5ac8075313b5cac5e796510f755" + integrity sha512-yE5x/LzZ3XdPdREmJijxzfrf+BDRewvO0zl8kvORgSWmxpRrkqY39KZSq6TSgIWBxkK4SrzlS3BsMCv2s1FpsQ== + +"@webassemblyjs/helper-wasm-bytecode@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.10.tgz#797b1e734bbcfdea8399669cdc58308ef1c7ffc0" + integrity sha512-u5qy4SJ/OrxKxZqJ9N3qH4ZQgHaAzsopsYwLvoWJY6Q33r8PhT3VPyNMaJ7ZFoqzBnZlCcS/0f4Sp8WBxylXfg== + +"@webassemblyjs/helper-wasm-section@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.10.tgz#c0ea3703c615d7bc3e3507c3b7991c8767b2f20e" + integrity sha512-Ecvww6sCkcjatcyctUrn22neSJHLN/TTzolMGG/N7S9rpbsTZ8c6Bl98GpSpV77EvzNijiNRHBG0+JO99qKz6g== dependencies: - mamacro "^0.0.3" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-buffer" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/wasm-gen" "1.7.10" -"@webassemblyjs/helper-wasm-bytecode@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz#98e515eaee611aa6834eb5f6a7f8f5b29fefb6f1" - -"@webassemblyjs/helper-wasm-section@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz#783835867bdd686df7a95377ab64f51a275e8333" - dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - -"@webassemblyjs/ieee754@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz#c34fc058f2f831fae0632a8bb9803cf2d3462eb1" +"@webassemblyjs/ieee754@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.10.tgz#62c1728b7ef0f66ef8221e2966a0afd75db430df" + integrity sha512-HRcWcY+YWt4+s/CvQn+vnSPfRaD4KkuzQFt5MNaELXXHSjelHlSEA8ZcqT69q0GTIuLWZ6JaoKar4yWHVpZHsQ== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.6.tgz#197f75376a29f6ed6ace15898a310d871d92f03b" +"@webassemblyjs/leb128@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.10.tgz#167e0bb4b06d7701585772a73fba9f4df85439f6" + integrity sha512-og8MciYlA8hvzCLR71hCuZKPbVBfLQeHv7ImKZ4nlyxrYbG7uJHYtHiHu6OV9SqrGuD03H/HtXC4Bgdjfm9FHw== dependencies: "@xtuc/long" "4.2.1" -"@webassemblyjs/utf8@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.6.tgz#eb62c66f906af2be70de0302e29055d25188797d" +"@webassemblyjs/utf8@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.10.tgz#b6728f5b6f50364abc155be029f9670e6685605a" + integrity sha512-Ng6Pxv6siyZp635xCSnH3mKmIFgqWPCcGdoo0GBYgyGdxu7cUj4agV7Uu1a8REP66UYUFXJLudeGgd4RvuJAnQ== -"@webassemblyjs/wasm-edit@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz#fa41929160cd7d676d4c28ecef420eed5b3733c5" +"@webassemblyjs/wasm-edit@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.10.tgz#83fe3140f5a58f5a30b914702be9f0e59a399092" + integrity sha512-e9RZFQlb+ZuYcKRcW9yl+mqX/Ycj9+3/+ppDI8nEE/NCY6FoK8f3dKBcfubYV/HZn44b+ND4hjh+4BYBt+sDnA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/helper-wasm-section" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-opt" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-buffer" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/helper-wasm-section" "1.7.10" + "@webassemblyjs/wasm-gen" "1.7.10" + "@webassemblyjs/wasm-opt" "1.7.10" + "@webassemblyjs/wasm-parser" "1.7.10" + "@webassemblyjs/wast-printer" "1.7.10" -"@webassemblyjs/wasm-gen@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz#695ac38861ab3d72bf763c8c75e5f087ffabc322" +"@webassemblyjs/wasm-gen@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.10.tgz#4de003806ae29c97ab3707782469b53299570174" + integrity sha512-M0lb6cO2Y0PzDye/L39PqwV+jvO+2YxEG5ax+7dgq7EwXdAlpOMx1jxyXJTScQoeTpzOPIb+fLgX/IkLF8h2yw== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/ieee754" "1.7.10" + "@webassemblyjs/leb128" "1.7.10" + "@webassemblyjs/utf8" "1.7.10" -"@webassemblyjs/wasm-opt@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz#fbafa78e27e1a75ab759a4b658ff3d50b4636c21" +"@webassemblyjs/wasm-opt@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.10.tgz#d151e31611934a556c82789fdeec41a814993c2a" + integrity sha512-R66IHGCdicgF5ZliN10yn5HaC7vwYAqrSVJGjtJJQp5+QNPBye6heWdVH/at40uh0uoaDN/UVUfXK0gvuUqtVg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-buffer" "1.7.10" + "@webassemblyjs/wasm-gen" "1.7.10" + "@webassemblyjs/wasm-parser" "1.7.10" -"@webassemblyjs/wasm-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz#84eafeeff405ad6f4c4b5777d6a28ae54eed51fe" +"@webassemblyjs/wasm-parser@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.10.tgz#0367be7bf8f09e3e6abc95f8e483b9206487ec65" + integrity sha512-AEv8mkXVK63n/iDR3T693EzoGPnNAwKwT3iHmKJNBrrALAhhEjuPzo/lTE4U7LquEwyvg5nneSNdTdgrBaGJcA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-api-error" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/ieee754" "1.7.10" + "@webassemblyjs/leb128" "1.7.10" + "@webassemblyjs/utf8" "1.7.10" -"@webassemblyjs/wast-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz#ca4d20b1516e017c91981773bd7e819d6bd9c6a7" +"@webassemblyjs/wast-parser@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.10.tgz#058f598b52f730b23fc874d4775b6286b6247264" + integrity sha512-YTPEtOBljkCL0VjDp4sHe22dAYSm3ZwdJ9+2NTGdtC7ayNvuip1wAhaAS8Zt9Q6SW9E5Jf5PX7YE3XWlrzR9cw== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/floating-point-hex-parser" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-code-frame" "1.7.6" - "@webassemblyjs/helper-fsm" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/floating-point-hex-parser" "1.7.10" + "@webassemblyjs/helper-api-error" "1.7.10" + "@webassemblyjs/helper-code-frame" "1.7.10" + "@webassemblyjs/helper-fsm" "1.7.10" "@xtuc/long" "4.2.1" - mamacro "^0.0.3" -"@webassemblyjs/wast-printer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz#a6002c526ac5fa230fe2c6d2f1bdbf4aead43a5e" +"@webassemblyjs/wast-printer@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.10.tgz#d817909d2450ae96c66b7607624d98a33b84223b" + integrity sha512-mJ3QKWtCchL1vhU/kZlJnLPuQZnlDOdZsyP0bbLWPGdYsQDnSBvyTLhzwBA3QAMlzEL9V4JHygEmK6/OTEyytA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/wast-parser" "1.7.10" "@xtuc/long" "4.2.1" "@xtuc/ieee754@^1.2.0": @@ -564,6 +631,19 @@ version "4.2.1" resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" +"@yarnpkg/lockfile@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +JSONStream@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -619,12 +699,19 @@ after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -agent-base@^4.1.0: +agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" dependencies: es6-promisify "^5.0.0" +agentkeepalive@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" + ajv-errors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" @@ -642,6 +729,16 @@ ajv@6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.7.0.tgz#e3ce7bb372d6577bb1839f1dfdfcbf5ad2948d96" + integrity sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -688,9 +785,11 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" -angular-in-memory-web-api@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/angular-in-memory-web-api/-/angular-in-memory-web-api-0.6.0.tgz#28262d6f7cdf1415c1d540c1a5cb838d58cb602a" +"angular-in-memory-web-api@github:brandonroberts/in-memory-web-api-bazel#50a34d8": + version "0.8.0" + resolved "https://codeload.github.com/brandonroberts/in-memory-web-api-bazel/tar.gz/50a34d84b627ec88816242dec77603d6dcb9c880" + dependencies: + tslib "^1.9.0" ansi-colors@^3.0.0: version "3.1.0" @@ -716,6 +815,11 @@ ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -909,16 +1013,17 @@ atob@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" -autoprefixer@9.1.5: - version "9.1.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.1.5.tgz#8675fd8d1c0d43069f3b19a2c316f3524e4f6671" +autoprefixer@9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.3.1.tgz#71b622174de2b783d5fd99f9ad617b7a3c78443e" + integrity sha512-DY9gOh8z3tnCbJ13JIWaeQsoYncTGdsrgCceBaQSIL4nvdrLxgbRSBPevg2XbX7u4QCSfLheSJEEIUUSlkbx6Q== dependencies: - browserslist "^4.1.0" - caniuse-lite "^1.0.30000884" + browserslist "^4.3.3" + caniuse-lite "^1.0.30000898" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.2" - postcss-value-parser "^3.2.3" + postcss "^7.0.5" + postcss-value-parser "^3.3.1" aws-sign2@~0.6.0: version "0.6.0" @@ -1091,6 +1196,11 @@ bluebird@^3.3.0, bluebird@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" +bluebird@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -1302,13 +1412,14 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.3.4.tgz#4477b737db6a1b07077275b24791e680d4300425" +browserslist@^4.3.3: + version "4.4.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062" + integrity sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A== dependencies: - caniuse-lite "^1.0.30000899" - electron-to-chromium "^1.3.82" - node-releases "^1.0.1" + caniuse-lite "^1.0.30000929" + electron-to-chromium "^1.3.103" + node-releases "^1.1.3" browserstack@^1.5.1: version "1.5.1" @@ -1382,6 +1493,26 @@ cacache@^10.0.4: unique-filename "^1.1.0" y18n "^4.0.0" +cacache@^11.0.1, cacache@^11.3.2: + version "11.3.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" + integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg== + dependencies: + bluebird "^3.5.3" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.3" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + cacache@^11.0.2: version "11.2.0" resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.2.0.tgz#617bdc0b02844af56310e411c0878941d5739965" @@ -1442,13 +1573,15 @@ camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000899: - version "1.0.30000900" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000900.tgz#015cfe37897a3386a3075a914498800c29afe77e" +caniuse-lite@^1.0.30000898: + version "1.0.30000935" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000935.tgz#d1b59df00b46f4921bb84a8a34c1d172b346df59" + integrity sha512-1Y2uJ5y56qDt3jsDTdBHL1OqiImzjoQcBG6Yl3Qizq8mcc2SgCFpi+ZwLLqkztYnk9l87IYqRlNBnPSOTbFkXQ== -canonical-path@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-0.0.2.tgz#e31eb937a8c93ee2a01df1839794721902874574" +caniuse-lite@^1.0.30000929: + version "1.0.30000932" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz#d01763e9ce77810962ca7391ff827b5949ce4272" + integrity sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A== canonical-path@1.0.0: version "1.0.0" @@ -1502,6 +1635,15 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -1579,6 +1721,11 @@ chownr@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + chrome-trace-event@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" @@ -1791,15 +1938,6 @@ concat-stream@1.6.0, concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - concurrently@^3.0.0: version "3.5.0" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.5.0.tgz#8cf1b7707a6916a78a4ff5b77bb04dec54b379b2" @@ -2059,7 +2197,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@*, debug@^3.1.0, debug@~3.1.0: +debug@*, debug@3.1.0, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2089,12 +2227,19 @@ debug@2.6.8: dependencies: ms "2.0.0" -debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" +debug@^3.2.5: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2334,9 +2479,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.3.82: - version "1.3.82" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" +electron-to-chromium@^1.3.103: + version "1.3.109" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.109.tgz#ee04a55a5157a5580a5ea88e526b02c84a3a7bc8" + integrity sha512-1qhgVZD9KIULMyeBkbjU/dWmm30zpPUfdWZfVO3nPhbtqMHJqHr4Ua5wBcWtAymVFrUCuAJxjMF1OhG+bR21Ow== elliptic@^6.0.0: version "6.4.0" @@ -2366,6 +2512,13 @@ encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" @@ -2468,6 +2621,11 @@ ent@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + errno@^0.1.1, errno@^0.1.3, errno@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" @@ -2571,11 +2729,12 @@ events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" -eventsource@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== dependencies: - original ">=0.0.5" + original "^1.0.0" evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" @@ -2813,9 +2972,10 @@ faye-websocket@^0.10.0: dependencies: websocket-driver ">=0.5.1" -faye-websocket@~0.11.0: +faye-websocket@~0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg= dependencies: websocket-driver ">=0.5.1" @@ -2825,7 +2985,7 @@ fd-slicer@~1.0.1: dependencies: pend "~1.2.0" -figgy-pudding@^3.1.0, figgy-pudding@^3.5.1: +figgy-pudding@^3.1.0, figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" @@ -3139,6 +3299,11 @@ gaze@^1.0.0: dependencies: globule "^1.0.0" +genfun@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" + integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== + get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -3151,6 +3316,13 @@ get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -3192,7 +3364,7 @@ glob@7.0.x: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.3: +glob@7.1.3, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" dependencies: @@ -3290,6 +3462,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +graceful-fs@^4.1.15: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + handle-thing@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" @@ -3506,6 +3683,11 @@ html-entities@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -3531,6 +3713,14 @@ http-parser-js@>=0.4.0: version "0.4.9" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + http-proxy-middleware@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" @@ -3594,11 +3784,18 @@ https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: @@ -3690,13 +3887,19 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" +ini@1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + ini@^1.3.4, ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" -inquirer@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" +inquirer@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" + integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -3709,7 +3912,7 @@ inquirer@6.2.0: run-async "^2.2.0" rxjs "^6.1.0" string-width "^2.1.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" through "^2.3.6" internal-ip@^3.0.1: @@ -4193,7 +4396,7 @@ jsesc@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -4243,6 +4446,11 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -4565,7 +4773,7 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" -loud-rejection@^1.0.0, loud-rejection@^1.6.0: +loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" dependencies: @@ -4583,6 +4791,14 @@ lru-cache@^4.0.1, lru-cache@^4.1.1: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^4.1.2: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + lru-cache@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" @@ -4590,6 +4806,13 @@ lru-cache@^4.1.3: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + magic-string@^0.22.4: version "0.22.4" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.4.tgz#31039b4e40366395618c1d6cf8193c53917475ff" @@ -4618,9 +4841,22 @@ make-error@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.0.tgz#52ad3a339ccf10ce62b4040b708fe707244b8b96" -mamacro@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" +make-fetch-happen@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" + integrity sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ== + dependencies: + agentkeepalive "^3.4.1" + cacache "^11.0.1" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" map-age-cleaner@^0.1.1: version "0.1.2" @@ -4806,9 +5042,10 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" -mini-css-extract-plugin@0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.3.tgz#98d60fcc5d228c3e36a9bd15a1d6816d6580beb8" +mini-css-extract-plugin@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.4.tgz#c10410a004951bd3cedac1da69053940fccb625d" + integrity sha512-o+Jm+ocb0asEngdM6FsZWtZsRzA8koFUudIDwYUfl94M3PejPHG7Vopw5hN9V8WsMkSFpm3tZP3Fesz89EyrfQ== dependencies: loader-utils "^1.1.0" schema-utils "^1.0.0" @@ -4847,12 +5084,27 @@ minipass@^2.2.1, minipass@^2.3.3: safe-buffer "^5.1.2" yallist "^3.0.0" +minipass@^2.3.4, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + minizlib@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" dependencies: minipass "^2.2.1" +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + mississippi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" @@ -4948,6 +5200,11 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +ms@^2.0.0, ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -5028,6 +5285,15 @@ nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + node-forge@0.6.33: version "0.6.33" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc" @@ -5123,15 +5389,17 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" -node-releases@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.1.tgz#957a2735d2ca737d7005588f8e85e6c27032555b" +node-releases@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.6.tgz#47d160033e24a64e79487a62de63cf691052ec54" + integrity sha512-lODUVHEIZutZx+TDdOk47qLik8FJMXzJ+WnyUGci1MTvTOyzZrz5eVPIIpc5Hb3NfHZGeGHeuwrRYVI1PEITWg== dependencies: semver "^5.3.0" -node-sass@4.9.3: - version "4.9.3" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.3.tgz#f407cf3d66f78308bb1e346b24fa428703196224" +node-sass@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.10.0.tgz#dcc2b364c0913630945ccbf7a2bbf1f926effca4" + integrity sha512-fDQJfXszw6vek63Fe/ldkYXmRYK/QS6NbvM3i5oEo9ntPDy4XX7BcKZyTKv+/kSSxRtXXc7l+MSwEmYc0CSy6Q== dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -5148,7 +5416,7 @@ node-sass@4.9.3: nan "^2.10.0" node-gyp "^3.8.0" npmlog "^4.0.0" - request "2.87.0" + request "^2.88.0" sass-graph "^2.2.4" stdout-stream "^1.4.0" "true-case-path" "^1.0.2" @@ -5166,7 +5434,7 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -5175,6 +5443,16 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +normalize-package-data@^2.4.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.2.tgz#6b2abd85774e51f7936f1395e45acb905dc849b2" + integrity sha512-YcMnjqeoUckXTPKZSAsPjUPLxH85XotbpqK3w4RyCwdFQSU5FxxBys8buehkSfg0j9fKvV1hn7O0+8reEgkAiw== + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -5189,15 +5467,24 @@ npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" -"npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0": +npm-package-arg@6.1.0, npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== dependencies: hosted-git-info "^2.6.0" osenv "^0.1.5" semver "^5.5.0" validate-npm-package-name "^3.0.0" +npm-packlist@^1.1.12: + version "1.2.0" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.2.0.tgz#55a60e793e272f00862c7089274439a4cc31fc7f" + integrity sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-packlist@^1.1.6: version "1.1.11" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" @@ -5205,23 +5492,26 @@ npm-packlist@^1.1.6: ignore-walk "^3.0.1" npm-bundled "^1.0.1" -npm-registry-client@8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.6.0.tgz#7f1529f91450732e89f8518e0f21459deea3e4c4" +npm-pick-manifest@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" + integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA== dependencies: - concat-stream "^1.5.2" - graceful-fs "^4.1.6" - normalize-package-data "~1.0.1 || ^2.0.0" - npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" - once "^1.3.3" - request "^2.74.0" - retry "^0.10.0" - safe-buffer "^5.1.1" - semver "2 >=2.2.1 || 3.x || 4 || 5" - slide "^1.1.3" - ssri "^5.2.4" - optionalDependencies: - npmlog "2 || ^3.1.0 || ^4.0.0" + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-registry-fetch@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz#44d841780e2833f06accb34488f8c7450d1a6856" + integrity sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" npm-run-path@^2.0.0: version "2.0.2" @@ -5229,7 +5519,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.0, npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -5352,6 +5642,13 @@ opn@5.3.0: dependencies: is-wsl "^1.1.0" +opn@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" + integrity sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw== + dependencies: + is-wsl "^1.1.0" + opn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.1.0.tgz#72ce2306a17dbea58ff1041853352b4a8fc77519" @@ -5380,11 +5677,12 @@ options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" -original@>=0.0.5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== dependencies: - url-parse "1.0.x" + url-parse "^1.4.3" os-browserify@^0.2.0: version "0.2.1" @@ -5486,6 +5784,39 @@ p-try@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" +pacote@9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.4.0.tgz#af979abdeb175cd347c3e33be3241af1ed254807" + integrity sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w== + dependencies: + bluebird "^3.5.3" + cacache "^11.3.2" + figgy-pudding "^3.5.1" + get-stream "^4.1.0" + glob "^7.1.3" + lru-cache "^5.1.1" + make-fetch-happen "^4.0.1" + minimatch "^3.0.4" + minipass "^2.3.5" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.12" + npm-pick-manifest "^2.2.3" + npm-registry-fetch "^3.8.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.1" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.6.0" + ssri "^6.0.1" + tar "^4.4.8" + unique-filename "^1.1.1" + which "^1.3.1" + pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" @@ -5751,7 +6082,12 @@ postcss-value-parser@^3.2.3: version "3.3.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" -postcss@7.0.5, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2: +postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss@7.0.5, postcss@^7.0.0, postcss@^7.0.1: version "7.0.5" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.5.tgz#70e6443e36a6d520b0fd4e7593fcca3635ee9f55" dependencies: @@ -5759,6 +6095,15 @@ postcss@7.0.5, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2: source-map "^0.6.1" supports-color "^5.5.0" +postcss@^7.0.5: + version "7.0.14" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5" + integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -5787,12 +6132,27 @@ promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" dependencies: asap "~2.0.3" +protoduck@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" + integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== + dependencies: + genfun "^5.0.0" + protractor@~5.4.0: version "5.4.1" resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.4.1.tgz#011a99e38df7aa45d22455b889ffbb13a6ce0bd9" @@ -5935,13 +6295,10 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -querystringify@0.0.x: - version "0.0.4" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" - -querystringify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" +querystringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" + integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== randomatic@^1.1.3: version "1.1.7" @@ -6166,58 +6523,6 @@ request@2.81.0, request@~2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@^2.74.0, request@^2.83.0: - version "2.85.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - request@^2.78.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" @@ -6245,7 +6550,34 @@ request@^2.78.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@^2.87.0: +request@^2.83.0: + version "2.85.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" dependencies: @@ -6282,7 +6614,7 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -requires-port@1.0.x, requires-port@1.x.x: +requires-port@1.x.x, requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -6539,10 +6871,6 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" -"semver@2 >=2.2.1 || 3.x || 4 || 5", semver@^5.0.0, semver@^5.0.1, semver@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - "semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -6551,6 +6879,15 @@ semver@5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" +semver@5.6.0, semver@^5.4.1, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +semver@^5.0.0, semver@^5.0.1, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -6757,9 +7094,10 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slide@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== snapdragon-node@^2.0.1: version "2.1.1" @@ -6886,16 +7224,17 @@ socket.io@2.1.1: socket.io-client "2.1.1" socket.io-parser "~3.2.0" -sockjs-client@1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.5.tgz#1bb7c0f7222c40f42adf14f4442cbd1269771a83" +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== dependencies: - debug "^2.6.6" - eventsource "0.1.6" - faye-websocket "~0.11.0" - inherits "^2.0.1" + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" json3 "^3.3.2" - url-parse "^1.1.8" + url-parse "^1.4.3" sockjs@0.3.19: version "0.3.19" @@ -6904,6 +7243,22 @@ sockjs@0.3.19: faye-websocket "^0.10.0" uuid "^3.0.1" +socks-proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + integrity sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw== + dependencies: + agent-base "~4.2.0" + socks "~2.2.0" + +socks@~2.2.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.3.tgz#7399ce11e19b2a997153c983a9ccb6306721f2dc" + integrity sha512-+2r83WaRT3PXYoO/1z+RDEBE7Z2f9YcdQnJ0K/ncXXbV5gJ6wYfNAebYFYiiUjM6E4JyXnPY8cimwyvFYHVUUA== + dependencies: + ip "^1.1.5" + smart-buffer "4.0.2" + source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" @@ -7038,9 +7393,10 @@ spdy@^3.4.1: select-hose "^2.0.0" spdy-transport "^2.0.18" -speed-measure-webpack-plugin@^1.2.3: +speed-measure-webpack-plugin@1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.2.3.tgz#de170b5cefbfa1c039d95e639edd3ad50cfc7c48" + integrity sha512-p+taQ69VkRUXYMoZOx2nxV/Tz8tt79ahctoZJyJDHWP7fEYvwFNf5Pd73k5kZ6auu0pTsPNLEUwWpM8mCk85Zw== dependencies: chalk "^2.0.1" @@ -7074,7 +7430,7 @@ ssri@^5.2.4: dependencies: safe-buffer "^5.1.1" -ssri@^6.0.0: +ssri@^6.0.0, ssri@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" dependencies: @@ -7204,6 +7560,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -7228,12 +7591,13 @@ strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" -style-loader@0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.0.tgz#8377fefab68416a2e05f1cabd8c3a3acfcce74f1" +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== dependencies: loader-utils "^1.1.0" - schema-utils "^0.4.5" + schema-utils "^1.0.0" stylus-loader@3.0.2: version "3.0.2" @@ -7292,6 +7656,13 @@ supports-color@^5.4.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + symbol-observable@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -7343,6 +7714,19 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" +tar@^4.4.8: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + temp@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" @@ -7389,7 +7773,7 @@ through2@^2.0.0: readable-stream "^2.1.5" xtend "~4.0.1" -through@^2.3.6: +"through@>=2.2.7 <3", through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -7584,9 +7968,15 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" +typescript@3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68" + integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA== + +typescript@3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d" + integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== typescript@~3.1.1: version "3.1.1" @@ -7677,6 +8067,13 @@ unique-filename@^1.1.0: dependencies: unique-slug "^2.0.0" +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + unique-slug@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" @@ -7722,23 +8119,13 @@ url-join@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" -url-join@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" - -url-parse@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" +url-parse@^1.4.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== dependencies: - querystringify "0.0.x" - requires-port "1.0.x" - -url-parse@^1.1.8: - version "1.1.9" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19" - dependencies: - querystringify "~1.0.0" - requires-port "1.0.x" + querystringify "^2.0.0" + requires-port "^1.0.0" url@^0.11.0: version "0.11.0" @@ -7898,32 +8285,20 @@ webpack-core@^0.6.8: source-list-map "~0.1.7" source-map "~0.4.1" -webpack-dev-middleware@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.2.0.tgz#a20ceef194873710052da678f3c6ee0aeed92552" +webpack-dev-middleware@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" + integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== dependencies: - loud-rejection "^1.6.0" - memory-fs "~0.4.1" - mime "^2.3.1" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - url-join "^4.0.0" - webpack-log "^2.0.0" - -webpack-dev-middleware@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.3.0.tgz#8104daf4d4f65defe06ee2eaaeea612a7c541462" - dependencies: - loud-rejection "^1.6.0" memory-fs "~0.4.1" mime "^2.3.1" range-parser "^1.0.3" - url-join "^4.0.0" webpack-log "^2.0.0" -webpack-dev-server@3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.8.tgz#eb7a95945d1108170f902604fb3b939533d9daeb" +webpack-dev-server@3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.10.tgz#507411bee727ee8d2fdffdc621b66a64ab3dea2b" + integrity sha512-RqOAVjfqZJtQcB0LmrzJ5y4Jp78lv9CK0MZ1YJDTaTmedMZ9PU9FLMQNrMCfVu8hHzaVLVOJKBlGEHMN10z+ww== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -7946,11 +8321,11 @@ webpack-dev-server@3.1.8: selfsigned "^1.9.1" serve-index "^1.7.2" sockjs "0.3.19" - sockjs-client "1.1.5" + sockjs-client "1.3.0" spdy "^3.4.1" strip-ansi "^3.0.0" supports-color "^5.1.0" - webpack-dev-middleware "3.2.0" + webpack-dev-middleware "3.4.0" webpack-log "^2.0.0" yargs "12.0.2" @@ -7974,6 +8349,14 @@ webpack-sources@1.2.0, webpack-sources@^1.2.0: source-list-map "^2.0.0" source-map "~0.6.1" +webpack-sources@1.3.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + webpack-sources@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" @@ -7987,14 +8370,15 @@ webpack-subresource-integrity@1.1.0-rc.6: dependencies: webpack-core "^0.6.8" -webpack@4.19.1: - version "4.19.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.19.1.tgz#096674bc3b573f8756c762754366e5b333d6576f" +webpack@4.23.1: + version "4.23.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.23.1.tgz#db7467b116771ae020c58bdfe2a0822785bb8239" + integrity sha512-iE5Cu4rGEDk7ONRjisTOjVHv3dDtcFfwitSxT7evtYj/rANJpt1OuC/Kozh1pBa99AUBr1L/LsaNB+D9Xz3CEg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/wasm-edit" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-module-context" "1.7.10" + "@webassemblyjs/wasm-edit" "1.7.10" + "@webassemblyjs/wasm-parser" "1.7.10" acorn "^5.6.2" acorn-dynamic-import "^3.0.0" ajv "^6.1.0" @@ -8014,7 +8398,7 @@ webpack@4.19.1: tapable "^1.1.0" uglifyjs-webpack-plugin "^1.2.4" watchpack "^1.5.0" - webpack-sources "^1.2.0" + webpack-sources "^1.3.0" websocket-driver@>=0.5.1: version "0.7.0" @@ -8057,6 +8441,13 @@ which@1, which@^1.1.1, which@^1.2.1, which@^1.2.9: dependencies: isexe "^2.0.0" +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + which@~1.2.10: version "1.2.14" resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" diff --git a/aio/tools/ng-packages-installer/index.js b/aio/tools/ng-packages-installer/index.js index d8b6fd0670..7a913ba4d9 100644 --- a/aio/tools/ng-packages-installer/index.js +++ b/aio/tools/ng-packages-installer/index.js @@ -2,11 +2,14 @@ const chalk = require('chalk'); const fs = require('fs-extra'); +const lockfile = require('@yarnpkg/lockfile'); const path = require('canonical-path'); +const semver = require('semver'); const shelljs = require('shelljs'); const yargs = require('yargs'); const PACKAGE_JSON = 'package.json'; +const YARN_LOCK = 'yarn.lock'; const LOCAL_MARKER_PATH = 'node_modules/_local_.json'; const PACKAGE_JSON_REGEX = /^[^/]+\/package\.json$/; @@ -62,8 +65,10 @@ class NgPackagesInstaller { * contents and acts as an indicator that dependencies have been overridden. */ installLocalDependencies() { - if (this._checkLocalMarker() !== true || this.force) { + if (this.force || !this._checkLocalMarker()) { const pathToPackageConfig = path.resolve(this.projectDir, PACKAGE_JSON); + const pathToLockfile = path.resolve(this.projectDir, YARN_LOCK); + const parsedLockfile = this._parseLockfile(pathToLockfile); const packages = this._getDistPackages(); try { @@ -88,17 +93,17 @@ class NgPackagesInstaller { }); }); - fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(tmpConfig)); + fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(tmpConfig, null, 2)); }); - const packageConfigFile = fs.readFileSync(pathToPackageConfig); + const packageConfigFile = fs.readFileSync(pathToPackageConfig, 'utf8'); const packageConfig = JSON.parse(packageConfigFile); const [dependencies, peers] = this._collectDependencies(packageConfig.dependencies || {}, packages); const [devDependencies, devPeers] = this._collectDependencies(packageConfig.devDependencies || {}, packages); - this._assignPeerDependencies(peers, dependencies, devDependencies); - this._assignPeerDependencies(devPeers, dependencies, devDependencies); + this._assignPeerDependencies(peers, dependencies, devDependencies, parsedLockfile); + this._assignPeerDependencies(devPeers, dependencies, devDependencies, parsedLockfile); const localPackageConfig = Object.assign(Object.create(null), packageConfig, { dependencies, devDependencies }); localPackageConfig.__angular = { local: true }; @@ -107,7 +112,7 @@ class NgPackagesInstaller { try { this._log(`Writing temporary local ${PACKAGE_JSON} to ${pathToPackageConfig}`); fs.writeFileSync(pathToPackageConfig, localPackageConfigJson); - this._installDeps('--no-lockfile', '--check-files'); + this._installDeps('--pure-lockfile', '--check-files'); this._setLocalMarker(localPackageConfigJson); } finally { this._log(`Restoring original ${PACKAGE_JSON} to ${pathToPackageConfig}`); @@ -118,7 +123,7 @@ class NgPackagesInstaller { this._log(`Restoring original ${PACKAGE_JSON} for local Angular packages.`); Object.keys(packages).forEach(key => { const pkg = packages[key]; - fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(pkg.config)); + fs.writeFileSync(pkg.packageJsonPath, JSON.stringify(pkg.config, null, 2)); }); } } @@ -134,15 +139,23 @@ class NgPackagesInstaller { // Protected helpers - _assignPeerDependencies(peerDependencies, dependencies, devDependencies) { + _assignPeerDependencies(peerDependencies, dependencies, devDependencies, parsedLockfile) { Object.keys(peerDependencies).forEach(key => { + const peerDepRange = peerDependencies[key]; + + // Ignore peerDependencies whose range is already satisfied by current version in lockfile. + const originalRange = dependencies[key] || devDependencies[key]; + const lockfileVersion = originalRange && parsedLockfile[`${key}@${originalRange}`].version; + + if (lockfileVersion && semver.satisfies(lockfileVersion, peerDepRange)) return; + // If there is already an equivalent dependency then override it - otherwise assign/override the devDependency if (dependencies[key]) { - this._log(`Overriding dependency with peerDependency: ${key}: ${peerDependencies[key]}`); - dependencies[key] = peerDependencies[key]; + this._log(`Overriding dependency with peerDependency: ${key}: ${peerDepRange}`); + dependencies[key] = peerDepRange; } else { - this._log(`${devDependencies[key] ? 'Overriding' : 'Assigning'} devDependency with peerDependency: ${key}: ${peerDependencies[key]}`); - devDependencies[key] = peerDependencies[key]; + this._log(`${devDependencies[key] ? 'Overriding' : 'Assigning'} devDependency with peerDependency: ${key}: ${peerDepRange}`); + devDependencies[key] = peerDepRange; } }); } @@ -166,11 +179,6 @@ class NgPackagesInstaller { } }); - // FIXME: Temporarily use RxJS from root `node_modules/`. - if (peerDependencies.rxjs) { - peerDependencies.rxjs = `file:${ANGULAR_ROOT_DIR}/node_modules/rxjs`; - } - return [mergedDependencies, peerDependencies]; } @@ -226,6 +234,20 @@ class NgPackagesInstaller { } } + /** + * Parse and return a `yarn.lock` file. + */ + _parseLockfile(lockfilePath) { + const lockfileContent = fs.readFileSync(lockfilePath, 'utf8'); + const parsed = lockfile.parse(lockfileContent); + + if (parsed.type !== 'success') { + throw new Error(`[${NgPackagesInstaller.name}]: Error parsing lockfile '${lockfilePath}' (result type: ${parsed.type}).`); + } + + return parsed.object; + } + _printWarning() { const relativeScriptPath = path.relative('.', __filename.replace(/\.js$/, '')); const absoluteProjectDir = path.resolve(this.projectDir); diff --git a/aio/tools/ng-packages-installer/index.spec.js b/aio/tools/ng-packages-installer/index.spec.js index f205947380..681abd1d9f 100644 --- a/aio/tools/ng-packages-installer/index.spec.js +++ b/aio/tools/ng-packages-installer/index.spec.js @@ -1,6 +1,7 @@ 'use strict'; const fs = require('fs-extra'); +const lockfile = require('@yarnpkg/lockfile'); const path = require('canonical-path'); const shelljs = require('shelljs'); @@ -11,6 +12,7 @@ describe('NgPackagesInstaller', () => { const absoluteRootDir = path.resolve(rootDir); const nodeModulesDir = path.resolve(absoluteRootDir, 'node_modules'); const packageJsonPath = path.resolve(absoluteRootDir, 'package.json'); + const yarnLockPath = path.resolve(absoluteRootDir, 'yarn.lock'); const packagesDir = path.resolve(path.resolve(__dirname, '../../../dist/packages-dist')); const toolsDir = path.resolve(path.resolve(__dirname, '../../../dist/tools/@angular')); let installer; @@ -52,13 +54,26 @@ describe('NgPackagesInstaller', () => { beforeEach(() => { spyOn(installer, '_checkLocalMarker'); + spyOn(installer, '_installDeps'); + spyOn(installer, '_setLocalMarker'); + + spyOn(installer, '_parseLockfile').and.returnValue({ + 'rxjs@^6.3.0': {version: '6.3.3'}, + 'zone.js@^0.8.26': {version: '0.8.27'} + }); // These are the packages that are "found" in the dist directory dummyNgPackages = { '@angular/core': { parentDir: packagesDir, packageJsonPath: `${packagesDir}/core/package.json`, - config: { peerDependencies: { 'some-package': '5.0.1' } } + config: { + peerDependencies: { + 'rxjs': '^6.4.0', + 'some-package': '5.0.1', + 'zone.js': '~0.8.26' + } + } }, '@angular/common': { parentDir: packagesDir, @@ -93,10 +108,12 @@ describe('NgPackagesInstaller', () => { dummyPackage = { dependencies: { '@angular/core': '4.4.1', - '@angular/common': '4.4.1' + '@angular/common': '4.4.1', + rxjs: '^6.3.0' }, devDependencies: { - '@angular/compiler-cli': '4.4.1' + '@angular/compiler-cli': '4.4.1', + 'zone.js': '^0.8.26' } }; dummyPackageJson = JSON.stringify(dummyPackage); @@ -104,14 +121,23 @@ describe('NgPackagesInstaller', () => { // This is the package.json that is temporarily written to the "test" folder // Note that the Angular (dev)dependencies have been modified to use a "file:" path - // And that the peerDependencies from `dummyNgPackages` have been added as (dev)dependencies. + // And that the peerDependencies from `dummyNgPackages` have been updated or added as + // (dev)dependencies (unless the current version in lockfile satisfies semver). + // + // For example, `zone.js@0.8.27` (from lockfile) satisfies `zone.js@~0.8.26` (from + // `@angular/core`), thus `zone.js: ^0.8.26` (from original `package.json`) is retained. + // In contrast, `rxjs@6.3.3` (from lockfile) does not satisfy `rxjs@^6.4.0 (from + // `@angular/core`), thus `rxjs: ^6.3.0` (from original `package.json`) is replaced with + // `rxjs: ^6.4.0` (from `@angular/core`). expectedModifiedPackage = { dependencies: { '@angular/core': `file:${packagesDir}/core`, - '@angular/common': `file:${packagesDir}/common` + '@angular/common': `file:${packagesDir}/common`, + 'rxjs': '^6.4.0' }, devDependencies: { '@angular/compiler-cli': `file:${toolsDir}/compiler-cli`, + 'zone.js': '^0.8.26', 'some-package': '5.0.1', typescript: '^2.4.2' }, @@ -121,12 +147,20 @@ describe('NgPackagesInstaller', () => { }); describe('when there is a local package marker', () => { + beforeEach(() => installer._checkLocalMarker.and.returnValue(true)); + it('should not continue processing', () => { - installer._checkLocalMarker.and.returnValue(true); installer.installLocalDependencies(); expect(installer._checkLocalMarker).toHaveBeenCalled(); expect(installer._getDistPackages).not.toHaveBeenCalled(); }); + + it('should continue processing (without checking for local marker) if `force` is true', () => { + installer.force = true; + installer.installLocalDependencies(); + expect(installer._checkLocalMarker).not.toHaveBeenCalled(); + expect(installer._getDistPackages).toHaveBeenCalled(); + }); }); describe('when there is no local package marker', () => { @@ -135,14 +169,14 @@ describe('NgPackagesInstaller', () => { beforeEach(() => { log = []; fs.writeFileSync.and.callFake((filePath, contents) => filePath === packageJsonPath && log.push(`writeFile: ${contents}`)); - spyOn(installer, '_installDeps').and.callFake(() => log.push('installDeps:')); - spyOn(installer, '_setLocalMarker'); + installer._installDeps.and.callFake((...args) => log.push(`installDeps: ${args.join(' ')}`)); installer._checkLocalMarker.and.returnValue(false); installer.installLocalDependencies(); }); - it('should get the dist packages', () => { + it('should parse the lockfile and get the dist packages', () => { expect(installer._checkLocalMarker).toHaveBeenCalled(); + expect(installer._parseLockfile).toHaveBeenCalledWith(yarnLockPath); expect(installer._getDistPackages).toHaveBeenCalled(); }); @@ -150,31 +184,32 @@ describe('NgPackagesInstaller', () => { const pkgJsonFor = pkgName => dummyNgPackages[`@angular/${pkgName}`].packageJsonPath; const pkgConfigFor = pkgName => copyJsonObj(dummyNgPackages[`@angular/${pkgName}`].config); const overwriteConfigFor = (pkgName, newProps) => Object.assign(pkgConfigFor(pkgName), newProps); + const stringifyConfig = config => JSON.stringify(config, null, 2); const allArgs = fs.writeFileSync.calls.allArgs(); const firstFiveArgs = allArgs.slice(0, 5); const lastFiveArgs = allArgs.slice(-5); expect(firstFiveArgs).toEqual([ - [pkgJsonFor('core'), JSON.stringify(overwriteConfigFor('core', {private: true}))], - [pkgJsonFor('common'), JSON.stringify(overwriteConfigFor('common', {private: true}))], - [pkgJsonFor('compiler'), JSON.stringify(overwriteConfigFor('compiler', {private: true}))], - [pkgJsonFor('compiler-cli'), JSON.stringify(overwriteConfigFor('compiler-cli', { + [pkgJsonFor('core'), stringifyConfig(overwriteConfigFor('core', {private: true}))], + [pkgJsonFor('common'), stringifyConfig(overwriteConfigFor('common', {private: true}))], + [pkgJsonFor('compiler'), stringifyConfig(overwriteConfigFor('compiler', {private: true}))], + [pkgJsonFor('compiler-cli'), stringifyConfig(overwriteConfigFor('compiler-cli', { private: true, dependencies: { '@angular/tsc-wrapped': `file:${toolsDir}/tsc-wrapped` } }))], - [pkgJsonFor('tsc-wrapped'), JSON.stringify(overwriteConfigFor('tsc-wrapped', { + [pkgJsonFor('tsc-wrapped'), stringifyConfig(overwriteConfigFor('tsc-wrapped', { private: true, devDependencies: { '@angular/common': `file:${packagesDir}/common` } }))], ]); expect(lastFiveArgs).toEqual(['core', 'common', 'compiler', 'compiler-cli', 'tsc-wrapped'] - .map(pkgName => [pkgJsonFor(pkgName), JSON.stringify(pkgConfigFor(pkgName))])); + .map(pkgName => [pkgJsonFor(pkgName), stringifyConfig(pkgConfigFor(pkgName))])); }); it('should load the package.json', () => { - expect(fs.readFileSync).toHaveBeenCalledWith(packageJsonPath); + expect(fs.readFileSync).toHaveBeenCalledWith(packageJsonPath, 'utf8'); }); it('should overwrite package.json with modified config', () => { @@ -188,7 +223,7 @@ describe('NgPackagesInstaller', () => { it('should overwrite package.json, then install deps, then restore original package.json', () => { expect(log).toEqual([ `writeFile: ${expectedModifiedPackageJson}`, - `installDeps:`, + `installDeps: --pure-lockfile --check-files`, `writeFile: ${dummyPackageJson}` ]); }); @@ -264,6 +299,42 @@ describe('NgPackagesInstaller', () => { }); }); + describe('_parseLockfile()', () => { + let originalLockfileParseDescriptor; + + beforeEach(() => { + // Workaround for `lockfile.parse()` being non-writable. + let parse = lockfile.parse; + originalLockfileParseDescriptor = Object.getOwnPropertyDescriptor(lockfile, 'parse'); + Object.defineProperty(lockfile, 'parse', { + get() { return parse; }, + set(newParse) { parse = newParse; }, + }); + + fs.readFileSync.and.returnValue('mock content'); + spyOn(lockfile, 'parse').and.returnValue({type: 'success', object: {foo: {version: 'bar'}}}); + }); + + afterEach(() => Object.defineProperty(lockfile, 'parse', originalLockfileParseDescriptor)); + + it('should parse the specified lockfile', () => { + installer._parseLockfile('/foo/bar/yarn.lock'); + expect(fs.readFileSync).toHaveBeenCalledWith('/foo/bar/yarn.lock', 'utf8'); + expect(lockfile.parse).toHaveBeenCalledWith('mock content'); + }); + + it('should throw if parsing the lockfile fails', () => { + lockfile.parse.and.returnValue({type: 'not success'}); + expect(() => installer._parseLockfile('/foo/bar/yarn.lock')).toThrowError( + '[NgPackagesInstaller]: Error parsing lockfile \'/foo/bar/yarn.lock\' (result type: not success).'); + }); + + it('should return the parsed lockfile content as an object', () => { + const parsed = installer._parseLockfile('/foo/bar/yarn.lock'); + expect(parsed).toEqual({foo: {version: 'bar'}}); + }); + }); + describe('_printWarning()', () => { it('should mention the message passed in the warning', () => { installer._printWarning(); diff --git a/aio/tools/stackblitz-builder/builder.js b/aio/tools/stackblitz-builder/builder.js index d55d6308f0..807b4c95e9 100644 --- a/aio/tools/stackblitz-builder/builder.js +++ b/aio/tools/stackblitz-builder/builder.js @@ -51,9 +51,9 @@ class StackblitzBuilder { } _buildCopyrightStrings() { - var copyright = 'Copyright 2017-2018 Google Inc. All Rights Reserved.\n' - + 'Use of this source code is governed by an MIT-style license that\n' - + 'can be found in the LICENSE file at http://angular.io/license'; + var copyright = 'Copyright Google LLC. All Rights Reserved.\n' + + 'Use of this source code is governed by an MIT-style license that\n' + + 'can be found in the LICENSE file at http://angular.io/license'; var pad = '\n\n'; this.copyrights.jsCss = `${pad}/*\n${copyright}\n*/`; this.copyrights.html = `${pad}`; diff --git a/aio/tools/transforms/cli-docs-package/processors/processCliCommands.js b/aio/tools/transforms/cli-docs-package/processors/processCliCommands.js index 3df3095ade..f39b7d6e39 100644 --- a/aio/tools/transforms/cli-docs-package/processors/processCliCommands.js +++ b/aio/tools/transforms/cli-docs-package/processors/processCliCommands.js @@ -1,10 +1,14 @@ -module.exports = function processCliCommands() { +module.exports = function processCliCommands(createDocMessage) { return { $runAfter: ['extra-docs-added'], $runBefore: ['rendering-docs'], $process(docs) { const navigationDoc = docs.find(doc => doc.docType === 'navigation-json'); - const navigationNode = navigationDoc && navigationDoc.data['SideNav'].find(node => node.title === 'CLI Commands'); + const navigationNode = navigationDoc && navigationDoc.data['SideNav'].find(node => node.children && node.children.length && node.children[0].url === 'cli'); + + if (!navigationNode) { + throw new Error(createDocMessage('Missing `cli` url - CLI Commands must include a first child node with url set at `cli`', navigationDoc)); + } docs.forEach(doc => { if (doc.docType === 'cli-command') { @@ -14,9 +18,7 @@ module.exports = function processCliCommands() { processOptions(doc, doc.options); // Add to navigation doc - if (navigationNode) { - navigationNode.children.push({ url: doc.path, title: `ng ${doc.name}` }); - } + navigationNode.children.push({ url: doc.path, title: `ng ${doc.name}` }); } }); } @@ -28,11 +30,6 @@ function processOptions(container, options) { container.namedOptions = []; options.forEach(option => { - - if (option.type === 'boolean' && option.default === undefined) { - option.default = false; - } - // Ignore any hidden options if (option.hidden) { return; } diff --git a/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js b/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js index cb80985ae2..5ab862f0c7 100644 --- a/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js +++ b/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js @@ -1,41 +1,51 @@ const testPackage = require('../../helpers/test-package'); -const processorFactory = require('./processCliCommands'); const Dgeni = require('dgeni'); describe('processCliCommands processor', () => { + let dgeni, injector, processor, createDocMessage; + + const navigationStub = { + docType: 'navigation-json', + data: { + SideNav: [{ + children: [{'url': 'cli'}] + }] + } + }; + + beforeEach(() => { + dgeni = new Dgeni([testPackage('cli-docs-package')]); + injector = dgeni.configureInjector(); + processor = injector.get('processCliCommands'); + createDocMessage = injector.get('createDocMessage'); + }); + it('should be available on the injector', () => { - const dgeni = new Dgeni([testPackage('cli-docs-package')]); - const injector = dgeni.configureInjector(); - const processor = injector.get('processCliCommands'); expect(processor.$process).toBeDefined(); }); it('should run after the correct processor', () => { - const processor = processorFactory(); expect(processor.$runAfter).toEqual(['extra-docs-added']); }); it('should run before the correct processor', () => { - const processor = processorFactory(); expect(processor.$runBefore).toEqual(['rendering-docs']); }); it('should collect the names (name + aliases)', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', commandAliases: ['alias1', 'alias2'], options: [], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.names).toEqual(['name', 'alias1', 'alias2']); }); describe('options', () => { it('should remove the hidden options', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', @@ -47,7 +57,7 @@ describe('processCliCommands processor', () => { { name: 'option4', hidden: true }, ], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.namedOptions).toEqual([ jasmine.objectContaining({ name: 'option1' }), jasmine.objectContaining({ name: 'option3' }), @@ -55,7 +65,6 @@ describe('processCliCommands processor', () => { }); it('should collect the non-hidden positional and named options', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', @@ -67,7 +76,7 @@ describe('processCliCommands processor', () => { { name: 'positional2', hidden: true, positional: 1}, ], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.positionalOptions).toEqual([ jasmine.objectContaining({ name: 'positional1', positional: 0}), ]); @@ -77,7 +86,6 @@ describe('processCliCommands processor', () => { }); it('should sort the named options into order by name', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', @@ -88,7 +96,7 @@ describe('processCliCommands processor', () => { { name: 'b' }, ], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.namedOptions).toEqual([ jasmine.objectContaining({ name: 'a' }), jasmine.objectContaining({ name: 'b' }), @@ -99,7 +107,6 @@ describe('processCliCommands processor', () => { describe('subcommands', () => { it('should convert subcommands hash into a collection', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', @@ -124,7 +131,7 @@ describe('processCliCommands processor', () => { }, }], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.options[0].subcommands).toEqual([ jasmine.objectContaining({ name: 'subcommand1' }), jasmine.objectContaining({ name: 'subcommand2' }), @@ -132,7 +139,6 @@ describe('processCliCommands processor', () => { }); it('should remove the hidden subcommand options', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', @@ -157,7 +163,7 @@ describe('processCliCommands processor', () => { }, }], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.options[0].subcommands[0].namedOptions).toEqual([ jasmine.objectContaining({ name: 'subcommand1-option1' }), ]); @@ -167,7 +173,6 @@ describe('processCliCommands processor', () => { }); it('should collect the non-hidden positional arguments and named options', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', @@ -192,7 +197,7 @@ describe('processCliCommands processor', () => { }, }], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.options[0].subcommands[0].positionalOptions).toEqual([ jasmine.objectContaining({ name: 'subcommand1-option2', positional: 0}), ]); @@ -205,7 +210,6 @@ describe('processCliCommands processor', () => { }); it('should sort the named subcommand options into order by name', () => { - const processor = processorFactory(); const doc = { docType: 'cli-command', name: 'name', @@ -224,7 +228,7 @@ describe('processCliCommands processor', () => { } }], }; - processor.$process([doc]); + processor.$process([doc, navigationStub]); expect(doc.options[0].subcommands[0].namedOptions).toEqual([ jasmine.objectContaining({ name: 'a' }), jasmine.objectContaining({ name: 'b' }), @@ -233,8 +237,7 @@ describe('processCliCommands processor', () => { }); }); - it('should add the command to the CLI node in the navigation doc', () => { - const processor = processorFactory(); + it('should add the command to the CLI node in the navigation doc if there is a first child node with a `cli` url', () => { const command = { docType: 'cli-command', name: 'command1', @@ -247,18 +250,55 @@ describe('processCliCommands processor', () => { data: { SideNav: [ { url: 'some/page', title: 'Some Page' }, - { url: 'cli', title: 'CLI Commands', children: [ - { url: 'cli', title: 'Using the CLI' }, - ]}, - { url: 'other/page', title: 'Other Page' }, + { + title: 'CLI Commands', + tooltip: 'Angular CLI command reference', + children: [ + { + 'title': 'Overview', + 'url': 'cli' + } + ] + }, + { url: 'other/page', title: 'Other Page' } ] } }; processor.$process([command, navigation]); expect(navigation.data.SideNav[1].title).toEqual('CLI Commands'); expect(navigation.data.SideNav[1].children).toEqual([ - { url: 'cli', title: 'Using the CLI' }, + { url: 'cli', title: 'Overview' }, { url: 'cli/command1', title: 'ng command1' }, ]); }); + + it('should complain if there is no child with `cli` url', () => { + const command = { + docType: 'cli-command', + name: 'command1', + commandAliases: ['alias1', 'alias2'], + options: [], + path: 'cli/command1', + }; + const navigation = { + docType: 'navigation-json', + data: { + SideNav: [ + { url: 'some/page', title: 'Some Page' }, + { + title: 'CLI Commands', + tooltip: 'Angular CLI command reference', + children: [ + { + 'title': 'Overview', + 'url': 'client' + } + ] + }, + { url: 'other/page', title: 'Other Page' } + ] + } + }; + expect(() => processor.$process([command, navigation])).toThrowError(createDocMessage('Missing `cli` url - CLI Commands must include a first child node with url set at `cli`', navigation)); + }); }); diff --git a/aio/tools/transforms/templates/api/lib/memberHelpers.html b/aio/tools/transforms/templates/api/lib/memberHelpers.html index 9c59a2740c..457987b3fb 100644 --- a/aio/tools/transforms/templates/api/lib/memberHelpers.html +++ b/aio/tools/transforms/templates/api/lib/memberHelpers.html @@ -95,6 +95,13 @@ {% if method.shortDescription %} {$ method.shortDescription | marked $} + {%- if method.see.length %} +

See also:

+
    + {% for see in method.see %} +
  • {$ see | marked $}
  • {% endfor %} +
+ {% endif %} {% endif %} {% if method.overloads.length == 0 %} @@ -203,10 +210,17 @@ {%- if (property.isGetAccessor or property.isReadonly) and not property.isSetAccessor %}只读{% endif %} {%- if property.isSetAccessor and not property.isGetAccessor %}Write-only.{% endif %} + {% if property.constructorParamDoc %} Declared in constructor.{% endif %} {% if property.shortDescription %}{$ property.shortDescription | marked $}{% endif %} {$ (property.description or property.constructorParamDoc.description) | marked $} - {% if property.constructorParamDoc %} 声明于构造函数中{% endif %} - + {%- if property.see.length %} +

参见:

+
    + {% for see in property.see %} +
  • {$ see | marked $}
  • {% endfor %} +
+ {% endif %} + {% endfor %} diff --git a/aio/tools/transforms/templates/cli/lib/cli.html b/aio/tools/transforms/templates/cli/lib/cli.html index 591124d58e..655f21c636 100644 --- a/aio/tools/transforms/templates/cli/lib/cli.html +++ b/aio/tools/transforms/templates/cli/lib/cli.html @@ -53,9 +53,16 @@ {% for option in options %} - {$ renderOption(option.name, option.type, option.default, option.enum) $} + {$ renderOption(option.name, option.type, option.default, option.enum) $} + {% if option.deprecated %} + {% if option.deprecated === true %} +

Deprecated

+ {% else %} + {$ ('**Deprecated:** ' + option.deprecated) | marked $} + {% endif %} + {% endif %} {$ option.description | marked $} {% if option.default !== undefined %}

默认值: {$ option.default $}

{% endif %} {% if option.aliases.length %}

别名: {% for alias in option.aliases %}{$ renderOptionName(alias) $}{% if not loop.last %}, {% endif %}{% endfor %}

{% endif %} diff --git a/aio/tslint.json b/aio/tslint.json index 693598c511..bb06be5d56 100644 --- a/aio/tslint.json +++ b/aio/tslint.json @@ -75,6 +75,7 @@ ], "radix": true, "semicolon": [ + true, "always" ], "triple-equals": [ diff --git a/aio/yarn.lock b/aio/yarn.lock index eaec5b4d7e..99220e2640 100644 --- a/aio/yarn.lock +++ b/aio/yarn.lock @@ -2,118 +2,104 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.10.1": - version "0.10.1" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.10.1.tgz#73996383ba040f858bf06595e90805c3f3bff1fe" +"@angular-devkit/architect@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.1.tgz#397768d1ccd0cef76db96d6b39db8aebad68c031" + integrity sha512-1ozBP0ZAApkSfuPpZ7b9vShU8smNxb98jW+65S12cPOxv1bVVxCj5sTmC3sSfXapgq/pMzblbaVSKOG7Ajz0vQ== dependencies: - "@angular-devkit/core" "7.0.1" + "@angular-devkit/core" "7.2.1" rxjs "6.3.3" -"@angular-devkit/architect@0.12.0-beta.2": - version "0.12.0-beta.2" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.0-beta.2.tgz#8fa8e0c7173b49fa06a844de78bf03a7e23ab5fe" - integrity sha512-RKp1xeMene28Ae3v8zJz70shqwzLeW+oN+lIu5VRNTz1veHGxbRRTng45LQsuDjQfnErVSc0N4/uFj6ZW0rUGg== +"@angular-devkit/build-angular@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.12.1.tgz#6aaa05413e8cbf9a49f263fa9808524efa57ecb9" + integrity sha512-TpaMgKECEm1Tta4jkvZVzWdbq2OakIwVyYSzZ/7ARVe0FXhEjVLgWB1pYAdhRx+Hv4/E2ZSPJW1J3N3DTE4W4Q== dependencies: - "@angular-devkit/core" "7.2.0-beta.2" - rxjs "6.3.3" - -"@angular-devkit/build-angular@~0.10.0": - version "0.10.1" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.10.1.tgz#6eccfd2eec4778c65e6b38b20304bfa5f134a4f1" - dependencies: - "@angular-devkit/architect" "0.10.1" - "@angular-devkit/build-optimizer" "0.10.1" - "@angular-devkit/build-webpack" "0.10.1" - "@angular-devkit/core" "7.0.1" - "@ngtools/webpack" "7.0.1" - ajv "6.5.3" - autoprefixer "8.4.1" + "@angular-devkit/architect" "0.12.1" + "@angular-devkit/build-optimizer" "0.12.1" + "@angular-devkit/build-webpack" "0.12.1" + "@angular-devkit/core" "7.2.1" + "@ngtools/webpack" "7.2.1" + ajv "6.6.2" + autoprefixer "9.4.3" circular-dependency-plugin "5.0.2" clean-css "4.2.1" - copy-webpack-plugin "4.5.2" + copy-webpack-plugin "4.6.0" file-loader "2.0.0" glob "7.1.3" istanbul "0.4.5" istanbul-instrumenter-loader "3.0.1" karma-source-map-support "1.3.0" - less "3.8.1" + less "3.9.0" less-loader "4.1.0" - license-webpack-plugin "2.0.1" + license-webpack-plugin "2.0.4" loader-utils "1.1.0" - mini-css-extract-plugin "0.4.3" + mini-css-extract-plugin "0.4.4" minimatch "3.0.4" opn "5.3.0" parse5 "4.0.0" portfinder "1.0.17" - postcss "6.0.23" - postcss-import "11.1.0" - postcss-loader "2.1.6" + postcss "7.0.5" + postcss-import "12.0.0" + postcss-loader "3.0.0" raw-loader "0.5.1" rxjs "6.3.3" sass-loader "7.1.0" semver "5.5.1" source-map-loader "0.2.4" source-map-support "0.5.9" - speed-measure-webpack-plugin "^1.2.3" + speed-measure-webpack-plugin "1.2.3" stats-webpack-plugin "0.7.0" - style-loader "0.23.0" + style-loader "0.23.1" stylus "0.54.5" stylus-loader "3.0.2" terser-webpack-plugin "1.1.0" tree-kill "1.2.0" - webpack "4.19.1" - webpack-dev-middleware "3.3.0" - webpack-dev-server "3.1.8" + webpack "4.23.1" + webpack-dev-middleware "3.4.0" + webpack-dev-server "3.1.14" webpack-merge "4.1.4" - webpack-sources "1.2.0" + webpack-sources "1.3.0" webpack-subresource-integrity "1.1.0-rc.6" optionalDependencies: - node-sass "4.9.3" + node-sass "4.10.0" -"@angular-devkit/build-optimizer@0.10.1": - version "0.10.1" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.10.1.tgz#09b1daaa375e03f768b46d995c111dd93ee802f0" +"@angular-devkit/build-optimizer@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.12.1.tgz#2160d75ca7d43fd91402538b0f5cc3a7a1037f10" + integrity sha512-zYea22pJ5kvMud8UBrdzIcR9F1FDYWJ3vwj5WRUFM0sF7mbbrmTC+OsIvNI7qDJuXWNZGySwNlHw0e+rhv30gg== dependencies: loader-utils "1.1.0" source-map "0.5.6" - typescript "3.1.3" + typescript "3.2.2" webpack-sources "1.2.0" -"@angular-devkit/build-webpack@0.10.1": - version "0.10.1" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.10.1.tgz#5101c0099067d6c09e0b17d03637e15ec1c2ef2c" +"@angular-devkit/build-webpack@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.12.1.tgz#f0dd128b864d81192339cfb34d1958f53fccb6ae" + integrity sha512-eDNgR2EV9/l4xYTkvS3861TthUv8ERBroWpMkkniX3HhpyjgaLyI5P1OB7fVMcF3RvJsxIlqYGRZ6zx7PjCbcA== dependencies: - "@angular-devkit/architect" "0.10.1" - "@angular-devkit/core" "7.0.1" + "@angular-devkit/architect" "0.12.1" + "@angular-devkit/core" "7.2.1" rxjs "6.3.3" -"@angular-devkit/core@7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.0.1.tgz#78e6af0be6364532186bf4ac2e1da0f1685d95cb" +"@angular-devkit/core@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.1.tgz#8c6df59eab77bcc98a348c8cdf9eb217c8b751a5" + integrity sha512-zOozPswSM1cTkltw5LeSPoZ/fJ2d3vN304IVgKgrM5/Fs54bd7nTaBcAK+HvjKS+5KmykYrXW47Q4CdFJikluQ== dependencies: - ajv "6.5.3" + ajv "6.6.2" chokidar "2.0.4" fast-json-stable-stringify "2.0.0" rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/core@7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.0-beta.2.tgz#bce756c9cabff24ec3d0f0aefe0e462e2a70de2e" - integrity sha512-aHvCxWifBWKEezARfNUgBQVcmKT42Mt8/1rnTVZcQF+YC/84Ad4L2B7NLwkXj8gkBsy+ghWJUzVrM0TvLlrQeQ== +"@angular-devkit/schematics@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.2.1.tgz#9c1c784f4a81a3a840fa4a1435948c6203be6062" + integrity sha512-jEhwkeDn8exgJBfUwMc6rdtDkxHJkUmKPTn4M436bkMMMa9KFPFbPpzp9weKpB3SbRjM3Mu90JprO4C7qDtCcg== dependencies: - ajv "6.5.3" - chokidar "2.0.4" - fast-json-stable-stringify "2.0.0" - rxjs "6.3.3" - source-map "0.7.3" - -"@angular-devkit/schematics@7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.2.0-beta.2.tgz#ef332966e66ae92f7a6a1169df7e5010928ab9c8" - integrity sha512-WEySXUS+0Vw9nVXTKzJfAcPcOIBk45tE1xs3MYk1BCbxEjT2QXWIDNDeBuNigvy3xQ5iQ2iWqXYwoFBUOrpEiQ== - dependencies: - "@angular-devkit/core" "7.2.0-beta.2" + "@angular-devkit/core" "7.2.1" rxjs "6.3.3" "@angular/animations@^7.0.0": @@ -130,17 +116,17 @@ optionalDependencies: parse5 "^5.0.0" -"@angular/cli@7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.2.0-beta.2.tgz#50ca5e2bd3642be72f5e6cf686c81af0b2ed3cbb" - integrity sha512-Id/nYyZa/0LQDkYhN3XyO7YL1kzIK3PPwM336kyXQSdDvh4ZANxqbinSTPozgl5LrmIOByf4BxqZ4Fs8Br5S3A== +"@angular/cli@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.2.1.tgz#cef405a6edc2747aa004f758c691496a81edc8d1" + integrity sha512-KA5HE+s2ZBV9T+3XAvLXZulvPzp2BQKEKCoj6aefZB+TZASeatXO8keDDm2+N/8zqoqSe/akf6hvB/u9x0xJ3w== dependencies: - "@angular-devkit/architect" "0.12.0-beta.2" - "@angular-devkit/core" "7.2.0-beta.2" - "@angular-devkit/schematics" "7.2.0-beta.2" - "@schematics/angular" "7.2.0-beta.2" - "@schematics/update" "0.12.0-beta.2" - inquirer "6.2.0" + "@angular-devkit/architect" "0.12.1" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + "@schematics/angular" "7.2.1" + "@schematics/update" "0.12.1" + inquirer "6.2.1" opn "5.3.0" semver "5.5.1" symbol-observable "1.2.0" @@ -320,11 +306,12 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" -"@ngtools/webpack@7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.0.1.tgz#c3a341674808e9d7938abb36e8eeeed0818acd23" +"@ngtools/webpack@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.2.1.tgz#8b801b93697fdeff348b0ffa6a440b42a91f8395" + integrity sha512-/mpXSyaHBP+wfiEt/ZYNsnUmnDmdUkLL1rcNxDyxMxlrL246CtNUcMzYSVqYiKp7ufz6GNklY2QqUa9pcOlW6Q== dependencies: - "@angular-devkit/core" "7.0.1" + "@angular-devkit/core" "7.2.1" enhanced-resolve "4.1.0" rxjs "6.3.3" tree-kill "1.2.0" @@ -335,22 +322,22 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -"@schematics/angular@7.2.0-beta.2": - version "7.2.0-beta.2" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.2.0-beta.2.tgz#e4015906cfc2cf40c9bd1eed3f7b8fcfc34133f4" - integrity sha512-s1grejDByxqRdLRSnHZsDZgQeoMTyyBx4HHMgMkFj//ZBO8Q6Sx02Lu4zybgg6DQuVf/DDAMi9Gl9uRR4PHdKw== +"@schematics/angular@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.2.1.tgz#9eeab1354ec8d970121cc067e9636098ab84e152" + integrity sha512-UdqU8udVr693BZ6uaZ7+el/VFlTjrmp56OS+6YaziyAko84e1Q1Fcx+fwdHugy4V3YmQhTVsyOPSEsphnwSwOA== dependencies: - "@angular-devkit/core" "7.2.0-beta.2" - "@angular-devkit/schematics" "7.2.0-beta.2" - typescript "3.1.6" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + typescript "3.2.2" -"@schematics/update@0.12.0-beta.2": - version "0.12.0-beta.2" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.12.0-beta.2.tgz#dd9a4e9b2baa217db5071f6dd91f129c5952f4a6" - integrity sha512-7jREVAInNJKKOwjgrwUO41u34EL1iLiXmmMtYU5JSRRQzFGXxiYiO6dUViu8wBfo03a3DLPPMnnaP4BU3HUShg== +"@schematics/update@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.12.1.tgz#44d853321ae8a56c43a579c0639d26d625001037" + integrity sha512-P92tDxy0AA1NPhaThiJ7fIFxIC4jzlGK7sJlpbnRREBImsI/O9gmGaV8Kjy+75vaEjqpWaU2oj1hnWqkmxSK1A== dependencies: - "@angular-devkit/core" "7.2.0-beta.2" - "@angular-devkit/schematics" "7.2.0-beta.2" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" "@yarnpkg/lockfile" "1.1.0" ini "1.3.5" pacote "9.1.1" @@ -436,6 +423,15 @@ version "2.53.42" resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz#74cb77fb6052edaff2a8984ddafd88d419f25cac" +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== + +"@types/webpack-sources@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" + integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== "@types/uglify-js@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" @@ -452,129 +448,151 @@ version "1.7.6" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.6.tgz#3ef8c45b3e5e943a153a05281317474fef63e21e" dependencies: - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" - mamacro "^0.0.3" + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" -"@webassemblyjs/floating-point-hex-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz#7cb37d51a05c3fe09b464ae7e711d1ab3837801f" - -"@webassemblyjs/helper-api-error@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz#99b7e30e66f550a2638299a109dda84a622070ef" - -"@webassemblyjs/helper-buffer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz#ba0648be12bbe560c25c997e175c2018df39ca3e" - -"@webassemblyjs/helper-code-frame@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz#5a94d21b0057b69a7403fca0c253c3aaca95b1a5" +"@webassemblyjs/ast@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.10.tgz#0cfc61d61286240b72fc522cb755613699eea40a" + integrity sha512-wTUeaByYN2EA6qVqhbgavtGc7fLTOx0glG2IBsFlrFG51uXIGlYBTyIZMf4SPLo3v1bgV/7lBN3l7Z0R6Hswew== dependencies: - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/helper-module-context" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/wast-parser" "1.7.10" -"@webassemblyjs/helper-fsm@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz#ae1741c6f6121213c7a0b587fb964fac492d3e49" +"@webassemblyjs/floating-point-hex-parser@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.10.tgz#ee63d729c6311a85863e369a473f9983f984e4d9" + integrity sha512-gMsGbI6I3p/P1xL2UxqhNh1ga2HCsx5VBB2i5VvJFAaqAjd2PBTRULc3BpTydabUQEGlaZCzEUQhLoLG7TvEYQ== -"@webassemblyjs/helper-module-context@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz#116d19a51a6cebc8900ad53ca34ff8269c668c23" +"@webassemblyjs/helper-api-error@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.10.tgz#bfcb3bbe59775357475790a2ad7b289f09b2f198" + integrity sha512-DoYRlPWtuw3yd5BOr9XhtrmB6X1enYF0/54yNvQWGXZEPDF5PJVNI7zQ7gkcKfTESzp8bIBWailaFXEK/jjCsw== + +"@webassemblyjs/helper-buffer@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.10.tgz#0a8c624c67ad0b214d2e003859921a1988cb151b" + integrity sha512-+RMU3dt/dPh4EpVX4u5jxsOlw22tp3zjqE0m3ftU2tsYxnPULb4cyHlgaNd2KoWuwasCQqn8Mhr+TTdbtj3LlA== + +"@webassemblyjs/helper-code-frame@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.10.tgz#0ab7e22fad0241a173178c73976fc0edf50832ce" + integrity sha512-UiytbpKAULOEab2hUZK2ywXen4gWJVrgxtwY3Kn+eZaaSWaRM8z/7dAXRSoamhKFiBh1uaqxzE/XD9BLlug3gw== dependencies: - mamacro "^0.0.3" + "@webassemblyjs/wast-printer" "1.7.10" -"@webassemblyjs/helper-wasm-bytecode@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz#98e515eaee611aa6834eb5f6a7f8f5b29fefb6f1" +"@webassemblyjs/helper-fsm@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.10.tgz#0915e7713fbbb735620a9d3e4fa3d7951f97ac64" + integrity sha512-w2vDtUK9xeSRtt5+RnnlRCI7wHEvLjF0XdnxJpgx+LJOvklTZPqWkuy/NhwHSLP19sm9H8dWxKeReMR7sCkGZA== -"@webassemblyjs/helper-wasm-section@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz#783835867bdd686df7a95377ab64f51a275e8333" +"@webassemblyjs/helper-module-context@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.10.tgz#9beb83f72740f5ac8075313b5cac5e796510f755" + integrity sha512-yE5x/LzZ3XdPdREmJijxzfrf+BDRewvO0zl8kvORgSWmxpRrkqY39KZSq6TSgIWBxkK4SrzlS3BsMCv2s1FpsQ== + +"@webassemblyjs/helper-wasm-bytecode@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.10.tgz#797b1e734bbcfdea8399669cdc58308ef1c7ffc0" + integrity sha512-u5qy4SJ/OrxKxZqJ9N3qH4ZQgHaAzsopsYwLvoWJY6Q33r8PhT3VPyNMaJ7ZFoqzBnZlCcS/0f4Sp8WBxylXfg== + +"@webassemblyjs/helper-wasm-section@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.10.tgz#c0ea3703c615d7bc3e3507c3b7991c8767b2f20e" + integrity sha512-Ecvww6sCkcjatcyctUrn22neSJHLN/TTzolMGG/N7S9rpbsTZ8c6Bl98GpSpV77EvzNijiNRHBG0+JO99qKz6g== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-buffer" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/wasm-gen" "1.7.10" -"@webassemblyjs/ieee754@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz#c34fc058f2f831fae0632a8bb9803cf2d3462eb1" +"@webassemblyjs/ieee754@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.10.tgz#62c1728b7ef0f66ef8221e2966a0afd75db430df" + integrity sha512-HRcWcY+YWt4+s/CvQn+vnSPfRaD4KkuzQFt5MNaELXXHSjelHlSEA8ZcqT69q0GTIuLWZ6JaoKar4yWHVpZHsQ== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.6.tgz#197f75376a29f6ed6ace15898a310d871d92f03b" +"@webassemblyjs/leb128@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.10.tgz#167e0bb4b06d7701585772a73fba9f4df85439f6" + integrity sha512-og8MciYlA8hvzCLR71hCuZKPbVBfLQeHv7ImKZ4nlyxrYbG7uJHYtHiHu6OV9SqrGuD03H/HtXC4Bgdjfm9FHw== dependencies: "@xtuc/long" "4.2.1" -"@webassemblyjs/utf8@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.6.tgz#eb62c66f906af2be70de0302e29055d25188797d" +"@webassemblyjs/utf8@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.10.tgz#b6728f5b6f50364abc155be029f9670e6685605a" + integrity sha512-Ng6Pxv6siyZp635xCSnH3mKmIFgqWPCcGdoo0GBYgyGdxu7cUj4agV7Uu1a8REP66UYUFXJLudeGgd4RvuJAnQ== -"@webassemblyjs/wasm-edit@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz#fa41929160cd7d676d4c28ecef420eed5b3733c5" +"@webassemblyjs/wasm-edit@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.10.tgz#83fe3140f5a58f5a30b914702be9f0e59a399092" + integrity sha512-e9RZFQlb+ZuYcKRcW9yl+mqX/Ycj9+3/+ppDI8nEE/NCY6FoK8f3dKBcfubYV/HZn44b+ND4hjh+4BYBt+sDnA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/helper-wasm-section" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-opt" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-buffer" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/helper-wasm-section" "1.7.10" + "@webassemblyjs/wasm-gen" "1.7.10" + "@webassemblyjs/wasm-opt" "1.7.10" + "@webassemblyjs/wasm-parser" "1.7.10" + "@webassemblyjs/wast-printer" "1.7.10" -"@webassemblyjs/wasm-gen@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz#695ac38861ab3d72bf763c8c75e5f087ffabc322" +"@webassemblyjs/wasm-gen@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.10.tgz#4de003806ae29c97ab3707782469b53299570174" + integrity sha512-M0lb6cO2Y0PzDye/L39PqwV+jvO+2YxEG5ax+7dgq7EwXdAlpOMx1jxyXJTScQoeTpzOPIb+fLgX/IkLF8h2yw== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/ieee754" "1.7.10" + "@webassemblyjs/leb128" "1.7.10" + "@webassemblyjs/utf8" "1.7.10" -"@webassemblyjs/wasm-opt@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz#fbafa78e27e1a75ab759a4b658ff3d50b4636c21" +"@webassemblyjs/wasm-opt@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.10.tgz#d151e31611934a556c82789fdeec41a814993c2a" + integrity sha512-R66IHGCdicgF5ZliN10yn5HaC7vwYAqrSVJGjtJJQp5+QNPBye6heWdVH/at40uh0uoaDN/UVUfXK0gvuUqtVg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-buffer" "1.7.10" + "@webassemblyjs/wasm-gen" "1.7.10" + "@webassemblyjs/wasm-parser" "1.7.10" -"@webassemblyjs/wasm-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz#84eafeeff405ad6f4c4b5777d6a28ae54eed51fe" +"@webassemblyjs/wasm-parser@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.10.tgz#0367be7bf8f09e3e6abc95f8e483b9206487ec65" + integrity sha512-AEv8mkXVK63n/iDR3T693EzoGPnNAwKwT3iHmKJNBrrALAhhEjuPzo/lTE4U7LquEwyvg5nneSNdTdgrBaGJcA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-api-error" "1.7.10" + "@webassemblyjs/helper-wasm-bytecode" "1.7.10" + "@webassemblyjs/ieee754" "1.7.10" + "@webassemblyjs/leb128" "1.7.10" + "@webassemblyjs/utf8" "1.7.10" -"@webassemblyjs/wast-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz#ca4d20b1516e017c91981773bd7e819d6bd9c6a7" +"@webassemblyjs/wast-parser@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.10.tgz#058f598b52f730b23fc874d4775b6286b6247264" + integrity sha512-YTPEtOBljkCL0VjDp4sHe22dAYSm3ZwdJ9+2NTGdtC7ayNvuip1wAhaAS8Zt9Q6SW9E5Jf5PX7YE3XWlrzR9cw== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/floating-point-hex-parser" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-code-frame" "1.7.6" - "@webassemblyjs/helper-fsm" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/floating-point-hex-parser" "1.7.10" + "@webassemblyjs/helper-api-error" "1.7.10" + "@webassemblyjs/helper-code-frame" "1.7.10" + "@webassemblyjs/helper-fsm" "1.7.10" "@xtuc/long" "4.2.1" - mamacro "^0.0.3" -"@webassemblyjs/wast-printer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz#a6002c526ac5fa230fe2c6d2f1bdbf4aead43a5e" +"@webassemblyjs/wast-printer@1.7.10": + version "1.7.10" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.10.tgz#d817909d2450ae96c66b7607624d98a33b84223b" + integrity sha512-mJ3QKWtCchL1vhU/kZlJnLPuQZnlDOdZsyP0bbLWPGdYsQDnSBvyTLhzwBA3QAMlzEL9V4JHygEmK6/OTEyytA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/wast-parser" "1.7.10" "@xtuc/long" "4.2.1" "@webcomponents/custom-elements@^1.2.0": @@ -589,7 +607,7 @@ version "4.2.1" resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" -"@yarnpkg/lockfile@1.1.0": +"@yarnpkg/lockfile@1.1.0", "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== @@ -742,9 +760,10 @@ ajv-keywords@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" -ajv@6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" +ajv@6.6.2: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -844,6 +863,11 @@ ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -874,9 +898,10 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -app-root-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46" +app-root-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.1.0.tgz#98bf6599327ecea199309866e8140368fd2e646a" + integrity sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo= append-transform@^0.4.0: version "0.4.0" @@ -1121,16 +1146,17 @@ atob@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" -autoprefixer@8.4.1: - version "8.4.1" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-8.4.1.tgz#c6b30001ea4b3daa6b611e50071f62dd24beb564" +autoprefixer@9.4.3: + version "9.4.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.3.tgz#c97384a8fd80477b78049163a91bbc725d9c41d9" + integrity sha512-/XSnzDepRkAU//xLcXA/lUWxpsBuw0WiriAHOqnxkuCtzLhaz+fL4it4gp20BQ8n5SyLzK/FOc7A0+u/rti2FQ== dependencies: - browserslist "^3.2.6" - caniuse-lite "^1.0.30000832" + browserslist "^4.3.6" + caniuse-lite "^1.0.30000921" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^6.0.22" - postcss-value-parser "^3.2.3" + postcss "^7.0.6" + postcss-value-parser "^3.3.1" aws-sign2@~0.6.0: version "0.6.0" @@ -1516,12 +1542,14 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^3.2.6: - version "3.2.8" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" +browserslist@^4.3.6: + version "4.4.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.0.tgz#7050d1412cbfc5274aba609ed5e50359ca1a5fdf" + integrity sha512-tQkHS8VVxWbrjnNDXgt7/+SuPJ7qDvD0Y2e6bLtoQluR2SPvlmPUcfcU75L1KAalhqULlIFJlJ6BDfnYyJxJsw== dependencies: - caniuse-lite "^1.0.30000844" - electron-to-chromium "^1.3.47" + caniuse-lite "^1.0.30000928" + electron-to-chromium "^1.3.100" + node-releases "^1.1.3" buffer-crc32@^0.2.1: version "0.2.13" @@ -1704,9 +1732,10 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== -caniuse-lite@^1.0.30000832, caniuse-lite@^1.0.30000844: - version "1.0.30000890" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000890.tgz#86a18ffcc65d79ec6a437e985761b8bf1c4efeaf" +caniuse-lite@^1.0.30000921, caniuse-lite@^1.0.30000928: + version "1.0.30000928" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000928.tgz#805e828dc72b06498e3683a32e61c7507fd67b88" + integrity sha512-aSpMWRXL6ZXNnzm8hgE4QDLibG5pVJ2Ujzsuj3icazlIkxXkPXtL+BWnMx6FBkWmkZgBHGUxPZQvrbRw2ZTxhg== canonical-path@0.0.2, canonical-path@~0.0.2: version "0.0.2" @@ -1775,7 +1804,7 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" -chalk@^2.3.0, chalk@^2.3.2: +chalk@^2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: @@ -1791,6 +1820,15 @@ chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + change-case@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.0.0.tgz#6c9c8e35f8790870a82b6b0745be8c3cbef9b081" @@ -2090,16 +2128,17 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -codelyzer@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.2.1.tgz#d56eaacefca7e8138aac0a630e484bdb09988544" +codelyzer@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.5.0.tgz#a65ddeeeca2894653253a89bfa229118ff9f59b1" + integrity sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ== dependencies: - app-root-path "^2.0.1" + app-root-path "^2.1.0" css-selector-tokenizer "^0.7.0" cssauron "^1.4.0" semver-dsl "^1.0.1" - source-map "^0.5.6" - sprintf-js "^1.0.3" + source-map "^0.5.7" + sprintf-js "^1.1.1" coffee-script@^1.12.5: version "1.12.7" @@ -2399,9 +2438,10 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" -copy-webpack-plugin@4.5.2: - version "4.5.2" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.5.2.tgz#d53444a8fea2912d806e78937390ddd7e632ee5c" +copy-webpack-plugin@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" + integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -2658,7 +2698,7 @@ debug@*, debug@3.1.0, debug@=3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@2, debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: +debug@2, debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2676,9 +2716,17 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@^3.0.0: +debug@^3.0.0, debug@^3.2.5: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" @@ -2849,9 +2897,10 @@ detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" -detect-node@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== devtools-timeline-model@1.1.6: version "1.1.6" @@ -2860,10 +2909,10 @@ devtools-timeline-model@1.1.6: chrome-devtools-frontend "1.0.401423" resolve "1.1.7" -dgeni-packages@^0.27.0: - version "0.27.0" - resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.27.0.tgz#99ddf4c97f75bb1f8deb5658ed7d60f6894e9b9d" - integrity sha512-BFWJGZTpLb1xAc/iHq7SOcbkyEoxD57NqVG84azfNu63wAVLxoez/9n8VISWNJkrOIT1ITQS7nacgcGxfl0MIw== +dgeni-packages@^0.27.1: + version "0.27.1" + resolved "https://registry.yarnpkg.com/dgeni-packages/-/dgeni-packages-0.27.1.tgz#f23d78fd3e222910106e45186e1c2e64649464fc" + integrity sha512-zM2HgMni9FvfBFHv2uhWrWRUV0CpaWl4ggoajbGLMT+TEqxkSPKRkCkCQMHek7ZYSXbPdpVb8DuoEKEem74X4g== dependencies: canonical-path "^1.0.0" catharsis "^0.8.1" @@ -3097,9 +3146,10 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.3.47: - version "1.3.77" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.77.tgz#9207a874a21a8fcb665bb4ff1675a11ba65517f4" +electron-to-chromium@^1.3.100: + version "1.3.102" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.102.tgz#3ac43a037c8a63bca3dfa189eb3d90f097196787" + integrity sha512-2nzZuXw/KBPnI3QX3UOCSRvJiVy7o9+VHRDQ3D/EHCvVc89X6aj/GlNmEgiR2GBIhmSWXIi4W1M5okA5ScSlNg== elliptic@^6.0.0: version "6.4.0" @@ -3476,11 +3526,12 @@ events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" -eventsource@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== dependencies: - original ">=0.0.5" + original "^1.0.0" evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" @@ -3753,9 +3804,10 @@ fastparse@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" -faye-websocket@>=0.6.0, faye-websocket@~0.11.0: +faye-websocket@>=0.6.0, faye-websocket@~0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg= dependencies: websocket-driver ">=0.5.1" @@ -4541,9 +4593,10 @@ gtoken@^2.3.0: mime "^2.2.0" pify "^3.0.0" -handle-thing@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== handlebars@^4.0.1, handlebars@^4.0.3: version "4.0.11" @@ -5113,9 +5166,10 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" -inquirer@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" +inquirer@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" + integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -5128,7 +5182,7 @@ inquirer@6.2.0: run-async "^2.2.0" rxjs "^6.1.0" string-width "^2.1.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" through "^2.3.6" inquirer@^0.12.0: @@ -6120,9 +6174,10 @@ less-loader@4.1.0: loader-utils "^1.1.0" pify "^3.0.0" -less@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/less/-/less-3.8.1.tgz#f31758598ef5a1930dd4caefa9e4340641e71e1d" +less@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/less/-/less-3.9.0.tgz#b7511c43f37cf57dc87dffd9883ec121289b1474" + integrity sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w== dependencies: clone "^2.1.2" optionalDependencies: @@ -6142,10 +6197,12 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -license-webpack-plugin@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.0.1.tgz#d8d24d0d0db70d328ec911ae728719b842260078" +license-webpack-plugin@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.0.4.tgz#48532e7d7b45f6ceb21a68b6826ce7241d7ea6da" + integrity sha512-FQgOqrrIcD4C/VQo6ecWgXZULK5rs0kIDJtHcSVO6SBUrD63kEHZwmKOvBTquFQSgMQn/yeH68qooKDfqiBF2Q== dependencies: + "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" lie@~3.1.0: @@ -6412,7 +6469,7 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" -loud-rejection@^1.0.0, loud-rejection@^1.6.0: +loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" dependencies: @@ -6509,10 +6566,6 @@ make-fetch-happen@^4.0.1: socks-proxy-agent "^4.0.0" ssri "^6.0.0" -mamacro@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" - map-age-cleaner@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74" @@ -6777,9 +6830,10 @@ mimic-response@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" -mini-css-extract-plugin@0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.3.tgz#98d60fcc5d228c3e36a9bd15a1d6816d6580beb8" +mini-css-extract-plugin@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.4.tgz#c10410a004951bd3cedac1da69053940fccb625d" + integrity sha512-o+Jm+ocb0asEngdM6FsZWtZsRzA8koFUudIDwYUfl94M3PejPHG7Vopw5hN9V8WsMkSFpm3tZP3Fesz89EyrfQ== dependencies: loader-utils "^1.1.0" schema-utils "^1.0.0" @@ -7162,9 +7216,17 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" -node-sass@4.9.3: - version "4.9.3" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.3.tgz#f407cf3d66f78308bb1e346b24fa428703196224" +node-releases@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.3.tgz#aad9ce0dcb98129c753f772c0aa01360fb90fbd2" + integrity sha512-6VrvH7z6jqqNFY200kdB6HdzkgM96Oaj9v3dqGfgp6mF+cHmU4wyQKZ2/WPDRVoR0Jz9KqbamaBN0ZhdUaysUQ== + dependencies: + semver "^5.3.0" + +node-sass@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.10.0.tgz#dcc2b364c0913630945ccbf7a2bbf1f926effca4" + integrity sha512-fDQJfXszw6vek63Fe/ldkYXmRYK/QS6NbvM3i5oEo9ntPDy4XX7BcKZyTKv+/kSSxRtXXc7l+MSwEmYc0CSy6Q== dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -7181,7 +7243,7 @@ node-sass@4.9.3: nan "^2.10.0" node-gyp "^3.8.0" npmlog "^4.0.0" - request "2.87.0" + request "^2.88.0" sass-graph "^2.2.4" stdout-stream "^1.4.0" "true-case-path" "^1.0.2" @@ -7382,7 +7444,7 @@ objectdiff@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/objectdiff/-/objectdiff-1.1.0.tgz#8d7a15be6cb8670df8a490cc6be12a4f05ea82f4" -obuf@^1.0.0, obuf@^1.1.1: +obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -7462,11 +7524,12 @@ ora@0.2.3: cli-spinners "^0.1.2" object-assign "^4.0.1" -original@>=0.0.5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== dependencies: - url-parse "1.0.x" + url-parse "^1.4.3" os-browserify@^0.3.0: version "0.3.0" @@ -7920,11 +7983,12 @@ posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" -postcss-import@11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-11.1.0.tgz#55c9362c9192994ec68865d224419df1db2981f0" +postcss-import@12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-12.0.0.tgz#149f96a4ef0b27525c419784be8517ebd17e92c5" + integrity sha512-3KqKRZcaZAvxbY8DVLdd81tG5uKzbUQuiWIvy0o0fzEC42bKacqPYFWbfCQyw6L4LWUaqPz/idvIdbhpgQ32eQ== dependencies: - postcss "^6.0.1" + postcss "^7.0.1" postcss-value-parser "^3.2.3" read-cache "^1.0.0" resolve "^1.1.7" @@ -7936,42 +8000,42 @@ postcss-load-config@^2.0.0: cosmiconfig "^4.0.0" import-cwd "^2.0.0" -postcss-loader@2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-2.1.6.tgz#1d7dd7b17c6ba234b9bed5af13e0bea40a42d740" +postcss-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== dependencies: loader-utils "^1.1.0" - postcss "^6.0.0" + postcss "^7.0.0" postcss-load-config "^2.0.0" - schema-utils "^0.4.0" + schema-utils "^1.0.0" postcss-value-parser@^3.2.3: version "3.3.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" -postcss@6.0.23: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" +postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss@7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.5.tgz#70e6443e36a6d520b0fd4e7593fcca3635ee9f55" + integrity sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ== dependencies: chalk "^2.4.1" source-map "^0.6.1" - supports-color "^5.4.0" + supports-color "^5.5.0" -postcss@^6.0.0, postcss@^6.0.1: - version "6.0.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.21.tgz#8265662694eddf9e9a5960db6da33c39e4cd069d" +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.6: + version "7.0.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.11.tgz#f63c513b78026d66263bb2ca995bf02e3d1a697d" + integrity sha512-9AXb//5UcjeOEof9T+yPw3XTa5SL207ZOIC/lHYP4mbUTEh4M0rDAQekQpVANCZdwQwKhBtFZCk3i3h3h2hdWg== dependencies: - chalk "^2.3.2" + chalk "^2.4.2" source-map "^0.6.1" - supports-color "^5.3.0" - -postcss@^6.0.22: - version "6.0.22" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.22.tgz#e23b78314905c3b90cbd61702121e7a78848f2a3" - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" + supports-color "^6.1.0" postinstall-build@^5.0.1: version "5.0.3" @@ -8233,13 +8297,10 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -querystringify@0.0.x: - version "0.0.4" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" - -querystringify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" +querystringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" + integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== randomatic@^1.1.3: version "1.1.7" @@ -8365,7 +8426,7 @@ read@1.0.x: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.1, readable-stream@^2.0.4, readable-stream@^2.1.4, readable-stream@^2.2.9, readable-stream@^2.3.3: +"readable-stream@1 || 2", readable-stream@^2.0.1, readable-stream@^2.0.4, readable-stream@^2.1.4, readable-stream@^2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -8389,6 +8450,15 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~1.0.3" util-deprecate "~1.0.1" +readable-stream@^3.0.6: + version "3.1.1" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" + integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readable-stream@~1.0.2: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" @@ -8684,31 +8754,6 @@ request@2.86.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - request@^2.72.0, request@^2.74.0, request@^2.78.0, request@^2.79.0, request@^2.81.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" @@ -8807,7 +8852,7 @@ require-uncached@^1.0.2: caller-path "^0.1.0" resolve-from "^1.0.0" -requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: +requires-port@1.x.x, requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -9055,7 +9100,7 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" -schema-utils@^0.4.0, schema-utils@^0.4.4, schema-utils@^0.4.5: +schema-utils@^0.4.4, schema-utils@^0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" dependencies: @@ -9411,16 +9456,17 @@ socket.io@1.7.3: socket.io-client "1.7.3" socket.io-parser "2.3.1" -sockjs-client@1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.5.tgz#1bb7c0f7222c40f42adf14f4442cbd1269771a83" +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== dependencies: - debug "^2.6.6" - eventsource "0.1.6" - faye-websocket "~0.11.0" - inherits "^2.0.1" + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" json3 "^3.3.2" - url-parse "^1.1.8" + url-parse "^1.4.3" sockjs@0.3.19: version "0.3.19" @@ -9476,7 +9522,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@0.5.9, source-map-support@^0.5.5, source-map-support@~0.5.6: +source-map-support@0.5.9, source-map-support@^0.5.5: version "0.5.9" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" dependencies: @@ -9489,6 +9535,14 @@ source-map-support@^0.4.0, source-map-support@^0.4.15, source-map-support@~0.4.0 dependencies: source-map "^0.5.6" +source-map-support@~0.5.9: + version "0.5.10" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" + integrity sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -9555,32 +9609,33 @@ spdx-license-list@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/spdx-license-list/-/spdx-license-list-2.1.0.tgz#3788ffb5c80b24afbe8283934e9e6684ea6a218d" -spdy-transport@^2.0.18: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.0.tgz#4bbb15aaffed0beefdd56ad61dbdc8ba3e2cb7a1" +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== dependencies: - debug "^2.6.8" - detect-node "^2.0.3" + debug "^4.1.0" + detect-node "^2.0.4" hpack.js "^2.1.6" - obuf "^1.1.1" - readable-stream "^2.2.9" - safe-buffer "^5.0.1" - wbuf "^1.7.2" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" -spdy@^3.4.1: - version "3.4.7" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== dependencies: - debug "^2.6.8" - handle-thing "^1.2.5" + debug "^4.1.0" + handle-thing "^2.0.0" http-deceiver "^1.2.7" - safe-buffer "^5.0.1" select-hose "^2.0.0" - spdy-transport "^2.0.18" + spdy-transport "^3.0.0" -speed-measure-webpack-plugin@^1.2.3: +speed-measure-webpack-plugin@1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.2.3.tgz#de170b5cefbfa1c039d95e639edd3ad50cfc7c48" + integrity sha512-p+taQ69VkRUXYMoZOx2nxV/Tz8tt79ahctoZJyJDHWP7fEYvwFNf5Pd73k5kZ6auu0pTsPNLEUwWpM8mCk85Zw== dependencies: chalk "^2.0.1" @@ -9605,9 +9660,10 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -sprintf-js@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== sprintf-js@~1.0.2: version "1.0.3" @@ -9770,6 +9826,13 @@ string_decoder@^1.0.0, string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -9814,6 +9877,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -9842,12 +9912,13 @@ stubs@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" -style-loader@0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.0.tgz#8377fefab68416a2e05f1cabd8c3a3acfcce74f1" +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== dependencies: loader-utils "^1.1.0" - schema-utils "^0.4.5" + schema-utils "^1.0.0" stylus-loader@3.0.2: version "3.0.2" @@ -9937,6 +10008,13 @@ supports-color@^5.5.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + swap-case@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3" @@ -10062,13 +10140,14 @@ terser-webpack-plugin@1.1.0: webpack-sources "^1.1.0" worker-farm "^1.5.2" -terser@^3.8.1: - version "3.10.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-3.10.0.tgz#6ae15dafecbd02c9788d5f36d27fca32196b533a" +terser@3.16.1, terser@^3.8.1: + version "3.16.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.16.1.tgz#5b0dd4fa1ffd0b0b43c2493b2c364fd179160493" + integrity sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow== dependencies: commander "~2.17.1" source-map "~0.6.1" - source-map-support "~0.5.6" + source-map-support "~0.5.9" text-table@~0.2.0: version "0.2.0" @@ -10385,24 +10464,15 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" - -typescript@3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68" - integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA== +typescript@3.2.2, typescript@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" + integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== typescript@^2.4.1: version "2.6.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" -typescript@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" - integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== - uglify-es@^3.3.4: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" @@ -10693,6 +10763,10 @@ url-join@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/url-join/-/url-join-0.0.1.tgz#1db48ad422d3402469a87f7d97bdebfe4fb1e3c8" +url-join@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" + url-join@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" @@ -10709,19 +10783,13 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@1.0.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.0.5.tgz#0854860422afdcfefeb6c965c662d4800169927b" +url-parse@^1.4.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== dependencies: - querystringify "0.0.x" - requires-port "1.0.x" - -url-parse@^1.1.8: - version "1.3.0" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.3.0.tgz#04a06c420d22beb9804f7ada2d57ad13160a4258" - dependencies: - querystringify "~1.0.0" - requires-port "~1.0.0" + querystringify "^2.0.0" + requires-port "^1.0.0" url-to-options@^1.0.1: version "1.0.1" @@ -10759,7 +10827,7 @@ useragent@^2.1.12: lru-cache "2.2.x" tmp "0.0.x" -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -10950,16 +11018,12 @@ watchr@^3.0.1: scandirectory "^2.5.0" taskgroup "^5.0.1" -wbuf@^1.1.0, wbuf@^1.7.2: +wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" dependencies: minimalistic-assert "^1.0.0" -web-animations-js@^2.2.5: - version "2.3.1" - resolved "https://registry.yarnpkg.com/web-animations-js/-/web-animations-js-2.3.1.tgz#3a6d9bc15196377a90f8e2803fa5262165b04510" - web-namespaces@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.2.tgz#c8dc267ab639505276bae19e129dbd6ae72b22b4" @@ -11014,32 +11078,20 @@ webpack-core@^0.6.8: source-list-map "~0.1.7" source-map "~0.4.1" -webpack-dev-middleware@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.2.0.tgz#a20ceef194873710052da678f3c6ee0aeed92552" +webpack-dev-middleware@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" + integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== dependencies: - loud-rejection "^1.6.0" - memory-fs "~0.4.1" - mime "^2.3.1" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - url-join "^4.0.0" - webpack-log "^2.0.0" - -webpack-dev-middleware@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.3.0.tgz#8104daf4d4f65defe06ee2eaaeea612a7c541462" - dependencies: - loud-rejection "^1.6.0" memory-fs "~0.4.1" mime "^2.3.1" range-parser "^1.0.3" - url-join "^4.0.0" webpack-log "^2.0.0" -webpack-dev-server@3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.8.tgz#eb7a95945d1108170f902604fb3b939533d9daeb" +webpack-dev-server@3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" + integrity sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -11060,13 +11112,15 @@ webpack-dev-server@3.1.8: portfinder "^1.0.9" schema-utils "^1.0.0" selfsigned "^1.9.1" + semver "^5.6.0" serve-index "^1.7.2" sockjs "0.3.19" - sockjs-client "1.1.5" - spdy "^3.4.1" + sockjs-client "1.3.0" + spdy "^4.0.0" strip-ansi "^3.0.0" supports-color "^5.1.0" - webpack-dev-middleware "3.2.0" + url "^0.11.0" + webpack-dev-middleware "3.4.0" webpack-log "^2.0.0" yargs "12.0.2" @@ -11090,16 +11144,16 @@ webpack-sources@1.2.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" +webpack-sources@1.3.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" dependencies: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" +webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" dependencies: source-list-map "^2.0.0" source-map "~0.6.1" @@ -11110,14 +11164,15 @@ webpack-subresource-integrity@1.1.0-rc.6: dependencies: webpack-core "^0.6.8" -webpack@4.19.1: - version "4.19.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.19.1.tgz#096674bc3b573f8756c762754366e5b333d6576f" +webpack@4.23.1: + version "4.23.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.23.1.tgz#db7467b116771ae020c58bdfe2a0822785bb8239" + integrity sha512-iE5Cu4rGEDk7ONRjisTOjVHv3dDtcFfwitSxT7evtYj/rANJpt1OuC/Kozh1pBa99AUBr1L/LsaNB+D9Xz3CEg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/wasm-edit" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.10" + "@webassemblyjs/helper-module-context" "1.7.10" + "@webassemblyjs/wasm-edit" "1.7.10" + "@webassemblyjs/wasm-parser" "1.7.10" acorn "^5.6.2" acorn-dynamic-import "^3.0.0" ajv "^6.1.0" @@ -11137,7 +11192,7 @@ webpack@4.19.1: tapable "^1.1.0" uglifyjs-webpack-plugin "^1.2.4" watchpack "^1.5.0" - webpack-sources "^1.2.0" + webpack-sources "^1.3.0" websocket-driver@>=0.5.1: version "0.7.0" diff --git a/bower.json b/bower.json deleted file mode 100644 index 007371a434..0000000000 --- a/bower.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "angular", - "dependencies": { - "polymer": "Polymer/polymer#^1.6.0" - } -} diff --git a/browser-providers.conf.js b/browser-providers.conf.js index 7676be87eb..f7c7a5bafb 100644 --- a/browser-providers.conf.js +++ b/browser-providers.conf.js @@ -10,7 +10,7 @@ // and BrowserStack (BS). // If the target is set to null, then the browser is not run anywhere during CI. // If a category becomes empty (e.g. BS and required), then the corresponding job must be commented -// out in Travis configuration. +// out in the CI configuration. var CIconfiguration = { 'Chrome': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}}, 'Firefox': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}}, diff --git a/browser_repositories.bzl b/browser_repositories.bzl new file mode 100644 index 0000000000..facd7cd9be --- /dev/null +++ b/browser_repositories.bzl @@ -0,0 +1,113 @@ +# Copyright 2018 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Pinned browser versions. + +This function is here temporarily to fix https://github.com/angular/angular/issues/28681. +It will be removed once the browser versions are fixed upstream and we can pull +working versions from rules_webtesting browser_repositories(). + +TODO(gregmagolan): remove this file once we have working browser versions from rules_webtesting. +""" + +load("@io_bazel_rules_webtesting//web/internal:platform_http_file.bzl", "platform_http_file") + +def browser_repositories(): + """Load pinned rules_webtesting browser versions.""" + + platform_http_file( + name = "org_chromium_chromium", + amd64_sha256 = + "941de83d78b27d43db07f427136ba159d661bb111db8d9ffe12499b863a003e1", + amd64_urls = [ + # Chromium 69.0.3497.0 (2018-07-19 snaphot 576668) + # https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Linux_x64/576668/ + "https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/576668/chrome-linux.zip", + ], + licenses = ["notice"], # BSD 3-clause (maybe more?) + macos_sha256 = + "bd01783e7d179e9f85d4b6f0c9df53118d13977cc7d365a1caa9d198c6afcfd8", + macos_urls = [ + # Chromium 69.0.3497.0 (2018-07-19 snaphot 576668) + # https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/576668/ + "https://commondatastorage.googleapis.com/chromium-browser-snapshots/Mac/576668/chrome-mac.zip", + ], + windows_sha256 = + "2997d6231867688a2bceb49af1d8dbdbe6ea5de848b98d686d40dd153ae4d271", + windows_urls = [ + # Chromium 69.0.3497.0 (2018-07-19 snaphot 576668) + # https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Win_x64/576668/ + "https://commondatastorage.googleapis.com/chromium-browser-snapshots/Win_x64/576668/chrome-win32.zip", + ], + ) + + platform_http_file( + name = "org_chromium_chromedriver", + amd64_sha256 = + "687d2e15c42908e2911344c08a949461b3f20a83017a7a682ef4d002e05b5d46", + amd64_urls = [ + # ChromeDriver 2.44 supports Chrome v69-71 + # http://chromedriver.chromium.org/downloads + "https://chromedriver.storage.googleapis.com/2.44/chromedriver_linux64.zip", + ], + licenses = ["reciprocal"], # BSD 3-clause, ICU, MPL 1.1, libpng (BSD/MIT-like), Academic Free License v. 2.0, BSD 2-clause, MIT + macos_sha256 = + "3fd49c2782a5f93cb48ff2dee021004d9a7fb393798e4c4807b391cedcd30ed9", + macos_urls = [ + # ChromeDriver 2.44 supports Chrome v69-71 + # http://chromedriver.chromium.org/downloads + "https://chromedriver.storage.googleapis.com/2.44/chromedriver_mac64.zip", + ], + windows_sha256 = + "5d2d2ddb2ed3730672484160c822b75b41c4e77f9cadb5111530699d561c548c", + windows_urls = [ + # ChromeDriver 2.44 supports Chrome v69-71 + # http://chromedriver.chromium.org/downloads + "https://chromedriver.storage.googleapis.com/2.44/chromedriver_win32.zip", + ], + ) + + platform_http_file( + name = "org_mozilla_firefox", + amd64_sha256 = + "3a729ddcb1e0f5d63933177a35177ac6172f12edbf9fbbbf45305f49333608de", + amd64_urls = [ + "https://mirror.bazel.build/ftp.mozilla.org/pub/firefox/releases/61.0.2/linux-x86_64/en-US/firefox-61.0.2.tar.bz2", + "https://ftp.mozilla.org/pub/firefox/releases/61.0.2/linux-x86_64/en-US/firefox-61.0.2.tar.bz2", + ], + licenses = ["reciprocal"], # MPL 2.0 + macos_sha256 = + "bf23f659ae34832605dd0576affcca060d1077b7bf7395bc9874f62b84936dc5", + macos_urls = [ + "https://mirror.bazel.build/ftp.mozilla.org/pub/firefox/releases/61.0.2/mac/en-US/Firefox%2061.0.2.dmg", + "https://ftp.mozilla.org/pub/firefox/releases/61.0.2/mac/en-US/Firefox%2061.0.2.dmg", + ], + ) + + platform_http_file( + name = "org_mozilla_geckodriver", + amd64_sha256 = + "c9ae92348cf00aa719be6337a608fae8304691a95668e8e338d92623ba9e0ec6", + amd64_urls = [ + "https://mirror.bazel.build/github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-linux64.tar.gz", + "https://github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-linux64.tar.gz", + ], + licenses = ["reciprocal"], # MPL 2.0 + macos_sha256 = + "ce4a3e9d706db94e8760988de1ad562630412fa8cf898819572522be584f01ce", + macos_urls = [ + "https://mirror.bazel.build/github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-macos.tar.gz", + "https://github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-macos.tar.gz", + ], + ) diff --git a/build.sh b/build.sh deleted file mode 100755 index 722b1fc2ea..0000000000 --- a/build.sh +++ /dev/null @@ -1,557 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -readonly currentDir=$(cd $(dirname $0); pwd) -source ${currentDir}/scripts/ci/_travis-fold.sh - -# TODO(i): wrap into subshell, so that we don't pollute CWD, but not yet to minimize diff collision with Jason -cd ${currentDir} - -PACKAGES=(compiler - core - common - animations - platform-browser - platform-browser-dynamic - forms - http - platform-server - platform-webworker - platform-webworker-dynamic - upgrade - router - compiler-cli - language-service - benchpress - service-worker - elements) - -TSC_PACKAGES=(compiler - compiler-cli - language-service - benchpress) - -NODE_PACKAGES=(compiler-cli - benchpress) - -SCOPED_PACKAGES=$( - for P in ${PACKAGES[@]}; do echo \\@angular/${P}; done -) -NG_UPDATE_PACKAGE_GROUP=$( - # The first sed creates an array of strings - # The second sed is to allow it to be run in the perl expression so forward slashes don't end - # the regular expression. - echo \[\"${SCOPED_PACKAGES[@]}\"] \ - | sed 's/ /", "/g' \ - | sed 's/\//\\\//g' -) - - -BUILD_ALL=true -BUNDLE=true -VERSION_PREFIX=$(node -p "require('./package.json').version") -VERSION_SUFFIX="-$(git log --oneline -1 | awk '{print $1}')" -REMOVE_BENCHPRESS=false -BUILD_EXAMPLES=true -COMPILE_SOURCE=true -TYPECHECK_ALL=true -BUILD_TOOLS=true -export NODE_PATH=${NODE_PATH:-}:${currentDir}/dist/tools - -for ARG in "$@"; do - case "$ARG" in - --quick-bundle=*) - COMPILE_SOURCE=false - TYPECHECK_ALL=false - BUILD_EXAMPLES=false - BUILD_TOOLS=false - ;; - --packages=*) - PACKAGES_STR=${ARG#--packages=} - PACKAGES=( ${PACKAGES_STR//,/ } ) - BUILD_ALL=false - ;; - --bundle=*) - BUNDLE=( "${ARG#--bundle=}" ) - ;; - --publish) - VERSION_SUFFIX="" - REMOVE_BENCHPRESS=true - ;; - --examples=*) - BUILD_EXAMPLES=${ARG#--examples=} - ;; - --compile=*) - COMPILE_SOURCE=${ARG#--compile=} - ;; - --typecheck=*) - TYPECHECK_ALL=${ARG#--typecheck=} - ;; - --tools=*) - BUILD_TOOLS=${ARG#--tools=} - ;; - *) - echo "Unknown option $ARG." - exit 1 - ;; - esac -done - -####################################### -# Verifies a directory isn't in the ignored list -# Arguments: -# param1 - Path to check -# Returns: -# Boolean -####################################### -isIgnoredDirectory() { - name=$(basename ${1}) - if [[ -f "${1}" || "${name}" == "src" || "${name}" == "test" || "${name}" == "integrationtest" || "${name}" == "locales" ]]; then - return 0 - else - return 1 - fi -} - -####################################### -# Check if array contains an element -# Arguments: -# param1 - Element to check -# param2 - Array to look for element in -# Returns: -# None -####################################### -containsElement () { - local e - for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done - return 1 -} - -####################################### -# Rollup index files recursively, ignoring blacklisted directories -# Arguments: -# param1 - Base source folder -# param2 - Destination directory -# param3 - Package name -# param4 - Is sub directory -# Returns: -# None -####################################### -rollupIndex() { - # Iterate over the files in this directory, rolling up each into ${2} directory - in_file="${1}/${3}.js" - if [ ${4:-} ]; then - out_file="$(dropLast ${2})/${3}.js" - else - out_file="${2}/${3}.js" - fi - - BANNER_TEXT=`cat ${LICENSE_BANNER}` - if [[ -f ${in_file} ]]; then - echo "=========== $ROLLUP -i ${in_file} -o ${out_file} --sourcemap -f es --banner BANNER_TEXT >/dev/null 2>&1" - $ROLLUP -i ${in_file} -o ${out_file} --sourcemap -f es --banner "$BANNER_TEXT" >/dev/null 2>&1 - fi - - # Recurse for sub directories - for DIR in ${1}/* ; do - local sub_package=$(basename "${DIR}") - isIgnoredDirectory ${DIR} && continue - local regex=".+/(.+)/${sub_package}.js" - if [[ "${DIR}/${sub_package}.js" =~ $regex ]]; then - - rollupIndex ${DIR} ${2}/${BASH_REMATCH[1]} ${sub_package} true - fi - done -} - -####################################### -# Recursively runs rollup on any entry point that has a "rollup.config.js" file -# Arguments: -# param1 - Base source folder containing rollup.config.js -# Returns: -# None -####################################### -runRollup() { - if [[ -f "${1}/rollup.config.js" ]]; then - cd ${1} - - echo "====== $ROLLUP -c ${1}/rollup.config.js --sourcemap" - $ROLLUP -c rollup.config.js --sourcemap >/dev/null 2>&1 - - # Recurse for sub directories - for DIR in ${1}/* ; do - isIgnoredDirectory ${DIR} && continue - runRollup ${DIR} - done - fi -} - -####################################### -# Adds banners to all files in a directory -# Arguments: -# param1 - Directory to add license banners to -# Returns: -# None -####################################### -addBanners() { - for file in ${1}/*; do - if [[ -f ${file} && "${file##*.}" != "map" ]]; then - cat ${LICENSE_BANNER} > ${file}.tmp - cat ${file} >> ${file}.tmp - mv ${file}.tmp ${file} - fi - done -} - -####################################### -# Minifies files in a directory -# Arguments: -# param1 - Directory to minify -# Returns: -# None -####################################### -minify() { - # Iterate over the files in this directory, rolling up each into ${2} directory - regex="(.+).js" - files=(${1}/*) - echo "${files[@]}" - for file in "${files[@]}"; do - echo "${file}" - base_file=$( basename "${file}" ) - if [[ "${base_file}" =~ $regex && "${base_file##*.}" != "map" ]]; then - local out_file=$(dirname "${file}")/${BASH_REMATCH[1]}.min.js - echo "====== $UGLIFY -c --comments -o ${out_file} --source-map "includeSources=true,content='${file}.map',filename='${out_file}.map'" ${file}" - $UGLIFY -c --comments -o ${out_file} --source-map "includeSources=true,content='${file}.map',filename='${out_file}.map'" ${file} - fi - done -} - -####################################### -# Recursively compile package -# Arguments: -# param1 - Source directory -# param2 - Out dir -# param3 - Package Name -# Returns: -# None -####################################### -compilePackage() { - # For TSC_PACKAGES items - if containsElement "${3}" "${TSC_PACKAGES[@]}"; then - echo "====== [${3}]: COMPILING: ${TSC} -p ${1}/tsconfig-build.json" - local package_name=$(basename "${2}") - $TSC -p ${1}/tsconfig-build.json - if [[ "${3}" = "compiler" ]]; then - if [[ "${package_name}" = "testing" ]]; then - echo "$(cat ${LICENSE_BANNER}) ${N} export * from './${package_name}/${package_name}'" > ${2}/../${package_name}.d.ts - fi - fi - else - echo "====== [${3}]: COMPILING: ${NGC} -p ${1}/tsconfig-build.json" - local package_name=$(basename "${2}") - $NGC -p ${1}/tsconfig-build.json - if [[ "${package_name}" != "locales" ]]; then - echo "====== Create ${1}/../${package_name}.d.ts re-export file for tsickle" - echo "$(cat ${LICENSE_BANNER}) ${N} export * from './${package_name}/${package_name}'" > ${2}/../${package_name}.d.ts - echo "{\"__symbolic\":\"module\",\"version\":3,\"metadata\":{},\"exports\":[{\"from\":\"./${package_name}/${package_name}\"}],\"flatModuleIndexRedirect\":true}" > ${2}/../${package_name}.metadata.json - fi - fi - - # Build subpackages - for DIR in ${1}/* ; do - [ -d "${DIR}" ] || continue - BASE_DIR=$(basename "${DIR}") - # Skip over directories that are not nested entry points - [[ -e ${DIR}/tsconfig-build.json && "${BASE_DIR}" != "integrationtest" ]] || continue - compilePackage ${DIR} ${2}/${BASE_DIR} ${3} - done -} - -####################################### -# Recursively compile package -# Arguments: -# param1 - Source directory -# param2 - Out dir -# param3 - Package Name -# Returns: -# None -####################################### -compilePackageES5() { - if containsElement "${3}" "${TSC_PACKAGES[@]}"; then - echo "====== [${3}]: COMPILING: ${TSC} -p ${1}/tsconfig-build.json --target es5 -d false --outDir ${2} --importHelpers true --sourceMap" - local package_name=$(basename "${2}") - $TSC -p ${1}/tsconfig-build.json --target es5 -d false --outDir ${2} --importHelpers true --sourceMap - else - echo "====== [${3}]: COMPILING: ${NGC} -p ${1}/tsconfig-build.json --target es5 -d false --outDir ${2} --importHelpers true --sourceMap" - local package_name=$(basename "${2}") - $NGC -p ${1}/tsconfig-build.json --target es5 -d false --outDir ${2} --importHelpers true --sourceMap - fi - - for DIR in ${1}/* ; do - [ -d "${DIR}" ] || continue - BASE_DIR=$(basename "${DIR}") - # Skip over directories that are not nested entry points - [[ -e ${DIR}/tsconfig-build.json && "${BASE_DIR}" != "integrationtest" ]] || continue - compilePackageES5 ${DIR} ${2} ${3} - done -} - -####################################### -# Adds a package.json in directories where needed (secondary entry point typings). -# This is read by NGC to be able to find the flat module index. -# Arguments: -# param1 - Source directory of typings files -# Returns: -# None -####################################### -addNgcPackageJson() { - for DIR in ${1}/* ; do - [ -d "${DIR}" ] || continue - # Confirm there is an ${PACKAGE}.d.ts and ${PACKAGE}.metadata.json file. If so, create - # the package.json and recurse. - if [[ -f ${DIR}/${PACKAGE}.d.ts && -f ${DIR}/${PACKAGE}.metadata.json ]]; then - echo '{"typings": "${PACKAGE}.d.ts"}' > ${DIR}/package.json - addNgcPackageJson ${DIR} - fi - done -} - -updateVersionReferences() { - NPM_DIR="$1" - ( - echo "====== VERSION: Updating version references in ${NPM_DIR}" - cd ${NPM_DIR} - echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-PLACEHOLDER/${VERSION}/g\" $""(grep -ril 0\.0\.0\-PLACEHOLDER .)" - perl -p -i -e "s/0\.0\.0\-PLACEHOLDER/${VERSION}/g" $(grep -ril 0\.0\.0\-PLACEHOLDER .) < /dev/null 2> /dev/null - ) -} - -####################################### -# Drops the last entry of a path. Similar to normalizing a path such as -# /parent/child/.. to /parent. -# Arguments: -# param1 - Directory on which to drop the last item -# Returns: -# None -####################################### - -dropLast() { - local last_item=$(basename ${1}) - local regex=local regex="(.+)/${last_item}" - if [[ "${1}" =~ $regex ]]; then - echo "${BASH_REMATCH[1]}" - else - echo "${1}" - fi -} - -VERSION="${VERSION_PREFIX}${VERSION_SUFFIX}" -echo "====== BUILDING: Version ${VERSION}" - -N=" -" -TSC=`pwd`/node_modules/.bin/tsc -NGC="node --max-old-space-size=3000 `pwd`/dist/tools/@angular/compiler-cli/src/main" -UGLIFY=`pwd`/node_modules/.bin/uglifyjs -TSCONFIG=./tools/tsconfig.json -ROLLUP=`pwd`/node_modules/.bin/rollup - -if [[ ${BUILD_TOOLS} == true ]]; then - travisFoldStart "build tools" "no-xtrace" - echo "====== (tools)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} =====" - rm -rf ./dist/tools/ - mkdir -p ./dist/tools/ - $(npm bin)/tsc -p ${TSCONFIG} - travisFoldEnd "build tools" -fi - - -if [[ ${BUILD_ALL} == true && ${TYPECHECK_ALL} == true ]]; then - travisFoldStart "clean dist" "no-xtrace" - rm -rf ./dist/all/ - rm -rf ./dist/packages - travisFoldEnd "clean dist" - - travisFoldStart "copy e2e files" "no-xtrace" - mkdir -p ./dist/all/ - - ( - echo "====== Copying files needed for e2e tests =====" - cp -r ./modules/playground ./dist/all/ - cp -r ./modules/playground/favicon.ico ./dist/ - #rsync -aP ./modules/playground/* ./dist/all/playground/ - mkdir ./dist/all/playground/vendor - cd ./dist/all/playground/vendor - ln -s ../../../../node_modules/core-js/client/core.js . - ln -s ../../../../node_modules/zone.js/dist/zone.js . - ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js . - ln -s ../../../../node_modules/systemjs/dist/system.src.js . - ln -s ../../../../node_modules/base64-js . - ln -s ../../../../node_modules/reflect-metadata/Reflect.js . - ln -s ../../../../node_modules/rxjs . - ln -s ../../../../node_modules/angular/angular.js . - ln -s ../../../../node_modules/hammerjs/hammer.js . - ) - - ( - echo "====== Copying files needed for benchmarks =====" - cp -r ./modules/benchmarks ./dist/all/ - cp -r ./modules/benchmarks/favicon.ico ./dist/ - mkdir ./dist/all/benchmarks/vendor - cd ./dist/all/benchmarks/vendor - ln -s ../../../../node_modules/core-js/client/core.js . - ln -s ../../../../node_modules/zone.js/dist/zone.js . - ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js . - ln -s ../../../../node_modules/systemjs/dist/system.src.js . - ln -s ../../../../node_modules/reflect-metadata/Reflect.js . - ln -s ../../../../node_modules/rxjs . - ln -s ../../../../node_modules/angular/angular.js . - ln -s ../../../../bower_components/polymer . - ln -s ../../../../node_modules/incremental-dom/dist/incremental-dom-cjs.js - ) - travisFoldEnd "copy e2e files" - - TSCONFIG="packages/tsconfig.json" - travisFoldStart "tsc -p ${TSCONFIG}" "no-xtrace" - $TSC -p ${TSCONFIG} - travisFoldEnd "tsc -p ${TSCONFIG}" - TSCONFIG="packages/examples/tsconfig.json" - travisFoldStart "tsc -p ${TSCONFIG}" "no-xtrace" - $TSC -p ${TSCONFIG} - travisFoldEnd "tsc -p ${TSCONFIG}" - TSCONFIG="modules/tsconfig.json" - travisFoldStart "tsc -p ${TSCONFIG}" "no-xtrace" - $TSC -p ${TSCONFIG} - travisFoldEnd "tsc -p ${TSCONFIG}" - -fi - -if [[ ${BUILD_ALL} == true ]]; then - rm -rf ./dist/packages - if [[ ${BUNDLE} == true ]]; then - rm -rf ./dist/packages-dist - fi -fi - -if [[ ${BUILD_TOOLS} == true || ${BUILD_ALL} == true ]]; then - echo "====== (compiler)COMPILING: \$(npm bin)/tsc -p packages/compiler/tsconfig-tools.json" - $(npm bin)/tsc -p packages/compiler/tsconfig-tools.json - echo "====== (compiler)COMPILING: \$(npm bin)/tsc -p packages/compiler-cli/tsconfig-tools.json" - $(npm bin)/tsc -p packages/compiler-cli/tsconfig-tools.json - - mkdir -p ./dist/packages-dist - rsync -a packages/bazel/ ./dist/packages-dist/bazel - echo "workspace(name=\"angular\")" > ./dist/packages-dist/bazel/WORKSPACE - # Remove BEGIN-INTERNAL...END-INTERAL blocks - # https://stackoverflow.com/questions/24175271/how-can-i-match-multi-line-patterns-in-the-command-line-with-perl-style-regex - perl -0777 -n -i -e "s/(?m)^.*BEGIN-INTERNAL[\w\W]*END-INTERNAL.*\n//g; print" $(grep -ril BEGIN-INTERNAL dist/packages-dist/bazel) < /dev/null 2> /dev/null - # Re-host //packages/bazel/ which is just // in the public distro - perl -0777 -n -i -e "s#//packages/bazel/#//#g; print" $(grep -ril packages/bazel dist/packages-dist/bazel) < /dev/null 2> /dev/null - perl -0777 -n -i -e "s#angular/packages/bazel/#angular/#g; print" $(grep -ril packages/bazel dist/packages-dist/bazel) < /dev/null 2> /dev/null - updateVersionReferences dist/packages-dist/bazel -fi - -for PACKAGE in ${PACKAGES[@]} -do - travisFoldStart "build package: ${PACKAGE}" "no-xtrace" - PWD=`pwd` - ROOT_DIR=${PWD}/packages - SRC_DIR=${ROOT_DIR}/${PACKAGE} - ROOT_OUT_DIR=${PWD}/dist/packages - OUT_DIR=${ROOT_OUT_DIR}/${PACKAGE} - OUT_DIR_ESM5=${ROOT_OUT_DIR}/${PACKAGE}/esm5 - NPM_DIR=${PWD}/dist/packages-dist/${PACKAGE} - ESM2015_DIR=${NPM_DIR}/esm2015 - FESM2015_DIR=${NPM_DIR}/fesm2015 - ESM5_DIR=${NPM_DIR}/esm5 - FESM5_DIR=${NPM_DIR}/fesm5 - BUNDLES_DIR=${NPM_DIR}/bundles - - LICENSE_BANNER=${ROOT_DIR}/license-banner.txt - - if [[ ${COMPILE_SOURCE} == true ]]; then - rm -rf ${OUT_DIR} - rm -f ${ROOT_OUT_DIR}/${PACKAGE}.js - compilePackage ${SRC_DIR} ${OUT_DIR} ${PACKAGE} - fi - - if [[ ${BUNDLE} == true ]]; then - echo "====== BUNDLING ${PACKAGE}: ${SRC_DIR} =====" - rm -rf ${NPM_DIR} && mkdir -p ${NPM_DIR} - - if ! containsElement "${PACKAGE}" "${NODE_PACKAGES[@]}"; then - - echo "====== Copy ${PACKAGE} typings" - rsync -a --exclude=*.js --exclude=*.js.map ${OUT_DIR}/ ${NPM_DIR} - - ( - cd ${SRC_DIR} - echo "====== Copy ESM2015 for ${PACKAGE}" - rsync -a --exclude="locale/**" --exclude="**/*.d.ts" --exclude="**/*.metadata.json" ${OUT_DIR}/ ${ESM2015_DIR} - - echo "====== Rollup ${PACKAGE}" - rollupIndex ${OUT_DIR} ${FESM2015_DIR} ${PACKAGE} - - echo "====== Produce ESM5 version" - compilePackageES5 ${SRC_DIR} ${OUT_DIR_ESM5} ${PACKAGE} - rsync -a --exclude="locale/**" --exclude="**/*.d.ts" --exclude="**/*.metadata.json" ${OUT_DIR_ESM5}/ ${ESM5_DIR} - rollupIndex ${OUT_DIR_ESM5} ${FESM5_DIR} ${PACKAGE} - - echo "====== Run rollup conversions on ${PACKAGE}" - runRollup ${SRC_DIR} - addBanners ${BUNDLES_DIR} - minify ${BUNDLES_DIR} - - if [[ -e ${SRC_DIR}/build.sh ]]; then - echo "====== Custom build for ${PACKAGE}" - cd ${SRC_DIR} && ${SRC_DIR}/build.sh - fi - - ) 2>&1 | grep -v "as external dependency" - - if [[ ${PACKAGE} == "common" ]]; then - echo "====== Copy i18n locale data" - rsync -a ${OUT_DIR}/locales/ ${NPM_DIR}/locales - fi - else - echo "====== Copy ${PACKAGE} node tool" - rsync -a ${OUT_DIR}/ ${NPM_DIR} - fi - - echo "====== Copy ${PACKAGE} package.json and .externs.js files" - rsync -am --include="package.json" --include="*/" --exclude=* ${SRC_DIR}/ ${NPM_DIR}/ - rsync -am --include="*.externs.js" --include="*/" --exclude=* ${SRC_DIR}/ ${NPM_DIR}/ - - # Replace the NG_UPDATE_PACKAGE_GROUP value with the JSON array of packages. - perl -p -i -e "s/\"NG_UPDATE_PACKAGE_GROUP\"/${NG_UPDATE_PACKAGE_GROUP}/g" ${NPM_DIR}/package.json < /dev/null - - cp ${ROOT_DIR}/README.md ${NPM_DIR}/ - fi - - - if [[ -d ${NPM_DIR} ]]; then - updateVersionReferences ${NPM_DIR} - fi - - travisFoldEnd "build package: ${PACKAGE}" -done - -if [[ ${BUILD_EXAMPLES} == true ]]; then - travisFoldStart "build examples" "no-xtrace" - echo "====== Building examples: ./packages/examples/build.sh =====" - ./packages/examples/build.sh - travisFoldEnd "build examples" -fi - -if [[ ${REMOVE_BENCHPRESS} == true ]]; then - travisFoldStart "remove benchpress" "no-xtrace" - echo "" - echo "==== Removing benchpress from publication" - rm -r dist/packages-dist/benchpress - travisFoldEnd "remove benchpress" -fi - - -# Print return arrows as a log separator -travisFoldReturnArrows diff --git a/docs/BAZEL.md b/docs/BAZEL.md index 730ba66e88..44d6c0d05d 100644 --- a/docs/BAZEL.md +++ b/docs/BAZEL.md @@ -133,7 +133,7 @@ Bazel supports the ability to include non-hermetic information from the version You can see an overview at https://www.kchodorow.com/blog/2017/03/27/stamping-your-builds/ In our repo, here is how it's configured: -1) In `tools/bazel_stamp_vars.sh` we run the `git` commands to generate our versioning info. +1) In `tools/bazel_stamp_vars.js` we run the `git` commands to generate our versioning info. 1) In `.bazelrc` we register this script as the value for the `workspace_status_command` flag. Bazel will run the script when it needs to stamp a binary. Note that Bazel has a `--stamp` argument to `yarn bazel build`, but this has no effect since our stamping takes place in Skylark rules. See https://github.com/bazelbuild/bazel/issues/1054 diff --git a/docs/COMMITTER.md b/docs/COMMITTER.md index 6592bc6b3e..be4aa8d616 100644 --- a/docs/COMMITTER.md +++ b/docs/COMMITTER.md @@ -8,7 +8,7 @@ Someone with committer access will do the rest. # Change approvals -Change approvals in our monorepo are managed via [pullapprove.com](https://about.pullapprove.com/) and are configured via the `.pullapprove.yaml` file. +Change approvals in our monorepo are managed via [GitHub CODEOWNERS](https://help.github.com/articles/about-codeowners/) and are configured via the `.github/CODEOWNERS` file. # Merging diff --git a/docs/DEBUG.md b/docs/DEBUG.md index af98cafb78..db7c6d0e31 100644 --- a/docs/DEBUG.md +++ b/docs/DEBUG.md @@ -5,55 +5,20 @@ The core packages are tested both in the browser (via Karma) and on the server ( ## Debugging in Karma -Run the unit tests as normal using via the `./test.sh` script. For example: - -```bash -./test.sh browserNoRouter -``` - -Once the initial build has completed and the Karma server has started up, you can go to the -Chrome browser that is automatically opened, usually pointing to `http://localhost:9876`. -The script will sit watching for code changes, recompiling the changed files and triggering -further runs of the unit tests in the browser. - -In this browser there is a "DEBUG" link (in the top right corner). Clicking this link will -open up a new tab that will run the unit tests and will not timeout, giving you time to -step through the code. - -Open up this tab's developer console to access the source code viewer where you can set -breakpoints and interrogate the current stack and variables. - It is useful to focus your debugging on one test at a time by changing that test to be defined using the `fit(...)` function, rather than `it(...)`. Moreover it can be helpful to place a `debugger` statement in this `fit` clause to cause the debugger to stop when it hits this test. +Read more about starting the debugger for Karma with Bazel in the [BAZEL.md](./BAZEL.md) +document. + ## Debugging in Node -Run the unit tests as normal using the `./test.sh` script, but add the `--debug` flag to -the command. For example: - -```bash -./test.sh node --debug -``` - -Once the initial building has completed, the script will watch for code changes, recompiling -and running the unit tests via a tool call `cjs-jasmine`. Due to the `--debug` flag, each -test run will create a debugging server listening on a port (such as 9229), which can be -connected to by a debugger. - -You can use Chrome as the debugger by navigating to `chrome://inspect` then clicking the -"Open dedicated DevTools for Node" link. This will open up a Developer console, which will -automatically connect to the debugging server. - It is useful to focus your debugging on one test at a time by changing that test to be defined using the `fit(...)` function, rather than `it(...)`. Moreover it can be helpful to place a `debugger` statement in this `fit` clause to cause the debugger to stop when it hits this test. -**Problem with node 6:** at the time of writing, the node process does not tell the Chrome -debugger when it has completed, and so the debugger is not able to automatically disconnect -from listening to the debugging server. To solve this, just close the developer tools window -after each run of the unit tests, before making changes to the code. This is fixed in node 8 -and may be backported to node 6. This issue is tracked in -https://github.com/nodejs/node/pull/12814#issuecomment-309908579. +Read more about starting the debugger for NodeJS tests with Bazel in the [BAZEL.md](./BAZEL.md) +document. \ No newline at end of file diff --git a/docs/DEVELOPER.md b/docs/DEVELOPER.md index fb596c47a9..cfa316457c 100644 --- a/docs/DEVELOPER.md +++ b/docs/DEVELOPER.md @@ -82,33 +82,22 @@ Before submitting a PR, do not forget to remove them: To build Angular run: ```shell -./build.sh +./scripts/build-packages-dist.sh ``` -* Results are put in the dist folder. +* Results are put in the `dist/packages-dist` folder. ## Running Tests Locally -To run tests: +Bazel is used as the primary tool for building and testing Angular. Building and testing is +incremental with Bazel, and it's possible to only run tests for an individual package instead +of for all packages. -```shell -$ ./test.sh node # Run all angular tests on node +Read more about this in the [BAZEL.md](./BAZEL.md) document. You should execute all test suites +before submitting a PR to Github. -$ ./test.sh browser # Run all angular tests in browser - -$ ./test.sh browserNoRouter # Optionally run all angular tests without router in browser - -$ ./test.sh router # Optionally run only the router tests in browser -``` - -You should execute the 3 test suites before submitting a PR to github. - -See [DEBUG.md](DEBUG.md) for information on debugging the code while running the unit tests. - -All the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass. - -- CircleCI fails if your code is not formatted properly, -- Travis CI fails if any of the test suites described above fails. +All the tests are executed on our Continuous Integration infrastructure and a PR could only be +merged if the code is formatted properly and all tests are passing. ## Formatting your source code @@ -116,8 +105,8 @@ Angular uses [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to form If the source code is not properly formatted, the CI will fail and the PR can not be merged. You can automatically format your code by running: -- `gulp format`: format all source code -- `gulp format:changed`: re-format only edited source code. +- `gulp format`: re-format only edited source code. +- `gulp format:all`: format _all_ source code A better way is to set up your IDE to format the changed file on each file save. @@ -147,13 +136,13 @@ http://github.com/angular/core-builds. You may find that your un-merged change needs some validation from external participants. Rather than requiring them to pull your Pull Request and build Angular locally, you can -publish the `*-builds` snapshots just like our Travis build does. +publish the `*-builds` snapshots just like our CircleCI build does. First time, you need to create the github repositories: ``` shell $ export TOKEN=[get one from https://github.com/settings/tokens] -$ CREATE_REPOS=1 TRAVIS= ./scripts/ci/publish-build-artifacts.sh [github username] +$ CREATE_REPOS=1 ./scripts/ci/publish-build-artifacts.sh [github username] ``` For subsequent snapshots, just run @@ -185,7 +174,6 @@ and create it if it doesn't exist. "files.exclude": { "bazel-out": true, ".idea": true, - ".bowerrc": true, ".circleci": true, ".github": true, "dist/**": true, diff --git a/docs/TRIAGE_AND_LABELS.md b/docs/TRIAGE_AND_LABELS.md index 248ba91084..41daeaa34e 100644 --- a/docs/TRIAGE_AND_LABELS.md +++ b/docs/TRIAGE_AND_LABELS.md @@ -65,6 +65,7 @@ What kind of problem is this? ## Caretaker Triage Process (Primary Triage) It is the caretaker's responsibility to assign `comp: *` to each new issue as they come in. +Issues that haven't been triaged can be found by selecting the issues with no milestone. If it's obvious that the issue or PR is related to a release regression, the caretaker is also responsible for assigning the `severity(5): regression` label to make the issue or PR highly visible. @@ -72,10 +73,12 @@ The primary triage should be done on a daily basis so that the issues become ava The reason why we limit the responsibility of the caretaker to this one label is that it is likely that without domain knowledge the caretaker could mislabel issues or lack knowledge of duplicate issues. +Once the primary triage is done, the ng-bot automatically adds the milestone `needsTriage`. + ## Component's owner Triage Process -The component owner is responsible for assigning one of the labels from each of these categories: +The component owner is responsible for assigning one of the labels from each of these categories to the issues that have the milestone `needsTriage`: - `type: *` - `frequency: *` @@ -83,6 +86,8 @@ The component owner is responsible for assigning one of the labels from each of We've adopted the issue categorization based on [user pain](http://www.lostgarden.com/2008/05/improving-bug-triage-with-user-pain.html) used by AngularJS. In this system every issue is assigned frequency and severity based on which the total user pain score is calculated. +The issues with type `type: feature`, `type: refactor` and `type: RFC / Discussion / question` do not require a frequency and severity. + Following is the definition of various frequency and severity levels: 1. `freq(score): *` – How often does this issue come up? How many developers does this affect? @@ -105,17 +110,23 @@ These criteria are then used to calculate a "user pain" score as follows: This score can then be used to estimate the impact of the issue which helps with prioritization. +Once the component's owner triage is done, the ng-bot automatically changes the milestone from `needsTriage` to `Backlog`. + ## Triaging PRs -Triaging PRs is the same as triaging issues, except that PRs have additional label categories that should be used to signal their state. +Triaging PRs is the same as triaging issues, except that the labels `frequency: *` and `severity: *` are replaced by: +- `effort*` +- `risk: *` + +PRs also have additional label categories that should be used to signal their state. Every triaged PR must have a `pr_action` label assigned to it: * `PR action: review` - work is complete and comment is needed from the reviewers. * `PR action: cleanup` - more work is needed from the author. * `PR action: discuss` - discussion is needed, to be led by the author. -* `PR action: merge` - the PR is ready to be merged by the caretaker. +* `PR action: merge` - the PR author is ready for the changes to be merged by the caretaker. In addition, PRs can have the following states: @@ -138,14 +149,14 @@ To communicate the target we use the following labels: * `PR target: LTS-only`: the PR should be merged only into the active LTS branch(es). Only security and critical fixes are allowed in these branches. Always send a new PR targeting just the LTS branch and request review approval from @IgorMinar. * `PR target: TBD`: the target is yet to be determined. -If a PR is missing the "PR target: *" label, or if the label is set to "TBD" when the PR is sent to the caretaker, the caretaker should reject the PR and request the appropriate target label to be applied before the PR is merged. +If a PR is missing the `PR target: *` label, or if the label is set to "TBD" when the PR is sent to the caretaker, the caretaker should reject the PR and request the appropriate target label to be applied before the PR is merged. ## PR Approvals Before a PR can be merged it must be approved by the appropriate reviewer(s). -To ensure that there right people review each change, we configured [PullApprove bot](https://about.pullapprove.com/) via (`.pullapprove.yaml`) to provide aggregate approval state via the GitHub PR Status API. +To ensure that the right people review each change, we configured [GitHub CODEOWNERS](https://help.github.com/articles/about-codeowners/) (via `.github/CODEOWNERS`) and require that each PR has at least one approval from the appropriate code owner. Note that approved state does not mean a PR is ready to be merged. For example, a reviewer might approve the PR but request a minor tweak that doesn't need further review, e.g., a rebase or small uncontroversial change. @@ -161,3 +172,10 @@ Only issues with `cla:yes` should be merged into master. ### `aio: preview` Applying this label to a PR makes the angular.io preview available regardless of the author. [More info](../aio/aio-builds-setup/docs/overview--security-model.md) + +### `PR action: merge-assistance` +This label can be added to let the caretaker know that the PR needs special attention. +There should always be a comment added to the PR to explain why the caretaker's assistance is needed. +The comment should be formatted like this: `merge-assistance: ` + +For example, the PR owner might not be a Googler and needs help to run g3sync; or one of the checks is failing due to external causes and the PR should still be merged. diff --git a/gulpfile.js b/gulpfile.js index 0560592e82..e77ab05b4f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -27,11 +27,25 @@ function loadTask(fileName, taskName) { return task(gulp); } +// Check source code for formatting errors in all source files. gulp.task('format:enforce', loadTask('format', 'enforce')); -gulp.task('format', loadTask('format', 'format')); + +// Format all source files. +gulp.task('format:all', loadTask('format', 'format')); + +// Format only untracked source code files. gulp.task('format:untracked', loadTask('format', 'format-untracked')); + +// Format only the changed, tracked source code files. gulp.task('format:diff', loadTask('format', 'format-diff')); + +// Format only changed lines based on the diff from the provided --branch +// argument (or `master` by default). gulp.task('format:changed', ['format:untracked', 'format:diff']); + +// Alias for `format:changed` that formerly formatted all files. +gulp.task('format', ['format:changed']); + gulp.task('lint', ['format:enforce', 'validate-commit-messages', 'tslint']); gulp.task('tslint', ['tools:build'], loadTask('lint')); gulp.task('validate-commit-messages', loadTask('validate-commit-message')); @@ -39,7 +53,6 @@ gulp.task('source-map-test', loadTask('source-map-test')); gulp.task('tools:build', loadTask('tools-build')); gulp.task('check-cycle', loadTask('check-cycle')); gulp.task('serve', loadTask('serve', 'default')); -gulp.task('serve-examples', loadTask('serve', 'examples')); gulp.task('changelog', loadTask('changelog')); gulp.task('check-env', () => {/* this is a noop because the env test ran already above */}); gulp.task('cldr:extract', loadTask('cldr', 'extract')); diff --git a/integration/README.md b/integration/README.md index 521bfc3f98..5de2089c14 100644 --- a/integration/README.md +++ b/integration/README.md @@ -20,12 +20,10 @@ $ yarn ng update @angular/cli @angular-devkit/build-angular ## Render3 tests -The directory `hello_world_cli` contains a test for render3 used with the angular cli. +The directory `cli-hello-world-ivy-compat` contains a test for render3 used with the angular cli. -If the Angular CLI is modified to generate a render3 application this should be replaced with that project. - -If the render3 is updated to support the Angular 5 bootstrap a version of this project should be created that -uses the Angular 5 bootstrap. +The `cli-hello-world-ivy-minimal` contains a minimal ivy app that is meant to mimic the bazel +equivalent in `packages/core/test/bundling/hello_world`, and should be kept similar. ## Writing an integration test diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index 893916586f..b93f10069f 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -3,8 +3,26 @@ "master": { "uncompressed": { "runtime": 1497, - "main": 185238, - "polyfills": 59608 + "main": 164671, + "polyfills": 38449 + } + } + }, + "cli-hello-world-ivy-minimal": { + "master": { + "uncompressed": { + "runtime": 1440, + "main": 12885, + "polyfills": 38390 + } + } + }, + "cli-hello-world-ivy-compat": { + "master": { + "uncompressed": { + "runtime": 1440, + "main": 194626, + "polyfills": 38390 } } }, diff --git a/integration/bazel-schematics/app.e2e-spec.ts b/integration/bazel-schematics/app.e2e-spec.ts deleted file mode 100644 index e2a9edb43d..0000000000 --- a/integration/bazel-schematics/app.e2e-spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { AppPage } from './app.po'; -import { browser } from 'protractor'; - -describe('workspace-project App', () => { - let page: AppPage; - - beforeEach(() => { - page = new AppPage(); - }); - - it('should display welcome message', () => { - page.navigateTo(); - expect(page.getTitleText()).toEqual('Welcome to demo!'); - }); - - afterEach(async () => { - const logs = await browser.manage().logs().get('browser'); - expect(logs).toEqual([]); - }); -}); diff --git a/integration/bazel-schematics/package.json b/integration/bazel-schematics/package.json index 5c13d3ff44..bbb5645a31 100644 --- a/integration/bazel-schematics/package.json +++ b/integration/bazel-schematics/package.json @@ -5,8 +5,7 @@ "license": "MIT", "devDependencies": { "@angular/bazel": "file:../../dist/packages-dist/bazel", - "@angular/cli": "^7.1.3", - "@angular/core": "^7.1.3", + "@angular/cli": "file:../../node_modules/@angular/cli", "@bazel/bazel": "file:../../node_modules/@bazel/bazel" }, "scripts": { diff --git a/integration/bazel-schematics/package.json.replace b/integration/bazel-schematics/package.json.replace new file mode 100644 index 0000000000..e3f0bd2998 --- /dev/null +++ b/integration/bazel-schematics/package.json.replace @@ -0,0 +1,53 @@ +{ + "name": "demo", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "file:../angular/dist/packages-dist/animations", + "@angular/common": "file:../angular/dist/packages-dist/common", + "@angular/compiler": "file:../angular/dist/packages-dist/compiler", + "@angular/core": "file:../angular/dist/packages-dist/core", + "@angular/forms": "file:../angular/dist/packages-dist/forms", + "@angular/platform-browser": "file:../angular/dist/packages-dist/platform-browser", + "@angular/platform-browser-dynamic": "file:../angular/dist/packages-dist/platform-browser-dynamic", + "@angular/router": "file:../angular/dist/packages-dist/router", + "core-js": "^2.5.4", + "rxjs": "~6.3.3", + "tslib": "^1.9.0", + "zone.js": "~0.8.26" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.12.0", + "@angular/bazel": "file:../angular/dist/packages-dist/bazel", + "@angular/cli": "~7.2.1", + "@angular/compiler-cli": "file:../angular/dist/packages-dist/compiler-cli", + "@angular/language-service": "file:../angular/dist/packages-dist/language-service", + "@bazel/bazel": "^0.21.0", + "@bazel/ibazel": "^0.9.0", + "@bazel/karma": "^0.23.2", + "@bazel/typescript": "^0.23.2", + "@types/node": "~8.9.4", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "codelyzer": "~4.5.0", + "jasmine-core": "~2.99.1", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~3.1.1", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~1.1.2", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tslint": "~5.11.0", + "typescript": "~3.2.2" + } +} diff --git a/integration/bazel-schematics/replace_angular_repo.js b/integration/bazel-schematics/replace_angular_repo.js new file mode 100644 index 0000000000..50a64e2986 --- /dev/null +++ b/integration/bazel-schematics/replace_angular_repo.js @@ -0,0 +1,29 @@ +// TODO(kyliau): This file should be removed when we use Angular npm distro from +// Bazel projects. + +const fs = require('fs'); + +function replaceAngular(content) { + const regex = /ANGULAR_VERSION.*\nhttp_archive\((.*\n){4}\)/; + if (!regex.test(content)) { + throw new Error('Failed to find http_archive rule for Angular in WORKSPACE'); + } + return content.replace(regex, ` +local_repository( + name = "angular", + path = "../../..", +)`); +} + +function main(argv) { + argv = argv.slice(2); + if (argv.length !== 1) { + throw new Error('Expect WORKSPACE to be first parameter'); + } + const workspace = argv[0]; + let content = fs.readFileSync(workspace, 'utf-8'); + content = replaceAngular(content); + fs.writeFileSync(workspace, content); +} + +main(process.argv) diff --git a/integration/bazel-schematics/test.sh b/integration/bazel-schematics/test.sh index b939e4f666..e781e81dd8 100755 --- a/integration/bazel-schematics/test.sh +++ b/integration/bazel-schematics/test.sh @@ -5,32 +5,28 @@ set -eux -o pipefail function testBazel() { # Set up bazel version + ng version rm -rf demo # Create project - ng new demo --collection=@angular/bazel --defaults --skip-git + ng new demo --collection=@angular/bazel --defaults --skip-git --style=scss + node replace_angular_repo.js "./demo/WORKSPACE" cd demo - # Run build - # TODO(kyliau): Use `bazel build` for now. Running `ng build` requires - # node_modules to be available in project directory. - bazel build //src:bundle - # Run test + yarn add @angular/bazel@file:../../../dist/packages-dist/bazel + yarn webdriver-manager update --gecko=false --standalone=false $CI_CHROMEDRIVER_VERSION_ARG + cp ../package.json.replace ./package.json + ng generate component widget --style=css + ng build ng test ng e2e } function testNonBazel() { # Replace angular.json that uses Bazel builder with the default generated by CLI - cp ../angular.json.original ./angular.json - # TODO(kyliau) Remove this once the additional assertion is added to CLI - cp ../app.e2e-spec.ts ./e2e/src/ - # TODO(kyliau) Remove this once web_package rule is in use - cp ../index.html ./src/ + mv ./angular.json.bak ./angular.json rm -rf dist src/main.dev.ts src/main.prod.ts - # Just make a symlink instead of full yarn install to expose node_modules - ln -s $(bazel info output_base)/external/npm/node_modules node_modules - ng build - ng test --watch=false - ng e2e + ng build --progress=false + ng test --progress=false --watch=false + ng e2e --configuration=production --webdriver-update=false } testBazel diff --git a/integration/bazel-schematics/yarn.lock b/integration/bazel-schematics/yarn.lock index 4c2c949e90..4d221e89c3 100644 --- a/integration/bazel-schematics/yarn.lock +++ b/integration/bazel-schematics/yarn.lock @@ -2,12 +2,12 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.11.3": - version "0.11.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.11.3.tgz#971135f340d073d434dc2ada1ae3873c77387243" - integrity sha512-Y88itM+UZt7ZJqUa9i74SxC08nhqbrYUZLCztxt5LEOyr4umxBxNV4lRyhNW7iED5jFKifgDZ7dNvdS0F18sWw== +"@angular-devkit/architect@0.13.0-rc.0": + version "0.13.0-rc.0" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.13.0-rc.0.tgz#d9bc43a3811f293269cf488539b72ce27afc6cdb" + integrity sha512-abqtT5qyfTL29hf9be1MnaSVjIMJXJq+Oc+FZJ4RyQ+Sjs2zo+DjAJo62P1vS55JkLE1TFpEcjHkg118Cz7yOw== dependencies: - "@angular-devkit/core" "7.1.3" + "@angular-devkit/core" "7.3.0-rc.0" rxjs "6.3.3" "@angular-devkit/architect@^0.10.6": @@ -29,112 +29,137 @@ rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/core@7.1.3", "@angular-devkit/core@^7.0.4": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.1.3.tgz#3d82a7e99aeb6259ff941d82b65759cb1c397042" - integrity sha512-pGBInxmuR5DAhZ1RSfIlkv7cdgh3EDNXXea9ZObEuI9MuFsIWUKODT5oKbRrsOWM6IqwNmx68VEW+xQm2DXyJw== +"@angular-devkit/core@7.2.3", "@angular-devkit/core@^7.0.4": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.3.tgz#03fad4edcbfbf5b2f0d35a121eca45b1273b238a" + integrity sha512-NnN8O+97nJAxqD2zVTDlU8dSzrGCZmqYMDqDoRJJChYxAgmGwP4lhb+Jyi5D34tPxgKRTnjTOwC+G7D+WrXSDQ== dependencies: - ajv "6.5.3" + ajv "6.6.2" chokidar "2.0.4" fast-json-stable-stringify "2.0.0" rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/schematics@7.1.3", "@angular-devkit/schematics@^7.0.4": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.1.3.tgz#30d03fde5bb27d6606d9a6e055188382408670d6" - integrity sha512-Snmfog/n5k1PWdDaI+Top1F978vlXZFTvxHRPzlMCGhGsY+LMOpeRLVHADI+WP1q1LZ+2BjLELZVA2GP35AH8A== +"@angular-devkit/core@7.3.0-rc.0": + version "7.3.0-rc.0" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.0-rc.0.tgz#e555a08d85259855ff1946f4268936a1aadd38f1" + integrity sha512-0vHuw1gIMh79tI+gRxCMn89U1DnjmBnqybVktaf9YXi9xshxd+nnFb31v7n1tJQVQiQNzGxk3hviFnkzxLZipw== dependencies: - "@angular-devkit/core" "7.1.3" + ajv "6.7.0" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.2.3.tgz#e85269fc44d87fd79314875084ecdecdc42020b5" + integrity sha512-zhnI1zxEcjx4OZ0yIzAAOujS8fzXE6nxjyC1viqliQbbjbikA6WIL7UT0jQXZKDsRBl8VXOyutBOaeOXuqktTQ== + dependencies: + "@angular-devkit/core" "7.2.3" + rxjs "6.3.3" + +"@angular-devkit/schematics@7.3.0-rc.0", "@angular-devkit/schematics@^7.3.0-rc.0": + version "7.3.0-rc.0" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.0-rc.0.tgz#9f1e1f6942da36b12c81241398ed6ca8b2e65875" + integrity sha512-noqcQIOvah2G126DTFKY5Kiga8UwI9cKzyhQdNlf+8hAZpnWwTURItQ5xuMJg/XfRQLUSg9gWS2h1cI9AD7mxQ== + dependencies: + "@angular-devkit/core" "7.3.0-rc.0" rxjs "6.3.3" "@angular/bazel@file:../../dist/packages-dist/bazel": - version "7.2.0-beta.2" + version "8.0.0-beta.2" dependencies: "@angular-devkit/architect" "^0.10.6" "@angular-devkit/core" "^7.0.4" - "@angular-devkit/schematics" "^7.0.4" - "@bazel/typescript" "^0.21.0" + "@angular-devkit/schematics" "^7.3.0-rc.0" + "@bazel/typescript" "^0.23.2" "@schematics/angular" "^7.0.4" "@types/node" "6.0.84" semver "^5.6.0" shelljs "0.8.2" tsickle "0.34.0" -"@angular/cli@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.1.3.tgz#591bdd104084b6f74819c4ddabc28d1cc1e35d84" - integrity sha512-mf1dBxMm2I3ER4849v5HyoX+IvjOno6/PL6rew1nFDR+KRNl4DU9Aa6jUVzuHgKqlMgu5+LjvPfJDud8lQc9sg== +"@angular/cli@file:../../node_modules/@angular/cli": + version "7.3.0-rc.0" dependencies: - "@angular-devkit/architect" "0.11.3" - "@angular-devkit/core" "7.1.3" - "@angular-devkit/schematics" "7.1.3" - "@schematics/angular" "7.1.3" - "@schematics/update" "0.11.3" - inquirer "6.2.0" - opn "5.3.0" - semver "5.5.1" + "@angular-devkit/architect" "0.13.0-rc.0" + "@angular-devkit/core" "7.3.0-rc.0" + "@angular-devkit/schematics" "7.3.0-rc.0" + "@schematics/angular" "7.3.0-rc.0" + "@schematics/update" "0.13.0-rc.0" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + inquirer "6.2.1" + npm-package-arg "6.1.0" + opn "5.4.0" + pacote "9.4.0" + semver "5.6.0" symbol-observable "1.2.0" -"@angular/core@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-7.1.3.tgz#759f626d734a90552936604d7adda5ac885a6887" - integrity sha512-Vv2Eolb5fZZZLIyodazDTIH6l3wT0ss7oJq+op0aqfrH43HlZ1LkkoovPskX2w0Om9bzPfvfPz+fWm36WXrFyA== - dependencies: - tslib "^1.9.0" +"@bazel/bazel-darwin_x64@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.22.0.tgz#a2bea5922dba9a32554a218ba4849a200115b248" + integrity sha512-LFxkyQgPATeB64z/1IvOWZhK+lc3JVHejbmdo96qB4lsoD8zselvOlgHvVXxlAjRxVZ9mlmXDvDRDyaXyyRdwA== -"@bazel/bazel-darwin_x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.20.0.tgz#648d61c32a3c5fccb7bf70b753071b6e54b11f21" - integrity sha512-zeoeVK504341GfnaxdaB4pFzQV0YOK1HLiYj3/ocamPFxAJRh9abvKB8iOpqD5Oal0j7VsINxnXCjovp9a4urA== +"@bazel/bazel-linux_x64@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.22.0.tgz#12e5884f2a7b7f3b62afbef9f8da4de0976f3bc8" + integrity sha512-xDs8cb2bbGZ9uvzYZOzCVrMBywzRhLj0J/t+py+FYZj+VO5B3wVg9eUf6nWWR0oJ2mzvToI9h31t2tNdqwy2kQ== -"@bazel/bazel-linux_x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.20.0.tgz#2568628a0d0b85dcc69d0ab701b1d6e10551357d" - integrity sha512-PpHzoEqfXty8dc1/p1tVFXtbPyrE1n0N79QmYePjJ5mJMyW7uBF/zV4IajYY8+IpJEcDVq5v4BavSexOmVJRmA== - -"@bazel/bazel-win32_x64@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.20.0.tgz#af7d041dae4c066e7aa8618949e2de1aad07495e" - integrity sha512-3bqHXFBvLnbvNzr1KCQ1zryTYvHMoQffaWVekbckgPyT2VPEj3abuB91+DrRYmZdPjcgPYnjnyanxZHDkKuF2g== +"@bazel/bazel-win32_x64@0.22.0": + version "0.22.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.22.0.tgz#a8a65986639583a8cc7b018e001aedfdafe41b50" + integrity sha512-FbJaXVDoCLnpIFLnPHFkQdfriYPXfnfQNuf9EXMliERdRuoeBVbwEZfwcuArxZWNFus7bD8QiTj0XzKVWO+Wbw== "@bazel/bazel@file:../../node_modules/@bazel/bazel": - version "0.20.0" + version "0.22.0" optionalDependencies: - "@bazel/bazel-darwin_x64" "0.20.0" - "@bazel/bazel-linux_x64" "0.20.0" - "@bazel/bazel-win32_x64" "0.20.0" + "@bazel/bazel-darwin_x64" "0.22.0" + "@bazel/bazel-linux_x64" "0.22.0" + "@bazel/bazel-win32_x64" "0.22.0" -"@bazel/typescript@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.21.0.tgz#41c304f77a42c6a016280d0f4c20e0749c3f4b2a" - integrity sha512-ASXj0RFybmqoa3LwqkTU3gNkX9bY9wL/VDNo5hlp9pynYWl4RMpe9V3m/qDIdtSuLJ+qD+Z3FKT/OcpWQHMlYA== +"@bazel/typescript@^0.23.2": + version "0.23.2" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.23.2.tgz#a3ff199880855259d84216cb41644c1d9a0fad14" + integrity sha512-GrTyDW6Fvp/rgnxZGYampB5/QmDWvxtLEtUyMCPa/QXFR1OVxaMWeHxxuFEcES2UKJegqBDKAA8IzX21x4UbEw== dependencies: + jasmine-core "2.8.0" protobufjs "5.0.3" + semver "5.6.0" source-map-support "0.5.9" tsutils "2.27.2" -"@schematics/angular@7.1.3", "@schematics/angular@^7.0.4": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.1.3.tgz#2cdbc6471358cf429fbea7ab192edc7246c87bd5" - integrity sha512-6Wq6vNjGTc0zmudPogTjiegtTUc0pORTCxI39iinUM+5iemMrCLYKJmYLi5mPFU4OG/Q2fnT06A3dYUorhtLkA== +"@schematics/angular@7.3.0-rc.0": + version "7.3.0-rc.0" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.3.0-rc.0.tgz#7519aa692dcaed63b9caa7d824846511905b1bfc" + integrity sha512-yjCHgLSAqQKVZrZgf8F37cPQthhucIA10ofpIHPEZrvHwKBQhM9K3yfB7uYgkj4gzPTdREedb7Rm3/HY45L/1A== dependencies: - "@angular-devkit/core" "7.1.3" - "@angular-devkit/schematics" "7.1.3" - typescript "3.1.6" + "@angular-devkit/core" "7.3.0-rc.0" + "@angular-devkit/schematics" "7.3.0-rc.0" + typescript "3.2.2" -"@schematics/update@0.11.3": - version "0.11.3" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.11.3.tgz#ffbe8d2d839773df171972193e0d8765eb2bcdc7" - integrity sha512-0bGuRZVsmNMF3SFFuhuuZcySImK4gxl+6tdb6r4LPBx5lKM7mIzdUuC0SIn6gArciAeW0GCKYSpwMO15P8zSOA== +"@schematics/angular@^7.0.4": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.2.3.tgz#e08baf642fad4ff7b27a2724379c4583a5a381b5" + integrity sha512-hKp+qaM8YU55+JukteXOVY2N5IQBDIIIXkyPcikbC2GBXUeNOMiPqw9au9sjHrgtFp+SVGoaFzzz9+MOCc1gig== dependencies: - "@angular-devkit/core" "7.1.3" - "@angular-devkit/schematics" "7.1.3" + "@angular-devkit/core" "7.2.3" + "@angular-devkit/schematics" "7.2.3" + typescript "3.2.2" + +"@schematics/update@0.13.0-rc.0": + version "0.13.0-rc.0" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.13.0-rc.0.tgz#3d5bb6ce7d8d1ea44a0e0a644022bc655b80ae80" + integrity sha512-XoU3TnaDcIFX7TU37bfjfAW0tI1tRD5DYQFHDBNOgS+78InGvR9+1CVzRJ4uWOjk0i+ZzDaGbYyR0iA47jSOTA== + dependencies: + "@angular-devkit/core" "7.3.0-rc.0" + "@angular-devkit/schematics" "7.3.0-rc.0" "@yarnpkg/lockfile" "1.1.0" ini "1.3.5" - pacote "9.1.1" + pacote "9.4.0" rxjs "6.3.3" - semver "5.5.1" + semver "5.6.0" semver-intersect "1.4.0" "@types/node@6.0.84": @@ -184,10 +209,30 @@ ajv@6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@6.6.2: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.7.0.tgz#e3ce7bb372d6577bb1839f1dfdfcbf5ad2948d96" + integrity sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== ansi-regex@^2.0.0: version "2.1.1" @@ -199,6 +244,11 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -293,7 +343,7 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== -bluebird@^3.5.1, bluebird@^3.5.2: +bluebird@^3.5.1, bluebird@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== @@ -344,24 +394,24 @@ bytebuffer@~5: dependencies: long "~3" -cacache@^11.0.1, cacache@^11.2.0: - version "11.3.1" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.1.tgz#d09d25f6c4aca7a6d305d141ae332613aa1d515f" - integrity sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA== +cacache@^11.0.1, cacache@^11.3.2: + version "11.3.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" + integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg== dependencies: - bluebird "^3.5.1" - chownr "^1.0.1" - figgy-pudding "^3.1.0" - glob "^7.1.2" - graceful-fs "^4.1.11" - lru-cache "^4.1.3" + bluebird "^3.5.3" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.3" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" mississippi "^3.0.0" mkdirp "^0.5.1" move-concurrently "^1.0.1" promise-inflight "^1.0.1" rimraf "^2.6.2" - ssri "^6.0.0" - unique-filename "^1.1.0" + ssri "^6.0.1" + unique-filename "^1.1.1" y18n "^4.0.0" cache-base@^1.0.1: @@ -385,9 +435,9 @@ camelcase@^2.0.1: integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= chalk@^2.0.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -418,7 +468,7 @@ chokidar@2.0.4: optionalDependencies: fsevents "^1.2.2" -chownr@^1.0.1, chownr@^1.1.1: +chownr@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== @@ -711,7 +761,7 @@ fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -figgy-pudding@^3.1.0, figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: +figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== @@ -784,9 +834,9 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" @@ -830,7 +880,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob@^7.0.0, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3: +glob@^7.0.0, glob@^7.0.5, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -842,7 +892,7 @@ glob@^7.0.0, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== @@ -963,10 +1013,10 @@ ini@1.3.5, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -inquirer@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" - integrity sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg== +inquirer@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" + integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -979,13 +1029,13 @@ inquirer@6.2.0: run-async "^2.2.0" rxjs "^6.1.0" string-width "^2.1.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" through "^2.3.6" interpret@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== invert-kv@^1.0.0: version "1.0.0" @@ -1156,6 +1206,11 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +jasmine-core@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" + integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= + json-parse-better-errors@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -1225,6 +1280,13 @@ lru-cache@^4.1.2, lru-cache@^4.1.3: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + make-fetch-happen@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" @@ -1369,9 +1431,9 @@ mute-stream@0.0.7: integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= nan@^2.9.2: - version "2.11.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766" - integrity sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA== + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== nanomatch@^1.2.9: version "1.2.13" @@ -1454,7 +1516,7 @@ npm-bundled@^1.0.1: resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== -npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: +npm-package-arg@6.1.0, npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== @@ -1465,14 +1527,14 @@ npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: validate-npm-package-name "^3.0.0" npm-packlist@^1.1.12, npm-packlist@^1.1.6: - version "1.1.12" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a" - integrity sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g== + version "1.2.0" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.2.0.tgz#55a60e793e272f00862c7089274439a4cc31fc7f" + integrity sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" -npm-pick-manifest@^2.1.0: +npm-pick-manifest@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA== @@ -1482,9 +1544,9 @@ npm-pick-manifest@^2.1.0: semver "^5.4.1" npm-registry-fetch@^3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.8.0.tgz#aa7d9a7c92aff94f48dba0984bdef4bd131c88cc" - integrity sha512-hrw8UMD+Nob3Kl3h8Z/YjmKamb1gf7D1ZZch2otrIXM3uFLB5vjEY6DhMlq80z/zZet6eETLbOXcuQudCB3Zpw== + version "3.9.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz#44d841780e2833f06accb34488f8c7450d1a6856" + integrity sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw== dependencies: JSONStream "^1.3.4" bluebird "^3.5.1" @@ -1550,10 +1612,10 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -opn@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" - integrity sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g== +opn@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" + integrity sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw== dependencies: is-wsl "^1.1.0" @@ -1587,17 +1649,17 @@ osenv@^0.1.4, osenv@^0.1.5: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -pacote@9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.1.1.tgz#25091f75a25021de8be8d34cc6408728fca3579b" - integrity sha512-f28Rq5ozzKAA9YwIKw61/ipwAatUZseYmVssDbHHaexF0wRIVotapVEZPAjOT7Eu3LYVqEp0NVpNizoAnYBUaA== +pacote@9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.4.0.tgz#af979abdeb175cd347c3e33be3241af1ed254807" + integrity sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w== dependencies: - bluebird "^3.5.2" - cacache "^11.2.0" + bluebird "^3.5.3" + cacache "^11.3.2" figgy-pudding "^3.5.1" get-stream "^4.1.0" glob "^7.1.3" - lru-cache "^4.1.3" + lru-cache "^5.1.1" make-fetch-happen "^4.0.1" minimatch "^3.0.4" minipass "^2.3.5" @@ -1606,7 +1668,7 @@ pacote@9.1.1: normalize-package-data "^2.4.0" npm-package-arg "^6.1.0" npm-packlist "^1.1.12" - npm-pick-manifest "^2.1.0" + npm-pick-manifest "^2.2.3" npm-registry-fetch "^3.8.0" osenv "^0.1.5" promise-inflight "^1.0.1" @@ -1616,7 +1678,7 @@ pacote@9.1.1: safe-buffer "^5.1.2" semver "^5.6.0" ssri "^6.0.1" - tar "^4.4.6" + tar "^4.4.8" unique-filename "^1.1.1" which "^1.3.1" @@ -1644,7 +1706,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-parse@^1.0.5: +path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== @@ -1792,11 +1854,11 @@ resolve-url@^0.2.1: integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@^1.1.6: - version "1.8.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== + version "1.10.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" + integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== dependencies: - path-parse "^1.0.5" + path-parse "^1.0.6" restore-cursor@^2.0.0: version "2.0.0" @@ -1817,11 +1879,11 @@ retry@^0.10.0: integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: - glob "^7.0.5" + glob "^7.1.3" run-async@^2.2.0: version "2.3.0" @@ -1873,16 +1935,11 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" -"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@5.6.0, semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== -semver@5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== - set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -1922,10 +1979,10 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -smart-buffer@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" - integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== +smart-buffer@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d" + integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw== snapdragon-node@^2.0.1: version "2.1.1" @@ -1966,12 +2023,12 @@ socks-proxy-agent@^4.0.0: socks "~2.2.0" socks@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.2.tgz#f061219fc2d4d332afb4af93e865c84d3fa26e2b" - integrity sha512-g6wjBnnMOZpE0ym6e0uHSddz9p3a+WsBaaYQaBaSCJYvrC4IXykQR9MNGjLQf38e9iIIhp3b1/Zk8YZI3KGJ0Q== + version "2.2.3" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.3.tgz#7399ce11e19b2a997153c983a9ccb6306721f2dc" + integrity sha512-+2r83WaRT3PXYoO/1z+RDEBE7Z2f9YcdQnJ0K/ncXXbV5gJ6wYfNAebYFYiiUjM6E4JyXnPY8cimwyvFYHVUUA== dependencies: ip "^1.1.5" - smart-buffer "^4.0.1" + smart-buffer "4.0.2" source-map-resolve@^0.5.0: version "0.5.2" @@ -2034,9 +2091,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz#a59efc09784c2a5bada13cfeaf5c75dd214044d2" - integrity sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" + integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -2111,6 +2168,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -2128,7 +2192,7 @@ symbol-observable@1.2.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -tar@^4, tar@^4.4.6: +tar@^4, tar@^4.4.8: version "4.4.8" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== @@ -2212,10 +2276,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68" - integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA== +typescript@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" + integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== union-value@^1.0.0: version "1.0.0" @@ -2227,7 +2291,7 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" -unique-filename@^1.1.0, unique-filename@^1.1.1: +unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== diff --git a/integration/bazel/.bazelrc b/integration/bazel/.bazelrc index 8a3a7fd256..1a9ab9f69f 100644 --- a/integration/bazel/.bazelrc +++ b/integration/bazel/.bazelrc @@ -6,8 +6,13 @@ build --strategy=AngularTemplateCompile=worker test --test_output=errors # Workaround https://github.com/bazelbuild/bazel/issues/3645 -# Limit Bazel to consuming 3072K of RAM -build --local_resources=3072,2.0,1.0 +# Bazel doesn't calculate the memory ceiling correctly when running under Docker. +# Limit Bazel to consuming resources that fit in CircleCI "xlarge" class +# https://circleci.com/docs/2.0/configuration-reference/#resource_class +build --local_resources=14336,8.0,1.0 # Use the Angular 6 compiler -build --define=compile=legacy \ No newline at end of file +build --define=compile=legacy + +# Don't create symlinks +build --symlink_prefix=/ diff --git a/integration/bazel/WORKSPACE b/integration/bazel/WORKSPACE index e34220c94e..366688099b 100644 --- a/integration/bazel/WORKSPACE +++ b/integration/bazel/WORKSPACE @@ -2,34 +2,14 @@ workspace(name = "bazel_integration_test") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -# -# Download Bazel toolchain dependencies as needed by build actions -# - -local_repository( - name = "angular", - path = "../..", -) - +# Fetch rules_nodejs so we can install our npm dependencies http_archive( - name = "rxjs", - sha256 = "72b0b4e517f43358f554c125e40e39f67688cd2738a8998b4a266981ed32f403", - strip_prefix = "package/src", - url = "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz", + name = "build_bazel_rules_nodejs", + sha256 = "1416d03823fed624b49a0abbd9979f7c63bbedfd37890ddecedd2fe25cccebc6", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.18.6/rules_nodejs-0.18.6.tar.gz"], ) -load("@angular//packages/bazel:package.bzl", "rules_angular_dependencies") - -rules_angular_dependencies() - -load("@build_bazel_rules_typescript//:package.bzl", "rules_typescript_dependencies") - -rules_typescript_dependencies() - -load("@build_bazel_rules_nodejs//:package.bzl", "rules_nodejs_dependencies") - -rules_nodejs_dependencies() - +# Fetch sass rules for compiling sass files http_archive( name = "io_bazel_rules_sass", sha256 = "dbe9fb97d5a7833b2a733eebc78c9c1e3880f676ac8af16e58ccf2139cbcad03", @@ -37,48 +17,84 @@ http_archive( url = "https://github.com/bazelbuild/rules_sass/archive/1.11.0.zip", ) -# -# Setup dependencies loaded above -# +# Fetch the angular repository since we build angular from source +# TODO(gregmagolan): use angular bundles in the Bazel build +local_repository( + name = "angular", + path = "../..", +) +# Fetch the rxjs repository since we build rxjs from source +# TODO(gregmagolan): use rxjs bundles in the Bazel build +http_archive( + name = "rxjs", + sha256 = "72b0b4e517f43358f554c125e40e39f67688cd2738a8998b4a266981ed32f403", + strip_prefix = "package/src", + url = "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz", +) + +# Check the bazel version and download npm dependencies load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install") -check_bazel_version("0.17.0") +# Bazel version must be at least v0.21.0 because: +# - 0.21.0 Using --incompatible_strict_action_env flag fixes cache when running `yarn bazel` +# (see https://github.com/angular/angular/issues/27514#issuecomment-451438271) +check_bazel_version("0.21.0", """ +You no longer need to install Bazel on your machine. +Angular has a dependency on the @bazel/bazel package which supplies it. +Try running `yarn bazel` instead. + (If you did run that, check that you've got a fresh `yarn install`) +""") + +# Setup the Node.js toolchain node_repositories( node_version = "10.9.0", yarn_version = "1.12.1", ) +# Install our npm dependencies into @npm yarn_install( name = "npm", + # Need a reference to @angular here so that Bazel sets up the + # external repository before calling yarn_install + data = ["@angular//:LICENSE"], package_json = "//src:package.json", yarn_lock = "//src:yarn.lock", ) -load("@io_bazel_rules_go//go:def.bzl", "go_register_toolchains", "go_rules_dependencies") +# Install all bazel dependencies of our npm packages +load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies") -go_rules_dependencies() +install_bazel_dependencies() -go_register_toolchains() +# Load karma dependencies +load("@build_bazel_rules_karma//:package.bzl", "rules_karma_dependencies") -load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories") +rules_karma_dependencies() + +# Setup the rules_webtesting toolchain +load("@io_bazel_rules_webtesting//web:repositories.bzl", "web_test_repositories") web_test_repositories() -browser_repositories( - chromium = True, - firefox = True, -) +# Temporary work-around for https://github.com/angular/angular/issues/28681 +# TODO(gregmagolan): go back to @io_bazel_rules_webtesting browser_repositories +load("@angular//:browser_repositories.bzl", "browser_repositories") +browser_repositories() + +# Setup the rules_typescript tooolchain load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace") ts_setup_workspace() +# Setup the rules_sass toolchain load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories") sass_repositories() +# Setup the angular toolchain load("@angular//:index.bzl", "ng_setup_workspace") ng_setup_workspace() diff --git a/integration/bazel/src/BUILD.bazel b/integration/bazel/src/BUILD.bazel index 6a716e868c..1cb689e5b3 100644 --- a/integration/bazel/src/BUILD.bazel +++ b/integration/bazel/src/BUILD.bazel @@ -37,9 +37,14 @@ ts_devserver( load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary", "rollup_bundle") +filegroup( + name = "empty_node_modules", +) + rollup_bundle( name = "bundle", entry_point = "src/main", + node_modules = ":empty_node_modules", deps = ["//src"], ) diff --git a/integration/bazel/src/hello-world/BUILD.bazel b/integration/bazel/src/hello-world/BUILD.bazel index 5022712729..8656ffa9d8 100644 --- a/integration/bazel/src/hello-world/BUILD.bazel +++ b/integration/bazel/src/hello-world/BUILD.bazel @@ -2,7 +2,8 @@ package(default_visibility = ["//visibility:public"]) load("@angular//:index.bzl", "ng_module", "ng_package") load("@io_bazel_rules_sass//sass:sass.bzl", "sass_binary") -load("@build_bazel_rules_typescript//:defs.bzl", "ts_library", "ts_web_test_suite") +load("@build_bazel_rules_karma//:defs.bzl", "ts_web_test_suite") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_library") sass_binary( name = "hello-world-styles", diff --git a/integration/bazel/src/package.json b/integration/bazel/src/package.json index 22381af730..5a6bf49e5d 100644 --- a/integration/bazel/src/package.json +++ b/integration/bazel/src/package.json @@ -13,8 +13,8 @@ "@angular/bazel": "file:../angular/dist/packages-dist/bazel", "@angular/compiler": "file:../angular/dist/packages-dist/compiler", "@angular/compiler-cli": "file:../angular/dist/packages-dist/compiler-cli", - "@bazel/karma": "0.22.0", - "@bazel/typescript": "0.22.0", + "@bazel/karma": "0.23.2", + "@bazel/typescript": "0.23.2", "@types/jasmine": "2.8.8", "@types/source-map": "0.5.1", "protractor": "5.1.2", @@ -23,4 +23,4 @@ "scripts": { "//": "TODO(gregmagolan): figure out how to keep dependencies here up to date with the root package.json" } -} +} \ No newline at end of file diff --git a/integration/bazel/src/yarn.lock b/integration/bazel/src/yarn.lock index b0af79e074..b22506d956 100644 --- a/integration/bazel/src/yarn.lock +++ b/integration/bazel/src/yarn.lock @@ -32,7 +32,18 @@ rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/schematics@7.1.2", "@angular-devkit/schematics@^7.0.4": +"@angular-devkit/core@7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.0.tgz#fc272e39b4c307833e9a7db77007418a246f5410" + integrity sha512-b0qtAUpgqLpWY8W6vWRv1aj6bXkZCP1rvywl8i8TbGMY67CWRcy5J3fNAMmjiZS+LJixFlIXYf4iOydglyJMfg== + dependencies: + ajv "6.7.0" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.1.2": version "7.1.2" resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.1.2.tgz#847639044417d044bf1bc87f64508a0c3f99fae2" integrity sha512-NFhHLYWf9gpGQm0s19lq+nAw3CZ0udBpoBLzCm8Crlmu6+7aAXgw7Fv5P4ukWJ/e1m7NDGVids+B6kBGXaY6Ig== @@ -40,20 +51,29 @@ "@angular-devkit/core" "7.1.2" rxjs "6.3.3" -"@angular/bazel@file:../../../dist/packages-dist/bazel": - version "0.0.0" +"@angular-devkit/schematics@^7.3.0-rc.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.0.tgz#112c1f59ff2778157aff6fb7484a6c132d4156ac" + integrity sha512-glOduymftH0LmJhITWgWUJK8QCDUltgTZ943/OyArIvLXTLL/8zCb+G6xL+3k33EQjwJicgQ3WIjonJmeTK/Ww== + dependencies: + "@angular-devkit/core" "7.3.0" + rxjs "6.3.3" + +"@angular/bazel@file:../angular/dist/packages-dist/bazel": + version "8.0.0-beta.2" dependencies: "@angular-devkit/architect" "^0.10.6" "@angular-devkit/core" "^7.0.4" - "@angular-devkit/schematics" "^7.0.4" - "@bazel/typescript" "^0.21.0" + "@angular-devkit/schematics" "^7.3.0-rc.0" + "@bazel/typescript" "^0.23.2" "@schematics/angular" "^7.0.4" "@types/node" "6.0.84" + semver "^5.6.0" shelljs "0.8.2" tsickle "0.34.0" -"@angular/compiler-cli@file:../../../dist/packages-dist/compiler-cli": - version "0.0.0" +"@angular/compiler-cli@file:../angular/dist/packages-dist/compiler-cli": + version "8.0.0-beta.2" dependencies: canonical-path "1.0.0" chokidar "^1.4.2" @@ -67,42 +87,36 @@ tslib "^1.9.0" yargs "9.0.1" -"@angular/compiler@file:../../../dist/packages-dist/compiler": - version "0.0.0" +"@angular/compiler@file:../angular/dist/packages-dist/compiler": + version "8.0.0-beta.2" dependencies: tslib "^1.9.0" -"@bazel/karma@0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.22.0.tgz#d2688ed05ea7e0be320802847ccc936da2688c70" - integrity sha512-ZhdkVR92UEOdON7hNjBJPdAUEFzibc/RC3TqBWupowl2+YsMZmxk8AsGjAmc9FaMkhCX9SDQC0OzGkUkuC6r3w== +"@bazel/karma@0.23.2": + version "0.23.2" + resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.23.2.tgz#17421a61cbcc6c917902beaaef88d61f22471f11" + integrity sha512-aNujXKusUjJIkc6CF03LS8AS7ULwNE0MKEL2TlYvnGCZviQ3nKrpRiEtWFmZlT+GrTOeu7AM4t3l4pSdQx/jnw== dependencies: jasmine-core "2.8.0" - karma alexeagle/karma#fa1a84ac881485b5657cb669e9b4e5da77b79f0a + karma "^4.0.0" karma-chrome-launcher "2.2.0" karma-firefox-launcher "1.1.0" karma-jasmine "1.1.1" karma-requirejs "1.1.0" - karma-sauce-launcher "1.2.0" + karma-sauce-launcher "2.0.2" karma-sourcemap-loader "0.3.7" requirejs "2.3.5" + semver "5.6.0" tmp "0.0.33" -"@bazel/typescript@0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.22.0.tgz#8b38183125c3f25e6023b12a371561d9b54182d8" - integrity sha512-2oKxPHlt3TNJx2RVVvC00ahcYNuIg1pQPjKQO7qyMNGGme3fqqzv5gRUDa5be/B01FxQDFpuBCHoavH7PilPRA== - dependencies: - protobufjs "5.0.3" - source-map-support "0.5.9" - tsutils "2.27.2" - -"@bazel/typescript@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.21.0.tgz#41c304f77a42c6a016280d0f4c20e0749c3f4b2a" - integrity sha512-ASXj0RFybmqoa3LwqkTU3gNkX9bY9wL/VDNo5hlp9pynYWl4RMpe9V3m/qDIdtSuLJ+qD+Z3FKT/OcpWQHMlYA== +"@bazel/typescript@0.23.2", "@bazel/typescript@^0.23.2": + version "0.23.2" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.23.2.tgz#a3ff199880855259d84216cb41644c1d9a0fad14" + integrity sha512-GrTyDW6Fvp/rgnxZGYampB5/QmDWvxtLEtUyMCPa/QXFR1OVxaMWeHxxuFEcES2UKJegqBDKAA8IzX21x4UbEw== dependencies: + jasmine-core "2.8.0" protobufjs "5.0.3" + semver "5.6.0" source-map-support "0.5.9" tsutils "2.27.2" @@ -158,11 +172,6 @@ accepts@~1.3.4: mime-types "~2.1.18" negotiator "0.6.1" -addressparser@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" - integrity sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y= - adm-zip@0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" @@ -186,7 +195,7 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" -agent-base@4, agent-base@^4.1.0, agent-base@^4.2.0, agent-base@~4.2.0: +agent-base@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== @@ -203,7 +212,17 @@ ajv@6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^5.1.0, ajv@^5.3.0: +ajv@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.7.0.tgz#e3ce7bb372d6577bb1839f1dfdfcbf5ad2948d96" + integrity sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= @@ -213,17 +232,6 @@ ajv@^5.1.0, ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -amqplib@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.5.2.tgz#d2d7313c7ffaa4d10bcf1e6252de4591b6cc7b63" - integrity sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA== - dependencies: - bitsyntax "~0.0.4" - bluebird "^3.4.6" - buffer-more-ints "0.0.2" - readable-stream "1.x >=1.1.9" - safe-buffer "^5.0.1" - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -260,32 +268,6 @@ aproba@^1.0.3: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -archiver-utils@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174" - integrity sha1-5QtMCccL89aA4y/xt5lOn52JUXQ= - dependencies: - glob "^7.0.0" - graceful-fs "^4.1.0" - lazystream "^1.0.0" - lodash "^4.8.0" - normalize-path "^2.0.0" - readable-stream "^2.0.0" - -archiver@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-2.1.1.tgz#ff662b4a78201494a3ee544d3a33fe7496509ebc" - integrity sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw= - dependencies: - archiver-utils "^1.3.0" - async "^2.0.0" - buffer-crc32 "^0.2.1" - glob "^7.0.0" - lodash "^4.8.0" - readable-stream "^2.0.0" - tar-stream "^1.5.0" - zip-stream "^1.2.0" - are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -373,21 +355,11 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= - assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-types@0.x.x: - version "0.11.5" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.5.tgz#9890825d660c03c28339f315e9fa0a360e31ec28" - integrity sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw== - async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -398,14 +370,7 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== -async@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/async/-/async-2.0.1.tgz#b709cc0280a9c36f09f4536be823c838a9049e25" - integrity sha1-twnMAoCpw28J9FNr6CPIOKkEniU= - dependencies: - lodash "^4.8.0" - -async@^2.0.0, async@^2.1.2, async@~2.6.0: +async@^2.1.2: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== @@ -422,28 +387,16 @@ atob@^2.1.1: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8= - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= -aws4@^1.2.1, aws4@^1.6.0, aws4@^1.8.0: +aws4@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== -axios@^0.15.3: - version "0.15.3" - resolved "http://registry.npmjs.org/axios/-/axios-0.15.3.tgz#2c9d638b2e191a08ea1d6cc988eadd6ba5bdc053" - integrity sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM= - dependencies: - follow-redirects "1.0.0" - backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -459,11 +412,6 @@ base64-arraybuffer@0.1.5: resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= -base64-js@^1.0.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== - base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" @@ -501,28 +449,6 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== -bitsyntax@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.0.4.tgz#eb10cc6f82b8c490e3e85698f07e83d46e0cba82" - integrity sha1-6xDMb4K4xJDj6FaY8H6D1G4MuoI= - dependencies: - buffer-more-ints "0.0.2" - -bl@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - -bl@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" - integrity sha1-/cqHGplxOqANGeO7ukHER4emU5g= - dependencies: - readable-stream "~2.0.5" - blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" @@ -535,7 +461,7 @@ blocking-proxy@0.0.5: dependencies: minimist "^1.2.0" -bluebird@^3.3.0, bluebird@^3.4.6: +bluebird@^3.3.0: version "3.5.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a" integrity sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg== @@ -556,27 +482,6 @@ body-parser@^1.16.1: raw-body "2.3.3" type-is "~1.6.16" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= - dependencies: - hoek "2.x.x" - -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - integrity sha1-T4owBctKfjiJ90kDD9JbluAdLjE= - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - integrity sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw== - dependencies: - hoek "4.x.x" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -630,11 +535,6 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" -buffer-crc32@^0.2.1: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" @@ -645,32 +545,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -buffer-more-ints@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" - integrity sha1-JrOIXRD6E9t/wBquOquHAZngEkw= - -buffer@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" - integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - -buildmail@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/buildmail/-/buildmail-4.0.1.tgz#877f7738b78729871c9a105e3b837d2be11a7a72" - integrity sha1-h393OLeHKYccmhBeO4N9K+EaenI= - dependencies: - addressparser "1.0.1" - libbase64 "0.1.0" - libmime "3.0.0" - libqp "1.1.0" - nodemailer-fetch "1.6.0" - nodemailer-shared "1.1.0" - punycode "1.4.1" - builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -723,11 +597,6 @@ canonical-path@1.0.0: resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c= - caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -744,7 +613,7 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chokidar@2.0.4: +chokidar@2.0.4, chokidar@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== @@ -764,7 +633,7 @@ chokidar@2.0.4: optionalDependencies: fsevents "^1.2.2" -chokidar@^1.4.1, chokidar@^1.4.2: +chokidar@^1.4.2: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= @@ -785,10 +654,10 @@ chownr@^1.0.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== -circular-json@^0.5.4: - version "0.5.7" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.7.tgz#b8be478d72ea58c7eeda26bf1cf1fba43d188842" - integrity sha512-/pXoV1JA847qRKPrHbBK6YIBGFF8GOP4wzSgUOA7q0ew0vAv0iJswP+2/nZQ9uzA3Azi7eTrg9L2yzXc/7ZMIA== +circular-json@^0.5.5: + version "0.5.9" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" + integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== class-utils@^0.3.5: version "0.3.6" @@ -851,18 +720,13 @@ combined-stream@1.0.6: dependencies: delayed-stream "~1.0.0" -combined-stream@^1.0.5, combined-stream@~1.0.5, combined-stream@~1.0.6: +combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== dependencies: delayed-stream "~1.0.0" -commander@^2.9.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970" - integrity sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ== - component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -878,16 +742,6 @@ component-inherit@0.0.3: resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= -compress-commons@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" - integrity sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8= - dependencies: - buffer-crc32 "^0.2.1" - crc32-stream "^2.0.0" - normalize-path "^2.0.0" - readable-stream "^2.0.0" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -935,26 +789,16 @@ core-js@^2.2.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -crc32-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" - integrity sha1-483TtN8xaN10494/u8t7KX/pCPQ= - dependencies: - crc "^3.4.4" - readable-stream "^2.0.0" - -crc@^3.4.4: - version "3.8.0" - resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" - integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== - dependencies: - buffer "^5.1.0" - cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -964,20 +808,6 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= - dependencies: - boom "2.x.x" - -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - integrity sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4= - dependencies: - boom "5.x.x" - custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" @@ -990,24 +820,19 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-uri-to-buffer@1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz#77163ea9c20d8641b4707e8f18abdf9a78f34835" - integrity sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ== - date-format@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/date-format/-/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8" integrity sha1-YV6CjiM90aubua4JUODOzPpuytg= -debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@~2.6.4, debug@~2.6.6: +debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@3.1.0, debug@=3.1.0, debug@~3.1.0: +debug@=3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== @@ -1036,11 +861,6 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -1063,15 +883,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -degenerator@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-1.0.4.tgz#fcf490a37ece266464d9cc431ab98c5819ced095" - integrity sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU= - dependencies: - ast-types "0.x.x" - escodegen "1.x.x" - esprima "3.x.x" - del@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -1125,11 +936,6 @@ dom-serialize@^2.2.0: extend "^3.0.0" void-elements "^2.0.0" -double-ended-queue@^2.1.0-0: - version "2.1.0-0" - resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" - integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw= - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -1148,17 +954,10 @@ encodeurl@~1.0.1: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== - dependencies: - once "^1.4.0" - -engine.io-client@~3.1.0: - version "3.1.6" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.1.6.tgz#5bdeb130f8b94a50ac5cbeb72583e7a4a063ddfd" - integrity sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg== +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -1183,10 +982,10 @@ engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: blob "0.0.4" has-binary2 "~1.0.2" -engine.io@~3.1.0: - version "3.1.5" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.1.5.tgz#0e7ef9d690eb0b35597f1d4ad02a26ca2dba3845" - integrity sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA== +engine.io@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.1.tgz#b60281c35484a70ee0351ea0ebff83ec8c9522a2" + integrity sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w== dependencies: accepts "~1.3.4" base64id "1.0.0" @@ -1194,8 +993,6 @@ engine.io@~3.1.0: debug "~3.1.0" engine.io-parser "~2.1.0" ws "~3.3.1" - optionalDependencies: - uws "~9.14.0" ent@~2.2.0: version "2.2.0" @@ -1214,6 +1011,11 @@ es6-promise@^4.0.3: resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg== +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= + es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" @@ -1231,33 +1033,6 @@ escape-string-regexp@^1.0.2: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@1.x.x: - version "1.11.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589" - integrity sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw== - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -esprima@3.x.x, esprima@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= - -estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= - -esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= - eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" @@ -1340,7 +1115,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.1, extend@~3.0.2: +extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -1391,16 +1166,6 @@ fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -file-uri-to-path@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -1447,12 +1212,10 @@ find-up@^2.0.0: dependencies: locate-path "^2.0.0" -follow-redirects@1.0.0: - version "1.0.0" - resolved "http://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz#8e34298cbd2e176f254effec75a1c78cc849fd37" - integrity sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc= - dependencies: - debug "^2.2.0" +flatted@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" + integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== follow-redirects@^1.0.0: version "1.5.8" @@ -1478,16 +1241,7 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -form-data@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" - integrity sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU= - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.11" - -form-data@~2.3.0, form-data@~2.3.1, form-data@~2.3.2: +form-data@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" integrity sha1-SXBJi+YEwgwAXU9cI67NIda0kJk= @@ -1510,11 +1264,6 @@ fs-access@^1.0.0: dependencies: null-check "^1.0.0" -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -1535,14 +1284,6 @@ fsevents@^1.0.0, fsevents@^1.2.2: nan "^2.9.2" node-pre-gyp "^0.10.0" -ftp@~0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -1557,20 +1298,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generate-function@^2.0.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA= - dependencies: - is-property "^1.0.0" - get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -1581,18 +1308,6 @@ get-stream@^3.0.0: resolved "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= -get-uri@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.2.tgz#5c795e71326f6ca1286f2fc82575cd2bab2af578" - integrity sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw== - dependencies: - data-uri-to-buffer "1" - debug "2" - extend "3" - file-uri-to-path "1" - ftp "~0.3.10" - readable-stream "2" - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -1652,7 +1367,7 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2: +graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= @@ -1662,24 +1377,6 @@ har-schema@^2.0.0: resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= -har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - integrity sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0= - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - integrity sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0= - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - har-validator@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" @@ -1743,44 +1440,6 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - integrity sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ== - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - -hipchat-notifier@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz#b6d249755437c191082367799d3ba9a0f23b231e" - integrity sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4= - dependencies: - lodash "^4.0.0" - request "^2.0.0" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= - -hoek@4.x.x: - version "4.2.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" - integrity sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA== - hosted-git-info@^2.1.4: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -1796,14 +1455,6 @@ http-errors@1.6.3, http-errors@~1.6.3: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy@^1.13.0: version "1.17.0" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" @@ -1813,15 +1464,6 @@ http-proxy@^1.13.0: follow-redirects "^1.0.0" requires-port "^1.0.0" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8= - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -1831,19 +1473,6 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -httpntlm@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/httpntlm/-/httpntlm-1.6.1.tgz#ad01527143a2e8773cfae6a96f58656bb52a34b2" - integrity sha1-rQFScUOi6Hc8+uapb1hla7UqNLI= - dependencies: - httpreq ">=0.4.22" - underscore "~1.7.0" - -httpreq@>=0.4.22: - version "0.4.24" - resolved "https://registry.yarnpkg.com/httpreq/-/httpreq-0.4.24.tgz#4335ffd82cd969668a39465c929ac61d6393627f" - integrity sha1-QzX/2CzZaWaKOUZckprGHWOTYn8= - https-proxy-agent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" @@ -1861,11 +1490,6 @@ https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" -iconv-lite@0.4.15: - version "0.4.15" - resolved "http://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - integrity sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es= - iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" @@ -1880,11 +1504,6 @@ iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.4: - version "1.1.12" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" - integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== - ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" @@ -1892,21 +1511,16 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= -inflection@~1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" - integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= - -inflection@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.3.8.tgz#cbd160da9f75b14c3cc63578d4f396784bf3014e" - integrity sha1-y9Fg2p91sUw8xjV41POWeEvzAU4= - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1935,11 +1549,6 @@ invert-kv@^1.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= -ip@^1.1.2, ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -2077,22 +1686,6 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== - -is-my-json-valid@^2.12.4: - version "2.19.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" - integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q== - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" @@ -2153,11 +1746,6 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= -is-property@^1.0.0, is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= - is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -2173,11 +1761,6 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -2261,16 +1844,11 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stringify-safe@5.0.x, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk= - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2281,6 +1859,17 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + karma-chrome-launcher@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" @@ -2304,15 +1893,14 @@ karma-requirejs@1.1.0: resolved "https://registry.yarnpkg.com/karma-requirejs/-/karma-requirejs-1.1.0.tgz#fddae2cb87d7ebc16fb0222893564d7fee578798" integrity sha1-/driy4fX68FvsCIok1ZNf+5Xh5g= -karma-sauce-launcher@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/karma-sauce-launcher/-/karma-sauce-launcher-1.2.0.tgz#6f2558ddef3cf56879fa27540c8ae9f8bfd16bca" - integrity sha512-lEhtGRGS+3Yw6JSx/vJY9iQyHNtTjcojrSwNzqNUOaDceKDu9dPZqA/kr69bUO9G2T6GKbu8AZgXqy94qo31Jg== +karma-sauce-launcher@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/karma-sauce-launcher/-/karma-sauce-launcher-2.0.2.tgz#dbf98e70d86bf287b03a537cf637eb7aefa975c3" + integrity sha512-jLUFaJhHMcKpxFWUesyWYihzM5FvQiJsDwGcCtKeOy2lsWhkVw0V0Byqb1d+wU6myU1mribBtsIcub23HS4kWA== dependencies: - q "^1.5.0" - sauce-connect-launcher "^1.2.2" - saucelabs "^1.4.0" - wd "^1.4.0" + sauce-connect-launcher "^1.2.4" + saucelabs "^1.5.0" + selenium-webdriver "^4.0.0-alpha.1" karma-sourcemap-loader@0.3.7: version "0.3.7" @@ -2321,13 +1909,14 @@ karma-sourcemap-loader@0.3.7: dependencies: graceful-fs "^4.1.2" -"karma@github:alexeagle/karma#fa1a84ac881485b5657cb669e9b4e5da77b79f0a": - version "1.7.1" - resolved "https://codeload.github.com/alexeagle/karma/tar.gz/fa1a84ac881485b5657cb669e9b4e5da77b79f0a" +karma@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-4.0.0.tgz#f28e38a2b66243fde3f98e12a8dcaa2c6ff8ca9c" + integrity sha512-EFoFs3F6G0BcUGPNOn/YloGOb3h09hzTguyXlg6loHlKY76qbJikkcyPk43m2kfRF65TUGda/mig29QQtyhm1g== dependencies: bluebird "^3.3.0" body-parser "^1.16.1" - chokidar "^1.4.1" + chokidar "^2.0.3" colors "^1.1.0" combine-lists "^1.0.0" connect "^3.6.0" @@ -2335,23 +1924,24 @@ karma-sourcemap-loader@0.3.7: di "^0.0.1" dom-serialize "^2.2.0" expand-braces "^0.1.1" + flatted "^2.0.0" glob "^7.1.1" graceful-fs "^4.1.2" http-proxy "^1.13.0" isbinaryfile "^3.0.0" - lodash "^4.17.4" - log4js "^2.3.9" - mime "^1.3.4" + lodash "^4.17.5" + log4js "^3.0.0" + mime "^2.3.1" minimatch "^3.0.2" optimist "^0.6.1" qjobs "^1.1.4" range-parser "^1.2.0" rimraf "^2.6.0" safe-buffer "^5.0.1" - socket.io "2.0.4" + socket.io "2.1.1" source-map "^0.6.1" tmp "0.0.33" - useragent "^2.1.12" + useragent "2.3.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" @@ -2377,13 +1967,6 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== -lazystream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" - integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= - dependencies: - readable-stream "^2.0.5" - lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -2391,32 +1974,12 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -libbase64@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/libbase64/-/libbase64-0.1.0.tgz#62351a839563ac5ff5bd26f12f60e9830bb751e6" - integrity sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY= - -libmime@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/libmime/-/libmime-3.0.0.tgz#51a1a9e7448ecbd32cda54421675bb21bc093da6" - integrity sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY= - dependencies: - iconv-lite "0.4.15" - libbase64 "0.1.0" - libqp "1.1.0" - -libqp@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" - integrity sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g= + immediate "~3.0.5" load-json-file@^2.0.0: version "2.0.0" @@ -2441,51 +2004,28 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash@4.17.10: - version "4.17.10" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== - -lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.5.0, lodash@^4.8.0: +lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.5, lodash@^4.5.0: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== -log4js@^2.3.9: - version "2.11.0" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-2.11.0.tgz#bf3902eff65c6923d9ce9cfbd2db54160e34005a" - integrity sha512-z1XdwyGFg8/WGkOyF6DPJjivCWNLKrklGdViywdYnSKOvgtEBo2UyEMZS5sD2mZrQlU3TvO8wDWLc8mzE1ncBQ== +log4js@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-3.0.6.tgz#e6caced94967eeeb9ce399f9f8682a4b2b28c8ff" + integrity sha512-ezXZk6oPJCWL483zj64pNkMuY/NcRX5MPiB0zE6tjZM137aeusrOnW1ecxgF9cmwMWkBMhjteQxBPoZBh9FDxQ== dependencies: - circular-json "^0.5.4" + circular-json "^0.5.5" date-format "^1.2.0" debug "^3.1.0" - semver "^5.5.0" + rfdc "^1.1.2" streamroller "0.7.0" - optionalDependencies: - amqplib "^0.5.2" - axios "^0.15.3" - hipchat-notifier "^1.1.0" - loggly "^1.1.0" - mailgun-js "^0.18.0" - nodemailer "^2.5.0" - redis "^2.7.1" - slack-node "~0.2.0" - -loggly@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/loggly/-/loggly-1.1.1.tgz#0a0fc1d3fa3a5ec44fdc7b897beba2a4695cebee" - integrity sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4= - dependencies: - json-stringify-safe "5.0.x" - request "2.75.x" - timespan "2.3.x" long@~3: version "3.2.0" resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s= -lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.2: +lru-cache@4.1.x, lru-cache@^4.0.1: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== @@ -2500,29 +2040,6 @@ magic-string@^0.25.0: dependencies: sourcemap-codec "^1.4.1" -mailcomposer@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/mailcomposer/-/mailcomposer-4.0.1.tgz#0e1c44b2a07cf740ee17dc149ba009f19cadfeb4" - integrity sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ= - dependencies: - buildmail "4.0.1" - libmime "3.0.0" - -mailgun-js@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/mailgun-js/-/mailgun-js-0.18.1.tgz#ee39aa18d7bb598a5ce9ede84afb681defc8a6b0" - integrity sha512-lvuMP14u24HS2uBsJEnzSyPMxzU2b99tQsIx1o6QNjqxjk8b3WvR+vq5oG1mjqz/IBYo+5gF+uSoDS0RkMVHmg== - dependencies: - async "~2.6.0" - debug "~3.1.0" - form-data "~2.3.0" - inflection "~1.12.0" - is-stream "^1.1.0" - path-proxy "~1.0.0" - promisify-call "^2.0.2" - proxy-agent "~3.0.0" - tsscmp "~1.0.0" - map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -2595,17 +2112,17 @@ mime-db@~1.36.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw== -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19: version "2.1.20" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" integrity sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A== dependencies: mime-db "~1.36.0" -mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@^2.3.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" + integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w== mimic-fn@^1.0.0: version "1.2.0" @@ -2710,11 +2227,6 @@ negotiator@0.6.1: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= -netmask@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" - integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= - node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" @@ -2731,67 +2243,6 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-uuid@~1.4.7: - version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - integrity sha1-sEDrCSOWivq/jTL7HxfxFn/auQc= - -nodemailer-direct-transport@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz#e96fafb90358560947e569017d97e60738a50a86" - integrity sha1-6W+vuQNYVglH5WkBfZfmBzilCoY= - dependencies: - nodemailer-shared "1.1.0" - smtp-connection "2.12.0" - -nodemailer-fetch@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz#79c4908a1c0f5f375b73fe888da9828f6dc963a4" - integrity sha1-ecSQihwPXzdbc/6IjamCj23JY6Q= - -nodemailer-shared@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz#cf5994e2fd268d00f5cf0fa767a08169edb07ec0" - integrity sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA= - dependencies: - nodemailer-fetch "1.6.0" - -nodemailer-smtp-pool@2.8.2: - version "2.8.2" - resolved "https://registry.yarnpkg.com/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz#2eb94d6cf85780b1b4725ce853b9cbd5e8da8c72" - integrity sha1-LrlNbPhXgLG0clzoU7nL1ejajHI= - dependencies: - nodemailer-shared "1.1.0" - nodemailer-wellknown "0.1.10" - smtp-connection "2.12.0" - -nodemailer-smtp-transport@2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz#03d71c76314f14ac7dbc7bf033a6a6d16d67fb77" - integrity sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c= - dependencies: - nodemailer-shared "1.1.0" - nodemailer-wellknown "0.1.10" - smtp-connection "2.12.0" - -nodemailer-wellknown@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz#586db8101db30cb4438eb546737a41aad0cf13d5" - integrity sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U= - -nodemailer@^2.5.0: - version "2.7.2" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-2.7.2.tgz#f242e649aeeae39b6c7ed740ef7b061c404d30f9" - integrity sha1-8kLmSa7q45tsftdA73sGHEBNMPk= - dependencies: - libmime "3.0.0" - mailcomposer "4.0.1" - nodemailer-direct-transport "3.3.2" - nodemailer-shared "1.1.0" - nodemailer-smtp-pool "2.8.2" - nodemailer-smtp-transport "2.7.2" - socks "1.1.9" - nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -2857,11 +2308,6 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -oauth-sign@~0.8.1, oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -2915,7 +2361,7 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" -once@^1.3.0, once@^1.4.0: +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -2930,18 +2376,6 @@ optimist@^0.6.1, optimist@~0.6.0: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" @@ -3010,30 +2444,10 @@ p-try@^1.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= -pac-proxy-agent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-3.0.0.tgz#11d578b72a164ad74bf9d5bac9ff462a38282432" - integrity sha512-AOUX9jES/EkQX2zRz0AW7lSx9jD//hQS8wFXBvcnd/J2Py9KaMJMqV/LPqJssj1tgGufotb2mmopGPR15ODv1Q== - dependencies: - agent-base "^4.2.0" - debug "^3.1.0" - get-uri "^2.0.0" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" - pac-resolver "^3.0.0" - raw-body "^2.2.0" - socks-proxy-agent "^4.0.1" - -pac-resolver@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-3.0.0.tgz#6aea30787db0a891704deb7800a722a7615a6f26" - integrity sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA== - dependencies: - co "^4.6.0" - degenerator "^1.0.4" - ip "^1.1.5" - netmask "^1.0.6" - thunkify "^2.1.2" +pako@~1.0.2: + version "1.0.8" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4" + integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA== parse-glob@^3.0.4: version "3.0.4" @@ -3106,13 +2520,6 @@ path-parse@^1.0.5: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== -path-proxy@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-proxy/-/path-proxy-1.0.0.tgz#18e8a36859fc9d2f1a53b48dee138543c020de5e" - integrity sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4= - dependencies: - inflection "~1.3.0" - path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -3147,11 +2554,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" @@ -3167,13 +2569,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== -promisify-call@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/promisify-call/-/promisify-call-2.0.4.tgz#d48c2d45652ccccd52801ddecbd533a6d4bd5fba" - integrity sha1-1IwtRWUszM1SgB3ey9UzptS9X7o= - dependencies: - with-callback "^1.0.2" - protobufjs@5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17" @@ -3205,25 +2600,6 @@ protractor@5.1.2: webdriver-js-extender "^1.0.0" webdriver-manager "^12.0.6" -proxy-agent@~3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-3.0.3.tgz#1c1a33db60ef5f2e9e35b876fd63c2bc681c611d" - integrity sha512-PXVVVuH9tiQuxQltFJVSnXWuDtNr+8aNBP6XVDDCDiUuDN8eRCm+ii4/mFWmXWEA0w8jjJSlePa4LXlM4jIzNA== - dependencies: - agent-base "^4.2.0" - debug "^3.1.0" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" - lru-cache "^4.1.2" - pac-proxy-agent "^3.0.0" - proxy-from-env "^1.0.0" - socks-proxy-agent "^4.0.1" - -proxy-from-env@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= - pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -3234,7 +2610,7 @@ psl@^1.1.24: resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" integrity sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ== -punycode@1.4.1, punycode@^1.4.1: +punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= @@ -3249,7 +2625,7 @@ q@1.4.1: resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= -q@^1.4.1, q@^1.5.0: +q@^1.4.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= @@ -3259,16 +2635,11 @@ qjobs@^1.1.4: resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== -qs@6.5.2, qs@~6.5.1, qs@~6.5.2: +qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -qs@~6.2.0: - version "6.2.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" - integrity sha1-HPyyXBCpsrSDBT/zn138kjOQjP4= - randomatic@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.0.tgz#36f2ca708e9e567f5ed2ec01949026d50aa10116" @@ -3283,7 +2654,7 @@ range-parser@^1.2.0: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= -raw-body@2.3.3, raw-body@^2.2.0: +raw-body@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== @@ -3320,17 +2691,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -readable-stream@1.1.x, "readable-stream@1.x >=1.1.9": - version "1.1.14" - resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.0: version "2.3.6" resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -3343,9 +2704,9 @@ readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stre string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@~2.0.5: +readable-stream@~2.0.6: version "2.0.6" - resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= dependencies: core-util-is "~1.0.0" @@ -3371,25 +2732,6 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" -redis-commands@^1.2.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.5.tgz#4495889414f1e886261180b1442e7295602d83a2" - integrity sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA== - -redis-parser@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b" - integrity sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs= - -redis@^2.7.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02" - integrity sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A== - dependencies: - double-ended-queue "^2.1.0-0" - redis-commands "^1.2.0" - redis-parser "^2.6.0" - reflect-metadata@0.1.12, reflect-metadata@^0.1.2: version "0.1.12" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" @@ -3430,62 +2772,7 @@ repeat-string@^1.5.2, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -request@2.75.x: - version "2.75.0" - resolved "http://registry.npmjs.org/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" - integrity sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM= - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - bl "~1.1.2" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.0.0" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.1" - qs "~6.2.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - -request@2.85.0: - version "2.85.0" - resolved "http://registry.npmjs.org/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" - integrity sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@^2.0.0, request@^2.74.0, request@^2.87.0: +request@^2.87.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -3511,16 +2798,6 @@ request@^2.0.0, request@^2.74.0, request@^2.87.0: tunnel-agent "^0.6.0" uuid "^3.3.2" -requestretry@^1.2.2: - version "1.13.0" - resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-1.13.0.tgz#213ec1006eeb750e8b8ce54176283d15a8d55d94" - integrity sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg== - dependencies: - extend "^3.0.0" - lodash "^4.15.0" - request "^2.74.0" - when "^3.7.7" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -3558,6 +2835,11 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +rfdc@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" + integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== + rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" @@ -3572,7 +2854,7 @@ rxjs@6.3.3: dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -3589,7 +2871,7 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sauce-connect-launcher@^1.2.2: +sauce-connect-launcher@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.2.4.tgz#8d38f85242a9fbede1b2303b559f7e20c5609a1c" integrity sha512-X2vfwulR6brUGiicXKxPm1GJ7dBEeP1II450Uv4bHGrcGOapZNgzJvn9aioea5IC5BPp/7qjKdE3xbbTBIVXMA== @@ -3600,7 +2882,7 @@ sauce-connect-launcher@^1.2.2: lodash "^4.16.6" rimraf "^2.5.4" -saucelabs@^1.4.0: +saucelabs@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== @@ -3645,11 +2927,26 @@ selenium-webdriver@^2.53.2: ws "^1.0.1" xml2js "0.4.4" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0: +selenium-webdriver@^4.0.0-alpha.1: + version "4.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.1.tgz#cc93415e21d2dc1dfd85dfc5f6b55f3ac53933b1" + integrity sha512-z88rdjHAv3jmTZ7KSGUkTvo4rGzcDGMq0oXWHNIDK96Gs31JKVdu9+FMtT4KBrVoibg8dUicJDok6GnqqttO5Q== + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.5.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== +semver@5.6.0, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" @@ -3711,31 +3008,6 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -slack-node@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/slack-node/-/slack-node-0.2.0.tgz#de4b8dddaa8b793f61dbd2938104fdabf37dfa30" - integrity sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA= - dependencies: - requestretry "^1.2.2" - -smart-buffer@^1.0.4: - version "1.1.15" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" - integrity sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY= - -smart-buffer@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" - integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== - -smtp-connection@2.12.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.12.0.tgz#d76ef9127cb23c2259edb1e8349c2e8d5e2d74c1" - integrity sha1-1275EnyyPCJZ7bHoNJwujV4tdME= - dependencies: - httpntlm "1.6.1" - nodemailer-shared "1.1.0" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -3766,88 +3038,51 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= - dependencies: - hoek "2.x.x" - -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - integrity sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg== - dependencies: - hoek "4.x.x" - socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= -socket.io-client@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.0.4.tgz#0918a552406dc5e540b380dcd97afc4a64332f8e" - integrity sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44= +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" component-bind "1.0.0" component-emitter "1.2.1" - debug "~2.6.4" - engine.io-client "~3.1.0" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" has-cors "1.1.0" indexof "0.0.1" object-component "0.0.3" parseqs "0.0.5" parseuri "0.0.5" - socket.io-parser "~3.1.1" + socket.io-parser "~3.2.0" to-array "0.1.4" -socket.io-parser@~3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.1.3.tgz#ed2da5ee79f10955036e3da413bfd7f1e4d86c8e" - integrity sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g== +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== dependencies: component-emitter "1.2.1" debug "~3.1.0" - has-binary2 "~1.0.2" isarray "2.0.1" -socket.io@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.0.4.tgz#c1a4590ceff87ecf13c72652f046f716b29e6014" - integrity sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ= +socket.io@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== dependencies: - debug "~2.6.6" - engine.io "~3.1.0" + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" socket.io-adapter "~1.1.0" - socket.io-client "2.0.4" - socket.io-parser "~3.1.1" - -socks-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" - integrity sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw== - dependencies: - agent-base "~4.2.0" - socks "~2.2.0" - -socks@1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.9.tgz#628d7e4d04912435445ac0b6e459376cb3e6d691" - integrity sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE= - dependencies: - ip "^1.1.2" - smart-buffer "^1.0.4" - -socks@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" - integrity sha512-0GabKw7n9mI46vcNrVfs0o6XzWzjVa3h6GaSo2UPxtWAROXUWavfJWh1M4PR5tnE0dcnQXZIDFP4yrAysLze/w== - dependencies: - ip "^1.1.5" - smart-buffer "^4.0.1" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" source-map-resolve@^0.5.0: version "0.5.2" @@ -3890,7 +3125,7 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -4006,11 +3241,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4, stringstream@~0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" - integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA== - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -4045,19 +3275,6 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -tar-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - tar@^4: version "4.4.6" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" @@ -4071,16 +3288,6 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" -thunkify@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" - integrity sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0= - -timespan@2.3.x: - version "2.3.0" - resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" - integrity sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk= - tmp@0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" @@ -4105,11 +3312,6 @@ to-array@0.1.4: resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -4135,13 +3337,6 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@~2.3.0, tough-cookie@~2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA== - dependencies: - punycode "^1.4.1" - tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -4164,11 +3359,6 @@ tslib@1.9.3, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tsscmp@~1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" - integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== - tsutils@2.27.2: version "2.27.2" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7" @@ -4183,23 +3373,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - integrity sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us= - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" @@ -4228,11 +3406,6 @@ ultron@~1.1.0: resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== -underscore@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" - integrity sha1-a7rwh3UA02vjTsqlhODbn+8DUgk= - union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -4278,7 +3451,7 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -useragent@^2.1.12: +useragent@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== @@ -4296,16 +3469,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.1.0, uuid@^3.3.2: +uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== -uws@~9.14.0: - version "9.14.0" - resolved "https://registry.yarnpkg.com/uws/-/uws-9.14.0.tgz#fac8386befc33a7a3705cbd58dc47b430ca4dd95" - integrity sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg== - validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -4314,11 +3482,6 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -vargs@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff" - integrity sha1-a2GE2mUgzDIEzhtAfKwm2SYJ6/8= - verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -4333,19 +3496,6 @@ void-elements@^2.0.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= -wd@^1.4.0: - version "1.10.3" - resolved "https://registry.yarnpkg.com/wd/-/wd-1.10.3.tgz#395ac7eb58a98e556369f8f8e5f845d91fb152a3" - integrity sha512-ffqqZDtFFLeg5u/4pw2vYKECW+z+vW6vc+7rcqF15uu1/rmw3BydV84BONNc9DIcQ5Z7gQFS/hAuMvj53eVtSg== - dependencies: - archiver "2.1.1" - async "2.0.1" - lodash "4.17.10" - mkdirp "^0.5.1" - q "1.4.1" - request "2.85.0" - vargs "0.1.0" - webdriver-js-extender@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515" @@ -4371,11 +3521,6 @@ webdriver-manager@^12.0.6: semver "^5.3.0" xml2js "^0.4.17" -when@^3.7.7: - version "3.7.8" - resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" - integrity sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I= - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -4400,21 +3545,11 @@ window-size@^0.1.4: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY= -with-callback@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/with-callback/-/with-callback-1.0.2.tgz#a09629b9a920028d721404fb435bdcff5c91bc21" - integrity sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE= - wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - wrap-ansi@^2.0.0: version "2.1.0" resolved "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -4476,16 +3611,6 @@ xmlhttprequest-ssl@~1.5.4: resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" - integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= - -xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= - y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -4545,16 +3670,6 @@ yeast@0.1.2: resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= -zip-stream@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" - integrity sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ= - dependencies: - archiver-utils "^1.3.0" - compress-commons "^1.2.0" - lodash "^4.8.0" - readable-stream "^2.0.0" - zone.js@0.8.26: version "0.8.26" resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.26.tgz#7bdd72f7668c5a7ad6b118148b4ea39c59d08d2d" diff --git a/integration/bazel/yarn.lock b/integration/bazel/yarn.lock index 9f17e24dee..ea9cd9f0f0 100644 --- a/integration/bazel/yarn.lock +++ b/integration/bazel/yarn.lock @@ -2,24 +2,24 @@ # yarn lockfile v1 -"@bazel/bazel-darwin_x64@0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.18.0.tgz#bab437605a702279d42f59caa4741bb327eb7dbc" - integrity sha512-um2OzgLL2Gd/W6joOpvrSTcqpnupliPNpwe/uE7sB0huBSJ/4Im0w2IlCTI6C7OfgMcbpUj4YxgUa9T6u6WY6w== +"@bazel/bazel-darwin_x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-0.20.0.tgz#648d61c32a3c5fccb7bf70b753071b6e54b11f21" + integrity sha512-zeoeVK504341GfnaxdaB4pFzQV0YOK1HLiYj3/ocamPFxAJRh9abvKB8iOpqD5Oal0j7VsINxnXCjovp9a4urA== -"@bazel/bazel-linux_x64@0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.18.0.tgz#0c02b2404ec95c180e17615cc7079ee07df48a69" - integrity sha512-Rq8X8bL6SgQvbOHnfPhSgF6hp+f6Fbt2w6pRmBlFvV1J+CeUyrSrrRXfnnO1bjIuq05Ur3mV8ULA0qK6rtA5lQ== +"@bazel/bazel-linux_x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-0.20.0.tgz#2568628a0d0b85dcc69d0ab701b1d6e10551357d" + integrity sha512-PpHzoEqfXty8dc1/p1tVFXtbPyrE1n0N79QmYePjJ5mJMyW7uBF/zV4IajYY8+IpJEcDVq5v4BavSexOmVJRmA== -"@bazel/bazel-win32_x64@0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.18.0.tgz#aa4575fb00066dcf59a6d464971774dea6a0bafd" - integrity sha512-U2TbfK8B7dc3JqXSFwj2oXCQrxEaSzCCUkAHjAOIGOKzx/HLKIKs+NJj9IQkLLr7BsMU+Qqzo8aqo11E+Vs+aA== +"@bazel/bazel-win32_x64@0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-0.20.0.tgz#af7d041dae4c066e7aa8618949e2de1aad07495e" + integrity sha512-3bqHXFBvLnbvNzr1KCQ1zryTYvHMoQffaWVekbckgPyT2VPEj3abuB91+DrRYmZdPjcgPYnjnyanxZHDkKuF2g== "@bazel/bazel@file:../../node_modules/@bazel/bazel": - version "0.18.0" + version "0.20.0" optionalDependencies: - "@bazel/bazel-darwin_x64" "0.18.0" - "@bazel/bazel-linux_x64" "0.18.0" - "@bazel/bazel-win32_x64" "0.18.0" + "@bazel/bazel-darwin_x64" "0.20.0" + "@bazel/bazel-linux_x64" "0.20.0" + "@bazel/bazel-win32_x64" "0.20.0" diff --git a/integration/cli-hello-world-ivy/.editorconfig b/integration/cli-hello-world-ivy-compat/.editorconfig similarity index 78% rename from integration/cli-hello-world-ivy/.editorconfig rename to integration/cli-hello-world-ivy-compat/.editorconfig index 6e87a003da..e89330a618 100644 --- a/integration/cli-hello-world-ivy/.editorconfig +++ b/integration/cli-hello-world-ivy-compat/.editorconfig @@ -1,4 +1,4 @@ -# Editor configuration, see http://editorconfig.org +# Editor configuration, see https://editorconfig.org root = true [*] diff --git a/integration/cli-hello-world-ivy/README.md b/integration/cli-hello-world-ivy-compat/README.md similarity index 86% rename from integration/cli-hello-world-ivy/README.md rename to integration/cli-hello-world-ivy-compat/README.md index b56c8fedaf..85900831eb 100644 --- a/integration/cli-hello-world-ivy/README.md +++ b/integration/cli-hello-world-ivy-compat/README.md @@ -1,6 +1,6 @@ -# CliHelloWorld +# CliHelloWorldIvy -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.6.6. +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.0-rc.0. ## Development server @@ -12,7 +12,7 @@ Run `ng generate component component-name` to generate a new component. You can ## Build -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. ## Running unit tests diff --git a/integration/cli-hello-world-ivy/angular.json b/integration/cli-hello-world-ivy-compat/angular.json similarity index 57% rename from integration/cli-hello-world-ivy/angular.json rename to integration/cli-hello-world-ivy-compat/angular.json index 67d63e6c45..d86da96275 100644 --- a/integration/cli-hello-world-ivy/angular.json +++ b/integration/cli-hello-world-ivy-compat/angular.json @@ -1,14 +1,17 @@ { - "$schema": "./node_modules/@angular-devkit/core/src/workspace/workspace-schema.json", + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "cli": { "packageManager": "yarn" }, "newProjectRoot": "projects", "projects": { - "cli-hello-world": { + "cli-hello-world-ivy-compat": { "root": "", + "sourceRoot": "src", "projectType": "application", + "prefix": "app", + "schematics": {}, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", @@ -19,47 +22,36 @@ "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "assets": [ - { - "glob": "assets", - "input": "/src", - "output": "/" - }, - { - "glob": "favicon.ico", - "input": "/src", - "output": "/" - } + "src/favicon.ico", + "src/assets" ], "styles": [ - { - "input": "src/styles.css" - } + "src/styles.css" ], "scripts": [] }, "configurations": { - "dev": { + "production": { "fileReplacements": [ { - "from": "src/environments/environment.ts", - "to": "dist/environments/environment.ts" + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" } - ] - }, - "production": { + ], "optimization": true, "outputHashing": "all", - "sourceMap": true, + "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, - "fileReplacements": [ + "budgets": [ { - "src": "src/environments/environment.ts", - "replaceWith": "src/environments/environment.prod.ts" + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" } ] } @@ -68,20 +60,17 @@ "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "cli-hello-world:build" + "browserTarget": "cli-hello-world-ivy-compat:build" }, "configurations": { - "dev": { - "browserTarget": "cli-hello-world:build:dev" - }, "production": { - "browserTarget": "cli-hello-world:build:production" + "browserTarget": "cli-hello-world-ivy-compat:build:production" }, "ci": { "progress": false }, "ci-production": { - "browserTarget": "cli-hello-world:build:production", + "browserTarget": "cli-hello-world-ivy-compat:build:production", "progress": false } } @@ -89,7 +78,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "cli-hello-world:build" + "browserTarget": "cli-hello-world-ivy-compat:build" } }, "test": { @@ -97,25 +86,15 @@ "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", - "karmaConfig": "./karma.conf.js", "tsConfig": "src/tsconfig.spec.json", - "scripts": [], + "karmaConfig": "src/karma.conf.js", "styles": [ - { - "input": "src/styles.css" - } + "src/styles.css" ], + "scripts": [], "assets": [ - { - "glob": "assets", - "input": "/src", - "output": "/" - }, - { - "glob": "favicon.ico", - "input": "/src", - "output": "/" - } + "src/favicon.ico", + "src/assets" ] } }, @@ -133,36 +112,33 @@ } } }, - "cli-hello-world-e2e": { - "root": "", + "cli-hello-world-ivy-compat-e2e": { + "root": "e2e/", "projectType": "application", - "cli": {}, - "schematics": {}, + "prefix": "", "architect": { "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { - "protractorConfig": "./protractor.conf.js", - "devServerTarget": "cli-hello-world:serve" + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "cli-hello-world-ivy-compat:serve" }, "configurations": { "production": { - "devServerTarget": "cli-hello-world:serve:production" + "devServerTarget": "cli-hello-world-ivy-compat:serve:production" }, "ci": { - "devServerTarget": "cli-hello-world:serve:ci" + "devServerTarget": "cli-hello-world-ivy-compat:serve:ci" }, "ci-production": { - "devServerTarget": "cli-hello-world:serve:ci-production" + "devServerTarget": "cli-hello-world-ivy-compat:serve:ci-production" } } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { - "tsConfig": [ - "e2e/tsconfig.e2e.json" - ], + "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ "**/node_modules/**" ] @@ -171,13 +147,5 @@ } } }, - "schematics": { - "@schematics/angular:component": { - "prefix": "app", - "styleext": "css" - }, - "@schematics/angular:directive": { - "prefix": "app" - } - } + "defaultProject": "cli-hello-world-ivy-compat" } diff --git a/integration/cli-hello-world-ivy/debug-test.sh b/integration/cli-hello-world-ivy-compat/debug-test.sh similarity index 100% rename from integration/cli-hello-world-ivy/debug-test.sh rename to integration/cli-hello-world-ivy-compat/debug-test.sh diff --git a/integration/cli-hello-world-ivy/protractor.conf.js b/integration/cli-hello-world-ivy-compat/e2e/protractor.conf.js similarity index 88% rename from integration/cli-hello-world-ivy/protractor.conf.js rename to integration/cli-hello-world-ivy-compat/e2e/protractor.conf.js index 1c07cbce63..71baa5048b 100644 --- a/integration/cli-hello-world-ivy/protractor.conf.js +++ b/integration/cli-hello-world-ivy-compat/e2e/protractor.conf.js @@ -6,7 +6,7 @@ const { SpecReporter } = require('jasmine-spec-reporter'); exports.config = { allScriptsTimeout: 11000, specs: [ - './e2e/**/*.e2e-spec.ts' + './src/**/*.e2e-spec.ts' ], capabilities: { browserName: 'chrome', @@ -25,7 +25,7 @@ exports.config = { }, onPrepare() { require('ts-node').register({ - project: 'e2e/tsconfig.e2e.json' + project: require('path').join(__dirname, './tsconfig.e2e.json') }); jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); } diff --git a/integration/cli-hello-world-ivy/e2e/app.e2e-spec.ts b/integration/cli-hello-world-ivy-compat/e2e/src/app.e2e-spec.ts similarity index 71% rename from integration/cli-hello-world-ivy/e2e/app.e2e-spec.ts rename to integration/cli-hello-world-ivy-compat/e2e/src/app.e2e-spec.ts index 899e84d526..29e27e6edb 100644 --- a/integration/cli-hello-world-ivy/e2e/app.e2e-spec.ts +++ b/integration/cli-hello-world-ivy-compat/e2e/src/app.e2e-spec.ts @@ -1,6 +1,6 @@ import { AppPage } from './app.po'; -describe('cli-hello-world App', () => { +describe('cli-hello-world-ivy App', () => { let page: AppPage; beforeEach(() => { @@ -9,7 +9,7 @@ describe('cli-hello-world App', () => { it('should display welcome message', () => { page.navigateTo(); - expect(page.getParagraphText()).toEqual('Welcome to app!'); + expect(page.getParagraphText()).toEqual('Welcome to cli-hello-world-ivy-compat!'); }); it('the percent pipe should work', () => { diff --git a/integration/cli-hello-world-ivy/e2e/app.po.ts b/integration/cli-hello-world-ivy-compat/e2e/src/app.po.ts similarity index 100% rename from integration/cli-hello-world-ivy/e2e/app.po.ts rename to integration/cli-hello-world-ivy-compat/e2e/src/app.po.ts diff --git a/integration/cli-hello-world-ivy/e2e/tsconfig.e2e.json b/integration/cli-hello-world-ivy-compat/e2e/tsconfig.e2e.json similarity index 76% rename from integration/cli-hello-world-ivy/e2e/tsconfig.e2e.json rename to integration/cli-hello-world-ivy-compat/e2e/tsconfig.e2e.json index 1d9e5edf09..a6dd622028 100644 --- a/integration/cli-hello-world-ivy/e2e/tsconfig.e2e.json +++ b/integration/cli-hello-world-ivy-compat/e2e/tsconfig.e2e.json @@ -1,8 +1,7 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "outDir": "../out-tsc/e2e", - "baseUrl": "./", + "outDir": "../out-tsc/app", "module": "commonjs", "target": "es5", "types": [ @@ -11,4 +10,4 @@ "node" ] } -} +} \ No newline at end of file diff --git a/integration/cli-hello-world-ivy/package.json b/integration/cli-hello-world-ivy-compat/package.json similarity index 67% rename from integration/cli-hello-world-ivy/package.json rename to integration/cli-hello-world-ivy-compat/package.json index 18bb1c0b7a..8b6914f937 100644 --- a/integration/cli-hello-world-ivy/package.json +++ b/integration/cli-hello-world-ivy-compat/package.json @@ -1,5 +1,5 @@ { - "name": "cli-hello-world", + "name": "cli-hello-world-ivy-compat", "version": "0.0.0", "license": "MIT", "scripts": { @@ -7,11 +7,10 @@ "e2e": "ng e2e --webdriver-update=false", "lint": "ng lint", "ng": "ng", - "postinstall": "webdriver-manager update --gecko=false --standalone=false $CHROMEDRIVER_VERSION_ARG && yarn ivy-ngcc", + "postinstall": "webdriver-manager update --gecko=false --standalone=false $CI_CHROMEDRIVER_VERSION_ARG && yarn ivy-ngcc", "start": "ng serve", - "//test1": "TODO FW-813: Re-enable `ci-production`. Currently, it fails after a timeout as Protractor reports Angular cannot be found on the page", - "//test2": "ng test --progress=false --watch=false && yarn e2e --configuration=ci && yarn e2e --configuration=ci-production", - "test": "ng test --progress=false --watch=false && yarn e2e --configuration=ci" + "pretest": "ng version", + "test": "ng test --progress=false --watch=false && yarn e2e --configuration=ci && yarn e2e --configuration=ci-production" }, "private": true, "dependencies": { @@ -26,27 +25,28 @@ "@angular/router": "file:../../dist/packages-dist/router", "core-js": "file:../../node_modules/core-js", "rxjs": "file:../../node_modules/rxjs", + "tslib": "^1.9.3", "zone.js": "file:../../node_modules/zone.js" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.10.3", - "@angular/cli": "7.0.3", + "@angular-devkit/build-angular": "0.13.0-rc.0", + "@angular/cli": "file:../../node_modules/@angular/cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/language-service": "file:../../dist/packages-dist/language-service", - "@types/jasmine": "~2.8.3", - "@types/jasminewd2": "~2.0.4", - "@types/node": "~6.0.60", - "codelyzer": "^4.3.0", - "jasmine-core": "~2.8.0", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "@types/node": "~8.9.4", + "codelyzer": "~4.5.0", + "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", - "karma": "~2.0.0", + "karma": "~3.1.1", "karma-chrome-launcher": "~2.2.0", - "karma-coverage-istanbul-reporter": "^1.2.1", - "karma-jasmine": "~1.1.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~1.1.2", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "file:../../node_modules/protractor", - "ts-node": "~4.1.0", - "tslint": "~5.9.1", + "ts-node": "~7.0.0", + "tslint": "~5.11.0", "typescript": "file:../../node_modules/typescript" } } diff --git a/packages/bazel/src/schematics/bazel-workspace/files/yarn.lock b/integration/cli-hello-world-ivy-compat/src/app/app.component.css similarity index 100% rename from packages/bazel/src/schematics/bazel-workspace/files/yarn.lock rename to integration/cli-hello-world-ivy-compat/src/app/app.component.css diff --git a/integration/cli-hello-world-ivy/src/app/app.component.html b/integration/cli-hello-world-ivy-compat/src/app/app.component.html similarity index 89% rename from integration/cli-hello-world-ivy/src/app/app.component.html rename to integration/cli-hello-world-ivy-compat/src/app/app.component.html index fade7834d1..85ec4009d8 100644 --- a/integration/cli-hello-world-ivy/src/app/app.component.html +++ b/integration/cli-hello-world-ivy-compat/src/app/app.component.html @@ -12,7 +12,7 @@

Tour of Heroes

  • -

    CLI Documentation

    +

    CLI Documentation

  • Angular blog

    diff --git a/integration/cli-hello-world-ivy-compat/src/app/app.component.spec.ts b/integration/cli-hello-world-ivy-compat/src/app/app.component.spec.ts new file mode 100644 index 0000000000..9d618f8944 --- /dev/null +++ b/integration/cli-hello-world-ivy-compat/src/app/app.component.spec.ts @@ -0,0 +1,31 @@ +import { TestBed, async } from '@angular/core/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); + + it(`should have as title 'cli-hello-world-ivy-compat'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('cli-hello-world-ivy-compat'); + }); + + it('should render title in a h1 tag', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('Welcome to cli-hello-world-ivy-compat!'); + }); +}); diff --git a/integration/cli-hello-world-ivy/src/app/app.component.ts b/integration/cli-hello-world-ivy-compat/src/app/app.component.ts similarity index 82% rename from integration/cli-hello-world-ivy/src/app/app.component.ts rename to integration/cli-hello-world-ivy-compat/src/app/app.component.ts index 7b0f672831..c29d68ec2f 100644 --- a/integration/cli-hello-world-ivy/src/app/app.component.ts +++ b/integration/cli-hello-world-ivy-compat/src/app/app.component.ts @@ -6,5 +6,5 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.css'] }) export class AppComponent { - title = 'app'; + title = 'cli-hello-world-ivy-compat'; } diff --git a/integration/cli-hello-world-ivy/src/app/app.module.ts b/integration/cli-hello-world-ivy-compat/src/app/app.module.ts similarity index 100% rename from integration/cli-hello-world-ivy/src/app/app.module.ts rename to integration/cli-hello-world-ivy-compat/src/app/app.module.ts diff --git a/integration/cli-hello-world-ivy-compat/src/assets/.gitkeep b/integration/cli-hello-world-ivy-compat/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integration/cli-hello-world-ivy-compat/src/browserslist b/integration/cli-hello-world-ivy-compat/src/browserslist new file mode 100644 index 0000000000..37371cb04b --- /dev/null +++ b/integration/cli-hello-world-ivy-compat/src/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/integration/cli-hello-world-ivy/src/environments/environment.prod.ts b/integration/cli-hello-world-ivy-compat/src/environments/environment.prod.ts similarity index 100% rename from integration/cli-hello-world-ivy/src/environments/environment.prod.ts rename to integration/cli-hello-world-ivy-compat/src/environments/environment.prod.ts diff --git a/integration/cli-hello-world-ivy-compat/src/environments/environment.ts b/integration/cli-hello-world-ivy-compat/src/environments/environment.ts new file mode 100644 index 0000000000..7b4f817adb --- /dev/null +++ b/integration/cli-hello-world-ivy-compat/src/environments/environment.ts @@ -0,0 +1,16 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/integration/cli-hello-world-ivy/src/favicon.ico b/integration/cli-hello-world-ivy-compat/src/favicon.ico similarity index 100% rename from integration/cli-hello-world-ivy/src/favicon.ico rename to integration/cli-hello-world-ivy-compat/src/favicon.ico diff --git a/packages/bazel/src/schematics/ng-new/files/index.html.template b/integration/cli-hello-world-ivy-compat/src/index.html similarity index 68% rename from packages/bazel/src/schematics/ng-new/files/index.html.template rename to integration/cli-hello-world-ivy-compat/src/index.html index bfd3c9b8c9..14112704fa 100644 --- a/packages/bazel/src/schematics/ng-new/files/index.html.template +++ b/integration/cli-hello-world-ivy-compat/src/index.html @@ -2,7 +2,7 @@ - <%= utils.classify(name) %> + CliHelloWorldIvyCompat @@ -10,7 +10,5 @@ - - diff --git a/integration/cli-hello-world-ivy/karma.conf.js b/integration/cli-hello-world-ivy-compat/src/karma.conf.js similarity index 86% rename from integration/cli-hello-world-ivy/karma.conf.js rename to integration/cli-hello-world-ivy-compat/src/karma.conf.js index 70468805f7..375eb671d0 100644 --- a/integration/cli-hello-world-ivy/karma.conf.js +++ b/integration/cli-hello-world-ivy-compat/src/karma.conf.js @@ -12,16 +12,14 @@ module.exports = function (config) { require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma') ], - client:{ + client: { clearContext: false // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { - dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ], + dir: require('path').join(__dirname, 'coverage'), + reports: ['html', 'lcovonly', 'text-summary'], fixWebpackSourcePaths: true }, - angularCli: { - environment: 'dev' - }, reporters: ['progress', 'kjhtml'], port: 9876, colors: true, diff --git a/integration/cli-hello-world-ivy-compat/src/main.ts b/integration/cli-hello-world-ivy-compat/src/main.ts new file mode 100644 index 0000000000..c7b673cf44 --- /dev/null +++ b/integration/cli-hello-world-ivy-compat/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/integration/cli-hello-world-ivy/src/polyfills.ts b/integration/cli-hello-world-ivy-compat/src/polyfills.ts similarity index 51% rename from integration/cli-hello-world-ivy/src/polyfills.ts rename to integration/cli-hello-world-ivy-compat/src/polyfills.ts index 1d12133ba9..a6d34ea67a 100644 --- a/integration/cli-hello-world-ivy/src/polyfills.ts +++ b/integration/cli-hello-world-ivy-compat/src/polyfills.ts @@ -11,14 +11,17 @@ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. * - * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + * Learn more in https://angular.io/guide/browser-support */ /*************************************************************************************************** * BROWSER POLYFILLS */ -/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +/** IE9, IE10, IE11, and Chrome <55 requires all of the following polyfills. + * This also includes Android Emulators with older versions of Chrome and Google Search/Googlebot + */ + // import 'core-js/es6/symbol'; // import 'core-js/es6/object'; // import 'core-js/es6/function'; @@ -40,21 +43,41 @@ /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ -/** Evergreen browsers require these. **/ -// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -import 'core-js/es7/reflect'; /*************************************************************************************************** * Zone JS is required by default for Angular itself. */ -import 'zone.js/dist/zone'; // Included with Angular CLI. - - -/** - * Required to support Web Animations `@angular/platform-browser/animations`. - * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation - **/ -// import 'web-animations-js'; // Run `npm install --save web-animations-js`. +import 'zone.js/dist/zone'; // Included with Angular CLI. /*************************************************************************************************** diff --git a/integration/cli-hello-world-ivy/src/styles.css b/integration/cli-hello-world-ivy-compat/src/styles.css similarity index 100% rename from integration/cli-hello-world-ivy/src/styles.css rename to integration/cli-hello-world-ivy-compat/src/styles.css diff --git a/integration/cli-hello-world-ivy/src/test.ts b/integration/cli-hello-world-ivy-compat/src/test.ts similarity index 100% rename from integration/cli-hello-world-ivy/src/test.ts rename to integration/cli-hello-world-ivy-compat/src/test.ts diff --git a/integration/cli-hello-world-ivy/src/tsconfig.app.json b/integration/cli-hello-world-ivy-compat/src/tsconfig.app.json similarity index 71% rename from integration/cli-hello-world-ivy/src/tsconfig.app.json rename to integration/cli-hello-world-ivy-compat/src/tsconfig.app.json index 39ba8dbacb..a5831fdc4a 100644 --- a/integration/cli-hello-world-ivy/src/tsconfig.app.json +++ b/integration/cli-hello-world-ivy-compat/src/tsconfig.app.json @@ -2,12 +2,13 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", - "baseUrl": "./", - "module": "es2015", "types": [] }, "exclude": [ "test.ts", "**/*.spec.ts" - ] + ], + "angularCompilerOptions": { + "enableIvy": "ngtsc" + } } diff --git a/integration/cli-hello-world-ivy/src/tsconfig.spec.json b/integration/cli-hello-world-ivy-compat/src/tsconfig.spec.json similarity index 84% rename from integration/cli-hello-world-ivy/src/tsconfig.spec.json rename to integration/cli-hello-world-ivy-compat/src/tsconfig.spec.json index 47c2dd0ca0..de7733630e 100644 --- a/integration/cli-hello-world-ivy/src/tsconfig.spec.json +++ b/integration/cli-hello-world-ivy-compat/src/tsconfig.spec.json @@ -2,8 +2,6 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/spec", - "baseUrl": "./", - "module": "commonjs", "types": [ "jasmine", "node" @@ -17,4 +15,4 @@ "**/*.spec.ts", "**/*.d.ts" ] -} \ No newline at end of file +} diff --git a/integration/cli-hello-world-ivy-compat/src/tslint.json b/integration/cli-hello-world-ivy-compat/src/tslint.json new file mode 100644 index 0000000000..52e2c1a5a7 --- /dev/null +++ b/integration/cli-hello-world-ivy-compat/src/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/integration/cli-hello-world-ivy/tsconfig.json b/integration/cli-hello-world-ivy-compat/tsconfig.json similarity index 79% rename from integration/cli-hello-world-ivy/tsconfig.json rename to integration/cli-hello-world-ivy-compat/tsconfig.json index 5ad1c48156..b271fd9f3d 100644 --- a/integration/cli-hello-world-ivy/tsconfig.json +++ b/integration/cli-hello-world-ivy-compat/tsconfig.json @@ -1,21 +1,21 @@ { - "angularCompilerOptions": { - "enableIvy": "ngtsc", - }, "compileOnSave": false, "compilerOptions": { + "baseUrl": "./", "outDir": "./dist/out-tsc", "sourceMap": true, "declaration": false, + "module": "es2015", "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, + "importHelpers": true, "target": "es5", "typeRoots": [ "node_modules/@types" ], "lib": [ - "es2017", + "es2018", "dom" ] } diff --git a/integration/cli-hello-world-ivy/tslint.json b/integration/cli-hello-world-ivy-compat/tslint.json similarity index 92% rename from integration/cli-hello-world-ivy/tslint.json rename to integration/cli-hello-world-ivy-compat/tslint.json index 9963d6c395..c740a7b2a5 100644 --- a/integration/cli-hello-world-ivy/tslint.json +++ b/integration/cli-hello-world-ivy-compat/tslint.json @@ -1,6 +1,6 @@ { "rulesDirectory": [ - "node_modules/codelyzer" + "codelyzer" ], "rules": { "arrow-return-shorthand": true, @@ -18,7 +18,6 @@ "forin": true, "import-blacklist": [ true, - "rxjs", "rxjs/Rx" ], "import-spacing": true, @@ -66,6 +65,7 @@ ], "no-misused-new": true, "no-non-null-assertion": true, + "no-redundant-jsdoc": true, "no-shadowed-variable": true, "no-string-literal": false, "no-string-throw": true, @@ -117,18 +117,6 @@ "check-separator", "check-type" ], - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ], "no-output-on-prefix": true, "use-input-property-decorator": true, "use-output-property-decorator": true, diff --git a/integration/cli-hello-world-ivy/yarn.lock b/integration/cli-hello-world-ivy-compat/yarn.lock similarity index 58% rename from integration/cli-hello-world-ivy/yarn.lock rename to integration/cli-hello-world-ivy-compat/yarn.lock index 9f76c45c03..c19466b11a 100644 --- a/integration/cli-hello-world-ivy/yarn.lock +++ b/integration/cli-hello-world-ivy-compat/yarn.lock @@ -2,42 +2,52 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.10.3.tgz#6e4fd76ca41fbb3e5dc2a29f662ba3ee4d1ad086" +"@angular-devkit/architect@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.1.tgz#397768d1ccd0cef76db96d6b39db8aebad68c031" + integrity sha512-1ozBP0ZAApkSfuPpZ7b9vShU8smNxb98jW+65S12cPOxv1bVVxCj5sTmC3sSfXapgq/pMzblbaVSKOG7Ajz0vQ== dependencies: - "@angular-devkit/core" "7.0.3" + "@angular-devkit/core" "7.2.1" rxjs "6.3.3" -"@angular-devkit/build-angular@~0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.10.3.tgz#610a174efaa9d70b68e966d59a29369ac1781369" +"@angular-devkit/architect@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.2.tgz#1bfa43881c8927b8e12ffd4a2a3a645d6356e748" + integrity sha512-32Eim3PM/CJKGcCF1FJQ91ohuF2vBGMd4t1DILaoOMXHWmPLI9N4ILzWHfqFLRvb8QFgLn4VNG7CI9K7GcSBlQ== dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/build-optimizer" "0.10.3" - "@angular-devkit/build-webpack" "0.10.3" - "@angular-devkit/core" "7.0.3" - "@ngtools/webpack" "7.0.3" - ajv "6.5.3" - autoprefixer "9.1.5" + "@angular-devkit/core" "7.2.2" + rxjs "6.3.3" + +"@angular-devkit/build-angular@~0.12.1": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.12.2.tgz#4776f535633227848c4bda34b1e8f89574c33746" + integrity sha512-4PDykCNDjjFo6Ximhq2efiufoUP6pj8KvhB8UI03mLbn/Os1W0y1lmiPJn+NjeBLwFWH9DqW9Vxk/pYek7MtEA== + dependencies: + "@angular-devkit/architect" "0.12.2" + "@angular-devkit/build-optimizer" "0.12.2" + "@angular-devkit/build-webpack" "0.12.2" + "@angular-devkit/core" "7.2.2" + "@ngtools/webpack" "7.2.2" + ajv "6.6.2" + autoprefixer "9.4.3" circular-dependency-plugin "5.0.2" clean-css "4.2.1" - copy-webpack-plugin "4.5.4" + copy-webpack-plugin "4.6.0" file-loader "2.0.0" glob "7.1.3" istanbul "0.4.5" istanbul-instrumenter-loader "3.0.1" karma-source-map-support "1.3.0" - less "3.8.1" + less "3.9.0" less-loader "4.1.0" - license-webpack-plugin "2.0.2" + license-webpack-plugin "2.0.4" loader-utils "1.1.0" - mini-css-extract-plugin "0.4.3" + mini-css-extract-plugin "0.4.4" minimatch "3.0.4" opn "5.3.0" parse5 "4.0.0" portfinder "1.0.17" - postcss "7.0.5" + postcss "7.0.11" postcss-import "12.0.0" postcss-loader "3.0.0" raw-loader "0.5.1" @@ -46,83 +56,96 @@ semver "5.5.1" source-map-loader "0.2.4" source-map-support "0.5.9" - speed-measure-webpack-plugin "^1.2.3" + speed-measure-webpack-plugin "1.2.5" stats-webpack-plugin "0.7.0" - style-loader "0.23.0" + style-loader "0.23.1" stylus "0.54.5" stylus-loader "3.0.2" - terser-webpack-plugin "1.1.0" + terser-webpack-plugin "1.2.1" tree-kill "1.2.0" - webpack "4.19.1" - webpack-dev-middleware "3.3.0" - webpack-dev-server "3.1.8" + webpack "4.28.4" + webpack-dev-middleware "3.4.0" + webpack-dev-server "3.1.14" webpack-merge "4.1.4" - webpack-sources "1.2.0" + webpack-sources "1.3.0" webpack-subresource-integrity "1.1.0-rc.6" optionalDependencies: - node-sass "4.9.3" + node-sass "4.10.0" -"@angular-devkit/build-optimizer@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.10.3.tgz#e649b9d715edbb8eb4779a4f5772cc5cd842700f" +"@angular-devkit/build-optimizer@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.12.2.tgz#c35f4a67a2304a4deeb8e5d2e6c1edde0429c309" + integrity sha512-5SARSE18X5/churU0Qc0gOfDt5EwuwKsJmIA7hHBzi44iotQm5c8ea0q0acua4/U4K+jOsF6A4Faa08Vr2624A== dependencies: loader-utils "1.1.0" source-map "0.5.6" - typescript "3.1.3" + typescript "3.2.2" webpack-sources "1.2.0" -"@angular-devkit/build-webpack@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.10.3.tgz#7bc42318f0d8cf71e52590a8a565b12d6fff67d0" +"@angular-devkit/build-webpack@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.12.2.tgz#00f1a3a5ab3f4bc8e35d1826f8b476dc0016a1e7" + integrity sha512-Uv3f8XJc/5UTj2T7XjxFYDhuybFIIitLGxBpp/hEIc7eXI4MsJKB6CoDJy+2BQch7c/QjKH7W3dmTxzuSJ2j3g== dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/core" "7.0.3" + "@angular-devkit/architect" "0.12.2" + "@angular-devkit/core" "7.2.2" rxjs "6.3.3" -"@angular-devkit/core@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.0.3.tgz#b9d0ef27f125e81dabfdac0813d310be1d8d40d2" +"@angular-devkit/core@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.1.tgz#8c6df59eab77bcc98a348c8cdf9eb217c8b751a5" + integrity sha512-zOozPswSM1cTkltw5LeSPoZ/fJ2d3vN304IVgKgrM5/Fs54bd7nTaBcAK+HvjKS+5KmykYrXW47Q4CdFJikluQ== dependencies: - ajv "6.5.3" + ajv "6.6.2" chokidar "2.0.4" fast-json-stable-stringify "2.0.0" rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/schematics@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.0.3.tgz#4bd58115899d4c8db682cdacdf86a78fc5a559b2" +"@angular-devkit/core@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.2.tgz#f0daf3e24f0ce8105341118f4505c1db4e284ab0" + integrity sha512-gDF8iXiPN870WuBMl7bCQ5+Qz5SjGL/qMcvP4hli5hkn+kMAhgG38ligUK1bbhPQUJ+Z/nSOEmyv8gLHO09SZg== dependencies: - "@angular-devkit/core" "7.0.3" + ajv "6.6.2" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.2.1.tgz#9c1c784f4a81a3a840fa4a1435948c6203be6062" + integrity sha512-jEhwkeDn8exgJBfUwMc6rdtDkxHJkUmKPTn4M436bkMMMa9KFPFbPpzp9weKpB3SbRjM3Mu90JprO4C7qDtCcg== + dependencies: + "@angular-devkit/core" "7.2.1" rxjs "6.3.3" "@angular/animations@file:../../dist/packages-dist/animations": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" -"@angular/cli@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.0.3.tgz#fcc41f9eaae2ee15d86115804f3dbb2bdb63a8c2" +"@angular/cli@file:../../node_modules/@angular/cli": + version "7.2.1" dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - "@schematics/angular" "7.0.3" - "@schematics/update" "0.10.3" - inquirer "6.2.0" + "@angular-devkit/architect" "0.12.1" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + "@schematics/angular" "7.2.1" + "@schematics/update" "0.12.1" + inquirer "6.2.1" opn "5.3.0" - rxjs "6.3.3" semver "5.5.1" symbol-observable "1.2.0" "@angular/common@file:../../dist/packages-dist/common": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "7.1.0" + version "8.0.0-beta.0" dependencies: canonical-path "1.0.0" chokidar "^1.4.2" @@ -137,250 +160,378 @@ yargs "9.0.1" "@angular/compiler@file:../../dist/packages-dist/compiler": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/core@file:../../dist/packages-dist/core": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/forms@file:../../dist/packages-dist/forms": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/http@file:../../dist/packages-dist/http": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/language-service@file:../../dist/packages-dist/language-service": - version "7.1.0" + version "8.0.0-beta.0" "@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/router@file:../../dist/packages-dist/router": - version "7.1.0" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" -"@ngtools/webpack@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.0.3.tgz#96bc0d94e9a8ac84eb34cf81c59fdd21bfbd18e3" +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== dependencies: - "@angular-devkit/core" "7.0.3" + "@babel/highlight" "^7.0.0" + +"@babel/generator@^7.0.0", "@babel/generator@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc" + integrity sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg== + dependencies: + "@babel/types" "^7.2.2" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/highlight@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" + integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489" + integrity sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA== + +"@babel/template@^7.0.0", "@babel/template@^7.1.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" + integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.2.2" + "@babel/types" "^7.2.2" + +"@babel/traverse@^7.0.0": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" + integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.2.2" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.2.3" + "@babel/types" "^7.2.2" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.10" + +"@babel/types@^7.0.0", "@babel/types@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" + integrity sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +"@ngtools/webpack@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.2.2.tgz#361d877f01feae800a58901b066b46539e1fe0e3" + integrity sha512-xjvQ8tlyyReE69q+whAubwX4fayPoy4NHSIDa429qdcUypkvhSScAtou003oVAKG519rznykDrUHAWtvFMVf4Q== + dependencies: + "@angular-devkit/core" "7.2.2" enhanced-resolve "4.1.0" rxjs "6.3.3" tree-kill "1.2.0" webpack-sources "1.2.0" -"@schematics/angular@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.0.3.tgz#7a43800cbf5b8971071cbab653b553b6c67b8809" +"@schematics/angular@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.2.1.tgz#9eeab1354ec8d970121cc067e9636098ab84e152" + integrity sha512-UdqU8udVr693BZ6uaZ7+el/VFlTjrmp56OS+6YaziyAko84e1Q1Fcx+fwdHugy4V3YmQhTVsyOPSEsphnwSwOA== dependencies: - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - typescript "3.1.3" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + typescript "3.2.2" -"@schematics/update@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.10.3.tgz#4bb7580b3e2f6af0689861bd0628d65a3eb0cd75" +"@schematics/update@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.12.1.tgz#44d853321ae8a56c43a579c0639d26d625001037" + integrity sha512-P92tDxy0AA1NPhaThiJ7fIFxIC4jzlGK7sJlpbnRREBImsI/O9gmGaV8Kjy+75vaEjqpWaU2oj1hnWqkmxSK1A== dependencies: - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - npm-registry-client "8.6.0" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + pacote "9.1.1" rxjs "6.3.3" semver "5.5.1" semver-intersect "1.4.0" "@types/jasmine@*": - version "2.8.5" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.5.tgz#96e58872583fa80c7ea0dd29024b180d5e133678" + version "3.3.4" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.3.4.tgz#492cc70364f6dee047887b4fa2135bedd41fb143" + integrity sha512-543S+ZCJfN4jKWzRkptbJqTY2vc4h7+lPVqU2hXb1XFofDcUxNANAimdZPYaH6/yhezVAsNeujoZjAFU06bfmA== -"@types/jasmine@~2.8.3": - version "2.8.6" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.6.tgz#14445b6a1613cf4e05dd61c3c3256d0e95c0421e" +"@types/jasmine@~2.8.8": + version "2.8.14" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.14.tgz#42a87032418b7d70f427d1df16a9921fca28d8c7" + integrity sha512-oHgE8xWsIoJfP0qU/yi5xrzhkHvYJhD7m40pSC3pw4+BUKWFwqTz+BUosuuODh8KyRpLp1Fdaibr3If4cgNsCg== -"@types/jasminewd2@~2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.4.tgz#12422ee719f372d30c3cc7d99cc72dadba6ace01" +"@types/jasminewd2@~2.0.3": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.6.tgz#2f57a8d9875a6c9ef328a14bd070ba14a055ac39" + integrity sha512-2ZOKrxb8bKRmP/po5ObYnRDgFE4i+lQiEB27bAMmtMWLgJSqlIDqlLx6S0IRorpOmOPRQ6O80NujTmQAtBkeNw== dependencies: "@types/jasmine" "*" -"@types/node@^6.0.46": - version "6.0.96" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.96.tgz#7bf0bf40d6ce51e93762cc47d010c8cc5ebb2179" +"@types/node@*": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== -"@types/node@~6.0.60": - version "6.0.104" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.104.tgz#5a17c151c223041602f11a404db9a00e54250174" +"@types/node@~8.9.4": + version "8.9.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.9.5.tgz#162b864bc70be077e6db212b322754917929e976" + integrity sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ== "@types/q@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" + integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= -"@types/selenium-webdriver@^2.53.35", "@types/selenium-webdriver@~2.53.39": - version "2.53.43" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz#2de3d718819bc20165754c4a59afb7e9833f6707" +"@types/selenium-webdriver@^3.0.0": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.14.tgz#0b20a2370e6b1b8322c9c3dfcaa409e6c7c0c0a9" + integrity sha512-4GbNCDs98uHCT/OMv40qQC/OpoPbYn9XdXeTiFwHBBFO6eJhYEPUu2zDKirXSbHlvDV8oZ9l8EQ+HrEx/YS9DQ== -"@types/strip-bom@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== -"@types/strip-json-comments@0.0.30": - version "0.0.30" - resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" - -"@webassemblyjs/ast@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.6.tgz#3ef8c45b3e5e943a153a05281317474fef63e21e" +"@types/webpack-sources@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" + integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== dependencies: - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" - mamacro "^0.0.3" + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" -"@webassemblyjs/floating-point-hex-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz#7cb37d51a05c3fe09b464ae7e711d1ab3837801f" - -"@webassemblyjs/helper-api-error@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz#99b7e30e66f550a2638299a109dda84a622070ef" - -"@webassemblyjs/helper-buffer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz#ba0648be12bbe560c25c997e175c2018df39ca3e" - -"@webassemblyjs/helper-code-frame@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz#5a94d21b0057b69a7403fca0c253c3aaca95b1a5" +"@webassemblyjs/ast@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" + integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA== dependencies: - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" -"@webassemblyjs/helper-fsm@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz#ae1741c6f6121213c7a0b587fb964fac492d3e49" +"@webassemblyjs/floating-point-hex-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" + integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg== -"@webassemblyjs/helper-module-context@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz#116d19a51a6cebc8900ad53ca34ff8269c668c23" +"@webassemblyjs/helper-api-error@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" + integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg== + +"@webassemblyjs/helper-buffer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" + integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w== + +"@webassemblyjs/helper-code-frame@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" + integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw== dependencies: - mamacro "^0.0.3" + "@webassemblyjs/wast-printer" "1.7.11" -"@webassemblyjs/helper-wasm-bytecode@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz#98e515eaee611aa6834eb5f6a7f8f5b29fefb6f1" +"@webassemblyjs/helper-fsm@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" + integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A== -"@webassemblyjs/helper-wasm-section@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz#783835867bdd686df7a95377ab64f51a275e8333" +"@webassemblyjs/helper-module-context@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" + integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg== + +"@webassemblyjs/helper-wasm-bytecode@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" + integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ== + +"@webassemblyjs/helper-wasm-section@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" + integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" -"@webassemblyjs/ieee754@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz#c34fc058f2f831fae0632a8bb9803cf2d3462eb1" +"@webassemblyjs/ieee754@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" + integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.6.tgz#197f75376a29f6ed6ace15898a310d871d92f03b" +"@webassemblyjs/leb128@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" + integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw== dependencies: "@xtuc/long" "4.2.1" -"@webassemblyjs/utf8@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.6.tgz#eb62c66f906af2be70de0302e29055d25188797d" +"@webassemblyjs/utf8@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" + integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA== -"@webassemblyjs/wasm-edit@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz#fa41929160cd7d676d4c28ecef420eed5b3733c5" +"@webassemblyjs/wasm-edit@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" + integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/helper-wasm-section" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-opt" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/helper-wasm-section" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-opt" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + "@webassemblyjs/wast-printer" "1.7.11" -"@webassemblyjs/wasm-gen@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz#695ac38861ab3d72bf763c8c75e5f087ffabc322" +"@webassemblyjs/wasm-gen@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" + integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" -"@webassemblyjs/wasm-opt@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz#fbafa78e27e1a75ab759a4b658ff3d50b4636c21" +"@webassemblyjs/wasm-opt@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" + integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" -"@webassemblyjs/wasm-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz#84eafeeff405ad6f4c4b5777d6a28ae54eed51fe" +"@webassemblyjs/wasm-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" + integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" -"@webassemblyjs/wast-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz#ca4d20b1516e017c91981773bd7e819d6bd9c6a7" +"@webassemblyjs/wast-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" + integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/floating-point-hex-parser" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-code-frame" "1.7.6" - "@webassemblyjs/helper-fsm" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/floating-point-hex-parser" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-code-frame" "1.7.11" + "@webassemblyjs/helper-fsm" "1.7.11" "@xtuc/long" "4.2.1" - mamacro "^0.0.3" -"@webassemblyjs/wast-printer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz#a6002c526ac5fa230fe2c6d2f1bdbf4aead43a5e" +"@webassemblyjs/wast-printer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" + integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" "@xtuc/long" "4.2.1" "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== "@xtuc/long@4.2.1": version "4.2.1" resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" + integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== -JSONStream@^1.0.3: - version "1.3.2" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" +"@yarnpkg/lockfile@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +JSONStream@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== dependencies: jsonparse "^1.2.0" through ">=2.2.7 <3" @@ -388,21 +539,17 @@ JSONStream@^1.0.3: abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - -accepts@1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" - dependencies: - mime-types "~2.1.11" - negotiator "0.6.1" + integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= dependencies: mime-types "~2.1.18" negotiator "0.6.1" @@ -410,145 +557,120 @@ accepts@~1.3.4, accepts@~1.3.5: acorn-dynamic-import@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg== dependencies: acorn "^5.0.0" -acorn@^4.0.3: - version "4.0.13" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" - -acorn@^5.0.0: - version "5.5.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" - -acorn@^5.2.1: - version "5.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" - -acorn@^5.6.2: +acorn@^5.0.0, acorn@^5.6.2: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== -addressparser@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" - -adm-zip@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" - -adm-zip@^0.4.7: - version "0.4.7" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" +adm-zip@^0.4.9: + version "0.4.13" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a" + integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw== after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= -agent-base@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" +agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== dependencies: - extend "~3.0.0" - semver "~5.0.1" + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" ajv-errors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== ajv-keywords@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= -ajv@6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" +ajv@6.6.2, ajv@^6.1.0, ajv@^6.5.5: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ajv@^5.0.0, ajv@^5.1.0, ajv@^5.3.0: +ajv@^5.0.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.1.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6" - dependencies: - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - uri-js "^3.0.2" - -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - -amqplib@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/amqplib/-/amqplib-0.5.2.tgz#d2d7313c7ffaa4d10bcf1e6252de4591b6cc7b63" - dependencies: - bitsyntax "~0.0.4" - bluebird "^3.4.6" - buffer-more-ints "0.0.2" - readable-stream "1.x >=1.1.9" - safe-buffer "^5.0.1" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= ansi-colors@^3.0.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.1.tgz#9638047e4213f3428a11944a7d4b31cba0a3ff95" + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== dependencies: micromatch "^2.1.5" normalize-path "^2.0.0" @@ -556,27 +678,32 @@ anymatch@^1.3.0: anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" -app-root-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46" +app-root-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.1.0.tgz#98bf6599327ecea199309866e8140368fd2e646a" + integrity sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo= -append-transform@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== dependencies: - default-require-extensions "^1.0.0" + default-require-extensions "^2.0.0" aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -584,203 +711,185 @@ are-we-there-yet@~1.1.2: argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= dependencies: arr-flatten "^1.0.1" arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - -array-filter@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= array-flatten@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" - -array-map@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" - -array-reduce@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" + integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= arraybuffer.slice@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== dependencies: bn.js "^4.0.0" inherits "^2.0.1" minimalistic-assert "^1.0.0" asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -assert@^1.1.1, assert@^1.4.0: +assert@^1.1.1: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= dependencies: util "0.10.3" assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - -ast-types@0.x.x: - version "0.10.1" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" - -astw@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/astw/-/astw-2.2.0.tgz#7bd41784d32493987aeb239b6b4e1c57a873b917" - dependencies: - acorn "^4.0.3" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + integrity sha1-GdOGodntxufByF04iu28xW0zYC0= async-foreach@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== -async@1.x, async@^1.4.0, async@^1.5.2: +async@1.x, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= -async@^2.1.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" - dependencies: - lodash "^4.14.0" - -async@^2.5.0: +async@^2.5.0, async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== dependencies: lodash "^4.17.10" -async@~2.1.2: - version "2.1.5" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" - dependencies: - lodash "^4.14.0" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -atob@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@9.1.5: - version "9.1.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.1.5.tgz#8675fd8d1c0d43069f3b19a2c316f3524e4f6671" +autoprefixer@9.4.3: + version "9.4.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.3.tgz#c97384a8fd80477b78049163a91bbc725d9c41d9" + integrity sha512-/XSnzDepRkAU//xLcXA/lUWxpsBuw0WiriAHOqnxkuCtzLhaz+fL4it4gp20BQ8n5SyLzK/FOc7A0+u/rti2FQ== dependencies: - browserslist "^4.1.0" - caniuse-lite "^1.0.30000884" + browserslist "^4.3.6" + caniuse-lite "^1.0.30000921" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.2" - postcss-value-parser "^3.2.3" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + postcss "^7.0.6" + postcss-value-parser "^3.3.1" aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.2.1, aws4@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - -axios@^0.15.3: - version "0.15.3" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.15.3.tgz#2c9d638b2e191a08ea1d6cc988eadd6ba5bdc053" - dependencies: - follow-redirects "1.0.0" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -789,6 +898,7 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: babel-generator@^6.18.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -802,12 +912,14 @@ babel-generator@^6.18.0: babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= dependencies: babel-runtime "^6.22.0" babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" @@ -815,6 +927,7 @@ babel-runtime@^6.22.0, babel-runtime@^6.26.0: babel-template@^6.16.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -825,6 +938,7 @@ babel-template@^6.16.0: babel-traverse@^6.18.0, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -839,6 +953,7 @@ babel-traverse@^6.18.0, babel-traverse@^6.26.0: babel-types@^6.18.0, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -848,30 +963,37 @@ babel-types@^6.18.0, babel-types@^6.26.0: babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= base64-js@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -884,81 +1006,81 @@ base@^0.11.1: batch@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= dependencies: callsite "1.0.0" big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + version "1.12.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" + integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== -bitsyntax@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/bitsyntax/-/bitsyntax-0.0.4.tgz#eb10cc6f82b8c490e3e85698f07e83d46e0cba82" - dependencies: - buffer-more-ints "0.0.2" - -bl@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" - dependencies: - readable-stream "~2.0.5" - -blob@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= dependencies: inherits "~2.0.0" -blocking-proxy@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-0.0.5.tgz#462905e0dcfbea970f41aa37223dda9c07b1912b" +blocking-proxy@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" + integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA== dependencies: minimist "^1.2.0" -bluebird@^3.3.0, bluebird@^3.4.6, bluebird@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" +bluebird@^3.3.0, bluebird@^3.5.1, bluebird@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -body-parser@1.18.2, body-parser@^1.16.1: - version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" +body-parser@1.18.3, body-parser@^1.16.1: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= dependencies: bytes "3.0.0" content-type "~1.0.4" debug "2.6.9" - depd "~1.1.1" - http-errors "~1.6.2" - iconv-lite "0.4.19" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" on-finished "~2.3.0" - qs "6.5.1" - raw-body "2.3.2" - type-is "~1.6.15" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" bonjour@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= dependencies: array-flatten "^2.1.0" deep-equal "^1.0.1" @@ -967,27 +1089,10 @@ bonjour@^3.5.0: multicast-dns "^6.0.1" multicast-dns-service-types "^1.1.0" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - dependencies: - hoek "4.x.x" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -995,28 +1100,29 @@ brace-expansion@^1.1.7: braces@^0.1.2: version "0.1.5" resolved "https://registry.yarnpkg.com/braces/-/braces-0.1.5.tgz#c085711085291d8b75fdd74eab0f8597280711e6" + integrity sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY= dependencies: expand-range "^0.1.0" braces@^1.8.2: version "1.8.5" resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= dependencies: expand-range "^1.8.1" preserve "^0.2.0" repeat-element "^1.1.2" braces@^2.3.0, braces@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" - define-property "^1.0.0" extend-shallow "^2.0.1" fill-range "^4.0.0" isobject "^3.0.1" - kind-of "^6.0.2" repeat-element "^1.1.2" snapdragon "^0.8.1" snapdragon-node "^2.0.1" @@ -1026,27 +1132,12 @@ braces@^2.3.0, braces@^2.3.1: brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - -browser-pack@^6.0.1: - version "6.0.3" - resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.3.tgz#91ca96518583ef580ab063a309de62e407767a39" - dependencies: - JSONStream "^1.0.3" - combine-source-map "~0.8.0" - defined "^1.0.0" - safe-buffer "^5.1.1" - through2 "^2.0.0" - umd "^3.0.0" - -browser-resolve@^1.11.0, browser-resolve@^1.7.0: - version "1.11.2" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" - dependencies: - resolve "1.1.7" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== dependencies: buffer-xor "^1.0.3" cipher-base "^1.0.0" @@ -1056,24 +1147,28 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4: safe-buffer "^5.0.1" browserify-cipher@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== dependencies: browserify-aes "^1.0.4" browserify-des "^1.0.0" evp_bytestokey "^1.0.0" browserify-des@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== dependencies: cipher-base "^1.0.1" des.js "^1.0.0" inherits "^2.0.1" + safe-buffer "^5.1.2" browserify-rsa@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= dependencies: bn.js "^4.1.0" randombytes "^2.0.1" @@ -1081,6 +1176,7 @@ browserify-rsa@^4.0.0: browserify-sign@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= dependencies: bn.js "^4.1.1" browserify-rsa "^4.0.0" @@ -1090,134 +1186,95 @@ browserify-sign@^4.0.0: inherits "^2.0.1" parse-asn1 "^5.0.0" -browserify-zlib@^0.2.0, browserify-zlib@~0.2.0: +browserify-zlib@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== dependencies: pako "~1.0.5" -browserify@^14.5.0: - version "14.5.0" - resolved "https://registry.yarnpkg.com/browserify/-/browserify-14.5.0.tgz#0bbbce521acd6e4d1d54d8e9365008efb85a9cc5" +browserslist@^4.3.6: + version "4.3.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.3.6.tgz#0f9d9081afc66b36f477c6bdf3813f784f42396a" + integrity sha512-kMGKs4BTzRWviZ8yru18xBpx+CyHG9eqgRbj9XbE3IMgtczf4aiA0Y1YCpVdvUieKGZ03kolSPXqTcscBCb9qw== dependencies: - JSONStream "^1.0.3" - assert "^1.4.0" - browser-pack "^6.0.1" - browser-resolve "^1.11.0" - browserify-zlib "~0.2.0" - buffer "^5.0.2" - cached-path-relative "^1.0.0" - concat-stream "~1.5.1" - console-browserify "^1.1.0" - constants-browserify "~1.0.0" - crypto-browserify "^3.0.0" - defined "^1.0.0" - deps-sort "^2.0.0" - domain-browser "~1.1.0" - duplexer2 "~0.1.2" - events "~1.1.0" - glob "^7.1.0" - has "^1.0.0" - htmlescape "^1.1.0" - https-browserify "^1.0.0" - inherits "~2.0.1" - insert-module-globals "^7.0.0" - labeled-stream-splicer "^2.0.0" - module-deps "^4.0.8" - os-browserify "~0.3.0" - parents "^1.0.1" - path-browserify "~0.0.0" - process "~0.11.0" - punycode "^1.3.2" - querystring-es3 "~0.2.0" - read-only-stream "^2.0.0" - readable-stream "^2.0.2" - resolve "^1.1.4" - shasum "^1.0.0" - shell-quote "^1.6.1" - stream-browserify "^2.0.0" - stream-http "^2.0.0" - string_decoder "~1.0.0" - subarg "^1.0.0" - syntax-error "^1.1.1" - through2 "^2.0.0" - timers-browserify "^1.0.1" - tty-browserify "~0.0.0" - url "~0.11.0" - util "~0.10.1" - vm-browserify "~0.0.1" - xtend "^4.0.0" + caniuse-lite "^1.0.30000921" + electron-to-chromium "^1.3.92" + node-releases "^1.1.1" -browserslist@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.3.4.tgz#4477b737db6a1b07077275b24791e680d4300425" +browserstack@^1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.2.tgz#17d8bb76127a1cc0ea416424df80d218f803673f" + integrity sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg== dependencies: - caniuse-lite "^1.0.30000899" - electron-to-chromium "^1.3.82" - node-releases "^1.0.1" + https-proxy-agent "^2.2.1" -buffer-from@^1.0.0: +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0, buffer-from@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" - -buffer-more-ints@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz#26b3885d10fa13db7fc01aae3aab870199e0124c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= buffer@^4.3.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.0.2: - version "5.0.8" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.8.tgz#84daa52e7cf2fa8ce4195bc5cf0f7809e0930b24" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - -buildmail@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/buildmail/-/buildmail-4.0.1.tgz#877f7738b78729871c9a105e3b837d2be11a7a72" - dependencies: - addressparser "1.0.1" - libbase64 "0.1.0" - libmime "3.0.0" - libqp "1.1.0" - nodemailer-fetch "1.6.0" - nodemailer-shared "1.1.0" - punycode "1.4.1" - builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= cacache@^10.0.4: version "10.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== dependencies: bluebird "^3.5.1" chownr "^1.0.1" @@ -1233,9 +1290,10 @@ cacache@^10.0.4: unique-filename "^1.1.0" y18n "^4.0.0" -cacache@^11.0.2: - version "11.2.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.2.0.tgz#617bdc0b02844af56310e411c0878941d5739965" +cacache@^11.0.1, cacache@^11.0.2, cacache@^11.2.0: + version "11.3.1" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.1.tgz#d09d25f6c4aca7a6d305d141ae332613aa1d515f" + integrity sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA== dependencies: bluebird "^3.5.1" chownr "^1.0.1" @@ -1255,6 +1313,7 @@ cacache@^11.0.2: cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -1266,63 +1325,53 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -cached-path-relative@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7" - callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= dependencies: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= -caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000899: - version "1.0.30000903" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000903.tgz#86d46227759279b3db345ddbe778335dbba9e858" +caniuse-lite@^1.0.30000921: + version "1.0.30000923" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000923.tgz#148f9bda508024b5ce957b463ae2e8302b451bb2" + integrity sha512-j5ur7eeluOFjjPUkydtXP4KFAsmH3XaQNch5tvWSO+dLHYt5PE+VgJZLWtbVOodfWij6m6zas28T4gB/cLYq1w== canonical-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" - -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1330,17 +1379,19 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^2.3.0: - version "2.3.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -1349,10 +1400,12 @@ chalk@^2.3.0: chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chokidar@2.0.4: +chokidar@2.0.4, chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== dependencies: anymatch "^2.0.0" async-each "^1.0.0" @@ -1369,9 +1422,10 @@ chokidar@2.0.4: optionalDependencies: fsevents "^1.2.2" -chokidar@^1.4.1, chokidar@^1.4.2: +chokidar@^1.4.2: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= dependencies: anymatch "^1.3.0" async-each "^1.0.0" @@ -1384,37 +1438,22 @@ chokidar@^1.4.1, chokidar@^1.4.2: optionalDependencies: fsevents "^1.0.0" -chokidar@^2.0.0, chokidar@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" - dependencies: - anymatch "^2.0.0" - async-each "^1.0.0" - braces "^2.3.0" - glob-parent "^3.1.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^2.1.1" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - upath "^1.0.0" - optionalDependencies: - fsevents "^1.1.2" - -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" +chownr@^1.0.1, chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== chrome-trace-event@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A== dependencies: tslib "^1.9.0" cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" @@ -1422,14 +1461,17 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: circular-dependency-plugin@5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz#da168c0b37e7b43563fb9f912c1c007c213389ef" + integrity sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA== -circular-json@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.1.tgz#b8942a09e535863dc21b04417a91971e1d9cd91f" +circular-json@^0.5.5: + version "0.5.9" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" + integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -1439,30 +1481,26 @@ class-utils@^0.3.5: clean-css@4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" + integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== dependencies: source-map "~0.6.0" cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= dependencies: restore-cursor "^2.0.0" cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= 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" @@ -1471,6 +1509,7 @@ cliui@^3.2.0: cliui@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== dependencies: string-width "^2.1.1" strip-ansi "^4.0.0" @@ -1479,6 +1518,7 @@ cliui@^4.0.0: clone-deep@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" + integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== dependencies: for-own "^1.0.0" is-plain-object "^2.0.4" @@ -1488,214 +1528,207 @@ clone-deep@^2.0.1: clone@^2.1.1, clone@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -co@~3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/co/-/co-3.0.6.tgz#1445f226c5eb956138e68c9ac30167ea7d2e6bda" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -codelyzer@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.3.0.tgz#6bf3ba68efd9d655a451ecaa14a2852001a43dfb" +codelyzer@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.5.0.tgz#a65ddeeeca2894653253a89bfa229118ff9f59b1" + integrity sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ== dependencies: - app-root-path "^2.0.1" + app-root-path "^2.1.0" css-selector-tokenizer "^0.7.0" cssauron "^1.4.0" semver-dsl "^1.0.1" source-map "^0.5.7" - sprintf-js "^1.0.3" + sprintf-js "^1.1.1" collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" object-visit "^1.0.0" color-convert@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: - color-name "^1.1.1" + color-name "1.1.3" -color-name@^1.1.1: +color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -colors@1.1.2, colors@^1.1.0: +colors@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= + +colors@^1.1.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== combine-lists@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6" + integrity sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y= dependencies: lodash "^4.5.0" -combine-source-map@~0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e" - dependencies: - convert-source-map "~1.1.0" - inline-source-map "~0.6.0" - lodash.memoize "~3.0.3" - source-map "~0.5.3" - -combine-source-map@~0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" - dependencies: - convert-source-map "~1.1.0" - inline-source-map "~0.6.0" - lodash.memoize "~3.0.3" - source-map "~0.5.3" - -combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - dependencies: - delayed-stream "~1.0.0" - combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== dependencies: delayed-stream "~1.0.0" -commander@^2.12.1, commander@~2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" - -commander@^2.9.0: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" +commander@^2.12.1: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== commander@~2.17.1: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +compare-versions@^3.2.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26" + integrity sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg== component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= -compressible@~2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" +compressible@~2.0.14: + version "2.0.15" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.15.tgz#857a9ab0a7e5a07d8d837ed43fe2defff64fe212" + integrity sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw== dependencies: - mime-db ">= 1.33.0 < 2" + mime-db ">= 1.36.0 < 2" compression@^1.5.2: - version "1.7.2" - resolved "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== dependencies: - accepts "~1.3.4" + accepts "~1.3.5" bytes "3.0.0" - compressible "~2.0.13" + compressible "~2.0.14" debug "2.6.9" on-headers "~1.0.1" - safe-buffer "5.1.1" + safe-buffer "5.1.2" vary "~1.1.2" concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0, concat-stream@^1.5.2: +concat-stream@^1.5.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: buffer-from "^1.0.0" inherits "^2.0.3" readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@~1.5.0, concat-stream@~1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" - dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" - connect-history-api-fallback@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" + integrity sha1-sGhzk0vF40T+9hGhlqb6rgruAVo= connect@^3.6.0: - version "3.6.5" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.5.tgz#fb8dde7ba0763877d0ec9df9dac0b4b40e72c7da" + version "3.6.6" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= dependencies: debug "2.6.9" - finalhandler "1.0.6" + finalhandler "1.1.0" parseurl "~1.3.2" utils-merge "1.0.1" console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= dependencies: date-now "^0.1.4" console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -constants-browserify@^1.0.0, constants-browserify@~1.0.0: +constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - -convert-source-map@^1.5.1: +convert-source-map@^1.5.0, convert-source-map@^1.5.1: version "1.6.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== dependencies: safe-buffer "~5.1.1" -convert-source-map@~1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" - cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== dependencies: aproba "^1.1.1" fs-write-stream-atomic "^1.0.8" @@ -1707,10 +1740,12 @@ copy-concurrently@^1.0.0: copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-webpack-plugin@4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.5.4.tgz#f2b2782b3cd5225535c3dc166a80067e7d940f27" +copy-webpack-plugin@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" + integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -1721,24 +1756,28 @@ copy-webpack-plugin@4.5.4: p-limit "^1.0.0" serialize-javascript "^1.4.0" -core-js@^2.2.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" - -core-js@^2.4.0: - version "2.5.4" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.4.tgz#f2c8bf181f2a80b92f360121429ce63a2f0aeae0" +core-js@^2.2.0, core-js@^2.4.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042" + integrity sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg== "core-js@file:../../node_modules/core-js": version "2.5.7" +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= cosmiconfig@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" + integrity sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ== dependencies: is-directory "^0.3.1" js-yaml "^3.9.0" @@ -1746,24 +1785,28 @@ cosmiconfig@^4.0.0: require-from-string "^2.0.1" create-ecdh@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== dependencies: bn.js "^4.1.0" elliptic "^6.0.0" create-hash@^1.1.0, create-hash@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== dependencies: cipher-base "^1.0.1" inherits "^2.0.1" - ripemd160 "^2.0.0" + md5.js "^1.3.4" + ripemd160 "^2.0.1" sha.js "^2.4.0" create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== dependencies: cipher-base "^1.0.3" create-hash "^1.1.0" @@ -1775,6 +1818,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: cross-spawn@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= dependencies: lru-cache "^4.0.1" which "^1.2.9" @@ -1782,6 +1826,7 @@ cross-spawn@^3.0.0: cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -1790,6 +1835,7 @@ cross-spawn@^5.0.1: cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -1797,21 +1843,10 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - dependencies: - boom "5.x.x" - -crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: +crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== dependencies: browserify-cipher "^1.0.0" browserify-sign "^4.0.0" @@ -1828,10 +1863,12 @@ crypto-browserify@^3.0.0, crypto-browserify@^3.11.0: css-parse@1.7.x: version "1.7.0" resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b" + integrity sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs= css-selector-tokenizer@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + version "0.7.1" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d" + integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA== dependencies: cssesc "^0.1.0" fastparse "^1.1.1" @@ -1840,140 +1877,150 @@ css-selector-tokenizer@^0.7.0: cssauron@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" + integrity sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg= dependencies: through X.X.X cssesc@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q= currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= dependencies: array-find-index "^1.0.1" custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" -data-uri-to-buffer@1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz#77163ea9c20d8641b4707e8f18abdf9a78f34835" - date-format@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/date-format/-/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8" + integrity sha1-YV6CjiM90aubua4JUODOzPpuytg= date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= -debug@*, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" +debug@*, debug@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== dependencies: - ms "2.0.0" + ms "^2.1.1" -debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6, debug@~2.6.9: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" +debug@3.1.0, debug@=3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: - ms "0.7.1" + ms "2.0.0" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: +debug@^3.1.0, debug@^3.2.5: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= decamelize@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" + integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg== dependencies: xregexp "4.0.0" decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= default-gateway@^2.6.0: version "2.7.2" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f" + integrity sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ== dependencies: execa "^0.10.0" ip-regex "^2.1.0" -default-require-extensions@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= dependencies: - strip-bom "^2.0.0" + strip-bom "^3.0.0" define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -degenerator@~1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-1.0.4.tgz#fcf490a37ece266464d9cc431ab98c5819ced095" - dependencies: - ast-types "0.x.x" - escodegen "1.x.x" - esprima "3.x.x" - del@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -1986,6 +2033,7 @@ del@^2.2.0: del@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU= dependencies: globby "^6.1.0" is-path-cwd "^1.0.0" @@ -1997,35 +2045,27 @@ del@^3.0.0: delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - -depd@~1.1.1, depd@~1.1.2: +depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= dependency-graph@^0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" - -deps-sort@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" - dependencies: - JSONStream "^1.0.3" - shasum "^1.0.0" - subarg "^1.0.0" - through2 "^2.0.0" + integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= dependencies: inherits "^2.0.1" minimalistic-assert "^1.0.0" @@ -2033,39 +2073,39 @@ des.js@^1.0.0: destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= dependencies: repeating "^2.0.0" detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -detect-node@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" - -detective@^4.0.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" - dependencies: - acorn "^5.2.1" - defined "^1.0.0" +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= diff@^3.1.0, diff@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== diffie-hellman@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== dependencies: bn.js "^4.1.0" miller-rabin "^4.0.0" @@ -2074,6 +2114,7 @@ diffie-hellman@^5.0.0: dir-glob@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== dependencies: arrify "^1.0.1" path-type "^3.0.0" @@ -2081,10 +2122,12 @@ dir-glob@^2.0.0: dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= dns-packet@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== dependencies: ip "^1.1.0" safe-buffer "^5.0.1" @@ -2092,12 +2135,14 @@ dns-packet@^1.3.1: dns-txt@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= dependencies: buffer-indexof "^1.0.0" dom-serialize@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs= dependencies: custom-event "~1.0.0" ent "~2.2.0" @@ -2107,24 +2152,12 @@ dom-serialize@^2.2.0: domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domain-browser@~1.1.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" - -double-ended-queue@^2.1.0-0: - version "2.1.0-0" - resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" - -duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - dependencies: - readable-stream "^2.0.2" - -duplexify@^3.4.2, duplexify@^3.5.3: - version "3.5.4" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.4.tgz#4bb46c1796eabebeec4ca9a2e66b808cb7a3d8b4" +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.1.tgz#b1a7a29c4abfd639585efaecce80d666b1e34125" + integrity sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA== dependencies: end-of-stream "^1.0.0" inherits "^2.0.1" @@ -2132,22 +2165,27 @@ duplexify@^3.4.2, duplexify@^3.5.3: stream-shift "^1.0.0" ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" + safer-buffer "^2.1.0" ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.82: - version "1.3.82" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" +electron-to-chromium@^1.3.92: + version "1.3.96" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.96.tgz#25770ec99b8b07706dedf3a5f43fa50cb54c4f9a" + integrity sha512-ZUXBUyGLeoJxp4Nt6G/GjBRLnyz8IKQGexZ2ndWaoegThgMGFO1tdDYID5gBV32/1S83osjJHyfzvanE/8HY4Q== elliptic@^6.0.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2160,24 +2198,35 @@ elliptic@^6.0.0: emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== dependencies: once "^1.4.0" -engine.io-client@~3.1.0: - version "3.1.4" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.1.4.tgz#4fcf1370b47163bd2ce9be2733972430350d4ea1" +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== dependencies: component-emitter "1.2.1" component-inherit "0.0.3" - debug "~2.6.9" + debug "~3.1.0" engine.io-parser "~2.1.1" has-cors "1.1.0" indexof "0.0.1" @@ -2188,31 +2237,32 @@ engine.io-client@~3.1.0: yeast "0.1.2" engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" base64-arraybuffer "0.1.5" - blob "0.0.4" + blob "0.0.5" has-binary2 "~1.0.2" -engine.io@~3.1.0: - version "3.1.4" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.1.4.tgz#3d0211b70a552ce841ffc7da8627b301a9a4162e" +engine.io@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.1.tgz#b60281c35484a70ee0351ea0ebff83ec8c9522a2" + integrity sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w== dependencies: - accepts "1.3.3" + accepts "~1.3.4" base64id "1.0.0" cookie "0.3.1" - debug "~2.6.9" + debug "~3.1.0" engine.io-parser "~2.1.0" ws "~3.3.1" - optionalDependencies: - uws "~0.14.4" enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== dependencies: graceful-fs "^4.1.2" memory-fs "^0.4.0" @@ -2221,36 +2271,58 @@ enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0: ent@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== dependencies: prr "~1.0.1" -error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" +es6-promise@^4.0.3: + version "4.2.5" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" + integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg== + +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= dependencies: - is-arrayish "^0.2.1" + es6-promise "^4.0.3" escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= escodegen@1.8.x: version "1.8.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= dependencies: esprima "^2.7.1" estraverse "^1.9.1" @@ -2259,20 +2331,10 @@ escodegen@1.8.x: optionalDependencies: source-map "~0.2.0" -escodegen@1.x.x: - version "1.9.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852" - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.5.6" - eslint-scope@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -2280,54 +2342,61 @@ eslint-scope@^4.0.0: esprima@2.7.x, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - -esprima@3.x.x, esprima@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== dependencies: estraverse "^4.1.0" estraverse@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eventemitter3@1.x.x: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" +eventemitter3@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== -events@^1.0.0, events@~1.1.0: +events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= -eventsource@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== dependencies: - original ">=0.0.5" + original "^1.0.0" evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== dependencies: md5.js "^1.3.4" safe-buffer "^5.1.1" @@ -2335,6 +2404,7 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: execa@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== dependencies: cross-spawn "^6.0.0" get-stream "^3.0.0" @@ -2347,6 +2417,7 @@ execa@^0.10.0: execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -2359,10 +2430,12 @@ execa@^0.7.0: exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= expand-braces@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" + integrity sha1-SIsdHSRRyz06axks/AMPRMWFX+o= dependencies: array-slice "^0.2.3" array-unique "^0.2.1" @@ -2371,12 +2444,14 @@ expand-braces@^0.1.1: expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= dependencies: is-posix-bracket "^0.1.0" expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -2389,6 +2464,7 @@ expand-brackets@^2.1.4: expand-range@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-0.1.1.tgz#4cb8eda0993ca56fa4f41fc42f3cbb4ccadff044" + integrity sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ= dependencies: is-number "^0.1.1" repeat-string "^0.2.2" @@ -2396,16 +2472,18 @@ expand-range@^0.1.0: expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= dependencies: fill-range "^2.1.0" express@^4.16.2: - version "4.16.3" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== dependencies: accepts "~1.3.5" array-flatten "1.1.1" - body-parser "1.18.2" + body-parser "1.18.3" content-disposition "0.5.2" content-type "~1.0.4" cookie "0.3.1" @@ -2422,10 +2500,10 @@ express@^4.16.2: on-finished "~2.3.0" parseurl "~1.3.2" path-to-regexp "0.1.7" - proxy-addr "~2.0.3" - qs "6.5.1" + proxy-addr "~2.0.4" + qs "6.5.2" range-parser "~1.2.0" - safe-buffer "5.1.1" + safe-buffer "5.1.2" send "0.16.2" serve-static "1.13.2" setprototypeof "1.1.0" @@ -2437,27 +2515,27 @@ express@^4.16.2: extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -extend@~3.0.2: +extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" + integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== dependencies: chardet "^0.7.0" iconv-lite "^0.4.24" @@ -2466,12 +2544,14 @@ external-editor@^3.0.0: extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= dependencies: is-extglob "^1.0.0" extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -2485,97 +2565,110 @@ extglob@^2.0.4: extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fastparse@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + version "1.1.2" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" + integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= dependencies: websocket-driver ">=0.5.1" -faye-websocket@~0.11.0: +faye-websocket@~0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg= dependencies: websocket-driver ">=0.5.1" -figgy-pudding@^3.1.0, figgy-pudding@^3.5.1: +figgy-pudding@^3.1.0, figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= dependencies: escape-string-regexp "^1.0.5" file-loader@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-2.0.0.tgz#39749c82f020b9e85901dcff98e8004e6401cfde" + integrity sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ== dependencies: loader-utils "^1.0.2" schema-utils "^1.0.0" -file-uri-to-path@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= -fileset@^2.0.2: +fileset@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= dependencies: glob "^7.0.3" minimatch "^3.0.3" fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== dependencies: is-number "^2.1.0" isobject "^2.0.0" - randomatic "^1.1.3" + randomatic "^3.0.0" repeat-element "^1.1.2" repeat-string "^1.5.2" fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" repeat-string "^1.6.1" to-regex-range "^2.1.0" -finalhandler@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.6.tgz#007aea33d1a4d3e42017f624848ad58d212f814f" +finalhandler@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= dependencies: debug "2.6.9" encodeurl "~1.0.1" @@ -2588,6 +2681,7 @@ finalhandler@1.0.6: finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== dependencies: debug "2.6.9" encodeurl "~1.0.2" @@ -2600,6 +2694,7 @@ finalhandler@1.1.1: find-cache-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= dependencies: commondir "^1.0.1" make-dir "^1.0.0" @@ -2608,6 +2703,7 @@ find-cache-dir@^1.0.0: find-cache-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d" + integrity sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA== dependencies: commondir "^1.0.1" make-dir "^1.0.0" @@ -2616,6 +2712,7 @@ find-cache-dir@^2.0.0: find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -2623,79 +2720,70 @@ find-up@^1.0.0: find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: locate-path "^3.0.0" +flatted@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" + integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== + flush-write-stream@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + integrity sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw== dependencies: inherits "^2.0.1" readable-stream "^2.0.4" -follow-redirects@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.0.0.tgz#8e34298cbd2e176f254effec75a1c78cc849fd37" +follow-redirects@^1.0.0: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== dependencies: - debug "^2.2.0" + debug "=3.1.0" for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= for-own@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= dependencies: for-in "^1.0.1" for-own@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= dependencies: for-in "^1.0.1" forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.11" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -form-data@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" - dependencies: - asynckit "^0.4.0" - combined-stream "1.0.6" - mime-types "^2.1.12" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.6" @@ -2704,20 +2792,24 @@ form-data@~2.3.2: forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= from2@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= dependencies: inherits "^2.0.1" readable-stream "^2.0.0" @@ -2725,18 +2817,21 @@ from2@^2.1.0: fs-access@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" + integrity sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o= dependencies: null-check "^1.0.0" fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== dependencies: minipass "^2.2.1" fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= dependencies: graceful-fs "^4.1.2" iferr "^0.1.5" @@ -2746,52 +2841,30 @@ fs-write-stream-atomic@^1.0.8: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.0.0, fsevents@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fsevents@^1.2.2: +fsevents@^1.0.0, fsevents@^1.2.2: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: +fstream@^1.0.0, fstream@^1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" mkdirp ">=0.5 0" rimraf "2" -ftp@~0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" - dependencies: - readable-stream "1.1.x" - xregexp "2.0.0" - -function-bind@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2803,57 +2876,55 @@ gauge@~2.7.3: wide-align "^1.1.0" gaze@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== dependencies: globule "^1.0.0" -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" +genfun@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" + integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= -get-uri@2: - version "2.0.1" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.1.tgz#dbdcacacd8c608a38316869368117697a1631c59" +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== dependencies: - data-uri-to-buffer "1" - debug "2" - extend "3" - file-uri-to-path "1" - ftp "~0.3.10" - readable-stream "2" + pump "^3.0.0" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" @@ -2861,12 +2932,14 @@ glob-base@^0.3.0: glob-parent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= dependencies: is-glob "^2.0.0" glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= dependencies: is-glob "^3.1.0" path-dirname "^1.0.0" @@ -2874,6 +2947,7 @@ glob-parent@^3.1.0: glob@7.0.x: version "7.0.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + integrity sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo= dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2882,9 +2956,10 @@ glob@7.0.x: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.3: +glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2896,6 +2971,7 @@ glob@7.1.3: glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= dependencies: inflight "^1.0.4" inherits "2" @@ -2903,34 +2979,20 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^6.0.4: - version "6.0.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" +globals@^11.1.0: + version "11.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.9.0.tgz#bde236808e987f290768a93d065060d78e6ab249" + integrity sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg== globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -2942,6 +3004,7 @@ globby@^5.0.0: globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= dependencies: array-union "^1.0.1" glob "^7.0.3" @@ -2952,6 +3015,7 @@ globby@^6.1.0: globby@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= dependencies: array-union "^1.0.1" dir-glob "^2.0.0" @@ -2961,100 +3025,86 @@ globby@^7.1.1: slash "^1.0.0" globule@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.0.tgz#1dc49c6822dd9e8a2fa00ba2a295006e8664bd09" + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ== dependencies: glob "~7.1.1" - lodash "~4.17.4" + lodash "~4.17.10" minimatch "~3.0.2" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== -handle-thing@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== -handlebars@^4.0.1, handlebars@^4.0.3: - version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" +handlebars@^4.0.1, handlebars@^4.0.11: + version "4.0.12" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" + integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== dependencies: - async "^1.4.0" + async "^2.5.0" optimist "^0.6.1" - source-map "^0.4.4" + source-map "^0.6.1" optionalDependencies: - uglify-js "^2.6" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + uglify-js "^3.1.4" har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== dependencies: - ajv "^5.3.0" + ajv "^6.5.5" har-schema "^2.0.0" has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= dependencies: ansi-regex "^2.0.0" has-binary2@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.2.tgz#e83dba49f0b9be4d026d27365350d9f03f54be98" + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== dependencies: isarray "2.0.1" has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -3063,6 +3113,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -3071,98 +3122,50 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - dependencies: - function-bind "^1.0.2" - -hash-base@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" - dependencies: - inherits "^2.0.1" - hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== dependencies: inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - -hipchat-notifier@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz#b6d249755437c191082367799d3ba9a0f23b231e" - dependencies: - lodash "^4.0.0" - request "^2.0.0" + minimalistic-assert "^1.0.1" hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= dependencies: hash.js "^1.0.3" minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -hoek@4.x.x: - version "4.2.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" - -homedir-polyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - dependencies: - parse-passwd "^1.0.0" - -hosted-git-info@^2.1.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" - -hosted-git-info@^2.6.0: +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== hpack.js@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= dependencies: inherits "^2.0.1" obuf "^1.0.0" @@ -3172,27 +3175,22 @@ hpack.js@^2.1.6: html-entities@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= -htmlescape@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= -http-errors@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - -http-errors@~1.6.2: +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= dependencies: depd "~1.1.2" inherits "2.0.3" @@ -3200,20 +3198,22 @@ http-errors@~1.6.2: statuses ">= 1.4.0 < 2" http-parser-js@>=0.4.0: - version "0.4.11" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.11.tgz#5b720849c650903c27e521633d94696ee95f3529" + version "0.5.0" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8" + integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w== -http-proxy-agent@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz#cc1ce38e453bf984a0f7702d2dd59c73d081284a" +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== dependencies: - agent-base "2" - debug "2" - extend "3" + agent-base "4" + debug "3.1.0" http-proxy-middleware@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" + integrity sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q== dependencies: http-proxy "^1.16.2" is-glob "^4.0.0" @@ -3221,102 +3221,107 @@ http-proxy-middleware@~0.18.0: micromatch "^3.1.9" http-proxy@^1.13.0, http-proxy@^1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== dependencies: - eventemitter3 "1.x.x" - requires-port "1.x.x" - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" sshpk "^1.7.0" -httpntlm@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/httpntlm/-/httpntlm-1.6.1.tgz#ad01527143a2e8773cfae6a96f58656bb52a34b2" - dependencies: - httpreq ">=0.4.22" - underscore "~1.7.0" - -httpreq@>=0.4.22: - version "0.4.24" - resolved "https://registry.yarnpkg.com/httpreq/-/httpreq-0.4.24.tgz#4335ffd82cd969668a39465c929ac61d6393627f" - https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@1, https-proxy-agent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== dependencies: - agent-base "2" - debug "2" - extend "3" + agent-base "^4.1.0" + debug "^3.1.0" -iconv-lite@0.4.15: - version "0.4.15" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" -iconv-lite@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" ieee754@^1.1.4: - version "1.1.11" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== iferr@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== dependencies: minimatch "^3.0.4" ignore@^3.3.5: - version "3.3.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== image-size@~0.5.0: version "0.5.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" + integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= dependencies: import-from "^2.1.0" import-from@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= dependencies: resolve-from "^3.0.0" import-local@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== dependencies: pkg-dir "^3.0.0" resolve-cwd "^2.0.0" @@ -3324,32 +3329,29 @@ import-local@^2.0.0: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= in-publish@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= dependencies: repeating "^2.0.0" indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - -inflection@~1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" - -inflection@~1.3.0: - version "1.3.8" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.3.8.tgz#cbd160da9f75b14c3cc63578d4f396784bf3014e" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" @@ -3357,24 +3359,22 @@ inflight@^1.0.4: inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= -ini@^1.3.4, ini@~1.3.0: +ini@1.3.5, ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -inline-source-map@~0.6.0: - version "0.6.2" - resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" - dependencies: - source-map "~0.5.3" - -inquirer@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" +inquirer@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" + integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -3387,25 +3387,13 @@ inquirer@6.2.0: run-async "^2.2.0" rxjs "^6.1.0" string-width "^2.1.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" through "^2.3.6" -insert-module-globals@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3" - dependencies: - JSONStream "^1.0.3" - combine-source-map "~0.7.1" - concat-stream "~1.5.1" - is-buffer "^1.1.0" - lexical-scope "^1.2.0" - process "~0.11.0" - through2 "^2.0.0" - xtend "^4.0.0" - internal-ip@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-3.0.1.tgz#df5c99876e1d2eb2ea2d74f520e3f669a00ece27" + integrity sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q== dependencies: default-gateway "^2.6.0" ipaddr.js "^1.5.2" @@ -3413,88 +3401,101 @@ internal-ip@^3.0.1: interpret@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.0.1.tgz#c7e356cdea225ae71b36d70f2e71a92ba4e42590" - -ip@^1.1.0, ip@^1.1.2, ip@^1.1.4, ip@^1.1.5: +ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= -ipaddr.js@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= ipaddr.js@^1.5.2: version "1.8.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.1.tgz#fa4b79fa47fd3def5e3b159825161c0a519c9427" + integrity sha1-+kt5+kf9Pe9eOxWYJRYcClGclCc= is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= dependencies: binary-extensions "^1.0.0" -is-buffer@^1.1.0, is-buffer@^1.1.5: +is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= dependencies: builtin-modules "^1.0.0" is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -3503,6 +3504,7 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" @@ -3511,288 +3513,313 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= is-equal-shallow@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= dependencies: is-primitive "^2.0.0" is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= dependencies: is-extglob "^1.0.0" is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= dependencies: is-extglob "^2.1.0" is-glob@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= dependencies: is-extglob "^2.1.1" -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - -is-my-json-valid@^2.12.4: - version "2.17.2" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" + integrity sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY= is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" is-number@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - -is-odd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" - dependencies: - is-number "^4.0.0" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= is-path-in-cwd@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= dependencies: path-is-inside "^1.0.1" is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - -isarray@0.0.1, isarray@~0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= isbinaryfile@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + version "3.0.3" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" + integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== + dependencies: + buffer-alloc "^1.2.0" isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-api@^1.1.14: - version "1.2.1" - resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.2.1.tgz#0c60a0515eb11c7d65c6b50bba2c6e999acd8620" +istanbul-api@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.0.6.tgz#cd7b33ee678f6c01531d05f5e567ebbcd25f8ecc" + integrity sha512-8W5oeAGWXhtTJjAyVfvavOLVyZCTNCKsyF6GON/INKlBdO7uJ/bv3qnPj5M6ERKzmMCJS1kntnjjGuJ86fn3rQ== dependencies: - async "^2.1.4" - fileset "^2.0.2" - istanbul-lib-coverage "^1.1.1" - istanbul-lib-hook "^1.1.0" - istanbul-lib-instrument "^1.9.1" - istanbul-lib-report "^1.1.2" - istanbul-lib-source-maps "^1.2.2" - istanbul-reports "^1.1.3" - js-yaml "^3.7.0" - mkdirp "^0.5.1" + async "^2.6.1" + compare-versions "^3.2.1" + fileset "^2.0.3" + istanbul-lib-coverage "^2.0.1" + istanbul-lib-hook "^2.0.1" + istanbul-lib-instrument "^3.0.0" + istanbul-lib-report "^2.0.2" + istanbul-lib-source-maps "^2.0.1" + istanbul-reports "^2.0.1" + js-yaml "^3.12.0" + make-dir "^1.3.0" once "^1.4.0" istanbul-instrumenter-loader@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz#9957bd59252b373fae5c52b7b5188e6fde2a0949" + integrity sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w== dependencies: convert-source-map "^1.5.0" istanbul-lib-instrument "^1.7.3" loader-utils "^1.1.0" schema-utils "^0.3.0" -istanbul-lib-coverage@^1.1.1, istanbul-lib-coverage@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341" +istanbul-lib-coverage@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" + integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== -istanbul-lib-hook@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz#8538d970372cb3716d53e55523dd54b557a8d89b" +istanbul-lib-coverage@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#2aee0e073ad8c5f6a0b00e0dfbf52b4667472eda" + integrity sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA== + +istanbul-lib-hook@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.1.tgz#918a57b75a0f951d552a08487ca1fa5336433d72" + integrity sha512-ufiZoiJ8CxY577JJWEeFuxXZoMqiKpq/RqZtOAYuQLvlkbJWscq9n3gc4xrCGH9n4pW0qnTxOz1oyMmVtk8E1w== dependencies: - append-transform "^0.4.0" + append-transform "^1.0.0" istanbul-lib-instrument@^1.7.3: - version "1.10.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b" + version "1.10.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" + integrity sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== dependencies: babel-generator "^6.18.0" babel-template "^6.16.0" babel-traverse "^6.18.0" babel-types "^6.18.0" babylon "^6.18.0" - istanbul-lib-coverage "^1.2.0" + istanbul-lib-coverage "^1.2.1" semver "^5.3.0" -istanbul-lib-instrument@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.1.tgz#250b30b3531e5d3251299fdd64b0b2c9db6b558e" +istanbul-lib-instrument@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz#b5f066b2a161f75788be17a9d556f40a0cf2afc9" + integrity sha512-eQY9vN9elYjdgN9Iv6NS/00bptm02EBBk70lRMaVjeA6QYocQgenVrSgC28TJurdnZa80AGO3ASdFN+w/njGiQ== dependencies: - babel-generator "^6.18.0" - babel-template "^6.16.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" - babylon "^6.18.0" - istanbul-lib-coverage "^1.1.1" - semver "^5.3.0" + "@babel/generator" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + istanbul-lib-coverage "^2.0.1" + semver "^5.5.0" -istanbul-lib-report@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.2.tgz#922be27c13b9511b979bd1587359f69798c1d425" +istanbul-lib-report@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.2.tgz#430a2598519113e1da7af274ba861bd42dd97535" + integrity sha512-rJ8uR3peeIrwAxoDEbK4dJ7cqqtxBisZKCuwkMtMv0xYzaAnsAi3AHrHPAAtNXzG/bcCgZZ3OJVqm1DTi9ap2Q== dependencies: - istanbul-lib-coverage "^1.1.1" - mkdirp "^0.5.1" - path-parse "^1.0.5" - supports-color "^3.1.2" + istanbul-lib-coverage "^2.0.1" + make-dir "^1.3.0" + supports-color "^5.4.0" -istanbul-lib-source-maps@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.2.tgz#750578602435f28a0c04ee6d7d9e0f2960e62c1c" +istanbul-lib-source-maps@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.1.tgz#ce8b45131d8293fdeaa732f4faf1852d13d0a97e" + integrity sha512-30l40ySg+gvBLcxTrLzR4Z2XTRj3HgRCA/p2rnbs/3OiTaoj054gAbuP5DcLOtwqmy4XW8qXBHzrmP2/bQ9i3A== dependencies: debug "^3.1.0" - istanbul-lib-coverage "^1.1.1" - mkdirp "^0.5.1" - rimraf "^2.6.1" - source-map "^0.5.3" + istanbul-lib-coverage "^2.0.1" + make-dir "^1.3.0" + rimraf "^2.6.2" + source-map "^0.6.1" -istanbul-reports@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.3.tgz#3b9e1e8defb6d18b1d425da8e8b32c5a163f2d10" +istanbul-reports@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.0.1.tgz#fb8d6ea850701a3984350b977a969e9a556116a7" + integrity sha512-CT0QgMBJqs6NJLF678ZHcquUAZIoBIUNzdJrRJfpkI9OnzG6MkUfHxbJC3ln981dMswC7/B1mfX3LNkhgJxsuw== dependencies: - handlebars "^4.0.3" + handlebars "^4.0.11" istanbul@0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" + integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= dependencies: abbrev "1.0.x" async "1.x" @@ -3812,54 +3839,53 @@ istanbul@0.4.5: jasmine-core@~2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" + integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= -jasmine-core@~2.9.0: - version "2.9.1" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.9.1.tgz#b6bbc1d8e65250d56f5888461705ebeeeb88f22f" +jasmine-core@~2.99.1: + version "2.99.1" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15" + integrity sha1-5kAN8ea1bhMLYcS80JPap/boyhU= jasmine-spec-reporter@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz#1d632aec0341670ad324f92ba84b4b32b35e9e22" + integrity sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg== dependencies: colors "1.1.2" -jasmine@^2.5.3: - version "2.9.0" - resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.9.0.tgz#76571f925c8783409e7c6153572e5a6341cf93eb" +jasmine@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" + integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4= dependencies: exit "^0.1.2" glob "^7.0.6" - jasmine-core "~2.9.0" + jasmine-core "~2.8.0" jasminewd2@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" + integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= js-base64@^2.1.8: - version "2.4.3" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.3.tgz#2e545ec2b0f2957f41356510205214e98fad6582" + version "2.5.0" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.0.tgz#42255ba183ab67ce59a0dee640afdc00ab5ae93e" + integrity sha512-wlEBIZ5LP8usDylWbDNhKPEFVFdI5hCHpnVoT/Ysvoi/PRhJENm/Rlh9TvjYB38HFfKZN7OzEbRjmjvLkFw11g== -js-tokens@^3.0.0, js-tokens@^3.0.2: +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.x: - version "3.11.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^3.7.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^3.9.0: +js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.7.0, js-yaml@^3.9.0: version "3.12.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -3867,114 +3893,127 @@ js-yaml@^3.9.0: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stable-stringify@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@5.0.x, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= json5@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" - -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" extsprintf "1.3.0" json-schema "0.2.3" verror "1.10.0" +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + karma-chrome-launcher@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" + integrity sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w== dependencies: fs-access "^1.0.0" which "^1.2.1" -karma-coverage-istanbul-reporter@^1.2.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.1.tgz#2b42d145ddbb4868d85d52888c495a21c61d873c" +karma-coverage-istanbul-reporter@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.4.tgz#402ae4ed6eadb9d9dafbd408ffda17897c0d003a" + integrity sha512-xJS7QSQIVU6VK9HuJ/ieE5yynxKhjCCkd96NLY/BX/HXsx0CskU9JJiMQbd4cHALiddMwI4OWh1IIzeWrsavJw== dependencies: - istanbul-api "^1.1.14" + istanbul-api "^2.0.5" minimatch "^3.0.4" karma-jasmine-html-reporter@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz#48a8e5ef18807617ee2b5e33c1194c35b439524c" + integrity sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw= dependencies: karma-jasmine "^1.0.2" -karma-jasmine@^1.0.2, karma-jasmine@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.1.tgz#6fe840e75a11600c9d91e84b33c458e1c46a3529" +karma-jasmine@^1.0.2, karma-jasmine@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.2.tgz#394f2b25ffb4a644b9ada6f22d443e2fd08886c3" + integrity sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM= karma-source-map-support@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz#36dd4d8ca154b62ace95696236fae37caf0a7dde" + integrity sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q== dependencies: source-map-support "^0.5.5" -karma@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/karma/-/karma-2.0.0.tgz#a02698dd7f0f05ff5eb66ab8f65582490b512e58" +karma@~3.1.1: + version "3.1.4" + resolved "https://registry.yarnpkg.com/karma/-/karma-3.1.4.tgz#3890ca9722b10d1d14b726e1335931455788499e" + integrity sha512-31Vo8Qr5glN+dZEVIpnPCxEGleqE0EY6CtC2X9TagRV3rRQ3SNrvfhddICkJgUK3AgqpeKSZau03QumTGhGoSw== dependencies: bluebird "^3.3.0" body-parser "^1.16.1" - browserify "^14.5.0" - chokidar "^1.4.1" + chokidar "^2.0.3" colors "^1.1.0" combine-lists "^1.0.0" connect "^3.6.0" @@ -3982,83 +4021,81 @@ karma@~2.0.0: di "^0.0.1" dom-serialize "^2.2.0" expand-braces "^0.1.1" + flatted "^2.0.0" glob "^7.1.1" graceful-fs "^4.1.2" http-proxy "^1.13.0" isbinaryfile "^3.0.0" - lodash "^4.17.4" - log4js "^2.3.9" - mime "^1.3.4" + lodash "^4.17.5" + log4js "^3.0.0" + mime "^2.3.1" minimatch "^3.0.2" optimist "^0.6.1" qjobs "^1.1.4" range-parser "^1.2.0" rimraf "^2.6.0" safe-buffer "^5.0.1" - socket.io "2.0.4" + socket.io "2.1.1" source-map "^0.6.1" tmp "0.0.33" - useragent "^2.1.12" + useragent "2.3.0" killable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.0.tgz#da8b84bd47de5395878f95d64d02f2449fe05e6b" + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - -labeled-stream-splicer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59" - dependencies: - inherits "^2.0.1" - isarray "~0.0.1" - stream-splicer "^2.0.0" - -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= dependencies: invert-kv "^1.0.0" lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== dependencies: invert-kv "^2.0.0" less-loader@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e" + integrity sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg== dependencies: clone "^2.1.1" loader-utils "^1.1.0" pify "^3.0.0" -less@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/less/-/less-3.8.1.tgz#f31758598ef5a1930dd4caefa9e4340641e71e1d" +less@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/less/-/less-3.9.0.tgz#b7511c43f37cf57dc87dffd9883ec121289b1474" + integrity sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w== dependencies: clone "^2.1.2" optionalDependencies: @@ -4074,41 +4111,30 @@ less@3.8.1: levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" -lexical-scope@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4" - dependencies: - astw "^2.0.0" - -libbase64@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/libbase64/-/libbase64-0.1.0.tgz#62351a839563ac5ff5bd26f12f60e9830bb751e6" - -libmime@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/libmime/-/libmime-3.0.0.tgz#51a1a9e7448ecbd32cda54421675bb21bc093da6" - dependencies: - iconv-lite "0.4.15" - libbase64 "0.1.0" - libqp "1.1.0" - -libqp@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" - -license-webpack-plugin@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.0.2.tgz#9d34b521cb7fca8527945310b05be6ef0248b687" +license-webpack-plugin@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.0.4.tgz#48532e7d7b45f6ceb21a68b6826ce7241d7ea6da" + integrity sha512-FQgOqrrIcD4C/VQo6ecWgXZULK5rs0kIDJtHcSVO6SBUrD63kEHZwmKOvBTquFQSgMQn/yeH68qooKDfqiBF2Q== dependencies: + "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -4119,6 +4145,7 @@ load-json-file@^1.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" @@ -4126,12 +4153,14 @@ load-json-file@^2.0.0: strip-bom "^3.0.0" loader-runner@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + version "2.3.1" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.1.tgz#026f12fe7c3115992896ac02ba022ba92971b979" + integrity sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw== loader-utils@1.1.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= dependencies: big.js "^3.1.3" emojis-list "^2.0.0" @@ -4140,6 +4169,7 @@ loader-utils@1.1.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1. locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -4147,6 +4177,7 @@ locate-path@^2.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" @@ -4154,190 +4185,162 @@ locate-path@^3.0.0: lodash.assign@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - -lodash.memoize@~3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= lodash.mergewith@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" + integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ== lodash.tail@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" + integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.4: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" - -lodash@^4.15.0, lodash@^4.5.0: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - -lodash@^4.17.10: +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.0, lodash@~4.17.10: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== -log4js@^2.3.9: - version "2.5.2" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-2.5.2.tgz#234e9c688bc4aab3999bd4b149c85851a4e62faa" +log4js@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-3.0.6.tgz#e6caced94967eeeb9ce399f9f8682a4b2b28c8ff" + integrity sha512-ezXZk6oPJCWL483zj64pNkMuY/NcRX5MPiB0zE6tjZM137aeusrOnW1ecxgF9cmwMWkBMhjteQxBPoZBh9FDxQ== dependencies: - circular-json "^0.5.1" + circular-json "^0.5.5" date-format "^1.2.0" debug "^3.1.0" - semver "^5.3.0" - streamroller "^0.7.0" - optionalDependencies: - amqplib "^0.5.2" - axios "^0.15.3" - hipchat-notifier "^1.1.0" - loggly "^1.1.0" - mailgun-js "^0.7.0" - nodemailer "^2.5.0" - redis "^2.7.1" - slack-node "~0.2.0" - -loggly@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/loggly/-/loggly-1.1.1.tgz#0a0fc1d3fa3a5ec44fdc7b897beba2a4695cebee" - dependencies: - json-stringify-safe "5.0.x" - request "2.75.x" - timespan "2.3.x" + rfdc "^1.1.2" + streamroller "0.7.0" loglevel@^1.4.1: version "1.6.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" - -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po= loose-envify@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: - js-tokens "^3.0.0" + js-tokens "^3.0.0 || ^4.0.0" -loud-rejection@^1.0.0, loud-rejection@^1.6.0: +loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" -lru-cache@2.2.x: - version "2.2.4" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d" - -lru-cache@^4.0.1, lru-cache@^4.1.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" +lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== dependencies: pseudomap "^1.0.2" yallist "^2.1.2" -lru-cache@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@~2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.6.5.tgz#e56d6354148ede8d7707b58d143220fd08df0fd5" - magic-string@^0.25.0: version "0.25.1" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.1.tgz#b1c248b399cd7485da0fe7385c2fc7011843266e" + integrity sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg== dependencies: sourcemap-codec "^1.4.1" -mailcomposer@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/mailcomposer/-/mailcomposer-4.0.1.tgz#0e1c44b2a07cf740ee17dc149ba009f19cadfeb4" - dependencies: - buildmail "4.0.1" - libmime "3.0.0" - -mailgun-js@^0.7.0: - version "0.7.15" - resolved "https://registry.yarnpkg.com/mailgun-js/-/mailgun-js-0.7.15.tgz#ee366a20dac64c3c15c03d6c1b3e0ed795252abb" - dependencies: - async "~2.1.2" - debug "~2.2.0" - form-data "~2.1.1" - inflection "~1.10.0" - is-stream "^1.1.0" - path-proxy "~1.0.0" - proxy-agent "~2.0.0" - q "~1.4.0" - tsscmp "~1.0.0" - -make-dir@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" +make-dir@^1.0.0, make-dir@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== dependencies: pify "^3.0.0" make-error@^1.1.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.2.tgz#8762ffad2444dd8ff1f7c819629fa28e24fea1c4" + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== -mamacro@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" +make-fetch-happen@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" + integrity sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ== + dependencies: + agentkeepalive "^3.4.1" + cacache "^11.0.1" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" map-age-cleaner@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74" + 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.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= + md5.js@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== dependencies: hash-base "^3.0.0" inherits "^2.0.1" + safe-buffer "^5.1.2" media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= mem@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= dependencies: mimic-fn "^1.0.0" mem@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf" + integrity sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA== dependencies: map-age-cleaner "^0.1.1" mimic-fn "^1.0.0" @@ -4346,6 +4349,7 @@ mem@^4.0.0: memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= dependencies: errno "^0.1.3" readable-stream "^2.0.1" @@ -4353,6 +4357,7 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: meow@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -4368,14 +4373,17 @@ meow@^3.7.0: merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= micromatch@^2.1.5: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -4391,9 +4399,10 @@ micromatch@^2.1.5: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -4412,106 +4421,103 @@ micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== dependencies: bn.js "^4.0.0" brorand "^1.0.1" -"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - -mime-db@~1.37.0: +"mime-db@>= 1.36.0 < 2", mime-db@~1.37.0: version "1.37.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== -mime-types@^2.1.11, mime-types@~2.1.11: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - dependencies: - mime-db "~1.30.0" - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.7: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - dependencies: - mime-db "~1.33.0" - -mime-types@~2.1.19: +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: version "2.1.21" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== dependencies: mime-db "~1.37.0" mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== -mime@^1.3.4, mime@^1.4.1: +mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mime@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" + version "2.4.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" + integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w== mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mini-css-extract-plugin@0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.3.tgz#98d60fcc5d228c3e36a9bd15a1d6816d6580beb8" +mini-css-extract-plugin@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.4.tgz#c10410a004951bd3cedac1da69053940fccb625d" + integrity sha512-o+Jm+ocb0asEngdM6FsZWtZsRzA8koFUudIDwYUfl94M3PejPHG7Vopw5hN9V8WsMkSFpm3tZP3Fesz89EyrfQ== dependencies: loader-utils "^1.1.0" schema-utils "^1.0.0" webpack-sources "^1.1.0" -minimalistic-assert@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= -minipass@^2.2.1, minipass@^2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" +minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" -minizlib@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== dependencies: minipass "^2.2.1" mississippi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== dependencies: concat-stream "^1.5.0" duplexify "^3.4.2" @@ -4527,6 +4533,7 @@ mississippi@^2.0.0: mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== dependencies: concat-stream "^1.5.0" duplexify "^3.4.2" @@ -4542,6 +4549,7 @@ mississippi@^3.0.0: mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -4549,6 +4557,7 @@ mixin-deep@^1.2.0: mixin-object@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= dependencies: for-in "^0.1.3" is-extendable "^0.1.1" @@ -4556,32 +4565,14 @@ mixin-object@^2.0.1: mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" -module-deps@^4.0.8: - version "4.1.1" - resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.1.1.tgz#23215833f1da13fd606ccb8087b44852dcb821fd" - dependencies: - JSONStream "^1.0.3" - browser-resolve "^1.7.0" - cached-path-relative "^1.0.0" - concat-stream "~1.5.0" - defined "^1.0.0" - detective "^4.0.0" - duplexer2 "^0.1.2" - inherits "^2.0.1" - parents "^1.0.0" - readable-stream "^2.0.2" - resolve "^1.1.3" - stream-combiner2 "^1.1.1" - subarg "^1.0.0" - through2 "^2.0.0" - xtend "^4.0.0" - move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= dependencies: aproba "^1.1.1" copy-concurrently "^1.0.0" @@ -4590,21 +4581,25 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" -ms@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.0.0, ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= multicast-dns@^6.0.1: version "6.2.3" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== dependencies: dns-packet "^1.3.1" thunky "^1.0.2" @@ -4612,25 +4607,23 @@ multicast-dns@^6.0.1: mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@^2.10.0, nan@^2.3.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - -nan@^2.9.2: - version "2.11.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" +nan@^2.10.0, nan@^2.9.2: + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== nanomatch@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" define-property "^2.0.2" extend-shallow "^3.0.2" fragment-cache "^0.2.1" - is-odd "^2.0.0" is-windows "^1.0.2" kind-of "^6.0.2" object.pick "^1.3.0" @@ -4641,6 +4634,7 @@ nanomatch@^1.2.9: needle@^2.2.1: version "2.2.4" resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== dependencies: debug "^2.1.2" iconv-lite "^0.4.4" @@ -4649,26 +4643,36 @@ needle@^2.2.1: negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= neo-async@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f" - -netmask@~1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-forge@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300" +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-forge@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ== node-gyp@^3.8.0: version "3.8.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== dependencies: fstream "^1.0.0" glob "^7.0.3" @@ -4686,6 +4690,7 @@ node-gyp@^3.8.0: node-libs-browser@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg== dependencies: assert "^1.1.1" browserify-zlib "^0.2.0" @@ -4714,6 +4719,7 @@ node-libs-browser@^2.0.0: node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" @@ -4726,31 +4732,17 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - dependencies: - detect-libc "^1.0.2" - hawk "3.1.3" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" - -node-releases@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.2.tgz#27c296d9fca3b659c64f7d43ea47a31ad2a90e4b" +node-releases@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.2.tgz#93c17fba5eec8650ad908de5433fa8763baebe4d" + integrity sha512-j1gEV/zX821yxdWp/1vBMN0pSUjuH9oGUdLCb4PfUko6ZW7KdRs3Z+QGGwDUhYtSpQvdVVyLd2V0YvLsmdg5jQ== dependencies: semver "^5.3.0" -node-sass@4.9.3: - version "4.9.3" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.3.tgz#f407cf3d66f78308bb1e346b24fa428703196224" +node-sass@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.10.0.tgz#dcc2b364c0913630945ccbf7a2bbf1f926effca4" + integrity sha512-fDQJfXszw6vek63Fe/ldkYXmRYK/QS6NbvM3i5oEo9ntPDy4XX7BcKZyTKv+/kSSxRtXXc7l+MSwEmYc0CSy6Q== dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -4767,80 +4759,30 @@ node-sass@4.9.3: nan "^2.10.0" node-gyp "^3.8.0" npmlog "^4.0.0" - request "2.87.0" + request "^2.88.0" sass-graph "^2.2.4" stdout-stream "^1.4.0" "true-case-path" "^1.0.2" -node-uuid@~1.4.7: - version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - -nodemailer-direct-transport@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz#e96fafb90358560947e569017d97e60738a50a86" - dependencies: - nodemailer-shared "1.1.0" - smtp-connection "2.12.0" - -nodemailer-fetch@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz#79c4908a1c0f5f375b73fe888da9828f6dc963a4" - -nodemailer-shared@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz#cf5994e2fd268d00f5cf0fa767a08169edb07ec0" - dependencies: - nodemailer-fetch "1.6.0" - -nodemailer-smtp-pool@2.8.2: - version "2.8.2" - resolved "https://registry.yarnpkg.com/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz#2eb94d6cf85780b1b4725ce853b9cbd5e8da8c72" - dependencies: - nodemailer-shared "1.1.0" - nodemailer-wellknown "0.1.10" - smtp-connection "2.12.0" - -nodemailer-smtp-transport@2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz#03d71c76314f14ac7dbc7bf033a6a6d16d67fb77" - dependencies: - nodemailer-shared "1.1.0" - nodemailer-wellknown "0.1.10" - smtp-connection "2.12.0" - -nodemailer-wellknown@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz#586db8101db30cb4438eb546737a41aad0cf13d5" - -nodemailer@^2.5.0: - version "2.7.2" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-2.7.2.tgz#f242e649aeeae39b6c7ed740ef7b061c404d30f9" - dependencies: - libmime "3.0.0" - mailcomposer "4.0.1" - nodemailer-direct-transport "3.3.2" - nodemailer-shared "1.1.0" - nodemailer-smtp-pool "2.8.2" - nodemailer-smtp-transport "2.7.2" - socks "1.1.9" - "nopt@2 || 3", nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= dependencies: abbrev "1" nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= dependencies: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4850,60 +4792,70 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" normalize-range@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" + integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== -"npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0": +npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== dependencies: hosted-git-info "^2.6.0" osenv "^0.1.5" semver "^5.5.0" validate-npm-package-name "^3.0.0" -npm-packlist@^1.1.6: - version "1.1.11" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" +npm-packlist@^1.1.12, npm-packlist@^1.1.6: + version "1.1.12" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a" + integrity sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" -npm-registry-client@8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.6.0.tgz#7f1529f91450732e89f8518e0f21459deea3e4c4" +npm-pick-manifest@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" + integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA== dependencies: - concat-stream "^1.5.2" - graceful-fs "^4.1.6" - normalize-package-data "~1.0.1 || ^2.0.0" - npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" - once "^1.3.3" - request "^2.74.0" - retry "^0.10.0" - safe-buffer "^5.1.1" - semver "2 >=2.2.1 || 3.x || 4 || 5" - slide "^1.1.3" - ssri "^5.2.4" - optionalDependencies: - npmlog "2 || ^3.1.0 || ^4.0.0" + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-registry-fetch@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.8.0.tgz#aa7d9a7c92aff94f48dba0984bdef4bd131c88cc" + integrity sha512-hrw8UMD+Nob3Kl3h8Z/YjmKamb1gf7D1ZZch2otrIXM3uFLB5vjEY6DhMlq80z/zZet6eETLbOXcuQudCB3Zpw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.0, npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4913,34 +4865,37 @@ npm-run-path@^2.0.0: null-check@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" + integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.8.1, oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" @@ -4949,12 +4904,14 @@ object-copy@^0.1.0: object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= dependencies: for-own "^0.1.4" is-extendable "^0.1.1" @@ -4962,44 +4919,59 @@ object.omit@^2.0.0: object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" -obuf@^1.0.0, obuf@^1.1.1: +obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= -once@1.x, once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: +once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= dependencies: mimic-fn "^1.0.0" -opn@5.3.0, opn@^5.1.0: +opn@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + integrity sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g== + dependencies: + is-wsl "^1.1.0" + +opn@^5.1.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" + integrity sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw== dependencies: is-wsl "^1.1.0" optimist@^0.6.1, optimist@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -5007,6 +4979,7 @@ optimist@^0.6.1, optimist@~0.6.0: optionator@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -5015,33 +4988,34 @@ optionator@^0.8.1: type-check "~0.3.2" wordwrap "~1.0.0" -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - -original@>=0.0.5: +original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== dependencies: url-parse "^1.4.3" -os-browserify@^0.3.0, os-browserify@~0.3.0: +os-browserify@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-locale@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= dependencies: lcid "^1.0.0" os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== dependencies: execa "^0.7.0" lcid "^1.0.0" @@ -5050,6 +5024,7 @@ os-locale@^2.0.0: os-locale@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620" + integrity sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw== dependencies: execa "^0.10.0" lcid "^2.0.0" @@ -5058,10 +5033,12 @@ os-locale@^3.0.0: os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= osenv@0, osenv@^0.1.4, osenv@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" @@ -5069,96 +5046,117 @@ osenv@0, osenv@^0.1.4, osenv@^0.1.5: p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-is-promise@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= p-limit@^1.0.0, p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" p-limit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + integrity sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A== dependencies: p-try "^2.0.0" p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: p-limit "^2.0.0" p-map@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= p-try@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== -pac-proxy-agent@1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz#34a385dfdf61d2f0ecace08858c745d3e791fd4d" +pacote@9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.1.1.tgz#25091f75a25021de8be8d34cc6408728fca3579b" + integrity sha512-f28Rq5ozzKAA9YwIKw61/ipwAatUZseYmVssDbHHaexF0wRIVotapVEZPAjOT7Eu3LYVqEp0NVpNizoAnYBUaA== dependencies: - agent-base "2" - debug "2" - extend "3" - get-uri "2" - http-proxy-agent "1" - https-proxy-agent "1" - pac-resolver "~2.0.0" - raw-body "2" - socks-proxy-agent "2" + bluebird "^3.5.2" + cacache "^11.2.0" + figgy-pudding "^3.5.1" + get-stream "^4.1.0" + glob "^7.1.3" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + minimatch "^3.0.4" + minipass "^2.3.5" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.12" + npm-pick-manifest "^2.1.0" + npm-registry-fetch "^3.8.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.1" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.6.0" + ssri "^6.0.1" + tar "^4.4.6" + unique-filename "^1.1.1" + which "^1.3.1" -pac-resolver@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-2.0.0.tgz#99b88d2f193fbdeefc1c9a529c1f3260ab5277cd" - dependencies: - co "~3.0.6" - degenerator "~1.0.2" - ip "1.0.1" - netmask "~1.0.4" - thunkify "~2.1.1" +pako@~1.0.2: + version "1.0.8" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4" + integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA== pako@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + version "1.0.7" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.7.tgz#2473439021b57f1516c82f58be7275ad8ef1bb27" + integrity sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ== parallel-transform@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= dependencies: cyclist "~0.2.2" inherits "^2.0.3" readable-stream "^2.1.5" -parents@^1.0.0, parents@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" - dependencies: - path-platform "~0.11.15" - parse-asn1@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + integrity sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw== dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" @@ -5169,6 +5167,7 @@ parse-asn1@^5.0.0: parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -5178,95 +5177,98 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= dependencies: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= dependencies: better-assert "~1.0.0" parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -path-browserify@0.0.0, path-browserify@~0.0.0: +path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - -path-platform@~0.11.15: - version "0.11.15" - resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" - -path-proxy@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-proxy/-/path-proxy-1.0.0.tgz#18e8a36859fc9d2f1a53b48dee138543c020de5e" - dependencies: - inflection "~1.3.0" +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -5275,18 +5277,21 @@ path-type@^1.0.0: path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= dependencies: pify "^2.0.0" path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== dependencies: pify "^3.0.0" pbkdf2@^3.0.3: - version "3.0.14" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== dependencies: create-hash "^1.1.2" create-hmac "^1.1.4" @@ -5294,55 +5299,60 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= dependencies: find-up "^2.1.0" pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== dependencies: find-up "^3.0.0" portfinder@1.0.17: version "1.0.17" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.17.tgz#a8a1691143e46c4735edefcf4fbcccedad26456a" + integrity sha512-syFcRIRzVI1BoEFOCaAiizwDolh1S1YXSodsVhncbhjzjZQulhczNRbqnUl9N31Q4dKGOXsNDqxC2BWBgSMqeQ== dependencies: async "^1.5.2" debug "^2.2.0" mkdirp "0.5.x" portfinder@^1.0.9: - version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + version "1.0.20" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" + integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== dependencies: async "^1.5.2" debug "^2.2.0" @@ -5351,10 +5361,12 @@ portfinder@^1.0.9: posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= postcss-import@12.0.0: version "12.0.0" resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-12.0.0.tgz#149f96a4ef0b27525c419784be8517ebd17e92c5" + integrity sha512-3KqKRZcaZAvxbY8DVLdd81tG5uKzbUQuiWIvy0o0fzEC42bKacqPYFWbfCQyw6L4LWUaqPz/idvIdbhpgQ32eQ== dependencies: postcss "^7.0.1" postcss-value-parser "^3.2.3" @@ -5364,6 +5376,7 @@ postcss-import@12.0.0: postcss-load-config@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484" + integrity sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ== dependencies: cosmiconfig "^4.0.0" import-cwd "^2.0.0" @@ -5371,19 +5384,31 @@ postcss-load-config@^2.0.0: postcss-loader@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== dependencies: loader-utils "^1.1.0" postcss "^7.0.0" postcss-load-config "^2.0.0" schema-utils "^1.0.0" -postcss-value-parser@^3.2.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" +postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss@7.0.5, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2: - version "7.0.5" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.5.tgz#70e6443e36a6d520b0fd4e7593fcca3635ee9f55" +postcss@7.0.11: + version "7.0.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.11.tgz#f63c513b78026d66263bb2ca995bf02e3d1a697d" + integrity sha512-9AXb//5UcjeOEof9T+yPw3XTa5SL207ZOIC/lHYP4mbUTEh4M0rDAQekQpVANCZdwQwKhBtFZCk3i3h3h2hdWg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.6: + version "7.0.7" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.7.tgz#2754d073f77acb4ef08f1235c36c5721a7201614" + integrity sha512-HThWSJEPkupqew2fnuQMEI2YcTj/8gMV3n80cMdJsKxfIh5tHf7nM5JigNX6LxVMqo6zkgQNAI88hyFvBk41Pg== dependencies: chalk "^2.4.1" source-map "^0.6.1" @@ -5392,97 +5417,113 @@ postcss@7.0.5, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2: prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== -process@^0.11.10, process@~0.11.0: +process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== dependencies: asap "~2.0.3" -"protractor@file:../../node_modules/protractor": - version "5.1.2" +protoduck@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" + integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== + dependencies: + genfun "^5.0.0" + +"protractor@file:../../node_modules/protractor": + version "5.4.2" dependencies: - "@types/node" "^6.0.46" "@types/q" "^0.0.32" - "@types/selenium-webdriver" "~2.53.39" - blocking-proxy "0.0.5" + "@types/selenium-webdriver" "^3.0.0" + blocking-proxy "^1.0.0" + browserstack "^1.5.1" chalk "^1.1.3" glob "^7.0.3" - jasmine "^2.5.3" + jasmine "2.8.0" jasminewd2 "^2.1.0" optimist "~0.6.0" q "1.4.1" - saucelabs "~1.3.0" - selenium-webdriver "3.0.1" + saucelabs "^1.5.0" + selenium-webdriver "3.6.0" source-map-support "~0.4.0" - webdriver-js-extender "^1.0.0" + webdriver-js-extender "2.1.0" webdriver-manager "^12.0.6" -proxy-addr@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== dependencies: forwarded "~0.1.2" - ipaddr.js "1.6.0" - -proxy-agent@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-2.0.0.tgz#57eb5347aa805d74ec681cb25649dba39c933499" - dependencies: - agent-base "2" - debug "2" - extend "3" - http-proxy-agent "1" - https-proxy-agent "1" - lru-cache "~2.6.5" - pac-proxy-agent "1" - socks-proxy-agent "2" + ipaddr.js "1.8.0" prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= psl@^1.1.24: - version "1.1.29" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== public-encrypt@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== dependencies: bn.js "^4.1.0" browserify-rsa "^4.0.0" create-hash "^1.1.0" parse-asn1 "^5.0.0" randombytes "^2.0.1" + safe-buffer "^5.1.2" pump@^2.0.0, pump@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== dependencies: end-of-stream "^1.1.0" once "^1.3.1" @@ -5490,86 +5531,90 @@ pump@^2.0.0, pump@^2.0.1: pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" once "^1.3.1" pumpify@^1.3.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb" + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== dependencies: - duplexify "^3.5.3" + duplexify "^3.6.0" inherits "^2.0.3" pump "^2.0.0" punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@1.4.1, punycode@^1.2.4, punycode@^1.3.2, punycode@^1.4.1: +punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= punycode@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -q@1.4.1, q@~1.4.0: +q@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= q@^1.4.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= qjobs@^1.1.4: - version "1.1.5" - resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.1.5.tgz#659de9f2cf8dcc27a1481276f205377272382e73" + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== -qs@6.5.1, qs@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - -qs@~6.2.0: - version "6.2.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - -qs@~6.5.2: +qs@6.5.2, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -querystring-es3@^0.2.0, querystring-es3@~0.2.0: +querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= querystringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" + integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== dependencies: safe-buffer "^5.1.0" randomfill@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== dependencies: randombytes "^2.0.5" safe-buffer "^5.1.0" @@ -5577,32 +5622,27 @@ randomfill@^1.0.3: range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= -raw-body@2, raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== dependencies: bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" + http-errors "1.6.3" + iconv-lite "0.4.23" unpipe "1.0.0" raw-loader@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" - -rc@^1.1.7: - version "1.2.6" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" + integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" ini "~1.3.0" @@ -5612,18 +5652,14 @@ rc@^1.2.7: read-cache@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q= dependencies: pify "^2.3.0" -read-only-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" - dependencies: - readable-stream "^2.0.2" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -5631,6 +5667,7 @@ read-pkg-up@^1.0.1: 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" @@ -5638,6 +5675,7 @@ read-pkg-up@^2.0.0: read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -5646,14 +5684,16 @@ read-pkg@^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" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -5663,30 +5703,19 @@ read-pkg@^2.0.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@1.1.x, "readable-stream@1.x >=1.1.9": - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" +readable-stream@^3.0.6: + version "3.1.1" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" + integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA== dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" -readable-stream@2, readable-stream@^2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readable-stream@~2.0.0, readable-stream@~2.0.5: +readable-stream@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -5696,64 +5725,55 @@ readable-stream@~2.0.0, readable-stream@~2.0.5: util-deprecate "~1.0.1" readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" + graceful-fs "^4.1.11" + micromatch "^3.1.10" readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= dependencies: resolve "^1.1.6" redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" -redis-commands@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.1.tgz#81d826f45fa9c8b2011f4cd7a0fe597d241d442b" - -redis-parser@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b" - -redis@^2.7.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02" - dependencies: - double-ended-queue "^2.1.0-0" - redis-commands "^1.2.0" - redis-parser "^2.6.0" - reflect-metadata@^0.1.2: version "0.1.12" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" + integrity sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A== regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== dependencies: is-equal-shallow "^0.1.3" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" @@ -5761,6 +5781,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: regexpu-core@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs= dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -5769,170 +5790,46 @@ regexpu-core@^1.0.0: regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= regjsparser@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= dependencies: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== repeat-string@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae" + integrity sha1-x6jTI2BoNiBZp+RlH8aITosftK4= repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= dependencies: is-finite "^1.0.0" -request@2.75.x: - version "2.75.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - bl "~1.1.2" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.0.0" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.1" - qs "~6.2.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - -request@2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@^2.0.0, request@^2.74.0, request@^2.78.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@^2.83.0: - version "2.85.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@^2.87.0: +request@^2.83.0, request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -5955,70 +5852,59 @@ request@^2.87.0: tunnel-agent "^0.6.0" uuid "^3.3.2" -requestretry@^1.2.2: - version "1.13.0" - resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-1.13.0.tgz#213ec1006eeb750e8b8ce54176283d15a8d55d94" - dependencies: - extend "^3.0.0" - lodash "^4.15.0" - request "^2.74.0" - when "^3.7.7" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-from-string@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= -requires-port@1.x.x, requires-port@^1.0.0: +requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= dependencies: resolve-from "^3.0.0" resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7, resolve@1.1.x: +resolve@1.1.x: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.3, resolve@^1.1.4, resolve@^1.3.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: + version "1.9.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" + integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== dependencies: - path-parse "^1.0.5" - -resolve@^1.1.6: - version "1.8.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - dependencies: - path-parse "^1.0.5" - -resolve@^1.1.7: - version "1.6.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c" - dependencies: - path-parse "^1.0.5" + path-parse "^1.0.6" restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= dependencies: onetime "^2.0.0" signal-exit "^3.0.2" @@ -6026,74 +5912,73 @@ restore-cursor@^2.0.0: ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== retry@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - dependencies: - align-text "^0.1.1" +rfdc@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" + integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== dependencies: glob "^7.0.5" ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== dependencies: - hash-base "^2.0.0" + hash-base "^3.0.0" inherits "^2.0.1" run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= dependencies: is-promise "^2.1.0" run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= dependencies: aproba "^1.1.1" -rxjs@6.3.3, "rxjs@file:../../node_modules/rxjs": +rxjs@6.3.3, rxjs@^6.1.0, "rxjs@file:../../node_modules/rxjs": version "6.3.3" dependencies: tslib "^1.9.0" -rxjs@^6.1.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.2.tgz#6a688b16c4e6e980e62ea805ec30648e1c60907f" - dependencies: - tslib "^1.9.0" - -safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -safe-buffer@^5.1.2: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sass-graph@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= dependencies: glob "^7.0.0" lodash "^4.0.0" @@ -6103,6 +5988,7 @@ sass-graph@^2.2.4: sass-loader@7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d" + integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w== dependencies: clone-deep "^2.0.1" loader-utils "^1.0.1" @@ -6111,40 +5997,34 @@ sass-loader@7.1.0: pify "^3.0.0" semver "^5.5.0" -saucelabs@~1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.3.0.tgz#d240e8009df7fa87306ec4578a69ba3b5c424fee" +saucelabs@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" + integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== dependencies: - https-proxy-agent "^1.0.0" + https-proxy-agent "^2.2.1" sax@0.5.x: version "0.5.8" resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" - -sax@0.6.x: - version "0.6.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" + integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= sax@>=0.6.0, sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== schema-utils@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" + integrity sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8= dependencies: ajv "^5.0.0" schema-utils@^0.4.4: version "0.4.7" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" - dependencies: - ajv "^6.1.0" - ajv-keywords "^3.1.0" - -schema-utils@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" + integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== dependencies: ajv "^6.1.0" ajv-keywords "^3.1.0" @@ -6152,6 +6032,7 @@ schema-utils@^0.4.5: schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== dependencies: ajv "^6.1.0" ajv-errors "^1.0.0" @@ -6160,6 +6041,7 @@ schema-utils@^1.0.0: scss-tokenizer@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= dependencies: js-base64 "^2.1.8" source-map "^0.4.2" @@ -6167,63 +6049,58 @@ scss-tokenizer@^0.2.3: select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -selenium-webdriver@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz#a2dea5da4a97f6672e89e7ca7276cefa365147a7" +selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q== dependencies: - adm-zip "^0.4.7" + jszip "^3.1.3" rimraf "^2.5.4" tmp "0.0.30" xml2js "^0.4.17" -selenium-webdriver@^2.53.2: - version "2.53.3" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz#d29ff5a957dff1a1b49dc457756e4e4bfbdce085" - dependencies: - adm-zip "0.4.4" - rimraf "^2.2.8" - tmp "0.0.24" - ws "^1.0.1" - xml2js "0.4.4" - selfsigned@^1.9.1: - version "1.10.2" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.2.tgz#b4449580d99929b65b10a48389301a6592088758" + version "1.10.4" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" + integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw== dependencies: - node-forge "0.7.1" + node-forge "0.7.5" semver-dsl@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/semver-dsl/-/semver-dsl-1.0.1.tgz#d3678de5555e8a61f629eed025366ae5f27340a0" + integrity sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA= dependencies: semver "^5.3.0" semver-intersect@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" + integrity sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ== dependencies: semver "^5.0.0" -"semver@2 >=2.2.1 || 3.x || 4 || 5", semver@5.5.1, semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +semver@5.5.1: version "5.5.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - -"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - -semver@~5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" + integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== dependencies: debug "2.6.9" depd "~1.1.2" @@ -6240,12 +6117,14 @@ send@0.16.2: statuses "~1.4.0" serialize-javascript@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + version "1.5.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" + integrity sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ== serve-index@^1.7.2: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= dependencies: accepts "~1.3.4" batch "0.6.1" @@ -6258,6 +6137,7 @@ serve-index@^1.7.2: serve-static@1.13.2: version "1.13.2" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" @@ -6267,14 +6147,12 @@ serve-static@1.13.2: set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -6284,6 +6162,7 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -6293,25 +6172,17 @@ set-value@^2.0.0: setimmediate@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -sha.js@~2.4.4: - version "2.4.10" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.10.tgz#b1fde5cd7d11a5626638a07c604ab909cfa31f9b" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" @@ -6319,40 +6190,28 @@ sha.js@~2.4.4: shallow-clone@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" + integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== dependencies: is-extendable "^0.1.1" kind-of "^5.0.0" mixin-object "^2.0.1" -shasum@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" - dependencies: - json-stable-stringify "~0.0.0" - sha.js "~2.4.4" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - -shell-quote@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" - dependencies: - array-filter "~0.0.0" - array-map "~0.0.0" - array-reduce "~0.0.0" - jsonify "~0.0.0" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shelljs@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.2.tgz#345b7df7763f4c2340d584abb532c5f752ca9e35" + version "0.8.3" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" + integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== dependencies: glob "^7.0.0" interpret "^1.0.0" @@ -6361,35 +6220,22 @@ shelljs@^0.8.1: signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -slack-node@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/slack-node/-/slack-node-0.2.0.tgz#de4b8dddaa8b793f61dbd2938104fdabf37dfa30" - dependencies: - requestretry "^1.2.2" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= -slide@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - -smart-buffer@^1.0.13, smart-buffer@^1.0.4: - version "1.1.15" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" - -smtp-connection@2.12.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.12.0.tgz#d76ef9127cb23c2259edb1e8349c2e8d5e2d74c1" - dependencies: - httpntlm "1.6.1" - nodemailer-shared "1.1.0" +smart-buffer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" + integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -6398,12 +6244,14 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" debug "^2.2.0" @@ -6414,279 +6262,289 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - dependencies: - hoek "4.x.x" - socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= -socket.io-client@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.0.4.tgz#0918a552406dc5e540b380dcd97afc4a64332f8e" +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" component-bind "1.0.0" component-emitter "1.2.1" - debug "~2.6.4" - engine.io-client "~3.1.0" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" has-cors "1.1.0" indexof "0.0.1" object-component "0.0.3" parseqs "0.0.5" parseuri "0.0.5" - socket.io-parser "~3.1.1" + socket.io-parser "~3.2.0" to-array "0.1.4" -socket.io-parser@~3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.1.2.tgz#dbc2282151fc4faebbe40aeedc0772eba619f7f2" +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== dependencies: component-emitter "1.2.1" - debug "~2.6.4" - has-binary2 "~1.0.2" + debug "~3.1.0" isarray "2.0.1" -socket.io@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.0.4.tgz#c1a4590ceff87ecf13c72652f046f716b29e6014" +socket.io@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== dependencies: - debug "~2.6.6" - engine.io "~3.1.0" + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" socket.io-adapter "~1.1.0" - socket.io-client "2.0.4" - socket.io-parser "~3.1.1" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" -sockjs-client@1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.5.tgz#1bb7c0f7222c40f42adf14f4442cbd1269771a83" +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== dependencies: - debug "^2.6.6" - eventsource "0.1.6" - faye-websocket "~0.11.0" - inherits "^2.0.1" + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" json3 "^3.3.2" - url-parse "^1.1.8" + url-parse "^1.4.3" sockjs@0.3.19: version "0.3.19" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== dependencies: faye-websocket "^0.10.0" uuid "^3.0.1" -socks-proxy-agent@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz#86ebb07193258637870e13b7bd99f26c663df3d3" +socks-proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + integrity sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw== dependencies: - agent-base "2" - extend "3" - socks "~1.1.5" + agent-base "~4.2.0" + socks "~2.2.0" -socks@1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.9.tgz#628d7e4d04912435445ac0b6e459376cb3e6d691" +socks@~2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.2.tgz#f061219fc2d4d332afb4af93e865c84d3fa26e2b" + integrity sha512-g6wjBnnMOZpE0ym6e0uHSddz9p3a+WsBaaYQaBaSCJYvrC4IXykQR9MNGjLQf38e9iIIhp3b1/Zk8YZI3KGJ0Q== dependencies: - ip "^1.1.2" - smart-buffer "^1.0.4" - -socks@~1.1.5: - version "1.1.10" - resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.10.tgz#5b8b7fc7c8f341c53ed056e929b7bf4de8ba7b5a" - dependencies: - ip "^1.1.4" - smart-buffer "^1.0.13" + ip "^1.1.5" + smart-buffer "^4.0.1" source-list-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== source-list-map@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + integrity sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY= source-map-loader@0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-0.2.4.tgz#c18b0dc6e23bf66f6792437557c569a11e072271" + integrity sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ== dependencies: async "^2.5.0" loader-utils "^1.1.0" source-map-resolve@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== dependencies: - atob "^2.0.0" + atob "^2.1.1" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@0.5.9, source-map-support@^0.5.5, source-map-support@~0.5.6: +source-map-support@0.5.9, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.6: version "0.5.9" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.0: - version "0.5.4" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.4.tgz#54456efa89caa9270af7cd624cc2f123e51fbae8" - dependencies: - source-map "^0.6.0" - source-map-support@~0.4.0: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== dependencies: source-map "^0.5.6" source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= source-map@0.1.x: version "0.1.43" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= dependencies: amdefine ">=0.0.4" source-map@0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= source-map@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -source-map@^0.4.2, source-map@^0.4.4, source-map@~0.4.1: +source-map@^0.4.2, source-map@~0.4.1: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= dependencies: amdefine ">=0.0.4" -source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= dependencies: amdefine ">=0.0.4" sourcemap-codec@^1.4.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.3.tgz#0ba615b73ec35112f63c2f2d9e7c3f87282b0e33" + version "1.4.4" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" + integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg== spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" + integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== + +spdy-transport@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - -spdy-transport@^2.0.18: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.0.tgz#4bbb15aaffed0beefdd56ad61dbdc8ba3e2cb7a1" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== dependencies: - debug "^2.6.8" - detect-node "^2.0.3" + debug "^4.1.0" + detect-node "^2.0.4" hpack.js "^2.1.6" - obuf "^1.1.1" - readable-stream "^2.2.9" - safe-buffer "^5.0.1" - wbuf "^1.7.2" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" -spdy@^3.4.1: - version "3.4.7" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== dependencies: - debug "^2.6.8" - handle-thing "^1.2.5" + debug "^4.1.0" + handle-thing "^2.0.0" http-deceiver "^1.2.7" - safe-buffer "^5.0.1" select-hose "^2.0.0" - spdy-transport "^2.0.18" + spdy-transport "^3.0.0" -speed-measure-webpack-plugin@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.2.3.tgz#de170b5cefbfa1c039d95e639edd3ad50cfc7c48" +speed-measure-webpack-plugin@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.2.5.tgz#8179936eb8c5e891f7481bd5075a9ea9a0f74823" + integrity sha512-S/guYjC4Izn5wY2d0+M4zowED/F77Lxh9yjkTZ+XAr244pr9c1MYNcXcRe9lx2hmAj0GPbOrBXgOF2YIp/CZ8A== dependencies: chalk "^2.0.1" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" -sprintf-js@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb" + version "1.16.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de" + integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" ecc-jsbn "~0.1.1" + getpass "^0.1.1" jsbn "~0.1.0" + safer-buffer "^2.0.2" tweetnacl "~0.14.0" ssri@^5.2.4: version "5.3.0" resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== dependencies: safe-buffer "^5.1.1" -ssri@^6.0.0: +ssri@^6.0.0, ssri@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== dependencies: figgy-pudding "^3.5.1" static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" object-copy "^0.1.0" @@ -6694,82 +6552,68 @@ static-extend@^0.1.1: stats-webpack-plugin@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/stats-webpack-plugin/-/stats-webpack-plugin-0.7.0.tgz#ccffe9b745de8bbb155571e063f8263fc0e2bc06" + integrity sha512-NT0YGhwuQ0EOX+uPhhUcI6/+1Sq/pMzNuSCBVT4GbFl/ac6I/JZefBcjlECNfAb1t3GOx5dEj1Z7x0cAxeeVLQ== dependencies: lodash "^4.17.4" -"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": +"statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== stdout-stream@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== dependencies: readable-stream "^2.0.1" -stream-browserify@^2.0.0, stream-browserify@^2.0.1: +stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds= dependencies: inherits "~2.0.1" readable-stream "^2.0.2" -stream-combiner2@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" - dependencies: - duplexer2 "~0.1.0" - readable-stream "^2.0.2" - stream-each@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.2.tgz#8e8c463f91da8991778765873fe4d960d8f616bd" + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== dependencies: end-of-stream "^1.1.0" stream-shift "^1.0.0" -stream-http@^2.0.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.0.tgz#fd86546dac9b1c91aff8fc5d287b98fafb41bc10" - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.3" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - stream-http@^2.7.2: - version "2.8.1" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.1.tgz#d0441be1a457a73a733a8a7b53570bebd9ef66a4" + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" - readable-stream "^2.3.3" + readable-stream "^2.3.6" to-arraybuffer "^1.0.0" xtend "^4.0.0" stream-shift@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= -stream-splicer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.2" - -streamroller@^0.7.0: +streamroller@0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-0.7.0.tgz#a1d1b7cf83d39afb0d63049a5acbf93493bdf64b" + integrity sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ== dependencies: date-format "^1.2.0" debug "^3.1.0" @@ -6779,84 +6623,101 @@ streamroller@^0.7.0: string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string_decoder@^1.0.0, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== dependencies: safe-buffer "~5.1.0" string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= -string_decoder@~1.0.0, string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4, stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= dependencies: get-stdin "^4.0.1" -strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: +strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -style-loader@0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.0.tgz#8377fefab68416a2e05f1cabd8c3a3acfcce74f1" +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== dependencies: loader-utils "^1.1.0" - schema-utils "^0.4.5" + schema-utils "^1.0.0" stylus-loader@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-3.0.2.tgz#27a706420b05a38e038e7cacb153578d450513c6" + integrity sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA== dependencies: loader-utils "^1.0.2" lodash.clonedeep "^4.5.0" @@ -6865,6 +6726,7 @@ stylus-loader@3.0.2: stylus@0.54.5: version "0.54.5" resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.5.tgz#42b9560931ca7090ce8515a798ba9e6aa3d6dc79" + integrity sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk= dependencies: css-parse "1.7.x" debug "*" @@ -6873,88 +6735,68 @@ stylus@0.54.5: sax "0.5.x" source-map "0.1.x" -subarg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" - dependencies: - minimist "^1.1.0" - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^3.1.0, supports-color@^3.1.2: +supports-color@^3.1.0: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= dependencies: has-flag "^1.0.0" -supports-color@^5.1.0, supports-color@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" +supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -supports-color@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== dependencies: has-flag "^3.0.0" symbol-observable@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -syntax-error@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.3.0.tgz#1ed9266c4d40be75dc55bf9bb1cb77062bb96ca1" - dependencies: - acorn "^4.0.3" +tapable@^1.0.0, tapable@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.1.tgz#4d297923c5a72a42360de2ab52dadfaaec00018e" + integrity sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA== -tapable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" - -tapable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.0.tgz#0d076a172e3d9ba088fd2272b2668fb8d194b78c" - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.0.0, tar@^2.2.1: +tar@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= dependencies: block-stream "*" fstream "^1.0.2" inherits "2" -tar@^4: - version "4.4.6" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" +tar@^4, tar@^4.4.6: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== dependencies: - chownr "^1.0.1" + chownr "^1.1.1" fs-minipass "^1.2.5" - minipass "^2.3.3" - minizlib "^1.1.0" + minipass "^2.3.4" + minizlib "^1.1.1" mkdirp "^0.5.0" safe-buffer "^5.1.2" yallist "^3.0.2" -terser-webpack-plugin@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz#cf7c25a1eee25bf121f4a587bb9e004e3f80e528" +terser-webpack-plugin@1.2.1, terser-webpack-plugin@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz#7545da9ae5f4f9ae6a0ac961eb46f5e7c845cc26" + integrity sha512-GGSt+gbT0oKcMDmPx4SRSfJPE1XaN3kQRWG4ghxKQw9cn5G9x6aCKSsgYdvyM0na9NJ4Drv0RG6jbBByZ5CMjw== dependencies: cacache "^11.0.2" find-cache-dir "^2.0.0" @@ -6966,85 +6808,84 @@ terser-webpack-plugin@1.1.0: worker-farm "^1.5.2" terser@^3.8.1: - version "3.10.7" - resolved "https://registry.yarnpkg.com/terser/-/terser-3.10.7.tgz#8b48f25f959eeef7ae48407c1b21149052535973" + version "3.13.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.13.1.tgz#a02e8827fb9705fe7b609c31093d010b28cea8eb" + integrity sha512-ogyZye4DFqOtMzT92Y3Nxxw8OvXmL39HOALro4fc+EUYFFF9G/kk0znkvwMz6PPYgBtdKAodh3FPR70eugdaQA== dependencies: commander "~2.17.1" source-map "~0.6.1" source-map-support "~0.5.6" through2@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== dependencies: - readable-stream "^2.1.5" + readable-stream "~2.3.6" xtend "~4.0.1" "through@>=2.2.7 <3", through@X.X.X, through@^2.3.6: version "2.3.8" - resolved "http://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -thunkify@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= thunky@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.2.tgz#a862e018e3fb1ea2ec3fce5d55605cf57f247371" - -timers-browserify@^1.0.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" - dependencies: - process "~0.11.0" + version "1.0.3" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" + integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== timers-browserify@^2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== dependencies: setimmediate "^1.0.4" -timespan@2.3.x: - version "2.3.0" - resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" - -tmp@0.0.24: - version "0.0.24" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" - tmp@0.0.30: version "0.0.30" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + integrity sha1-ckGdSovn1s51FI/YsyTlk6cRwu0= dependencies: os-tmpdir "~1.0.1" tmp@0.0.33, tmp@0.0.x, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -7052,21 +6893,17 @@ to-regex-range@^2.1.0: to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@~2.3.0, tough-cookie@~2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - dependencies: - punycode "^1.4.1" - tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== dependencies: psl "^1.1.24" punycode "^1.4.1" @@ -7074,52 +6911,48 @@ tough-cookie@~2.4.3: tree-kill@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" + integrity sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg== trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= "true-case-path@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62" + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== dependencies: - glob "^6.0.4" + glob "^7.1.2" -ts-node@~4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-4.1.0.tgz#36d9529c7b90bb993306c408cd07f7743de20712" +ts-node@~7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== dependencies: arrify "^1.0.0" - chalk "^2.3.0" + buffer-from "^1.1.0" diff "^3.1.0" make-error "^1.1.1" minimist "^1.2.0" mkdirp "^0.5.1" - source-map-support "^0.5.0" - tsconfig "^7.0.0" - v8flags "^3.0.0" + source-map-support "^0.5.6" yn "^2.0.0" -tsconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" - dependencies: - "@types/strip-bom" "^3.0.0" - "@types/strip-json-comments" "0.0.30" - strip-bom "^3.0.0" - strip-json-comments "^2.0.0" +tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" - -tslint@~5.9.1: - version "5.9.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae" +tslint@~5.11.0: + version "5.11.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" + integrity sha1-mPMMAurjzecAYgHkwzywi0hYHu0= dependencies: babel-code-frame "^6.22.0" builtin-modules "^1.1.1" @@ -7132,231 +6965,189 @@ tslint@~5.9.1: resolve "^1.3.2" semver "^5.3.0" tslib "^1.8.0" - tsutils "^2.12.1" + tsutils "^2.27.2" -tsscmp@~1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97" - -tsutils@^2.12.1: - version "2.19.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.19.1.tgz#76d7ebdea9d7a7bf4a05f50ead3701b0168708d7" +tsutils@^2.27.2: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== dependencies: tslib "^1.8.1" -tty-browserify@0.0.0, tty-browserify@~0.0.0: +tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" -tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" -type-is@~1.6.15, type-is@~1.6.16: +type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== dependencies: media-typer "0.3.0" mime-types "~2.1.18" -typedarray@^0.0.6, typedarray@~0.0.5: +typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" +typescript@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" + integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== "typescript@file:../../node_modules/typescript": - version "3.1.1" + version "3.2.2" -uglify-es@^3.3.4: - version "3.3.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" +uglify-js@^3.1.4: + version "3.4.9" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== dependencies: - commander "~2.13.0" + commander "~2.17.1" source-map "~0.6.1" -uglify-js@^2.6: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - -uglifyjs-webpack-plugin@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz#5eec941b2e9b8538be0a20fc6eda25b14c7c1043" - dependencies: - cacache "^10.0.4" - find-cache-dir "^1.0.0" - schema-utils "^0.4.5" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - uglify-es "^3.3.4" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -ultron@1.0.x: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - -umd@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" - -underscore@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= dependencies: arr-union "^3.1.0" get-value "^2.0.6" is-extendable "^0.1.1" set-value "^0.4.3" -unique-filename@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" +unique-filename@^1.1.0, unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== dependencies: unique-slug "^2.0.0" unique-slug@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + version "2.0.1" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" + integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== dependencies: imurmurhash "^0.1.4" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" -upath@^1.0.0, upath@^1.0.5: +upath@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" - -uri-js@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-3.0.2.tgz#f90b858507f81dea4dcfbb3c4c3dbfa2b557faaa" - dependencies: - punycode "^2.1.0" + integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== dependencies: punycode "^2.1.0" urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-join@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" - -url-parse@^1.1.8, url-parse@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.3.tgz#bfaee455c889023219d757e045fa6a684ec36c15" +url-parse@^1.4.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== dependencies: querystringify "^2.0.0" requires-port "^1.0.0" -url@^0.11.0, url@~0.11.0: +url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= dependencies: punycode "1.3.2" querystring "0.2.0" use@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" - dependencies: - kind-of "^6.0.2" + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -useragent@^2.1.12: - version "2.2.1" - resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.2.1.tgz#cf593ef4f2d175875e8bb658ea92e18a4fd06d8e" +useragent@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" + integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== dependencies: - lru-cache "2.2.x" + lru-cache "4.1.x" tmp "0.0.x" -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util@0.10.3, util@^0.10.3, util@~0.10.1: +util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= dependencies: inherits "2.0.1" +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" - -uuid@^3.3.2: +uuid@^3.0.1, uuid@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - -uws@~0.14.4: - version "0.14.5" - resolved "https://registry.yarnpkg.com/uws/-/uws-0.14.5.tgz#67aaf33c46b2a587a5f6666d00f7691328f149dc" - -v8flags@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.0.1.tgz#dce8fc379c17d9f2c9e9ed78d89ce00052b1b76b" - dependencies: - homedir-polyfill "^1.0.1" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" @@ -7364,64 +7155,73 @@ validate-npm-package-license@^3.0.1: validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= dependencies: builtins "^1.0.3" vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" extsprintf "^1.2.0" -vm-browserify@0.0.4, vm-browserify@~0.0.1: +vm-browserify@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= dependencies: indexof "0.0.1" void-elements@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= watchpack@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed" + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== dependencies: chokidar "^2.0.2" graceful-fs "^4.1.2" neo-async "^2.5.0" -wbuf@^1.1.0, wbuf@^1.7.2: +wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== dependencies: minimalistic-assert "^1.0.0" -webdriver-js-extender@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515" +webdriver-js-extender@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" + integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ== dependencies: - "@types/selenium-webdriver" "^2.53.35" - selenium-webdriver "^2.53.2" + "@types/selenium-webdriver" "^3.0.0" + selenium-webdriver "^3.0.1" webdriver-manager@^12.0.6: - version "12.0.6" - resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.0.6.tgz#3df1a481977010b4cbf8c9d85c7a577828c0e70b" + version "12.1.0" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.0.tgz#f6601e52de5f0c97fc7024c889eeb2416f2f1d9d" + integrity sha512-oEc5fmkpz6Yh6udhwir5m0eN5mgRPq9P/NU5YWuT3Up5slt6Zz+znhLU7q4+8rwCZz/Qq3Fgpr/4oao7NPCm2A== dependencies: - adm-zip "^0.4.7" + adm-zip "^0.4.9" chalk "^1.1.1" del "^2.2.0" glob "^7.0.3" ini "^1.3.4" minimist "^1.2.0" q "^1.4.1" - request "^2.78.0" + request "^2.87.0" rimraf "^2.5.2" semver "^5.3.0" xml2js "^0.4.17" @@ -7429,36 +7229,25 @@ webdriver-manager@^12.0.6: webpack-core@^0.6.8: version "0.6.9" resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" + integrity sha1-/FcViMhVjad76e+23r3Fo7FyvcI= dependencies: source-list-map "~0.1.7" source-map "~0.4.1" -webpack-dev-middleware@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.2.0.tgz#a20ceef194873710052da678f3c6ee0aeed92552" +webpack-dev-middleware@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" + integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== dependencies: - loud-rejection "^1.6.0" - memory-fs "~0.4.1" - mime "^2.3.1" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - url-join "^4.0.0" - webpack-log "^2.0.0" - -webpack-dev-middleware@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.3.0.tgz#8104daf4d4f65defe06ee2eaaeea612a7c541462" - dependencies: - loud-rejection "^1.6.0" memory-fs "~0.4.1" mime "^2.3.1" range-parser "^1.0.3" - url-join "^4.0.0" webpack-log "^2.0.0" -webpack-dev-server@3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.8.tgz#eb7a95945d1108170f902604fb3b939533d9daeb" +webpack-dev-server@3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" + integrity sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -7479,19 +7268,22 @@ webpack-dev-server@3.1.8: portfinder "^1.0.9" schema-utils "^1.0.0" selfsigned "^1.9.1" + semver "^5.6.0" serve-index "^1.7.2" sockjs "0.3.19" - sockjs-client "1.1.5" - spdy "^3.4.1" + sockjs-client "1.3.0" + spdy "^4.0.0" strip-ansi "^3.0.0" supports-color "^5.1.0" - webpack-dev-middleware "3.2.0" + url "^0.11.0" + webpack-dev-middleware "3.4.0" webpack-log "^2.0.0" yargs "12.0.2" webpack-log@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== dependencies: ansi-colors "^3.0.0" uuid "^3.3.2" @@ -7499,26 +7291,22 @@ webpack-log@^2.0.0: webpack-merge@4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.4.tgz#0fde38eabf2d5fd85251c24a5a8c48f8a3f4eb7b" + integrity sha512-TmSe1HZKeOPey3oy1Ov2iS3guIZjWvMT2BBJDzzT5jScHTjVC3mpjJofgueEzaEd6ibhxRDD6MIblDr8tzh8iQ== dependencies: lodash "^4.17.5" webpack-sources@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.2.0.tgz#18181e0d013fce096faf6f8e6d41eeffffdceac2" + integrity sha512-9BZwxR85dNsjWz3blyxdOhTgtnQvv3OEs5xofI0wPYTwu5kaWxS08UuD1oI7WLBLpRO+ylf0ofnXLXWmGb2WMw== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - -webpack-sources@^1.2.0: +webpack-sources@1.3.0, webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" @@ -7526,17 +7314,19 @@ webpack-sources@^1.2.0: webpack-subresource-integrity@1.1.0-rc.6: version "1.1.0-rc.6" resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz#37f6f1264e1eb378e41465a98da80fad76ab8886" + integrity sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w== dependencies: webpack-core "^0.6.8" -webpack@4.19.1: - version "4.19.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.19.1.tgz#096674bc3b573f8756c762754366e5b333d6576f" +webpack@4.28.4: + version "4.28.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.28.4.tgz#1ddae6c89887d7efb752adf0c3cd32b9b07eacd0" + integrity sha512-NxjD61WsK/a3JIdwWjtIpimmvE6UrRi3yG54/74Hk9rwNj5FPkA4DJCf1z4ByDWLkvZhTZE+P3C/eh6UD5lDcw== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/wasm-edit" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/wasm-edit" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" acorn "^5.6.2" acorn-dynamic-import "^3.0.0" ajv "^6.1.0" @@ -7554,13 +7344,14 @@ webpack@4.19.1: node-libs-browser "^2.0.0" schema-utils "^0.4.4" tapable "^1.1.0" - uglifyjs-webpack-plugin "^1.2.4" + terser-webpack-plugin "^1.1.0" watchpack "^1.5.0" - webpack-sources "^1.2.0" + webpack-sources "^1.3.0" websocket-driver@>=0.5.1: version "0.7.0" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs= dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" @@ -7568,60 +7359,58 @@ websocket-driver@>=0.5.1: websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" - -when@^3.7.7: - version "3.7.8" - resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== when@~3.6.x: version "3.6.4" resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" + integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404= which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@1, which@^1.1.1, which@^1.2.1, which@^1.2.9: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" +which@1, which@^1.1.1, which@^1.2.1, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: - string-width "^1.0.2" - -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + string-width "^1.0.2 || 2" wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= worker-farm@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ== dependencies: errno "~0.1.7" wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -7629,93 +7418,90 @@ wrap-ansi@^2.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -ws@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" - dependencies: - options ">=0.0.5" - ultron "1.0.x" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== dependencies: async-limiter "~1.0.0" safe-buffer "~5.1.0" ultron "~1.1.0" -xml2js@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d" - dependencies: - sax "0.6.x" - xmlbuilder ">=1.0.0" - xml2js@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== dependencies: sax ">=0.6.0" xmlbuilder "~9.0.1" -xmlbuilder@>=1.0.0, xmlbuilder@~9.0.1: - version "9.0.4" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" - -xregexp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= xregexp@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" + integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== xtend@^4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yallist@^3.0.0, yallist@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== yargs-parser@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== dependencies: camelcase "^4.1.0" yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= dependencies: camelcase "^3.0.0" yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= dependencies: camelcase "^4.1.0" yargs@12.0.2: version "12.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" + integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ== dependencies: cliui "^4.0.0" decamelize "^2.0.0" @@ -7733,6 +7519,7 @@ yargs@12.0.2: yargs@9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" + integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= dependencies: camelcase "^4.1.0" cliui "^3.2.0" @@ -7751,6 +7538,7 @@ yargs@9.0.1: yargs@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= dependencies: camelcase "^3.0.0" cliui "^3.2.0" @@ -7766,22 +7554,15 @@ yargs@^7.0.0: y18n "^3.2.1" yargs-parser "^5.0.0" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= yn@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo= "zone.js@file:../../node_modules/zone.js": version "0.8.26" diff --git a/integration/cli-hello-world-ivy-minimal/.editorconfig b/integration/cli-hello-world-ivy-minimal/.editorconfig new file mode 100644 index 0000000000..e89330a618 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/integration/cli-hello-world-ivy-minimal/README.md b/integration/cli-hello-world-ivy-minimal/README.md new file mode 100644 index 0000000000..b89f9e7dae --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/README.md @@ -0,0 +1,27 @@ +# CliHelloWorldIvyMinimal + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.0-rc.0. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/integration/cli-hello-world-ivy-minimal/angular.json b/integration/cli-hello-world-ivy-minimal/angular.json new file mode 100644 index 0000000000..af9ad83542 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/angular.json @@ -0,0 +1,151 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "cli": { + "packageManager": "yarn" + }, + "newProjectRoot": "projects", + "projects": { + "cli-hello-world-ivy-minimal": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "app", + "schematics": {}, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "cli-hello-world-ivy-minimal:build" + }, + "configurations": { + "production": { + "browserTarget": "cli-hello-world-ivy-minimal:build:production" + }, + "ci": { + "progress": false + }, + "ci-production": { + "browserTarget": "cli-hello-world-ivy-minimal:build:production", + "progress": false + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "cli-hello-world-ivy-minimal:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.css" + ], + "scripts": [], + "assets": [ + "src/favicon.ico", + "src/assets" + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "cli-hello-world-ivy-minimal-e2e": { + "root": "e2e/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "cli-hello-world-ivy-minimal:serve" + }, + "configurations": { + "production": { + "devServerTarget": "cli-hello-world-ivy-minimal:serve:production" + }, + "ci": { + "devServerTarget": "cli-hello-world-ivy-minimal:serve:ci" + }, + "ci-production": { + "devServerTarget": "cli-hello-world-ivy-minimal:serve:ci-production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "defaultProject": "cli-hello-world-ivy-minimal" +} diff --git a/integration/cli-hello-world-ivy-minimal/debug-test.sh b/integration/cli-hello-world-ivy-minimal/debug-test.sh new file mode 100644 index 0000000000..15b6252cb9 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/debug-test.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +##### Test Debug Utility ##### +############################## + +# Use this script to run the ngcc integration test locally +# in isolation from the other integration tests. +# This is useful when debugging the ngcc code-base. + +set -u -e -o pipefail + +cd "$(dirname "$0")" + +$(pwd)/../../scripts/build-packages-dist.sh + +# Workaround https://github.com/yarnpkg/yarn/issues/2165 +# Yarn will cache file://dist URIs and not update Angular code +readonly cache=../.yarn_local_cache +function rm_cache { + rm -rf $cache +} +rm_cache +mkdir $cache +trap rm_cache EXIT + +rm -rf dist +rm -rf node_modules +yarn install --cache-folder $cache +yarn test \ No newline at end of file diff --git a/integration/cli-hello-world-ivy-minimal/e2e/protractor.conf.js b/integration/cli-hello-world-ivy-minimal/e2e/protractor.conf.js new file mode 100644 index 0000000000..71baa5048b --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/e2e/protractor.conf.js @@ -0,0 +1,32 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + browserName: 'chrome', + chromeOptions: { + binary: process.env.CHROME_BIN, + args: ['--no-sandbox'] + } + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.e2e.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; diff --git a/integration/cli-hello-world-ivy-minimal/e2e/src/app.e2e-spec.ts b/integration/cli-hello-world-ivy-minimal/e2e/src/app.e2e-spec.ts new file mode 100644 index 0000000000..933df0f309 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/e2e/src/app.e2e-spec.ts @@ -0,0 +1,18 @@ +import { browser } from 'protractor'; +import { AppPage } from './app.po'; + +describe('cli-hello-world-ivy-minimal App', () => { + // Ivy renderComponent apps fail on protractor when waiting for Angular. + browser.waitForAngularEnabled(false); + + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getParagraphText()).toEqual('Welcome to cli-hello-world-ivy-minimal!'); + }); +}); diff --git a/integration/cli-hello-world-ivy-minimal/e2e/src/app.po.ts b/integration/cli-hello-world-ivy-minimal/e2e/src/app.po.ts new file mode 100644 index 0000000000..1d9f7e4e15 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get('/'); + } + + getParagraphText() { + return element(by.css('app-root')).getText(); + } +} diff --git a/integration/cli-hello-world-ivy-minimal/e2e/tsconfig.e2e.json b/integration/cli-hello-world-ivy-minimal/e2e/tsconfig.e2e.json new file mode 100644 index 0000000000..a6dd622028 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/e2e/tsconfig.e2e.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} \ No newline at end of file diff --git a/integration/cli-hello-world-ivy-minimal/package.json b/integration/cli-hello-world-ivy-minimal/package.json new file mode 100644 index 0000000000..4bf7345413 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/package.json @@ -0,0 +1,52 @@ +{ + "name": "cli-hello-world-ivy-minimal", + "version": "0.0.0", + "license": "MIT", + "scripts": { + "build": "ng build --prod --progress=false", + "e2e": "ng e2e --webdriver-update=false", + "lint": "ng lint", + "ng": "ng", + "postinstall": "webdriver-manager update --gecko=false --standalone=false $CI_CHROMEDRIVER_VERSION_ARG && yarn ivy-ngcc", + "start": "ng serve", + "pretest": "ng version", + "test": "ng test --progress=false --watch=false && yarn e2e --configuration=ci && yarn e2e --configuration=ci-production" + }, + "private": true, + "dependencies": { + "@angular/animations": "file:../../dist/packages-dist/animations", + "@angular/common": "file:../../dist/packages-dist/common", + "@angular/compiler": "file:../../dist/packages-dist/compiler", + "@angular/core": "file:../../dist/packages-dist/core", + "@angular/forms": "file:../../dist/packages-dist/forms", + "@angular/http": "file:../../dist/packages-dist/http", + "@angular/platform-browser": "file:../../dist/packages-dist/platform-browser", + "@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic", + "@angular/router": "file:../../dist/packages-dist/router", + "core-js": "file:../../node_modules/core-js", + "rxjs": "file:../../node_modules/rxjs", + "tslib": "^1.9.3", + "zone.js": "file:../../node_modules/zone.js" + }, + "devDependencies": { + "@angular-devkit/build-angular": "0.13.0-rc.0", + "@angular/cli": "file:../../node_modules/@angular/cli", + "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", + "@angular/language-service": "file:../../dist/packages-dist/language-service", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "@types/node": "~8.9.4", + "codelyzer": "~4.5.0", + "jasmine-core": "~2.99.1", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~3.1.1", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~1.1.2", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "file:../../node_modules/protractor", + "ts-node": "~7.0.0", + "tslint": "~5.11.0", + "typescript": "file:../../node_modules/typescript" + } +} diff --git a/integration/cli-hello-world-ivy-minimal/src/app/app.component.spec.ts b/integration/cli-hello-world-ivy-minimal/src/app/app.component.spec.ts new file mode 100644 index 0000000000..605dc20db3 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/app/app.component.spec.ts @@ -0,0 +1,25 @@ +import { TestBed, async } from '@angular/core/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); + + it('should render title in a h1 tag', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.textContent).toContain('Welcome to cli-hello-world-ivy-minimal!'); + }); +}); diff --git a/integration/cli-hello-world-ivy-minimal/src/app/app.component.ts b/integration/cli-hello-world-ivy-minimal/src/app/app.component.ts new file mode 100644 index 0000000000..23e081828f --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: 'Welcome to cli-hello-world-ivy-minimal!', +}) +export class AppComponent { } diff --git a/integration/cli-hello-world-ivy-minimal/src/assets/.gitkeep b/integration/cli-hello-world-ivy-minimal/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integration/cli-hello-world-ivy-minimal/src/browserslist b/integration/cli-hello-world-ivy-minimal/src/browserslist new file mode 100644 index 0000000000..37371cb04b --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/integration/cli-hello-world-ivy-minimal/src/environments/environment.prod.ts b/integration/cli-hello-world-ivy-minimal/src/environments/environment.prod.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integration/cli-hello-world-ivy-minimal/src/environments/environment.ts b/integration/cli-hello-world-ivy-minimal/src/environments/environment.ts new file mode 100644 index 0000000000..36563d6692 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/environments/environment.ts @@ -0,0 +1 @@ +import '@angular/compiler'; diff --git a/modules/benchmarks/favicon.ico b/integration/cli-hello-world-ivy-minimal/src/favicon.ico similarity index 100% rename from modules/benchmarks/favicon.ico rename to integration/cli-hello-world-ivy-minimal/src/favicon.ico diff --git a/integration/cli-hello-world-ivy-minimal/src/index.html b/integration/cli-hello-world-ivy-minimal/src/index.html new file mode 100644 index 0000000000..2c2998c7ce --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/index.html @@ -0,0 +1,14 @@ + + + + + CliHelloWorldIvyMinimal + + + + + + + + + diff --git a/integration/cli-hello-world-ivy-minimal/src/karma.conf.js b/integration/cli-hello-world-ivy-minimal/src/karma.conf.js new file mode 100644 index 0000000000..375eb671d0 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/karma.conf.js @@ -0,0 +1,37 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, 'coverage'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['CustomChrome'], + singleRun: false, + customLaunchers: { + CustomChrome: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + } + }); +}; diff --git a/integration/cli-hello-world-ivy-minimal/src/main.ts b/integration/cli-hello-world-ivy-minimal/src/main.ts new file mode 100644 index 0000000000..2245a3d9fb --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/main.ts @@ -0,0 +1,7 @@ +// This is a minimal ivy app that is meant to mimic the bazel equivalent +// in `packages/core/test/bundling/hello_world`, and should be kept similar. + +import { ɵrenderComponent as renderComponent } from '@angular/core'; +import { AppComponent } from './app/app.component'; +import './environments/environment'; +renderComponent(AppComponent); diff --git a/integration/cli-hello-world-ivy-minimal/src/polyfills.ts b/integration/cli-hello-world-ivy-minimal/src/polyfills.ts new file mode 100644 index 0000000000..a6d34ea67a --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/polyfills.ts @@ -0,0 +1,85 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10, IE11, and Chrome <55 requires all of the following polyfills. + * This also includes Android Emulators with older versions of Chrome and Google Search/Googlebot + */ + +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/integration/cli-hello-world-ivy-minimal/src/styles.css b/integration/cli-hello-world-ivy-minimal/src/styles.css new file mode 100644 index 0000000000..90d4ee0072 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/integration/cli-hello-world-ivy-minimal/src/test.ts b/integration/cli-hello-world-ivy-minimal/src/test.ts new file mode 100644 index 0000000000..16317897b1 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/test.ts @@ -0,0 +1,20 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/integration/cli-hello-world-ivy-minimal/src/tsconfig.app.json b/integration/cli-hello-world-ivy-minimal/src/tsconfig.app.json new file mode 100644 index 0000000000..a5831fdc4a --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ], + "angularCompilerOptions": { + "enableIvy": "ngtsc" + } +} diff --git a/integration/cli-hello-world-ivy-minimal/src/tsconfig.spec.json b/integration/cli-hello-world-ivy-minimal/src/tsconfig.spec.json new file mode 100644 index 0000000000..de7733630e --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts", + "polyfills.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/integration/cli-hello-world-ivy-minimal/src/tslint.json b/integration/cli-hello-world-ivy-minimal/src/tslint.json new file mode 100644 index 0000000000..52e2c1a5a7 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/src/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/integration/cli-hello-world-ivy-minimal/tsconfig.json b/integration/cli-hello-world-ivy-minimal/tsconfig.json new file mode 100644 index 0000000000..b271fd9f3d --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "module": "es2015", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + } +} diff --git a/integration/cli-hello-world-ivy-minimal/tslint.json b/integration/cli-hello-world-ivy-minimal/tslint.json new file mode 100644 index 0000000000..c740a7b2a5 --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/tslint.json @@ -0,0 +1,131 @@ +{ + "rulesDirectory": [ + "codelyzer" + ], + "rules": { + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "deprecation": { + "severity": "warn" + }, + "eofline": true, + "forin": true, + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "interface-over-type-literal": true, + "label-position": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-misused-new": true, + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "no-output-on-prefix": true, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true + } +} diff --git a/integration/cli-hello-world-ivy-minimal/yarn.lock b/integration/cli-hello-world-ivy-minimal/yarn.lock new file mode 100644 index 0000000000..c19466b11a --- /dev/null +++ b/integration/cli-hello-world-ivy-minimal/yarn.lock @@ -0,0 +1,7568 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@angular-devkit/architect@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.1.tgz#397768d1ccd0cef76db96d6b39db8aebad68c031" + integrity sha512-1ozBP0ZAApkSfuPpZ7b9vShU8smNxb98jW+65S12cPOxv1bVVxCj5sTmC3sSfXapgq/pMzblbaVSKOG7Ajz0vQ== + dependencies: + "@angular-devkit/core" "7.2.1" + rxjs "6.3.3" + +"@angular-devkit/architect@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.2.tgz#1bfa43881c8927b8e12ffd4a2a3a645d6356e748" + integrity sha512-32Eim3PM/CJKGcCF1FJQ91ohuF2vBGMd4t1DILaoOMXHWmPLI9N4ILzWHfqFLRvb8QFgLn4VNG7CI9K7GcSBlQ== + dependencies: + "@angular-devkit/core" "7.2.2" + rxjs "6.3.3" + +"@angular-devkit/build-angular@~0.12.1": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.12.2.tgz#4776f535633227848c4bda34b1e8f89574c33746" + integrity sha512-4PDykCNDjjFo6Ximhq2efiufoUP6pj8KvhB8UI03mLbn/Os1W0y1lmiPJn+NjeBLwFWH9DqW9Vxk/pYek7MtEA== + dependencies: + "@angular-devkit/architect" "0.12.2" + "@angular-devkit/build-optimizer" "0.12.2" + "@angular-devkit/build-webpack" "0.12.2" + "@angular-devkit/core" "7.2.2" + "@ngtools/webpack" "7.2.2" + ajv "6.6.2" + autoprefixer "9.4.3" + circular-dependency-plugin "5.0.2" + clean-css "4.2.1" + copy-webpack-plugin "4.6.0" + file-loader "2.0.0" + glob "7.1.3" + istanbul "0.4.5" + istanbul-instrumenter-loader "3.0.1" + karma-source-map-support "1.3.0" + less "3.9.0" + less-loader "4.1.0" + license-webpack-plugin "2.0.4" + loader-utils "1.1.0" + mini-css-extract-plugin "0.4.4" + minimatch "3.0.4" + opn "5.3.0" + parse5 "4.0.0" + portfinder "1.0.17" + postcss "7.0.11" + postcss-import "12.0.0" + postcss-loader "3.0.0" + raw-loader "0.5.1" + rxjs "6.3.3" + sass-loader "7.1.0" + semver "5.5.1" + source-map-loader "0.2.4" + source-map-support "0.5.9" + speed-measure-webpack-plugin "1.2.5" + stats-webpack-plugin "0.7.0" + style-loader "0.23.1" + stylus "0.54.5" + stylus-loader "3.0.2" + terser-webpack-plugin "1.2.1" + tree-kill "1.2.0" + webpack "4.28.4" + webpack-dev-middleware "3.4.0" + webpack-dev-server "3.1.14" + webpack-merge "4.1.4" + webpack-sources "1.3.0" + webpack-subresource-integrity "1.1.0-rc.6" + optionalDependencies: + node-sass "4.10.0" + +"@angular-devkit/build-optimizer@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.12.2.tgz#c35f4a67a2304a4deeb8e5d2e6c1edde0429c309" + integrity sha512-5SARSE18X5/churU0Qc0gOfDt5EwuwKsJmIA7hHBzi44iotQm5c8ea0q0acua4/U4K+jOsF6A4Faa08Vr2624A== + dependencies: + loader-utils "1.1.0" + source-map "0.5.6" + typescript "3.2.2" + webpack-sources "1.2.0" + +"@angular-devkit/build-webpack@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.12.2.tgz#00f1a3a5ab3f4bc8e35d1826f8b476dc0016a1e7" + integrity sha512-Uv3f8XJc/5UTj2T7XjxFYDhuybFIIitLGxBpp/hEIc7eXI4MsJKB6CoDJy+2BQch7c/QjKH7W3dmTxzuSJ2j3g== + dependencies: + "@angular-devkit/architect" "0.12.2" + "@angular-devkit/core" "7.2.2" + rxjs "6.3.3" + +"@angular-devkit/core@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.1.tgz#8c6df59eab77bcc98a348c8cdf9eb217c8b751a5" + integrity sha512-zOozPswSM1cTkltw5LeSPoZ/fJ2d3vN304IVgKgrM5/Fs54bd7nTaBcAK+HvjKS+5KmykYrXW47Q4CdFJikluQ== + dependencies: + ajv "6.6.2" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/core@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.2.tgz#f0daf3e24f0ce8105341118f4505c1db4e284ab0" + integrity sha512-gDF8iXiPN870WuBMl7bCQ5+Qz5SjGL/qMcvP4hli5hkn+kMAhgG38ligUK1bbhPQUJ+Z/nSOEmyv8gLHO09SZg== + dependencies: + ajv "6.6.2" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.2.1.tgz#9c1c784f4a81a3a840fa4a1435948c6203be6062" + integrity sha512-jEhwkeDn8exgJBfUwMc6rdtDkxHJkUmKPTn4M436bkMMMa9KFPFbPpzp9weKpB3SbRjM3Mu90JprO4C7qDtCcg== + dependencies: + "@angular-devkit/core" "7.2.1" + rxjs "6.3.3" + +"@angular/animations@file:../../dist/packages-dist/animations": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/cli@file:../../node_modules/@angular/cli": + version "7.2.1" + dependencies: + "@angular-devkit/architect" "0.12.1" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + "@schematics/angular" "7.2.1" + "@schematics/update" "0.12.1" + inquirer "6.2.1" + opn "5.3.0" + semver "5.5.1" + symbol-observable "1.2.0" + +"@angular/common@file:../../dist/packages-dist/common": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": + version "8.0.0-beta.0" + dependencies: + canonical-path "1.0.0" + chokidar "^1.4.2" + convert-source-map "^1.5.1" + dependency-graph "^0.7.2" + magic-string "^0.25.0" + minimist "^1.2.0" + reflect-metadata "^0.1.2" + shelljs "^0.8.1" + source-map "^0.6.1" + tslib "^1.9.0" + yargs "9.0.1" + +"@angular/compiler@file:../../dist/packages-dist/compiler": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/core@file:../../dist/packages-dist/core": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/forms@file:../../dist/packages-dist/forms": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/http@file:../../dist/packages-dist/http": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/language-service@file:../../dist/packages-dist/language-service": + version "8.0.0-beta.0" + +"@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/platform-browser@file:../../dist/packages-dist/platform-browser": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@angular/router@file:../../dist/packages-dist/router": + version "8.0.0-beta.0" + dependencies: + tslib "^1.9.0" + +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/generator@^7.0.0", "@babel/generator@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.2.tgz#18c816c70962640eab42fe8cae5f3947a5c65ccc" + integrity sha512-I4o675J/iS8k+P38dvJ3IBGqObLXyQLTxtrR4u9cSUJOURvafeEWb/pFMOTwtNrmq73mJzyF6ueTbO1BtN0Zeg== + dependencies: + "@babel/types" "^7.2.2" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/highlight@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" + integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.2.3.tgz#32f5df65744b70888d17872ec106b02434ba1489" + integrity sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA== + +"@babel/template@^7.0.0", "@babel/template@^7.1.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" + integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.2.2" + "@babel/types" "^7.2.2" + +"@babel/traverse@^7.0.0": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" + integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.2.2" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.2.3" + "@babel/types" "^7.2.2" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.10" + +"@babel/types@^7.0.0", "@babel/types@^7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.2.tgz#44e10fc24e33af524488b716cdaee5360ea8ed1e" + integrity sha512-fKCuD6UFUMkR541eDWL+2ih/xFZBXPOg/7EQFeTluMDebfqR4jrpaCjLhkWlQS4hT6nRa2PMEgXKbRB5/H2fpg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + +"@ngtools/webpack@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.2.2.tgz#361d877f01feae800a58901b066b46539e1fe0e3" + integrity sha512-xjvQ8tlyyReE69q+whAubwX4fayPoy4NHSIDa429qdcUypkvhSScAtou003oVAKG519rznykDrUHAWtvFMVf4Q== + dependencies: + "@angular-devkit/core" "7.2.2" + enhanced-resolve "4.1.0" + rxjs "6.3.3" + tree-kill "1.2.0" + webpack-sources "1.2.0" + +"@schematics/angular@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.2.1.tgz#9eeab1354ec8d970121cc067e9636098ab84e152" + integrity sha512-UdqU8udVr693BZ6uaZ7+el/VFlTjrmp56OS+6YaziyAko84e1Q1Fcx+fwdHugy4V3YmQhTVsyOPSEsphnwSwOA== + dependencies: + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + typescript "3.2.2" + +"@schematics/update@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.12.1.tgz#44d853321ae8a56c43a579c0639d26d625001037" + integrity sha512-P92tDxy0AA1NPhaThiJ7fIFxIC4jzlGK7sJlpbnRREBImsI/O9gmGaV8Kjy+75vaEjqpWaU2oj1hnWqkmxSK1A== + dependencies: + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + pacote "9.1.1" + rxjs "6.3.3" + semver "5.5.1" + semver-intersect "1.4.0" + +"@types/jasmine@*": + version "3.3.4" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.3.4.tgz#492cc70364f6dee047887b4fa2135bedd41fb143" + integrity sha512-543S+ZCJfN4jKWzRkptbJqTY2vc4h7+lPVqU2hXb1XFofDcUxNANAimdZPYaH6/yhezVAsNeujoZjAFU06bfmA== + +"@types/jasmine@~2.8.8": + version "2.8.14" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.14.tgz#42a87032418b7d70f427d1df16a9921fca28d8c7" + integrity sha512-oHgE8xWsIoJfP0qU/yi5xrzhkHvYJhD7m40pSC3pw4+BUKWFwqTz+BUosuuODh8KyRpLp1Fdaibr3If4cgNsCg== + +"@types/jasminewd2@~2.0.3": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.6.tgz#2f57a8d9875a6c9ef328a14bd070ba14a055ac39" + integrity sha512-2ZOKrxb8bKRmP/po5ObYnRDgFE4i+lQiEB27bAMmtMWLgJSqlIDqlLx6S0IRorpOmOPRQ6O80NujTmQAtBkeNw== + dependencies: + "@types/jasmine" "*" + +"@types/node@*": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== + +"@types/node@~8.9.4": + version "8.9.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.9.5.tgz#162b864bc70be077e6db212b322754917929e976" + integrity sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ== + +"@types/q@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" + integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= + +"@types/selenium-webdriver@^3.0.0": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.14.tgz#0b20a2370e6b1b8322c9c3dfcaa409e6c7c0c0a9" + integrity sha512-4GbNCDs98uHCT/OMv40qQC/OpoPbYn9XdXeTiFwHBBFO6eJhYEPUu2zDKirXSbHlvDV8oZ9l8EQ+HrEx/YS9DQ== + +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== + +"@types/webpack-sources@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" + integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== + dependencies: + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" + +"@webassemblyjs/ast@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" + integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA== + dependencies: + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + +"@webassemblyjs/floating-point-hex-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" + integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg== + +"@webassemblyjs/helper-api-error@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" + integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg== + +"@webassemblyjs/helper-buffer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" + integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w== + +"@webassemblyjs/helper-code-frame@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" + integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw== + dependencies: + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/helper-fsm@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" + integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A== + +"@webassemblyjs/helper-module-context@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" + integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg== + +"@webassemblyjs/helper-wasm-bytecode@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" + integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ== + +"@webassemblyjs/helper-wasm-section@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" + integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + +"@webassemblyjs/ieee754@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" + integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" + integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw== + dependencies: + "@xtuc/long" "4.2.1" + +"@webassemblyjs/utf8@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" + integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA== + +"@webassemblyjs/wasm-edit@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" + integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/helper-wasm-section" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-opt" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/wasm-gen@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" + integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wasm-opt@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" + integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + +"@webassemblyjs/wasm-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" + integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wast-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" + integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/floating-point-hex-parser" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-code-frame" "1.7.11" + "@webassemblyjs/helper-fsm" "1.7.11" + "@xtuc/long" "4.2.1" + +"@webassemblyjs/wast-printer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" + integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + "@xtuc/long" "4.2.1" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" + integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== + +"@yarnpkg/lockfile@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +JSONStream@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= + +accepts@~1.3.4, accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg== + dependencies: + acorn "^5.0.0" + +acorn@^5.0.0, acorn@^5.6.2: + version "5.7.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + +adm-zip@^0.4.9: + version "0.4.13" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a" + integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw== + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= + +ajv@6.6.2, ajv@^6.1.0, ajv@^6.5.5: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^5.0.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-colors@^3.0.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +app-root-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.1.0.tgz#98bf6599327ecea199309866e8140368fd2e646a" + integrity sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo= + +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + integrity sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw== + dependencies: + default-require-extensions "^2.0.0" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-slice@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" + integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + +arrify@^1.0.0, arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + +async@1.x, async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= + +async@^2.5.0, async@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== + dependencies: + lodash "^4.17.10" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@9.4.3: + version "9.4.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.3.tgz#c97384a8fd80477b78049163a91bbc725d9c41d9" + integrity sha512-/XSnzDepRkAU//xLcXA/lUWxpsBuw0WiriAHOqnxkuCtzLhaz+fL4it4gp20BQ8n5SyLzK/FOc7A0+u/rti2FQ== + dependencies: + browserslist "^4.3.6" + caniuse-lite "^1.0.30000921" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.6" + postcss-value-parser "^3.3.1" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-generator@^6.18.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= + dependencies: + babel-runtime "^6.22.0" + +babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.16.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.18.0, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.18.0, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== + +binary-extensions@^1.0.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" + integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +blocking-proxy@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" + integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA== + dependencies: + minimist "^1.2.0" + +bluebird@^3.3.0, bluebird@^3.5.1, bluebird@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.18.3, body-parser@^1.16.1: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^0.1.2: + version "0.1.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-0.1.5.tgz#c085711085291d8b75fdd74eab0f8597280711e6" + integrity sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY= + dependencies: + expand-range "^0.1.0" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.3.6: + version "4.3.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.3.6.tgz#0f9d9081afc66b36f477c6bdf3813f784f42396a" + integrity sha512-kMGKs4BTzRWviZ8yru18xBpx+CyHG9eqgRbj9XbE3IMgtczf4aiA0Y1YCpVdvUieKGZ03kolSPXqTcscBCb9qw== + dependencies: + caniuse-lite "^1.0.30000921" + electron-to-chromium "^1.3.92" + node-releases "^1.1.1" + +browserstack@^1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.2.tgz#17d8bb76127a1cc0ea416424df80d218f803673f" + integrity sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg== + dependencies: + https-proxy-agent "^2.2.1" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0, buffer-from@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0, builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cacache@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460" + integrity sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA== + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.1" + mississippi "^2.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^5.2.4" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cacache@^11.0.1, cacache@^11.0.2, cacache@^11.2.0: + version "11.3.1" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.1.tgz#d09d25f6c4aca7a6d305d141ae332613aa1d515f" + integrity sha512-2PEw4cRRDu+iQvBTTuttQifacYjLPhET+SYO/gEFMy8uhi+jlJREDAjSF5FWSdV/Aw5h18caHA7vMTw2c+wDzA== + dependencies: + bluebird "^3.5.1" + chownr "^1.0.1" + figgy-pudding "^3.1.0" + glob "^7.1.2" + graceful-fs "^4.1.11" + lru-cache "^4.1.3" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.0" + unique-filename "^1.1.0" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +caniuse-lite@^1.0.30000921: + version "1.0.30000923" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000923.tgz#148f9bda508024b5ce957b463ae2e8302b451bb2" + integrity sha512-j5ur7eeluOFjjPUkydtXP4KFAsmH3XaQNch5tvWSO+dLHYt5PE+VgJZLWtbVOodfWij6m6zas28T4gB/cLYq1w== + +canonical-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" + integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@2.0.4, chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chokidar@^1.4.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chownr@^1.0.1, chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +chrome-trace-event@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" + integrity sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A== + dependencies: + tslib "^1.9.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +circular-dependency-plugin@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz#da168c0b37e7b43563fb9f912c1c007c213389ef" + integrity sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA== + +circular-json@^0.5.5: + version "0.5.9" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" + integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" + integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== + dependencies: + source-map "~0.6.0" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone-deep@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" + integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ== + dependencies: + for-own "^1.0.0" + is-plain-object "^2.0.4" + kind-of "^6.0.0" + shallow-clone "^1.0.0" + +clone@^2.1.1, clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +codelyzer@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/codelyzer/-/codelyzer-4.5.0.tgz#a65ddeeeca2894653253a89bfa229118ff9f59b1" + integrity sha512-oO6vCkjqsVrEsmh58oNlnJkRXuA30hF8cdNAQV9DytEalDwyOFRvHMnlKFzmOStNerOmPGZU9GAHnBo4tGvtiQ== + dependencies: + app-root-path "^2.1.0" + css-selector-tokenizer "^0.7.0" + cssauron "^1.4.0" + semver-dsl "^1.0.1" + source-map "^0.5.7" + sprintf-js "^1.1.1" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +colors@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= + +colors@^1.1.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" + integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== + +combine-lists@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6" + integrity sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y= + dependencies: + lodash "^4.5.0" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.12.1: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + +commander@~2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +compare-versions@^3.2.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.4.0.tgz#e0747df5c9cb7f054d6d3dc3e1dbc444f9e92b26" + integrity sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg== + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1, component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +compressible@~2.0.14: + version "2.0.15" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.15.tgz#857a9ab0a7e5a07d8d837ed43fe2defff64fe212" + integrity sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw== + dependencies: + mime-db ">= 1.36.0 < 2" + +compression@^1.5.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.14" + debug "2.6.9" + on-headers "~1.0.1" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +connect-history-api-fallback@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" + integrity sha1-sGhzk0vF40T+9hGhlqb6rgruAVo= + +connect@^3.6.0: + version "3.6.6" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= + dependencies: + debug "2.6.9" + finalhandler "1.1.0" + parseurl "~1.3.2" + utils-merge "1.0.1" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.5.0, convert-source-map@^1.5.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-webpack-plugin@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" + integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== + dependencies: + cacache "^10.0.4" + find-cache-dir "^1.0.0" + globby "^7.1.1" + is-glob "^4.0.0" + loader-utils "^1.1.0" + minimatch "^3.0.4" + p-limit "^1.0.0" + serialize-javascript "^1.4.0" + +core-js@^2.2.0, core-js@^2.4.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042" + integrity sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg== + +"core-js@file:../../node_modules/core-js": + version "2.5.7" + +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" + integrity sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ== + dependencies: + is-directory "^0.3.1" + js-yaml "^3.9.0" + parse-json "^4.0.0" + require-from-string "^2.0.1" + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-parse@1.7.x: + version "1.7.0" + resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b" + integrity sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs= + +css-selector-tokenizer@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d" + integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA== + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +cssauron@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssauron/-/cssauron-1.4.0.tgz#a6602dff7e04a8306dc0db9a551e92e8b5662ad8" + integrity sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg= + dependencies: + through X.X.X + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q= + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU= + +cyclist@~0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" + integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +date-format@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-1.2.0.tgz#615e828e233dd1ab9bb9ae0950e0ceccfa6ecad8" + integrity sha1-YV6CjiM90aubua4JUODOzPpuytg= + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= + +debug@*, debug@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== + dependencies: + ms "^2.1.1" + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0, debug@=3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0, debug@^3.2.5: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decamelize@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7" + integrity sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg== + dependencies: + xregexp "4.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +default-gateway@^2.6.0: + version "2.7.2" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f" + integrity sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ== + dependencies: + execa "^0.10.0" + ip-regex "^2.1.0" + +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + integrity sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc= + dependencies: + strip-bom "^3.0.0" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +del@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" + integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU= + dependencies: + globby "^6.1.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + p-map "^1.1.1" + pify "^3.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +dependency-graph@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" + integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= + +diff@^3.1.0, diff@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== + dependencies: + arrify "^1.0.1" + path-type "^3.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +dom-serialize@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs= + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.1.tgz#b1a7a29c4abfd639585efaecce80d666b1e34125" + integrity sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.92: + version "1.3.96" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.96.tgz#25770ec99b8b07706dedf3a5f43fa50cb54c4f9a" + integrity sha512-ZUXBUyGLeoJxp4Nt6G/GjBRLnyz8IKQGexZ2ndWaoegThgMGFO1tdDYID5gBV32/1S83osjJHyfzvanE/8HY4Q== + +elliptic@^6.0.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encodeurl@~1.0.1, encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~3.3.1" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.1.tgz#b60281c35484a70ee0351ea0ebff83ec8c9522a2" + integrity sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~3.3.1" + +enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" + integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +ent@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + +errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es6-promise@^4.0.3: + version "4.2.5" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" + integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg== + +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escodegen@1.8.x: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@2.7.x, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= + +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.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" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.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@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-braces@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/expand-braces/-/expand-braces-0.1.2.tgz#488b1d1d2451cb3d3a6b192cfc030f44c5855fea" + integrity sha1-SIsdHSRRyz06axks/AMPRMWFX+o= + dependencies: + array-slice "^0.2.3" + array-unique "^0.2.1" + braces "^0.1.2" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-0.1.1.tgz#4cb8eda0993ca56fa4f41fc42f3cbb4ccadff044" + integrity sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ= + dependencies: + is-number "^0.1.1" + repeat-string "^0.2.2" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +express@^4.16.2: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" + integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastparse@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" + integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== + +faye-websocket@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" + integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg= + dependencies: + websocket-driver ">=0.5.1" + +figgy-pudding@^3.1.0, figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" + integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-loader@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-2.0.0.tgz#39749c82f020b9e85901dcff98e8004e6401cfde" + integrity sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ== + dependencies: + loader-utils "^1.0.2" + schema-utils "^1.0.0" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + +fileset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= + dependencies: + debug "2.6.9" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.3.1" + unpipe "~1.0.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" + integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8= + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^2.0.0" + +find-cache-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d" + integrity sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA== + dependencies: + commondir "^1.0.1" + make-dir "^1.0.0" + pkg-dir "^3.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flatted@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" + integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== + +flush-write-stream@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" + integrity sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw== + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.4" + +follow-redirects@^1.0.0: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-access@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" + integrity sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o= + dependencies: + null-check "^1.0.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.0.0, fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fstream@^1.0.0, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +genfun@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" + integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@7.0.x: + version "7.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + integrity sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo= + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.9.0.tgz#bde236808e987f290768a93d065060d78e6ab249" + integrity sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg== + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" + integrity sha1-+yzP+UAfhgCUXfral0QMypcrhoA= + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ== + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + +handlebars@^4.0.1, handlebars@^4.0.11: + version "4.0.12" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" + integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== + dependencies: + async "^2.5.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= + +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.4.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8" + integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w== + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +http-proxy-middleware@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" + integrity sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q== + dependencies: + http-proxy "^1.16.2" + is-glob "^4.0.0" + lodash "^4.17.5" + micromatch "^3.1.9" + +http-proxy@^1.13.0, http-proxy@^1.16.2: + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== + dependencies: + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +image-size@~0.5.0: + version "0.5.5" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" + integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= + dependencies: + import-from "^2.1.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= + dependencies: + resolve-from "^3.0.0" + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +ini@1.3.5, ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inquirer@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" + integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.0" + figures "^2.0.0" + lodash "^4.17.10" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.1.0" + string-width "^2.1.0" + strip-ansi "^5.0.0" + through "^2.3.6" + +internal-ip@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-3.0.1.tgz#df5c99876e1d2eb2ea2d74f520e3f669a00ece27" + integrity sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q== + dependencies: + default-gateway "^2.6.0" + ipaddr.js "^1.5.2" + +interpret@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= + +ipaddr.js@^1.5.2: + version "1.8.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.1.tgz#fa4b79fa47fd3def5e3b159825161c0a519c9427" + integrity sha1-+kt5+kf9Pe9eOxWYJRYcClGclCc= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= + dependencies: + builtin-modules "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= + dependencies: + is-extglob "^2.1.1" + +is-number@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" + integrity sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY= + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= + dependencies: + path-is-inside "^1.0.1" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + +isbinaryfile@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" + integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== + dependencies: + buffer-alloc "^1.2.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-api@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-2.0.6.tgz#cd7b33ee678f6c01531d05f5e567ebbcd25f8ecc" + integrity sha512-8W5oeAGWXhtTJjAyVfvavOLVyZCTNCKsyF6GON/INKlBdO7uJ/bv3qnPj5M6ERKzmMCJS1kntnjjGuJ86fn3rQ== + dependencies: + async "^2.6.1" + compare-versions "^3.2.1" + fileset "^2.0.3" + istanbul-lib-coverage "^2.0.1" + istanbul-lib-hook "^2.0.1" + istanbul-lib-instrument "^3.0.0" + istanbul-lib-report "^2.0.2" + istanbul-lib-source-maps "^2.0.1" + istanbul-reports "^2.0.1" + js-yaml "^3.12.0" + make-dir "^1.3.0" + once "^1.4.0" + +istanbul-instrumenter-loader@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz#9957bd59252b373fae5c52b7b5188e6fde2a0949" + integrity sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w== + dependencies: + convert-source-map "^1.5.0" + istanbul-lib-instrument "^1.7.3" + loader-utils "^1.1.0" + schema-utils "^0.3.0" + +istanbul-lib-coverage@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" + integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== + +istanbul-lib-coverage@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#2aee0e073ad8c5f6a0b00e0dfbf52b4667472eda" + integrity sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA== + +istanbul-lib-hook@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.1.tgz#918a57b75a0f951d552a08487ca1fa5336433d72" + integrity sha512-ufiZoiJ8CxY577JJWEeFuxXZoMqiKpq/RqZtOAYuQLvlkbJWscq9n3gc4xrCGH9n4pW0qnTxOz1oyMmVtk8E1w== + dependencies: + append-transform "^1.0.0" + +istanbul-lib-instrument@^1.7.3: + version "1.10.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" + integrity sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.2.1" + semver "^5.3.0" + +istanbul-lib-instrument@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.0.0.tgz#b5f066b2a161f75788be17a9d556f40a0cf2afc9" + integrity sha512-eQY9vN9elYjdgN9Iv6NS/00bptm02EBBk70lRMaVjeA6QYocQgenVrSgC28TJurdnZa80AGO3ASdFN+w/njGiQ== + dependencies: + "@babel/generator" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/template" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + istanbul-lib-coverage "^2.0.1" + semver "^5.5.0" + +istanbul-lib-report@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.2.tgz#430a2598519113e1da7af274ba861bd42dd97535" + integrity sha512-rJ8uR3peeIrwAxoDEbK4dJ7cqqtxBisZKCuwkMtMv0xYzaAnsAi3AHrHPAAtNXzG/bcCgZZ3OJVqm1DTi9ap2Q== + dependencies: + istanbul-lib-coverage "^2.0.1" + make-dir "^1.3.0" + supports-color "^5.4.0" + +istanbul-lib-source-maps@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-2.0.1.tgz#ce8b45131d8293fdeaa732f4faf1852d13d0a97e" + integrity sha512-30l40ySg+gvBLcxTrLzR4Z2XTRj3HgRCA/p2rnbs/3OiTaoj054gAbuP5DcLOtwqmy4XW8qXBHzrmP2/bQ9i3A== + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^2.0.1" + make-dir "^1.3.0" + rimraf "^2.6.2" + source-map "^0.6.1" + +istanbul-reports@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.0.1.tgz#fb8d6ea850701a3984350b977a969e9a556116a7" + integrity sha512-CT0QgMBJqs6NJLF678ZHcquUAZIoBIUNzdJrRJfpkI9OnzG6MkUfHxbJC3ln981dMswC7/B1mfX3LNkhgJxsuw== + dependencies: + handlebars "^4.0.11" + +istanbul@0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" + integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +jasmine-core@~2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" + integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= + +jasmine-core@~2.99.1: + version "2.99.1" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.99.1.tgz#e6400df1e6b56e130b61c4bcd093daa7f6e8ca15" + integrity sha1-5kAN8ea1bhMLYcS80JPap/boyhU= + +jasmine-spec-reporter@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz#1d632aec0341670ad324f92ba84b4b32b35e9e22" + integrity sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg== + dependencies: + colors "1.1.2" + +jasmine@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" + integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4= + dependencies: + exit "^0.1.2" + glob "^7.0.6" + jasmine-core "~2.8.0" + +jasminewd2@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" + integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= + +js-base64@^2.1.8: + version "2.5.0" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.0.tgz#42255ba183ab67ce59a0dee640afdc00ab5ae93e" + integrity sha512-wlEBIZ5LP8usDylWbDNhKPEFVFdI5hCHpnVoT/Ysvoi/PRhJENm/Rlh9TvjYB38HFfKZN7OzEbRjmjvLkFw11g== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + +js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.7.0, js-yaml@^3.9.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= + +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + +karma-chrome-launcher@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" + integrity sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w== + dependencies: + fs-access "^1.0.0" + which "^1.2.1" + +karma-coverage-istanbul-reporter@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.4.tgz#402ae4ed6eadb9d9dafbd408ffda17897c0d003a" + integrity sha512-xJS7QSQIVU6VK9HuJ/ieE5yynxKhjCCkd96NLY/BX/HXsx0CskU9JJiMQbd4cHALiddMwI4OWh1IIzeWrsavJw== + dependencies: + istanbul-api "^2.0.5" + minimatch "^3.0.4" + +karma-jasmine-html-reporter@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz#48a8e5ef18807617ee2b5e33c1194c35b439524c" + integrity sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw= + dependencies: + karma-jasmine "^1.0.2" + +karma-jasmine@^1.0.2, karma-jasmine@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-1.1.2.tgz#394f2b25ffb4a644b9ada6f22d443e2fd08886c3" + integrity sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM= + +karma-source-map-support@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz#36dd4d8ca154b62ace95696236fae37caf0a7dde" + integrity sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q== + dependencies: + source-map-support "^0.5.5" + +karma@~3.1.1: + version "3.1.4" + resolved "https://registry.yarnpkg.com/karma/-/karma-3.1.4.tgz#3890ca9722b10d1d14b726e1335931455788499e" + integrity sha512-31Vo8Qr5glN+dZEVIpnPCxEGleqE0EY6CtC2X9TagRV3rRQ3SNrvfhddICkJgUK3AgqpeKSZau03QumTGhGoSw== + dependencies: + bluebird "^3.3.0" + body-parser "^1.16.1" + chokidar "^2.0.3" + colors "^1.1.0" + combine-lists "^1.0.0" + connect "^3.6.0" + core-js "^2.2.0" + di "^0.0.1" + dom-serialize "^2.2.0" + expand-braces "^0.1.1" + flatted "^2.0.0" + glob "^7.1.1" + graceful-fs "^4.1.2" + http-proxy "^1.13.0" + isbinaryfile "^3.0.0" + lodash "^4.17.5" + log4js "^3.0.0" + mime "^2.3.1" + minimatch "^3.0.2" + optimist "^0.6.1" + qjobs "^1.1.4" + range-parser "^1.2.0" + rimraf "^2.6.0" + safe-buffer "^5.0.1" + socket.io "2.1.1" + source-map "^0.6.1" + tmp "0.0.33" + useragent "2.3.0" + +killable@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +less-loader@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-4.1.0.tgz#2c1352c5b09a4f84101490274fd51674de41363e" + integrity sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg== + dependencies: + clone "^2.1.1" + loader-utils "^1.1.0" + pify "^3.0.0" + +less@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/less/-/less-3.9.0.tgz#b7511c43f37cf57dc87dffd9883ec121289b1474" + integrity sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w== + dependencies: + clone "^2.1.2" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + mime "^1.4.1" + mkdirp "^0.5.0" + promise "^7.1.1" + request "^2.83.0" + source-map "~0.6.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +license-webpack-plugin@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.0.4.tgz#48532e7d7b45f6ceb21a68b6826ce7241d7ea6da" + integrity sha512-FQgOqrrIcD4C/VQo6ecWgXZULK5rs0kIDJtHcSVO6SBUrD63kEHZwmKOvBTquFQSgMQn/yeH68qooKDfqiBF2Q== + dependencies: + "@types/webpack-sources" "^0.1.5" + webpack-sources "^1.2.0" + +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.1.tgz#026f12fe7c3115992896ac02ba022ba92971b979" + integrity sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw== + +loader-utils@1.1.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= + +lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.mergewith@^4.6.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927" + integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ== + +lodash.tail@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" + integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ= + +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.0, lodash@~4.17.10: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +log4js@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-3.0.6.tgz#e6caced94967eeeb9ce399f9f8682a4b2b28c8ff" + integrity sha512-ezXZk6oPJCWL483zj64pNkMuY/NcRX5MPiB0zE6tjZM137aeusrOnW1ecxgF9cmwMWkBMhjteQxBPoZBh9FDxQ== + dependencies: + circular-json "^0.5.5" + date-format "^1.2.0" + debug "^3.1.0" + rfdc "^1.1.2" + streamroller "0.7.0" + +loglevel@^1.4.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa" + integrity sha1-4PyVEztu8nbNyIh82vJKpvFW+Po= + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +magic-string@^0.25.0: + version "0.25.1" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.1.tgz#b1c248b399cd7485da0fe7385c2fc7011843266e" + integrity sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg== + dependencies: + sourcemap-codec "^1.4.1" + +make-dir@^1.0.0, make-dir@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-error@^1.1.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + +make-fetch-happen@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" + integrity sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ== + dependencies: + agentkeepalive "^3.4.1" + cacache "^11.0.1" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" + +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.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +mem@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf" + integrity sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^1.0.0" + p-is-promise "^1.1.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +"mime-db@>= 1.36.0 < 2", mime-db@~1.37.0: + version "1.37.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: + version "2.1.21" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== + dependencies: + mime-db "~1.37.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.3.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" + integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mini-css-extract-plugin@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.4.tgz#c10410a004951bd3cedac1da69053940fccb625d" + integrity sha512-o+Jm+ocb0asEngdM6FsZWtZsRzA8koFUudIDwYUfl94M3PejPHG7Vopw5hN9V8WsMkSFpm3tZP3Fesz89EyrfQ== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + +minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mississippi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" + integrity sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^2.0.1" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mixin-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= + dependencies: + for-in "^0.1.3" + is-extendable "^0.1.1" + +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.0.0, ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +nan@^2.10.0, nan@^2.9.2: + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +neo-async@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + +node-forge@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df" + integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ== + +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.2.tgz#93c17fba5eec8650ad908de5433fa8763baebe4d" + integrity sha512-j1gEV/zX821yxdWp/1vBMN0pSUjuH9oGUdLCb4PfUko6ZW7KdRs3Z+QGGwDUhYtSpQvdVVyLd2V0YvLsmdg5jQ== + dependencies: + semver "^5.3.0" + +node-sass@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.10.0.tgz#dcc2b364c0913630945ccbf7a2bbf1f926effca4" + integrity sha512-fDQJfXszw6vek63Fe/ldkYXmRYK/QS6NbvM3i5oEo9ntPDy4XX7BcKZyTKv+/kSSxRtXXc7l+MSwEmYc0CSy6Q== + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + lodash.mergewith "^4.6.0" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.10.0" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + +"nopt@2 || 3", nopt@3.x: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +npm-bundled@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" + integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== + +npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== + dependencies: + hosted-git-info "^2.6.0" + osenv "^0.1.5" + semver "^5.5.0" + validate-npm-package-name "^3.0.0" + +npm-packlist@^1.1.12, npm-packlist@^1.1.6: + version "1.1.12" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a" + integrity sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-pick-manifest@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" + integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA== + dependencies: + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-registry-fetch@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.8.0.tgz#aa7d9a7c92aff94f48dba0984bdef4bd131c88cc" + integrity sha512-hrw8UMD+Nob3Kl3h8Z/YjmKamb1gf7D1ZZch2otrIXM3uFLB5vjEY6DhMlq80z/zZet6eETLbOXcuQudCB3Zpw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +null-check@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" + integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= + +once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +opn@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + integrity sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g== + dependencies: + is-wsl "^1.1.0" + +opn@^5.1.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.4.0.tgz#cb545e7aab78562beb11aa3bfabc7042e1761035" + integrity sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw== + dependencies: + is-wsl "^1.1.0" + +optimist@^0.6.1, optimist@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-locale@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620" + integrity sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw== + dependencies: + execa "^0.10.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0, osenv@^0.1.4, osenv@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= + +p-limit@^1.0.0, p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + integrity sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== + +pacote@9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.1.1.tgz#25091f75a25021de8be8d34cc6408728fca3579b" + integrity sha512-f28Rq5ozzKAA9YwIKw61/ipwAatUZseYmVssDbHHaexF0wRIVotapVEZPAjOT7Eu3LYVqEp0NVpNizoAnYBUaA== + dependencies: + bluebird "^3.5.2" + cacache "^11.2.0" + figgy-pudding "^3.5.1" + get-stream "^4.1.0" + glob "^7.1.3" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + minimatch "^3.0.4" + minipass "^2.3.5" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.12" + npm-pick-manifest "^2.1.0" + npm-registry-fetch "^3.8.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.1" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.6.0" + ssri "^6.0.1" + tar "^4.4.6" + unique-filename "^1.1.1" + which "^1.3.1" + +pako@~1.0.2: + version "1.0.8" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4" + integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA== + +pako@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.7.tgz#2473439021b57f1516c82f58be7275ad8ef1bb27" + integrity sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ== + +parallel-transform@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" + integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + dependencies: + cyclist "~0.2.2" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + integrity sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +portfinder@1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.17.tgz#a8a1691143e46c4735edefcf4fbcccedad26456a" + integrity sha512-syFcRIRzVI1BoEFOCaAiizwDolh1S1YXSodsVhncbhjzjZQulhczNRbqnUl9N31Q4dKGOXsNDqxC2BWBgSMqeQ== + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +portfinder@^1.0.9: + version "1.0.20" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" + integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-import@12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-12.0.0.tgz#149f96a4ef0b27525c419784be8517ebd17e92c5" + integrity sha512-3KqKRZcaZAvxbY8DVLdd81tG5uKzbUQuiWIvy0o0fzEC42bKacqPYFWbfCQyw6L4LWUaqPz/idvIdbhpgQ32eQ== + dependencies: + postcss "^7.0.1" + postcss-value-parser "^3.2.3" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-load-config@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484" + integrity sha512-V5JBLzw406BB8UIfsAWSK2KSwIJ5yoEIVFb4gVkXci0QdKgA24jLmHZ/ghe/GgX0lJ0/D1uUK1ejhzEY94MChQ== + dependencies: + cosmiconfig "^4.0.0" + import-cwd "^2.0.0" + +postcss-loader@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== + dependencies: + loader-utils "^1.1.0" + postcss "^7.0.0" + postcss-load-config "^2.0.0" + schema-utils "^1.0.0" + +postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss@7.0.11: + version "7.0.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.11.tgz#f63c513b78026d66263bb2ca995bf02e3d1a697d" + integrity sha512-9AXb//5UcjeOEof9T+yPw3XTa5SL207ZOIC/lHYP4mbUTEh4M0rDAQekQpVANCZdwQwKhBtFZCk3i3h3h2hdWg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.6: + version "7.0.7" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.7.tgz#2754d073f77acb4ef08f1235c36c5721a7201614" + integrity sha512-HThWSJEPkupqew2fnuQMEI2YcTj/8gMV3n80cMdJsKxfIh5tHf7nM5JigNX6LxVMqo6zkgQNAI88hyFvBk41Pg== + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.5.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +protoduck@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" + integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== + dependencies: + genfun "^5.0.0" + +"protractor@file:../../node_modules/protractor": + version "5.4.2" + dependencies: + "@types/q" "^0.0.32" + "@types/selenium-webdriver" "^3.0.0" + blocking-proxy "^1.0.0" + browserstack "^1.5.1" + chalk "^1.1.3" + glob "^7.0.3" + jasmine "2.8.0" + jasminewd2 "^2.1.0" + optimist "~0.6.0" + q "1.4.1" + saucelabs "^1.5.0" + selenium-webdriver "3.6.0" + source-map-support "~0.4.0" + webdriver-js-extender "2.1.0" + webdriver-manager "^12.0.6" + +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.24: + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0, pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= + +q@^1.4.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qjobs@^1.1.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.5.2, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" + integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.0.3, range-parser@^1.2.0, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +raw-loader@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" + integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q= + dependencies: + pify "^2.3.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.1.1" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" + integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +reflect-metadata@^0.1.2: + version "0.1.12" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" + integrity sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A== + +regenerate@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs= + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae" + integrity sha1-x6jTI2BoNiBZp+RlH8aITosftK4= + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +request@^2.83.0, request@^2.87.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@1.1.x: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= + +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: + version "1.9.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" + integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== + dependencies: + path-parse "^1.0.6" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= + +rfdc@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" + integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@6.3.3, rxjs@^6.1.0, "rxjs@file:../../node_modules/rxjs": + version "6.3.3" + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + +sass-loader@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d" + integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w== + dependencies: + clone-deep "^2.0.1" + loader-utils "^1.0.1" + lodash.tail "^4.1.1" + neo-async "^2.5.0" + pify "^3.0.0" + semver "^5.5.0" + +saucelabs@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" + integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== + dependencies: + https-proxy-agent "^2.2.1" + +sax@0.5.x: + version "0.5.8" + resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" + integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= + +sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" + integrity sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8= + dependencies: + ajv "^5.0.0" + +schema-utils@^0.4.4: + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" + integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q== + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + +selfsigned@^1.9.1: + version "1.10.4" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd" + integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw== + dependencies: + node-forge "0.7.5" + +semver-dsl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/semver-dsl/-/semver-dsl-1.0.1.tgz#d3678de5555e8a61f629eed025366ae5f27340a0" + integrity sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA= + dependencies: + semver "^5.3.0" + +semver-intersect@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/semver-intersect/-/semver-intersect-1.4.0.tgz#bdd9c06bedcdd2fedb8cd352c3c43ee8c61321f3" + integrity sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ== + dependencies: + semver "^5.0.0" + +"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +semver@5.5.1: + version "5.5.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" + integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serialize-javascript@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" + integrity sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ== + +serve-index@^1.7.2: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571" + integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA== + dependencies: + is-extendable "^0.1.1" + kind-of "^5.0.0" + mixin-object "^2.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shelljs@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" + integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +smart-buffer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" + integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= + +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.2.0" + to-array "0.1.4" + +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== + dependencies: + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" + +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" + json3 "^3.3.2" + url-parse "^1.4.3" + +sockjs@0.3.19: + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" + integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== + dependencies: + faye-websocket "^0.10.0" + uuid "^3.0.1" + +socks-proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + integrity sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw== + dependencies: + agent-base "~4.2.0" + socks "~2.2.0" + +socks@~2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.2.tgz#f061219fc2d4d332afb4af93e865c84d3fa26e2b" + integrity sha512-g6wjBnnMOZpE0ym6e0uHSddz9p3a+WsBaaYQaBaSCJYvrC4IXykQR9MNGjLQf38e9iIIhp3b1/Zk8YZI3KGJ0Q== + dependencies: + ip "^1.1.5" + smart-buffer "^4.0.1" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + integrity sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY= + +source-map-loader@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-0.2.4.tgz#c18b0dc6e23bf66f6792437557c569a11e072271" + integrity sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ== + dependencies: + async "^2.5.0" + loader-utils "^1.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@0.5.9, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.6: + version "0.5.9" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@~0.4.0: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@0.1.x: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= + dependencies: + amdefine ">=0.0.4" + +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= + +source-map@0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +source-map@^0.4.2, source-map@~0.4.1: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= + dependencies: + amdefine ">=0.0.4" + +sourcemap-codec@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" + integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg== + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" + integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +speed-measure-webpack-plugin@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.2.5.tgz#8179936eb8c5e891f7481bd5075a9ea9a0f74823" + integrity sha512-S/guYjC4Izn5wY2d0+M4zowED/F77Lxh9yjkTZ+XAr244pr9c1MYNcXcRe9lx2hmAj0GPbOrBXgOF2YIp/CZ8A== + dependencies: + chalk "^2.0.1" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de" + integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-5.3.0.tgz#ba3872c9c6d33a0704a7d71ff045e5ec48999d06" + integrity sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ== + dependencies: + safe-buffer "^5.1.1" + +ssri@^6.0.0, ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +stats-webpack-plugin@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/stats-webpack-plugin/-/stats-webpack-plugin-0.7.0.tgz#ccffe9b745de8bbb155571e063f8263fc0e2bc06" + integrity sha512-NT0YGhwuQ0EOX+uPhhUcI6/+1Sq/pMzNuSCBVT4GbFl/ac6I/JZefBcjlECNfAb1t3GOx5dEj1Z7x0cAxeeVLQ== + dependencies: + lodash "^4.17.4" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds= + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +streamroller@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-0.7.0.tgz#a1d1b7cf83d39afb0d63049a5acbf93493bdf64b" + integrity sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ== + dependencies: + date-format "^1.2.0" + debug "^3.1.0" + mkdirp "^0.5.1" + readable-stream "^2.3.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== + dependencies: + loader-utils "^1.1.0" + schema-utils "^1.0.0" + +stylus-loader@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/stylus-loader/-/stylus-loader-3.0.2.tgz#27a706420b05a38e038e7cacb153578d450513c6" + integrity sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA== + dependencies: + loader-utils "^1.0.2" + lodash.clonedeep "^4.5.0" + when "~3.6.x" + +stylus@0.54.5: + version "0.54.5" + resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.5.tgz#42b9560931ca7090ce8515a798ba9e6aa3d6dc79" + integrity sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk= + dependencies: + css-parse "1.7.x" + debug "*" + glob "7.0.x" + mkdirp "0.5.x" + sax "0.5.x" + source-map "0.1.x" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + dependencies: + has-flag "^1.0.0" + +supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +symbol-observable@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + +tapable@^1.0.0, tapable@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.1.tgz#4d297923c5a72a42360de2ab52dadfaaec00018e" + integrity sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA== + +tar@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tar@^4, tar@^4.4.6: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +terser-webpack-plugin@1.2.1, terser-webpack-plugin@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz#7545da9ae5f4f9ae6a0ac961eb46f5e7c845cc26" + integrity sha512-GGSt+gbT0oKcMDmPx4SRSfJPE1XaN3kQRWG4ghxKQw9cn5G9x6aCKSsgYdvyM0na9NJ4Drv0RG6jbBByZ5CMjw== + dependencies: + cacache "^11.0.2" + find-cache-dir "^2.0.0" + schema-utils "^1.0.0" + serialize-javascript "^1.4.0" + source-map "^0.6.1" + terser "^3.8.1" + webpack-sources "^1.1.0" + worker-farm "^1.5.2" + +terser@^3.8.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.13.1.tgz#a02e8827fb9705fe7b609c31093d010b28cea8eb" + integrity sha512-ogyZye4DFqOtMzT92Y3Nxxw8OvXmL39HOALro4fc+EUYFFF9G/kk0znkvwMz6PPYgBtdKAodh3FPR70eugdaQA== + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + source-map-support "~0.5.6" + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +"through@>=2.2.7 <3", through@X.X.X, through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +thunky@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" + integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== + dependencies: + setimmediate "^1.0.4" + +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + integrity sha1-ckGdSovn1s51FI/YsyTlk6cRwu0= + dependencies: + os-tmpdir "~1.0.1" + +tmp@0.0.33, tmp@0.0.x, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tree-kill@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" + integrity sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg== + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +"true-case-path@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== + dependencies: + glob "^7.1.2" + +ts-node@~7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + +tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + +tslint@~5.11.0: + version "5.11.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" + integrity sha1-mPMMAurjzecAYgHkwzywi0hYHu0= + dependencies: + babel-code-frame "^6.22.0" + builtin-modules "^1.1.1" + chalk "^2.3.0" + commander "^2.12.1" + diff "^3.2.0" + glob "^7.1.1" + js-yaml "^3.7.0" + minimatch "^3.0.4" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.8.0" + tsutils "^2.27.2" + +tsutils@^2.27.2: + version "2.29.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== + dependencies: + tslib "^1.8.1" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" + integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== + +"typescript@file:../../node_modules/typescript": + version "3.2.2" + +uglify-js@^3.1.4: + version "3.4.9" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-filename@^1.1.0, unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" + integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== + dependencies: + imurmurhash "^0.1.4" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse@^1.4.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== + dependencies: + querystringify "^2.0.0" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +useragent@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" + integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== + dependencies: + lru-cache "4.1.x" + tmp "0.0.x" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.0.1, uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + dependencies: + builtins "^1.0.3" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= + dependencies: + indexof "0.0.1" + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= + +watchpack@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webdriver-js-extender@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" + integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ== + dependencies: + "@types/selenium-webdriver" "^3.0.0" + selenium-webdriver "^3.0.1" + +webdriver-manager@^12.0.6: + version "12.1.0" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.0.tgz#f6601e52de5f0c97fc7024c889eeb2416f2f1d9d" + integrity sha512-oEc5fmkpz6Yh6udhwir5m0eN5mgRPq9P/NU5YWuT3Up5slt6Zz+znhLU7q4+8rwCZz/Qq3Fgpr/4oao7NPCm2A== + dependencies: + adm-zip "^0.4.9" + chalk "^1.1.1" + del "^2.2.0" + glob "^7.0.3" + ini "^1.3.4" + minimist "^1.2.0" + q "^1.4.1" + request "^2.87.0" + rimraf "^2.5.2" + semver "^5.3.0" + xml2js "^0.4.17" + +webpack-core@^0.6.8: + version "0.6.9" + resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2" + integrity sha1-/FcViMhVjad76e+23r3Fo7FyvcI= + dependencies: + source-list-map "~0.1.7" + source-map "~0.4.1" + +webpack-dev-middleware@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" + integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== + dependencies: + memory-fs "~0.4.1" + mime "^2.3.1" + range-parser "^1.0.3" + webpack-log "^2.0.0" + +webpack-dev-server@3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" + integrity sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ== + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.0.0" + compression "^1.5.2" + connect-history-api-fallback "^1.3.0" + debug "^3.1.0" + del "^3.0.0" + express "^4.16.2" + html-entities "^1.2.0" + http-proxy-middleware "~0.18.0" + import-local "^2.0.0" + internal-ip "^3.0.1" + ip "^1.1.5" + killable "^1.0.0" + loglevel "^1.4.1" + opn "^5.1.0" + portfinder "^1.0.9" + schema-utils "^1.0.0" + selfsigned "^1.9.1" + semver "^5.6.0" + serve-index "^1.7.2" + sockjs "0.3.19" + sockjs-client "1.3.0" + spdy "^4.0.0" + strip-ansi "^3.0.0" + supports-color "^5.1.0" + url "^0.11.0" + webpack-dev-middleware "3.4.0" + webpack-log "^2.0.0" + yargs "12.0.2" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.4.tgz#0fde38eabf2d5fd85251c24a5a8c48f8a3f4eb7b" + integrity sha512-TmSe1HZKeOPey3oy1Ov2iS3guIZjWvMT2BBJDzzT5jScHTjVC3mpjJofgueEzaEd6ibhxRDD6MIblDr8tzh8iQ== + dependencies: + lodash "^4.17.5" + +webpack-sources@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.2.0.tgz#18181e0d013fce096faf6f8e6d41eeffffdceac2" + integrity sha512-9BZwxR85dNsjWz3blyxdOhTgtnQvv3OEs5xofI0wPYTwu5kaWxS08UuD1oI7WLBLpRO+ylf0ofnXLXWmGb2WMw== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-sources@1.3.0, webpack-sources@^1.1.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-subresource-integrity@1.1.0-rc.6: + version "1.1.0-rc.6" + resolved "https://registry.yarnpkg.com/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz#37f6f1264e1eb378e41465a98da80fad76ab8886" + integrity sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w== + dependencies: + webpack-core "^0.6.8" + +webpack@4.28.4: + version "4.28.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.28.4.tgz#1ddae6c89887d7efb752adf0c3cd32b9b07eacd0" + integrity sha512-NxjD61WsK/a3JIdwWjtIpimmvE6UrRi3yG54/74Hk9rwNj5FPkA4DJCf1z4ByDWLkvZhTZE+P3C/eh6UD5lDcw== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/wasm-edit" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + acorn "^5.6.2" + acorn-dynamic-import "^3.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^0.4.4" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + +websocket-driver@>=0.5.1: + version "0.7.0" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs= + dependencies: + http-parser-js ">=0.4.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== + +when@~3.6.x: + version "3.6.4" + resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e" + integrity sha1-RztRfsFZ4rhQBUl6E5g/CVQS404= + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1, which@^1.1.1, which@^1.2.1, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wordwrap@^1.0.0, wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + +worker-farm@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" + integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ== + dependencies: + errno "~0.1.7" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@~3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +xml2js@^0.4.17: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xregexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" + integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== + dependencies: + camelcase "^4.1.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= + dependencies: + camelcase "^3.0.0" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= + dependencies: + camelcase "^4.1.0" + +yargs@12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc" + integrity sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ== + dependencies: + cliui "^4.0.0" + decamelize "^2.0.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^10.1.0" + +yargs@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" + integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= + +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo= + +"zone.js@file:../../node_modules/zone.js": + version "0.8.26" diff --git a/integration/cli-hello-world-ivy/src/environments/environment.ts b/integration/cli-hello-world-ivy/src/environments/environment.ts deleted file mode 100644 index b7f639aeca..0000000000 --- a/integration/cli-hello-world-ivy/src/environments/environment.ts +++ /dev/null @@ -1,8 +0,0 @@ -// The file contents for the current environment will overwrite these during build. -// The build system defaults to the dev environment which uses `environment.ts`, but if you do -// `ng build --env=prod` then `environment.prod.ts` will be used instead. -// The list of which env maps to which file can be found in `.angular-cli.json`. - -export const environment = { - production: false -}; diff --git a/integration/cli-hello-world/package.json b/integration/cli-hello-world/package.json index 4cf8e80d16..d6e5035aa1 100644 --- a/integration/cli-hello-world/package.json +++ b/integration/cli-hello-world/package.json @@ -7,8 +7,9 @@ "e2e": "ng e2e --webdriver-update=false", "lint": "ng lint", "ng": "ng", - "postinstall": "webdriver-manager update --gecko=false --standalone=false $CHROMEDRIVER_VERSION_ARG", + "postinstall": "webdriver-manager update --gecko=false --standalone=false $CI_CHROMEDRIVER_VERSION_ARG", "start": "ng serve", + "pretest": "ng version", "test": "ng test --progress=false --watch=false && yarn e2e --configuration=ci && yarn e2e --configuration=ci-production" }, "private": true, @@ -24,11 +25,12 @@ "@angular/router": "file:../../dist/packages-dist/router", "core-js": "file:../../node_modules/core-js", "rxjs": "file:../../node_modules/rxjs", + "tslib": "^1.9.3", "zone.js": "file:../../node_modules/zone.js" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.10.3", - "@angular/cli": "7.0.3", + "@angular-devkit/build-angular": "0.13.0-rc.0", + "@angular/cli": "file:../../node_modules/@angular/cli", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/language-service": "file:../../dist/packages-dist/language-service", "@types/jasmine": "~2.8.3", diff --git a/integration/cli-hello-world/src/polyfills.ts b/integration/cli-hello-world/src/polyfills.ts index d68672ffe4..a6d34ea67a 100644 --- a/integration/cli-hello-world/src/polyfills.ts +++ b/integration/cli-hello-world/src/polyfills.ts @@ -11,14 +11,17 @@ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. * - * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + * Learn more in https://angular.io/guide/browser-support */ /*************************************************************************************************** * BROWSER POLYFILLS */ -/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +/** IE9, IE10, IE11, and Chrome <55 requires all of the following polyfills. + * This also includes Android Emulators with older versions of Chrome and Google Search/Googlebot + */ + // import 'core-js/es6/symbol'; // import 'core-js/es6/object'; // import 'core-js/es6/function'; @@ -40,19 +43,36 @@ /** IE10 and IE11 requires the following for the Reflect API. */ // import 'core-js/es6/reflect'; - -/** Evergreen browsers require these. **/ -// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. -import 'core-js/es7/reflect'; - - /** - * Required to support Web Animations `@angular/platform-browser/animations`. - * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation - **/ + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ // import 'web-animations-js'; // Run `npm install --save web-animations-js`. - +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ /*************************************************************************************************** * Zone JS is required by default for Angular itself. @@ -60,7 +80,6 @@ import 'core-js/es7/reflect'; import 'zone.js/dist/zone'; // Included with Angular CLI. - /*************************************************************************************************** * APPLICATION IMPORTS */ diff --git a/integration/cli-hello-world/tsconfig.json b/integration/cli-hello-world/tsconfig.json index a6c016bf38..41d317aa0a 100644 --- a/integration/cli-hello-world/tsconfig.json +++ b/integration/cli-hello-world/tsconfig.json @@ -7,6 +7,7 @@ "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, + "importHelpers": true, "target": "es5", "typeRoots": [ "node_modules/@types" diff --git a/integration/cli-hello-world/yarn.lock b/integration/cli-hello-world/yarn.lock index e51603b944..adf36cb33d 100644 --- a/integration/cli-hello-world/yarn.lock +++ b/integration/cli-hello-world/yarn.lock @@ -2,44 +2,52 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.10.3.tgz#6e4fd76ca41fbb3e5dc2a29f662ba3ee4d1ad086" - integrity sha512-6isM3knVRsdS3RTh43cwgOpvp5EIm5OswQuimNru+7uP8qhOBDQdRTd/w/HthmHylKPsEFPqEo1l2KoZCCSwvw== +"@angular-devkit/architect@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.1.tgz#397768d1ccd0cef76db96d6b39db8aebad68c031" + integrity sha512-1ozBP0ZAApkSfuPpZ7b9vShU8smNxb98jW+65S12cPOxv1bVVxCj5sTmC3sSfXapgq/pMzblbaVSKOG7Ajz0vQ== dependencies: - "@angular-devkit/core" "7.0.3" + "@angular-devkit/core" "7.2.1" rxjs "6.3.3" -"@angular-devkit/build-angular@~0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.10.3.tgz#610a174efaa9d70b68e966d59a29369ac1781369" - integrity sha512-gV/mLAckS1jaXfuAEaO7p9LqcMrVSmwC2ad85J/unJMqkkxTk7S9TgMe8/A3LIOJ1oZyIKniz/Q30JL092EqRA== +"@angular-devkit/architect@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.12.2.tgz#1bfa43881c8927b8e12ffd4a2a3a645d6356e748" + integrity sha512-32Eim3PM/CJKGcCF1FJQ91ohuF2vBGMd4t1DILaoOMXHWmPLI9N4ILzWHfqFLRvb8QFgLn4VNG7CI9K7GcSBlQ== dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/build-optimizer" "0.10.3" - "@angular-devkit/build-webpack" "0.10.3" - "@angular-devkit/core" "7.0.3" - "@ngtools/webpack" "7.0.3" - ajv "6.5.3" - autoprefixer "9.1.5" + "@angular-devkit/core" "7.2.2" + rxjs "6.3.3" + +"@angular-devkit/build-angular@~0.12.1": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.12.2.tgz#4776f535633227848c4bda34b1e8f89574c33746" + integrity sha512-4PDykCNDjjFo6Ximhq2efiufoUP6pj8KvhB8UI03mLbn/Os1W0y1lmiPJn+NjeBLwFWH9DqW9Vxk/pYek7MtEA== + dependencies: + "@angular-devkit/architect" "0.12.2" + "@angular-devkit/build-optimizer" "0.12.2" + "@angular-devkit/build-webpack" "0.12.2" + "@angular-devkit/core" "7.2.2" + "@ngtools/webpack" "7.2.2" + ajv "6.6.2" + autoprefixer "9.4.3" circular-dependency-plugin "5.0.2" clean-css "4.2.1" - copy-webpack-plugin "4.5.4" + copy-webpack-plugin "4.6.0" file-loader "2.0.0" glob "7.1.3" istanbul "0.4.5" istanbul-instrumenter-loader "3.0.1" karma-source-map-support "1.3.0" - less "3.8.1" + less "3.9.0" less-loader "4.1.0" - license-webpack-plugin "2.0.2" + license-webpack-plugin "2.0.4" loader-utils "1.1.0" - mini-css-extract-plugin "0.4.3" + mini-css-extract-plugin "0.4.4" minimatch "3.0.4" opn "5.3.0" parse5 "4.0.0" portfinder "1.0.17" - postcss "7.0.5" + postcss "7.0.11" postcss-import "12.0.0" postcss-loader "3.0.0" raw-loader "0.5.1" @@ -48,90 +56,98 @@ semver "5.5.1" source-map-loader "0.2.4" source-map-support "0.5.9" - speed-measure-webpack-plugin "^1.2.3" + speed-measure-webpack-plugin "1.2.5" stats-webpack-plugin "0.7.0" - style-loader "0.23.0" + style-loader "0.23.1" stylus "0.54.5" stylus-loader "3.0.2" - terser-webpack-plugin "1.1.0" + terser-webpack-plugin "1.2.1" tree-kill "1.2.0" - webpack "4.19.1" - webpack-dev-middleware "3.3.0" - webpack-dev-server "3.1.8" + webpack "4.28.4" + webpack-dev-middleware "3.4.0" + webpack-dev-server "3.1.14" webpack-merge "4.1.4" - webpack-sources "1.2.0" + webpack-sources "1.3.0" webpack-subresource-integrity "1.1.0-rc.6" optionalDependencies: - node-sass "4.9.3" + node-sass "4.10.0" -"@angular-devkit/build-optimizer@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.10.3.tgz#e649b9d715edbb8eb4779a4f5772cc5cd842700f" - integrity sha512-NgsS0kdUh/Op9+Kzbq0X6AsTV/BgpVtiF5UxZjdWVQgPPOdur5V9PkpRn9odey+06S/wDTE/UzPmT3qKXTQVHw== +"@angular-devkit/build-optimizer@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.12.2.tgz#c35f4a67a2304a4deeb8e5d2e6c1edde0429c309" + integrity sha512-5SARSE18X5/churU0Qc0gOfDt5EwuwKsJmIA7hHBzi44iotQm5c8ea0q0acua4/U4K+jOsF6A4Faa08Vr2624A== dependencies: loader-utils "1.1.0" source-map "0.5.6" - typescript "3.1.3" + typescript "3.2.2" webpack-sources "1.2.0" -"@angular-devkit/build-webpack@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.10.3.tgz#7bc42318f0d8cf71e52590a8a565b12d6fff67d0" - integrity sha512-2uZselfqpxnPbV9d2dRCgl4lJjD1xemNpRijxFIuxeXvadqTPkHA0YuUkX7CTajtwSWy3Cs69StL87b9gYFLSA== +"@angular-devkit/build-webpack@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.12.2.tgz#00f1a3a5ab3f4bc8e35d1826f8b476dc0016a1e7" + integrity sha512-Uv3f8XJc/5UTj2T7XjxFYDhuybFIIitLGxBpp/hEIc7eXI4MsJKB6CoDJy+2BQch7c/QjKH7W3dmTxzuSJ2j3g== dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/core" "7.0.3" + "@angular-devkit/architect" "0.12.2" + "@angular-devkit/core" "7.2.2" rxjs "6.3.3" -"@angular-devkit/core@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.0.3.tgz#b9d0ef27f125e81dabfdac0813d310be1d8d40d2" - integrity sha512-Yp0AhTuJbp0VwCHTmUOANrKZNQxTD/F49jPmSCBa/VMYMIoU/sUIiHVNdwzfcFnMoExGoXYah0kutBxgNIG3OA== +"@angular-devkit/core@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.1.tgz#8c6df59eab77bcc98a348c8cdf9eb217c8b751a5" + integrity sha512-zOozPswSM1cTkltw5LeSPoZ/fJ2d3vN304IVgKgrM5/Fs54bd7nTaBcAK+HvjKS+5KmykYrXW47Q4CdFJikluQ== dependencies: - ajv "6.5.3" + ajv "6.6.2" chokidar "2.0.4" fast-json-stable-stringify "2.0.0" rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/schematics@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.0.3.tgz#4bd58115899d4c8db682cdacdf86a78fc5a559b2" - integrity sha512-FhfPvn5hBCNSj39qLgVaSwa6Zl0qt3Uyw4B9M+Kv01/FFc9xrowldzNT4QRxBjjWbr6DssEP+tYQCPV3Ouwx5w== +"@angular-devkit/core@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.2.2.tgz#f0daf3e24f0ce8105341118f4505c1db4e284ab0" + integrity sha512-gDF8iXiPN870WuBMl7bCQ5+Qz5SjGL/qMcvP4hli5hkn+kMAhgG38ligUK1bbhPQUJ+Z/nSOEmyv8gLHO09SZg== dependencies: - "@angular-devkit/core" "7.0.3" + ajv "6.6.2" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.2.1.tgz#9c1c784f4a81a3a840fa4a1435948c6203be6062" + integrity sha512-jEhwkeDn8exgJBfUwMc6rdtDkxHJkUmKPTn4M436bkMMMa9KFPFbPpzp9weKpB3SbRjM3Mu90JprO4C7qDtCcg== + dependencies: + "@angular-devkit/core" "7.2.1" rxjs "6.3.3" "@angular/animations@file:../../dist/packages-dist/animations": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" -"@angular/cli@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-7.0.3.tgz#fcc41f9eaae2ee15d86115804f3dbb2bdb63a8c2" - integrity sha512-la1Jktl9qGqGLXDy43lTU1D8KkN0zAohD9mOq4ilgNigzpedXFbzsGXJdWv7xVBMG51M6uhw3HWuFprQmbwgIw== +"@angular/cli@file:../../node_modules/@angular/cli": + version "7.2.1" dependencies: - "@angular-devkit/architect" "0.10.3" - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - "@schematics/angular" "7.0.3" - "@schematics/update" "0.10.3" - inquirer "6.2.0" + "@angular-devkit/architect" "0.12.1" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + "@schematics/angular" "7.2.1" + "@schematics/update" "0.12.1" + inquirer "6.2.1" opn "5.3.0" - rxjs "6.3.3" semver "5.5.1" symbol-observable "1.2.0" "@angular/common@file:../../dist/packages-dist/common": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: - canonical-path "0.0.2" + canonical-path "1.0.0" chokidar "^1.4.2" convert-source-map "^1.5.1" dependency-graph "^0.7.2" @@ -140,74 +156,77 @@ reflect-metadata "^0.1.2" shelljs "^0.8.1" source-map "^0.6.1" + tslib "^1.9.0" yargs "9.0.1" "@angular/compiler@file:../../dist/packages-dist/compiler": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/core@file:../../dist/packages-dist/core": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/forms@file:../../dist/packages-dist/forms": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/http@file:../../dist/packages-dist/http": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/language-service@file:../../dist/packages-dist/language-service": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" "@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/router@file:../../dist/packages-dist/router": - version "7.1.0-beta.0-8a54e97b1" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" -"@ngtools/webpack@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.0.3.tgz#96bc0d94e9a8ac84eb34cf81c59fdd21bfbd18e3" - integrity sha512-8vllt35aCARPF8LJ3YfVpqTG39/vDLtY8+8LZqUKnOIlX9F0uzuQl86pmKoIAyk6sLPkR0SpaMGwYDunVjzxRQ== +"@ngtools/webpack@7.2.2": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-7.2.2.tgz#361d877f01feae800a58901b066b46539e1fe0e3" + integrity sha512-xjvQ8tlyyReE69q+whAubwX4fayPoy4NHSIDa429qdcUypkvhSScAtou003oVAKG519rznykDrUHAWtvFMVf4Q== dependencies: - "@angular-devkit/core" "7.0.3" + "@angular-devkit/core" "7.2.2" enhanced-resolve "4.1.0" rxjs "6.3.3" tree-kill "1.2.0" webpack-sources "1.2.0" -"@schematics/angular@7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.0.3.tgz#7a43800cbf5b8971071cbab653b553b6c67b8809" - integrity sha512-x367+yMZIyGL+XWcSELsjyv2x0sZWlEd/5uEGalFqH2Q8ViXkTnXWek7TzzGjt+APM8WfF2JUbrmb8yxZ2g99Q== +"@schematics/angular@7.2.1": + version "7.2.1" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.2.1.tgz#9eeab1354ec8d970121cc067e9636098ab84e152" + integrity sha512-UdqU8udVr693BZ6uaZ7+el/VFlTjrmp56OS+6YaziyAko84e1Q1Fcx+fwdHugy4V3YmQhTVsyOPSEsphnwSwOA== dependencies: - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - typescript "3.1.3" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + typescript "3.2.2" -"@schematics/update@0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.10.3.tgz#4bb7580b3e2f6af0689861bd0628d65a3eb0cd75" - integrity sha512-ExL2+qeQERihsYSJnOvIk10z1uWdh848bLla5Tb1SfH8Qwd16mmFhlBb4p6plK6/jL2zf9FndjV6dVwZ8iyOkA== +"@schematics/update@0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.12.1.tgz#44d853321ae8a56c43a579c0639d26d625001037" + integrity sha512-P92tDxy0AA1NPhaThiJ7fIFxIC4jzlGK7sJlpbnRREBImsI/O9gmGaV8Kjy+75vaEjqpWaU2oj1hnWqkmxSK1A== dependencies: - "@angular-devkit/core" "7.0.3" - "@angular-devkit/schematics" "7.0.3" - npm-registry-client "8.6.0" + "@angular-devkit/core" "7.2.1" + "@angular-devkit/schematics" "7.2.1" + "@yarnpkg/lockfile" "1.1.0" + ini "1.3.5" + pacote "9.1.1" rxjs "6.3.3" semver "5.5.1" semver-intersect "1.4.0" @@ -229,10 +248,10 @@ dependencies: "@types/jasmine" "*" -"@types/node@^6.0.46": - version "6.0.96" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.96.tgz#7bf0bf40d6ce51e93762cc47d010c8cc5ebb2179" - integrity sha512-fsOOY6tMQ3jCB2wD51XFDmmpgm4wVKkJECdcVRqapbJEa7awJDcr+SaH8toz+4r4KW8YQ3M7ybXMoSDo1QGewA== +"@types/node@*": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== "@types/node@~6.0.60": version "6.0.104" @@ -244,10 +263,15 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= -"@types/selenium-webdriver@^2.53.35", "@types/selenium-webdriver@~2.53.39": - version "2.53.43" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz#2de3d718819bc20165754c4a59afb7e9833f6707" - integrity sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg== +"@types/selenium-webdriver@^3.0.0": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.14.tgz#0b20a2370e6b1b8322c9c3dfcaa409e6c7c0c0a9" + integrity sha512-4GbNCDs98uHCT/OMv40qQC/OpoPbYn9XdXeTiFwHBBFO6eJhYEPUu2zDKirXSbHlvDV8oZ9l8EQ+HrEx/YS9DQ== + +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== "@types/strip-bom@^3.0.0": version "3.0.0" @@ -259,151 +283,156 @@ resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== -"@webassemblyjs/ast@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.6.tgz#3ef8c45b3e5e943a153a05281317474fef63e21e" - integrity sha512-8nkZS48EVsMUU0v6F1LCIOw4RYWLm2plMtbhFTjNgeXmsTNLuU3xTRtnljt9BFQB+iPbLRobkNrCWftWnNC7wQ== +"@types/webpack-sources@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" + integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== dependencies: - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" - mamacro "^0.0.3" + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" -"@webassemblyjs/floating-point-hex-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz#7cb37d51a05c3fe09b464ae7e711d1ab3837801f" - integrity sha512-VBOZvaOyBSkPZdIt5VBMg3vPWxouuM13dPXGWI1cBh3oFLNcFJ8s9YA7S9l4mPI7+Q950QqOmqj06oa83hNWBA== - -"@webassemblyjs/helper-api-error@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz#99b7e30e66f550a2638299a109dda84a622070ef" - integrity sha512-SCzhcQWHXfrfMSKcj8zHg1/kL9kb3aa5TN4plc/EREOs5Xop0ci5bdVBApbk2yfVi8aL+Ly4Qpp3/TRAUInjrg== - -"@webassemblyjs/helper-buffer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz#ba0648be12bbe560c25c997e175c2018df39ca3e" - integrity sha512-1/gW5NaGsEOZ02fjnFiU8/OEEXU1uVbv2um0pQ9YVL3IHSkyk6xOwokzyqqO1qDZQUAllb+V8irtClPWntbVqw== - -"@webassemblyjs/helper-code-frame@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz#5a94d21b0057b69a7403fca0c253c3aaca95b1a5" - integrity sha512-+suMJOkSn9+vEvDvgyWyrJo5vJsWSDXZmJAjtoUq4zS4eqHyXImpktvHOZwXp1XQjO5H+YQwsBgqTQEc0J/5zg== +"@webassemblyjs/ast@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" + integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA== dependencies: - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" -"@webassemblyjs/helper-fsm@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz#ae1741c6f6121213c7a0b587fb964fac492d3e49" - integrity sha512-HCS6KN3wgxUihGBW7WFzEC/o8Eyvk0d56uazusnxXthDPnkWiMv+kGi9xXswL2cvfYfeK5yiM17z2K5BVlwypw== +"@webassemblyjs/floating-point-hex-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" + integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg== -"@webassemblyjs/helper-module-context@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz#116d19a51a6cebc8900ad53ca34ff8269c668c23" - integrity sha512-e8/6GbY7OjLM+6OsN7f2krC2qYVNaSr0B0oe4lWdmq5sL++8dYDD1TFbD1TdAdWMRTYNr/Qq7ovXWzia2EbSjw== +"@webassemblyjs/helper-api-error@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" + integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg== + +"@webassemblyjs/helper-buffer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" + integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w== + +"@webassemblyjs/helper-code-frame@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" + integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw== dependencies: - mamacro "^0.0.3" + "@webassemblyjs/wast-printer" "1.7.11" -"@webassemblyjs/helper-wasm-bytecode@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz#98e515eaee611aa6834eb5f6a7f8f5b29fefb6f1" - integrity sha512-PzYFCb7RjjSdAOljyvLWVqd6adAOabJW+8yRT+NWhXuf1nNZWH+igFZCUK9k7Cx7CsBbzIfXjJc7u56zZgFj9Q== +"@webassemblyjs/helper-fsm@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" + integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A== -"@webassemblyjs/helper-wasm-section@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz#783835867bdd686df7a95377ab64f51a275e8333" - integrity sha512-3GS628ppDPSuwcYlQ7cDCGr4W2n9c4hLzvnRKeuz+lGsJSmc/ADVoYpm1ts2vlB1tGHkjtQMni+yu8mHoMlKlA== +"@webassemblyjs/helper-module-context@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" + integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg== + +"@webassemblyjs/helper-wasm-bytecode@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" + integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ== + +"@webassemblyjs/helper-wasm-section@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" + integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" -"@webassemblyjs/ieee754@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz#c34fc058f2f831fae0632a8bb9803cf2d3462eb1" - integrity sha512-V4cIp0ruyw+hawUHwQLn6o2mFEw4t50tk530oKsYXQhEzKR+xNGDxs/SFFuyTO7X3NzEu4usA3w5jzhl2RYyzQ== +"@webassemblyjs/ieee754@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" + integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.6.tgz#197f75376a29f6ed6ace15898a310d871d92f03b" - integrity sha512-ojdlG8WpM394lBow4ncTGJoIVZ4aAtNOWHhfAM7m7zprmkVcKK+2kK5YJ9Bmj6/ketTtOn7wGSHCtMt+LzqgYQ== +"@webassemblyjs/leb128@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" + integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw== dependencies: "@xtuc/long" "4.2.1" -"@webassemblyjs/utf8@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.6.tgz#eb62c66f906af2be70de0302e29055d25188797d" - integrity sha512-oId+tLxQ+AeDC34ELRYNSqJRaScB0TClUU6KQfpB8rNT6oelYlz8axsPhf6yPTg7PBJ/Z5WcXmUYiHEWgbbHJw== +"@webassemblyjs/utf8@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" + integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA== -"@webassemblyjs/wasm-edit@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz#fa41929160cd7d676d4c28ecef420eed5b3733c5" - integrity sha512-pTNjLO3o41v/Vz9VFLl+I3YLImpCSpodFW77pNoH4agn5I6GgSxXHXtvWDTvYJFty0jSeXZWLEmbaSIRUDlekg== +"@webassemblyjs/wasm-edit@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" + integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/helper-wasm-section" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-opt" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" - "@webassemblyjs/wast-printer" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/helper-wasm-section" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-opt" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + "@webassemblyjs/wast-printer" "1.7.11" -"@webassemblyjs/wasm-gen@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz#695ac38861ab3d72bf763c8c75e5f087ffabc322" - integrity sha512-mQvFJVumtmRKEUXMohwn8nSrtjJJl6oXwF3FotC5t6e2hlKMh8sIaW03Sck2MDzw9xPogZD7tdP5kjPlbH9EcQ== +"@webassemblyjs/wasm-gen@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" + integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" -"@webassemblyjs/wasm-opt@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz#fbafa78e27e1a75ab759a4b658ff3d50b4636c21" - integrity sha512-go44K90fSIsDwRgtHhX14VtbdDPdK2sZQtZqUcMRvTojdozj5tLI0VVJAzLCfz51NOkFXezPeVTAYFqrZ6rI8Q== +"@webassemblyjs/wasm-opt@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" + integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-buffer" "1.7.6" - "@webassemblyjs/wasm-gen" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" -"@webassemblyjs/wasm-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz#84eafeeff405ad6f4c4b5777d6a28ae54eed51fe" - integrity sha512-t1T6TfwNY85pDA/HWPA8kB9xA4sp9ajlRg5W7EKikqrynTyFo+/qDzIpvdkOkOGjlS6d4n4SX59SPuIayR22Yg== +"@webassemblyjs/wasm-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" + integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-wasm-bytecode" "1.7.6" - "@webassemblyjs/ieee754" "1.7.6" - "@webassemblyjs/leb128" "1.7.6" - "@webassemblyjs/utf8" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" -"@webassemblyjs/wast-parser@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz#ca4d20b1516e017c91981773bd7e819d6bd9c6a7" - integrity sha512-1MaWTErN0ziOsNUlLdvwS+NS1QWuI/kgJaAGAMHX8+fMJFgOJDmN/xsG4h/A1Gtf/tz5VyXQciaqHZqp2q0vfg== +"@webassemblyjs/wast-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" + integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/floating-point-hex-parser" "1.7.6" - "@webassemblyjs/helper-api-error" "1.7.6" - "@webassemblyjs/helper-code-frame" "1.7.6" - "@webassemblyjs/helper-fsm" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/floating-point-hex-parser" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-code-frame" "1.7.11" + "@webassemblyjs/helper-fsm" "1.7.11" "@xtuc/long" "4.2.1" - mamacro "^0.0.3" -"@webassemblyjs/wast-printer@1.7.6": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz#a6002c526ac5fa230fe2c6d2f1bdbf4aead43a5e" - integrity sha512-vHdHSK1tOetvDcl1IV1OdDeGNe/NDDQ+KzuZHMtqTVP1xO/tZ/IKNpj5BaGk1OYFdsDWQqb31PIwdEyPntOWRQ== +"@webassemblyjs/wast-printer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" + integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/wast-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" "@xtuc/long" "4.2.1" "@xtuc/ieee754@^1.2.0": @@ -416,6 +445,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== +"@yarnpkg/lockfile@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + JSONStream@^1.0.3: version "1.3.2" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" @@ -424,6 +458,14 @@ JSONStream@^1.0.3: jsonparse "^1.2.0" through ">=2.2.7 <3" +JSONStream@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -482,11 +524,6 @@ addressparser@1.0.1: resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" integrity sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y= -adm-zip@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" - integrity sha1-ph7VrmkFw66lizplfSUDMJEFJzY= - adm-zip@^0.4.7: version "0.4.7" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" @@ -505,6 +542,20 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" +agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + +agentkeepalive@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" + integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== + dependencies: + humanize-ms "^1.2.1" + ajv-errors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" @@ -515,10 +566,10 @@ ajv-keywords@^3.1.0: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" integrity sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74= -ajv@6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" - integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg== +ajv@6.6.2: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -603,6 +654,11 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -856,17 +912,17 @@ atob@^2.0.0: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.0.tgz#ab2b150e51d7b122b9efc8d7340c06b6c41076bc" integrity sha512-SuiKH8vbsOyCALjA/+EINmt/Kdl+TQPrtFgW7XZZcwtryFu9e5kQoX3bjCW6mIvGH1fbeAZZuvwGR5IlBRznGw== -autoprefixer@9.1.5: - version "9.1.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.1.5.tgz#8675fd8d1c0d43069f3b19a2c316f3524e4f6671" - integrity sha512-kk4Zb6RUc58ld7gdosERHMF3DzIYJc2fp5sX46qEsGXQQy5bXsu8qyLjoxuY1NuQ/cJuCYnx99BfjwnRggrYIw== +autoprefixer@9.4.3: + version "9.4.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.3.tgz#c97384a8fd80477b78049163a91bbc725d9c41d9" + integrity sha512-/XSnzDepRkAU//xLcXA/lUWxpsBuw0WiriAHOqnxkuCtzLhaz+fL4it4gp20BQ8n5SyLzK/FOc7A0+u/rti2FQ== dependencies: - browserslist "^4.1.0" - caniuse-lite "^1.0.30000884" + browserslist "^4.3.6" + caniuse-lite "^1.0.30000921" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.2" - postcss-value-parser "^3.2.3" + postcss "^7.0.6" + postcss-value-parser "^3.3.1" aws-sign2@~0.6.0: version "0.6.0" @@ -1067,10 +1123,10 @@ block-stream@*: dependencies: inherits "~2.0.0" -blocking-proxy@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-0.0.5.tgz#462905e0dcfbea970f41aa37223dda9c07b1912b" - integrity sha1-RikF4Nz76pcPQao3Ij3anAexkSs= +blocking-proxy@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" + integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA== dependencies: minimist "^1.2.0" @@ -1079,6 +1135,11 @@ bluebird@^3.3.0, bluebird@^3.4.6, bluebird@^3.5.1: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== +bluebird@^3.5.2, bluebird@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -1310,14 +1371,21 @@ browserify@^14.5.0: vm-browserify "~0.0.1" xtend "^4.0.0" -browserslist@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.3.4.tgz#4477b737db6a1b07077275b24791e680d4300425" - integrity sha512-u5iz+ijIMUlmV8blX82VGFrB9ecnUg5qEt55CMZ/YJEhha+d8qpBfOFuutJ6F/VKRXjZoD33b6uvarpPxcl3RA== +browserslist@^4.3.6: + version "4.4.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.0.tgz#7050d1412cbfc5274aba609ed5e50359ca1a5fdf" + integrity sha512-tQkHS8VVxWbrjnNDXgt7/+SuPJ7qDvD0Y2e6bLtoQluR2SPvlmPUcfcU75L1KAalhqULlIFJlJ6BDfnYyJxJsw== dependencies: - caniuse-lite "^1.0.30000899" - electron-to-chromium "^1.3.82" - node-releases "^1.0.1" + caniuse-lite "^1.0.30000928" + electron-to-chromium "^1.3.100" + node-releases "^1.1.3" + +browserstack@^1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.2.tgz#17d8bb76127a1cc0ea416424df80d218f803673f" + integrity sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg== + dependencies: + https-proxy-agent "^2.2.1" buffer-from@^1.0.0: version "1.0.0" @@ -1408,6 +1476,26 @@ cacache@^10.0.4: unique-filename "^1.1.0" y18n "^4.0.0" +cacache@^11.0.1, cacache@^11.2.0: + version "11.3.2" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa" + integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg== + dependencies: + bluebird "^3.5.3" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.3" + graceful-fs "^4.1.15" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.2" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + cacache@^11.0.2: version "11.2.0" resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.2.0.tgz#617bdc0b02844af56310e411c0878941d5739965" @@ -1481,15 +1569,15 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= -caniuse-lite@^1.0.30000884, caniuse-lite@^1.0.30000899: - version "1.0.30000903" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000903.tgz#86d46227759279b3db345ddbe778335dbba9e858" - integrity sha512-T1XVJEpGCoaq7MDw7/6hCdYUukmSaS+1l/OQJkLtw7Cr2+/+d67tNGKEbyiqf7Ck8x6EhNFUxjYFXXka0N/w5g== +caniuse-lite@^1.0.30000921, caniuse-lite@^1.0.30000928: + version "1.0.30000929" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000929.tgz#7b391b781a9c3097ecc39ea053301aea8ea16317" + integrity sha512-n2w1gPQSsYyorSVYqPMqbSaz1w7o9ZC8VhOEGI9T5MfGDzp7sbopQxG6GaQmYsaq13Xfx/mkxJUWC1Dz3oZfzw== -canonical-path@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-0.0.2.tgz#e31eb937a8c93ee2a01df1839794721902874574" - integrity sha1-4x65N6jJPuKgHfGDl5RyGQKHRXQ= +canonical-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" + integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== caseless@~0.11.0: version "0.11.0" @@ -1538,6 +1626,15 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -1603,6 +1700,11 @@ chownr@^1.0.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + chrome-trace-event@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz#45a91bd2c20c9411f0963b5aaeb9a1b95e09cc48" @@ -1792,7 +1894,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.12.1, commander@~2.13.0: +commander@^2.12.1: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA== @@ -1852,7 +1954,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0, concat-stream@^1.5.2: +concat-stream@^1.5.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -1957,10 +2059,10 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-webpack-plugin@4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.5.4.tgz#f2b2782b3cd5225535c3dc166a80067e7d940f27" - integrity sha512-0lstlEyj74OAtYMrDxlNZsU7cwFijAI3Ofz2fD6Mpo9r4xCv4yegfa3uHIKvZY1NSuOtE9nvG6TAhJ+uz9gDaQ== +copy-webpack-plugin@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.6.0.tgz#e7f40dd8a68477d405dd1b7a854aae324b158bae" + integrity sha512-Y+SQCF+0NoWQryez2zXn5J5knmr9z/9qSQt7fbL78u83rxmigOy8X5+BFn8CFSuX+nKT8gpYwJX68ekqtQt6ZA== dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -1984,6 +2086,11 @@ core-js@^2.4.0: "core-js@file:../../node_modules/core-js": version "2.5.7" +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2153,20 +2260,34 @@ date-now@^0.1.4: resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= -debug@*, debug@^3.1.0: +debug@*, debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: ms "2.0.0" -debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6, debug@~2.6.9: +debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6, debug@~2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" +debug@^3.2.5: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" @@ -2347,10 +2468,10 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -detect-node@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" - integrity sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc= +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== detective@^4.0.0: version "4.7.1" @@ -2461,10 +2582,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.82: - version "1.3.82" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" - integrity sha512-NI4nB2IWGcU4JVT1AE8kBb/dFor4zjLHMLsOROPahppeHrR0FG5uslxMmkp/thO1MvPjM2xhlKoY29/I60s0ew== +electron-to-chromium@^1.3.100: + version "1.3.103" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.103.tgz#a695777efdbc419cad6cbb0e58458251302cd52f" + integrity sha512-tObPqGmY9X8MUM8i3MEimYmbnLLf05/QV5gPlkR8MQ3Uj8G8B2govE1U4cQcBYtv3ymck9Y8cIOu4waoiykMZQ== elliptic@^6.0.0: version "6.4.0" @@ -2489,6 +2610,13 @@ encodeurl@~1.0.1, encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= + dependencies: + iconv-lite "~0.4.13" + end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" @@ -2552,6 +2680,11 @@ ent@~2.2.0: resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= +err-code@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" @@ -2573,6 +2706,23 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es6-promise@^4.0.3: + version "4.2.5" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" + integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg== + +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2667,12 +2817,12 @@ events@^1.0.0, events@~1.1.0: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= -eventsource@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-0.1.6.tgz#0acede849ed7dd1ccc32c811bb11b944d4f29232" - integrity sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI= +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== dependencies: - original ">=0.0.5" + original "^1.0.0" evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" @@ -2890,14 +3040,14 @@ faye-websocket@^0.10.0: dependencies: websocket-driver ">=0.5.1" -faye-websocket@~0.11.0: +faye-websocket@~0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.1.tgz#f0efe18c4f56e4f40afc7e06c719fd5ee6188f38" integrity sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg= dependencies: websocket-driver ">=0.5.1" -figgy-pudding@^3.1.0, figgy-pudding@^3.5.1: +figgy-pudding@^3.1.0, figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== @@ -3237,6 +3387,11 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" +genfun@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" + integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== + get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -3252,6 +3407,13 @@ get-stream@^3.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + get-uri@2: version "2.0.1" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.1.tgz#dbdcacacd8c608a38316869368117697a1631c59" @@ -3311,7 +3473,7 @@ glob@7.0.x: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.3: +glob@7.1.3, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -3406,15 +3568,20 @@ globule@^1.0.0: lodash "~4.17.4" minimatch "~3.0.2" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= -handle-thing@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" - integrity sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ= +graceful-fs@^4.1.15: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== handlebars@^4.0.1, handlebars@^4.0.3: version "4.0.11" @@ -3650,6 +3817,11 @@ htmlescape@^1.1.0: resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" integrity sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E= +http-cache-semantics@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -3689,6 +3861,14 @@ http-proxy-agent@1: debug "2" extend "3" +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + http-proxy-middleware@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz#0987e6bb5a5606e5a69168d8f967a87f15dd8aab" @@ -3743,7 +3923,7 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@1, https-proxy-agent@^1.0.0: +https-proxy-agent@1: version "1.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" integrity sha1-NffabEjOTdv6JkiRrFk+5f+GceY= @@ -3752,6 +3932,21 @@ https-proxy-agent@1, https-proxy-agent@^1.0.0: debug "2" extend "3" +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= + dependencies: + ms "^2.0.0" + iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -3762,7 +3957,7 @@ iconv-lite@0.4.19: resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== -iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -3796,6 +3991,11 @@ image-size@~0.5.0: resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -3868,7 +4068,7 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= -ini@^1.3.4, ini@~1.3.0: +ini@1.3.5, ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -3880,10 +4080,10 @@ inline-source-map@~0.6.0: dependencies: source-map "~0.5.3" -inquirer@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" - integrity sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg== +inquirer@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52" + integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -3896,7 +4096,7 @@ inquirer@6.2.0: run-async "^2.2.0" rxjs "^6.1.0" string-width "^2.1.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" through "^2.3.6" insert-module-globals@^7.0.0: @@ -4395,11 +4595,6 @@ jasmine-core@~2.8.0: resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= -jasmine-core@~2.9.0: - version "2.9.1" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.9.1.tgz#b6bbc1d8e65250d56f5888461705ebeeeb88f22f" - integrity sha1-trvB2OZSUNVvWIhGFwXr7uuI8i8= - jasmine-spec-reporter@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz#1d632aec0341670ad324f92ba84b4b32b35e9e22" @@ -4407,14 +4602,14 @@ jasmine-spec-reporter@~4.2.1: dependencies: colors "1.1.2" -jasmine@^2.5.3: - version "2.9.0" - resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.9.0.tgz#76571f925c8783409e7c6153572e5a6341cf93eb" - integrity sha1-dlcfklyHg0CefGFTVy5aY0HPk+s= +jasmine@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" + integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4= dependencies: exit "^0.1.2" glob "^7.0.6" - jasmine-core "~2.9.0" + jasmine-core "~2.8.0" jasminewd2@^2.1.0: version "2.2.0" @@ -4470,7 +4665,7 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= -json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== @@ -4544,6 +4739,17 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + karma-chrome-launcher@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" @@ -4679,10 +4885,10 @@ less-loader@4.1.0: loader-utils "^1.1.0" pify "^3.0.0" -less@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/less/-/less-3.8.1.tgz#f31758598ef5a1930dd4caefa9e4340641e71e1d" - integrity sha512-8HFGuWmL3FhQR0aH89escFNBQH/nEiYPP2ltDFdQw2chE28Yx2E3lhAIq9Y2saYwLSwa699s4dBVEfCY8Drf7Q== +less@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/less/-/less-3.9.0.tgz#b7511c43f37cf57dc87dffd9883ec121289b1474" + integrity sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w== dependencies: clone "^2.1.2" optionalDependencies: @@ -4729,13 +4935,21 @@ libqp@1.1.0: resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" integrity sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g= -license-webpack-plugin@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.0.2.tgz#9d34b521cb7fca8527945310b05be6ef0248b687" - integrity sha512-GsomZw5VoT20ST8qH2tOjBgbyhn6Pgs9M94g0mbvfBIV1VXufm1iKY+4dbgfTObj1Mp6nSRE3Zf74deOZr0KwA== +license-webpack-plugin@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.0.4.tgz#48532e7d7b45f6ceb21a68b6826ce7241d7ea6da" + integrity sha512-FQgOqrrIcD4C/VQo6ecWgXZULK5rs0kIDJtHcSVO6SBUrD63kEHZwmKOvBTquFQSgMQn/yeH68qooKDfqiBF2Q== dependencies: + "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -4878,7 +5092,7 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" -loud-rejection@^1.0.0, loud-rejection@^1.6.0: +loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= @@ -4899,6 +5113,14 @@ lru-cache@^4.0.1, lru-cache@^4.1.1: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^4.1.2: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + lru-cache@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" @@ -4907,6 +5129,13 @@ lru-cache@^4.1.3: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@~2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.6.5.tgz#e56d6354148ede8d7707b58d143220fd08df0fd5" @@ -4954,10 +5183,22 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.2.tgz#8762ffad2444dd8ff1f7c819629fa28e24fea1c4" integrity sha512-l9ra35l5VWLF24y75Tg8XgfGLX0ueRhph118WKM6H5denx4bB5QF59+4UAm9oJ2qsPQZas/CQUDdtDdfvYHBdQ== -mamacro@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" - integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== +make-fetch-happen@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083" + integrity sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ== + dependencies: + agentkeepalive "^3.4.1" + cacache "^11.0.1" + http-cache-semantics "^3.8.1" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.1" + lru-cache "^4.1.2" + mississippi "^3.0.0" + node-fetch-npm "^2.0.2" + promise-retry "^1.1.1" + socks-proxy-agent "^4.0.0" + ssri "^6.0.0" map-age-cleaner@^0.1.1: version "0.1.2" @@ -5148,10 +5389,10 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mini-css-extract-plugin@0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.3.tgz#98d60fcc5d228c3e36a9bd15a1d6816d6580beb8" - integrity sha512-Mxs0nxzF1kxPv4TRi2NimewgXlJqh0rGE30vviCU2WHrpbta6wklnUV9dr9FUtoAHmB3p3LeXEC+ZjgHvB0Dzg== +mini-css-extract-plugin@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.4.tgz#c10410a004951bd3cedac1da69053940fccb625d" + integrity sha512-o+Jm+ocb0asEngdM6FsZWtZsRzA8koFUudIDwYUfl94M3PejPHG7Vopw5hN9V8WsMkSFpm3tZP3Fesz89EyrfQ== dependencies: loader-utils "^1.1.0" schema-utils "^1.0.0" @@ -5197,6 +5438,14 @@ minipass@^2.2.1, minipass@^2.3.3: safe-buffer "^5.1.2" yallist "^3.0.0" +minipass@^2.3.4, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + minizlib@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" @@ -5204,6 +5453,13 @@ minizlib@^1.1.0: dependencies: minipass "^2.2.1" +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + mississippi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" @@ -5302,6 +5558,11 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +ms@^2.0.0, ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -5377,6 +5638,15 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-fetch-npm@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" + integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + dependencies: + encoding "^0.1.11" + json-parse-better-errors "^1.0.0" + safe-buffer "^5.1.1" + node-forge@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300" @@ -5462,17 +5732,17 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" -node-releases@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.0.2.tgz#27c296d9fca3b659c64f7d43ea47a31ad2a90e4b" - integrity sha512-zP8Asfg13lG9KDAW85rylSxXBYvaSdtjMIYKHUk8c1fM8drmFwRqbSYKYD+UlNVPUvrceSvgLUKHMOWR5jPWQg== +node-releases@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.3.tgz#aad9ce0dcb98129c753f772c0aa01360fb90fbd2" + integrity sha512-6VrvH7z6jqqNFY200kdB6HdzkgM96Oaj9v3dqGfgp6mF+cHmU4wyQKZ2/WPDRVoR0Jz9KqbamaBN0ZhdUaysUQ== dependencies: semver "^5.3.0" -node-sass@4.9.3: - version "4.9.3" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.3.tgz#f407cf3d66f78308bb1e346b24fa428703196224" - integrity sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww== +node-sass@4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.10.0.tgz#dcc2b364c0913630945ccbf7a2bbf1f926effca4" + integrity sha512-fDQJfXszw6vek63Fe/ldkYXmRYK/QS6NbvM3i5oEo9ntPDy4XX7BcKZyTKv+/kSSxRtXXc7l+MSwEmYc0CSy6Q== dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -5489,7 +5759,7 @@ node-sass@4.9.3: nan "^2.10.0" node-gyp "^3.8.0" npmlog "^4.0.0" - request "2.87.0" + request "^2.88.0" sass-graph "^2.2.4" stdout-stream "^1.4.0" "true-case-path" "^1.0.2" @@ -5570,7 +5840,7 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== @@ -5597,7 +5867,7 @@ npm-bundled@^1.0.1: resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== -"npm-package-arg@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0": +npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== @@ -5607,6 +5877,14 @@ npm-bundled@^1.0.1: semver "^5.5.0" validate-npm-package-name "^3.0.0" +npm-packlist@^1.1.12: + version "1.2.0" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.2.0.tgz#55a60e793e272f00862c7089274439a4cc31fc7f" + integrity sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-packlist@^1.1.6: version "1.1.11" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" @@ -5615,24 +5893,26 @@ npm-packlist@^1.1.6: ignore-walk "^3.0.1" npm-bundled "^1.0.1" -npm-registry-client@8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-8.6.0.tgz#7f1529f91450732e89f8518e0f21459deea3e4c4" - integrity sha512-Qs6P6nnopig+Y8gbzpeN/dkt+n7IyVd8f45NTMotGk6Qo7GfBmzwYx6jRLoOOgKiMnaQfYxsuyQlD8Mc3guBhg== +npm-pick-manifest@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40" + integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA== dependencies: - concat-stream "^1.5.2" - graceful-fs "^4.1.6" - normalize-package-data "~1.0.1 || ^2.0.0" - npm-package-arg "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" - once "^1.3.3" - request "^2.74.0" - retry "^0.10.0" - safe-buffer "^5.1.1" - semver "2 >=2.2.1 || 3.x || 4 || 5" - slide "^1.1.3" - ssri "^5.2.4" - optionalDependencies: - npmlog "2 || ^3.1.0 || ^4.0.0" + figgy-pudding "^3.5.1" + npm-package-arg "^6.0.0" + semver "^5.4.1" + +npm-registry-fetch@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.8.0.tgz#aa7d9a7c92aff94f48dba0984bdef4bd131c88cc" + integrity sha512-hrw8UMD+Nob3Kl3h8Z/YjmKamb1gf7D1ZZch2otrIXM3uFLB5vjEY6DhMlq80z/zZet6eETLbOXcuQudCB3Zpw== + dependencies: + JSONStream "^1.3.4" + bluebird "^3.5.1" + figgy-pudding "^3.4.1" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + npm-package-arg "^6.1.0" npm-run-path@^2.0.0: version "2.0.2" @@ -5641,7 +5921,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.0, npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -5717,7 +5997,7 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" -obuf@^1.0.0, obuf@^1.1.1: +obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== @@ -5775,12 +6055,7 @@ optionator@^0.8.1: type-check "~0.3.2" wordwrap "~1.0.0" -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - integrity sha1-7CLTEoBrtT5zF3Pnza788cZDEo8= - -original@>=0.0.5: +original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== @@ -5919,6 +6194,44 @@ pac-resolver@~2.0.0: netmask "~1.0.4" thunkify "~2.1.1" +pacote@9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.1.1.tgz#25091f75a25021de8be8d34cc6408728fca3579b" + integrity sha512-f28Rq5ozzKAA9YwIKw61/ipwAatUZseYmVssDbHHaexF0wRIVotapVEZPAjOT7Eu3LYVqEp0NVpNizoAnYBUaA== + dependencies: + bluebird "^3.5.2" + cacache "^11.2.0" + figgy-pudding "^3.5.1" + get-stream "^4.1.0" + glob "^7.1.3" + lru-cache "^4.1.3" + make-fetch-happen "^4.0.1" + minimatch "^3.0.4" + minipass "^2.3.5" + mississippi "^3.0.0" + mkdirp "^0.5.1" + normalize-package-data "^2.4.0" + npm-package-arg "^6.1.0" + npm-packlist "^1.1.12" + npm-pick-manifest "^2.1.0" + npm-registry-fetch "^3.8.0" + osenv "^0.1.5" + promise-inflight "^1.0.1" + promise-retry "^1.1.1" + protoduck "^5.0.1" + rimraf "^2.6.2" + safe-buffer "^5.1.2" + semver "^5.6.0" + ssri "^6.0.1" + tar "^4.4.6" + unique-filename "^1.1.1" + which "^1.3.1" + +pako@~1.0.2: + version "1.0.8" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4" + integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA== + pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" @@ -6205,7 +6518,21 @@ postcss-value-parser@^3.2.3: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" integrity sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU= -postcss@7.0.5, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2: +postcss-value-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss@7.0.11: + version "7.0.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.11.tgz#f63c513b78026d66263bb2ca995bf02e3d1a697d" + integrity sha512-9AXb//5UcjeOEof9T+yPw3XTa5SL207ZOIC/lHYP4mbUTEh4M0rDAQekQpVANCZdwQwKhBtFZCk3i3h3h2hdWg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +postcss@^7.0.0, postcss@^7.0.1: version "7.0.5" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.5.tgz#70e6443e36a6d520b0fd4e7593fcca3635ee9f55" integrity sha512-HBNpviAUFCKvEh7NZhw1e8MBPivRszIiUnhrJ+sBFVSYSqubrzwX3KG51mYgcRHX8j/cAgZJedONZcm5jTBdgQ== @@ -6214,6 +6541,15 @@ postcss@7.0.5, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2: source-map "^0.6.1" supports-color "^5.5.0" +postcss@^7.0.6: + version "7.0.13" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.13.tgz#42bf716413e8f1c786ab71dc6e722b3671b16708" + integrity sha512-h8SY6kQTd1wISHWjz+E6cswdhMuyBZRb16pSTv3W4zYZ3/YbyWeJdNUeOXB5IdZqE1U76OUEjjjqsC3z2f3hVg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -6244,6 +6580,14 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise-retry@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" + integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= + dependencies: + err-code "^1.0.0" + retry "^0.10.0" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -6251,23 +6595,30 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -"protractor@file:../../node_modules/protractor": - version "5.1.2" +protoduck@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" + integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== + dependencies: + genfun "^5.0.0" + +"protractor@file:../../node_modules/protractor": + version "5.4.2" dependencies: - "@types/node" "^6.0.46" "@types/q" "^0.0.32" - "@types/selenium-webdriver" "~2.53.39" - blocking-proxy "0.0.5" + "@types/selenium-webdriver" "^3.0.0" + blocking-proxy "^1.0.0" + browserstack "^1.5.1" chalk "^1.1.3" glob "^7.0.3" - jasmine "^2.5.3" + jasmine "2.8.0" jasminewd2 "^2.1.0" optimist "~0.6.0" q "1.4.1" - saucelabs "~1.3.0" - selenium-webdriver "3.0.1" + saucelabs "^1.5.0" + selenium-webdriver "3.6.0" source-map-support "~0.4.0" - webdriver-js-extender "^1.0.0" + webdriver-js-extender "2.1.0" webdriver-manager "^12.0.6" proxy-addr@~2.0.3: @@ -6519,7 +6870,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -6555,7 +6906,16 @@ readable-stream@2, readable-stream@^2.3.0: string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@~2.0.0, readable-stream@~2.0.5: +readable-stream@^3.0.6: + version "3.1.1" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.1.1.tgz#ed6bbc6c5ba58b090039ff18ce670515795aeb06" + integrity sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~2.0.0, readable-stream@~2.0.5, readable-stream@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= @@ -6744,32 +7104,6 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - request@^2.0.0, request@^2.74.0, request@^2.78.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" @@ -6826,7 +7160,7 @@ request@^2.83.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@^2.87.0: +request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -7035,23 +7369,18 @@ sass-loader@7.1.0: pify "^3.0.0" semver "^5.5.0" -saucelabs@~1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.3.0.tgz#d240e8009df7fa87306ec4578a69ba3b5c424fee" - integrity sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4= +saucelabs@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" + integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== dependencies: - https-proxy-agent "^1.0.0" + https-proxy-agent "^2.2.1" sax@0.5.x: version "0.5.8" resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= -sax@0.6.x: - version "0.6.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" - integrity sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk= - sax@>=0.6.0, sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -7072,14 +7401,6 @@ schema-utils@^0.4.4: ajv "^6.1.0" ajv-keywords "^3.1.0" -schema-utils@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e" - integrity sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA== - dependencies: - ajv "^6.1.0" - ajv-keywords "^3.1.0" - schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -7102,27 +7423,16 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -selenium-webdriver@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz#a2dea5da4a97f6672e89e7ca7276cefa365147a7" - integrity sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c= +selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q== dependencies: - adm-zip "^0.4.7" + jszip "^3.1.3" rimraf "^2.5.4" tmp "0.0.30" xml2js "^0.4.17" -selenium-webdriver@^2.53.2: - version "2.53.3" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz#d29ff5a957dff1a1b49dc457756e4e4bfbdce085" - integrity sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU= - dependencies: - adm-zip "0.4.4" - rimraf "^2.2.8" - tmp "0.0.24" - ws "^1.0.1" - xml2js "0.4.4" - selfsigned@^1.9.1: version "1.10.2" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.2.tgz#b4449580d99929b65b10a48389301a6592088758" @@ -7144,16 +7454,21 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" -"semver@2 >=2.2.1 || 3.x || 4 || 5", semver@5.5.1, semver@^5.5.0: - version "5.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== - "semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== +semver@5.5.1, semver@^5.5.0: + version "5.5.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" + integrity sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw== + +semver@^5.4.1, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" @@ -7337,16 +7652,16 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= -slide@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - smart-buffer@^1.0.13, smart-buffer@^1.0.4: version "1.1.15" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-1.1.15.tgz#7f114b5b65fab3e2a35aa775bb12f0d1c649bf16" integrity sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY= +smart-buffer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" + integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== + smtp-connection@2.12.0: version "2.12.0" resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.12.0.tgz#d76ef9127cb23c2259edb1e8349c2e8d5e2d74c1" @@ -7444,17 +7759,17 @@ socket.io@2.0.4: socket.io-client "2.0.4" socket.io-parser "~3.1.1" -sockjs-client@1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.5.tgz#1bb7c0f7222c40f42adf14f4442cbd1269771a83" - integrity sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM= +sockjs-client@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177" + integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg== dependencies: - debug "^2.6.6" - eventsource "0.1.6" - faye-websocket "~0.11.0" - inherits "^2.0.1" + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" json3 "^3.3.2" - url-parse "^1.1.8" + url-parse "^1.4.3" sockjs@0.3.19: version "0.3.19" @@ -7473,6 +7788,14 @@ socks-proxy-agent@2: extend "3" socks "~1.1.5" +socks-proxy-agent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + integrity sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw== + dependencies: + agent-base "~4.2.0" + socks "~2.2.0" + socks@1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/socks/-/socks-1.1.9.tgz#628d7e4d04912435445ac0b6e459376cb3e6d691" @@ -7489,6 +7812,14 @@ socks@~1.1.5: ip "^1.1.4" smart-buffer "^1.0.13" +socks@~2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.2.tgz#f061219fc2d4d332afb4af93e865c84d3fa26e2b" + integrity sha512-g6wjBnnMOZpE0ym6e0uHSddz9p3a+WsBaaYQaBaSCJYvrC4IXykQR9MNGjLQf38e9iIIhp3b1/Zk8YZI3KGJ0Q== + dependencies: + ip "^1.1.5" + smart-buffer "^4.0.1" + source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" @@ -7617,35 +7948,33 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== -spdy-transport@^2.0.18: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.0.tgz#4bbb15aaffed0beefdd56ad61dbdc8ba3e2cb7a1" - integrity sha512-bpUeGpZcmZ692rrTiqf9/2EUakI6/kXX1Rpe0ib/DyOzbiexVfXkw6GnvI9hVGvIwVaUhkaBojjCZwLNRGQg1g== +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== dependencies: - debug "^2.6.8" - detect-node "^2.0.3" + debug "^4.1.0" + detect-node "^2.0.4" hpack.js "^2.1.6" - obuf "^1.1.1" - readable-stream "^2.2.9" - safe-buffer "^5.0.1" - wbuf "^1.7.2" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" -spdy@^3.4.1: - version "3.4.7" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc" - integrity sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw= +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== dependencies: - debug "^2.6.8" - handle-thing "^1.2.5" + debug "^4.1.0" + handle-thing "^2.0.0" http-deceiver "^1.2.7" - safe-buffer "^5.0.1" select-hose "^2.0.0" - spdy-transport "^2.0.18" + spdy-transport "^3.0.0" -speed-measure-webpack-plugin@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.2.3.tgz#de170b5cefbfa1c039d95e639edd3ad50cfc7c48" - integrity sha512-p+taQ69VkRUXYMoZOx2nxV/Tz8tt79ahctoZJyJDHWP7fEYvwFNf5Pd73k5kZ6auu0pTsPNLEUwWpM8mCk85Zw== +speed-measure-webpack-plugin@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.2.5.tgz#8179936eb8c5e891f7481bd5075a9ea9a0f74823" + integrity sha512-S/guYjC4Izn5wY2d0+M4zowED/F77Lxh9yjkTZ+XAr244pr9c1MYNcXcRe9lx2hmAj0GPbOrBXgOF2YIp/CZ8A== dependencies: chalk "^2.0.1" @@ -7688,7 +8017,7 @@ ssri@^5.2.4: dependencies: safe-buffer "^5.1.1" -ssri@^6.0.0: +ssri@^6.0.0, ssri@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== @@ -7825,6 +8154,13 @@ string_decoder@^1.0.0, string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -7856,6 +8192,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + integrity sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow== + dependencies: + ansi-regex "^4.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -7885,13 +8228,13 @@ strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -style-loader@0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.0.tgz#8377fefab68416a2e05f1cabd8c3a3acfcce74f1" - integrity sha512-uCcN7XWHkqwGVt7skpInW6IGO1tG6ReyFQ1Cseh0VcN6VdcFQi62aG/2F3Y9ueA8x4IVlfaSUxpmQXQD9QrEuQ== +style-loader@0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" + integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== dependencies: loader-utils "^1.1.0" - schema-utils "^0.4.5" + schema-utils "^1.0.0" stylus-loader@3.0.2: version "3.0.2" @@ -7947,6 +8290,13 @@ supports-color@^5.5.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + symbol-observable@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -8005,10 +8355,23 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" -terser-webpack-plugin@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz#cf7c25a1eee25bf121f4a587bb9e004e3f80e528" - integrity sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA== +tar@^4.4.6: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +terser-webpack-plugin@1.2.1, terser-webpack-plugin@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz#7545da9ae5f4f9ae6a0ac961eb46f5e7c845cc26" + integrity sha512-GGSt+gbT0oKcMDmPx4SRSfJPE1XaN3kQRWG4ghxKQw9cn5G9x6aCKSsgYdvyM0na9NJ4Drv0RG6jbBByZ5CMjw== dependencies: cacache "^11.0.2" find-cache-dir "^2.0.0" @@ -8070,11 +8433,6 @@ timespan@2.3.x: resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" integrity sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk= -tmp@0.0.24: - version "0.0.24" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" - integrity sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI= - tmp@0.0.30: version "0.0.30" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" @@ -8197,6 +8555,11 @@ tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ== +tslib@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + tslint@~5.9.1: version "5.9.1" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae" @@ -8269,21 +8632,13 @@ typedarray@^0.0.6, typedarray@~0.0.5: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" - integrity sha512-+81MUSyX+BaSo+u2RbozuQk/UWx6hfG0a5gHu4ANEM4sU96XbuIyAB+rWBW1u70c6a5QuZfuYICn3s2UjuHUpA== +typescript@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" + integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== "typescript@file:../../node_modules/typescript": - version "3.1.1" - -uglify-es@^3.3.4: - version "3.3.9" - resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" - integrity sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ== - dependencies: - commander "~2.13.0" - source-map "~0.6.1" + version "3.2.2" uglify-js@^2.6: version "2.8.29" @@ -8300,30 +8655,11 @@ uglify-to-browserify@~1.0.0: resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= -uglifyjs-webpack-plugin@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz#5eec941b2e9b8538be0a20fc6eda25b14c7c1043" - integrity sha512-z0IbjpW8b3O/OVn+TTZN4pI29RN1zktFBXLIzzfZ+++cUtZ1ERSlLWgpE/5OERuEUs1ijVQnpYAkSlpoVmQmSQ== - dependencies: - cacache "^10.0.4" - find-cache-dir "^1.0.0" - schema-utils "^0.4.5" - serialize-javascript "^1.4.0" - source-map "^0.6.1" - uglify-es "^3.3.4" - webpack-sources "^1.1.0" - worker-farm "^1.5.2" - uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= -ultron@1.0.x: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= - ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" @@ -8356,6 +8692,13 @@ unique-filename@^1.1.0: dependencies: unique-slug "^2.0.0" +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + unique-slug@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" @@ -8400,12 +8743,7 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-join@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a" - integrity sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo= - -url-parse@^1.1.8, url-parse@^1.4.3: +url-parse@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.3.tgz#bfaee455c889023219d757e045fa6a684ec36c15" integrity sha512-rh+KuAW36YKo0vClhQzLLveoj8FwPJNu65xLb7Mrt+eZht0IPT0IXgSv8gcMegZ6NvjJUALf6Mf25POlMwD1Fw== @@ -8436,7 +8774,7 @@ useragent@^2.1.12: lru-cache "2.2.x" tmp "0.0.x" -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -8525,20 +8863,20 @@ watchpack@^1.5.0: graceful-fs "^4.1.2" neo-async "^2.5.0" -wbuf@^1.1.0, wbuf@^1.7.2: +wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== dependencies: minimalistic-assert "^1.0.0" -webdriver-js-extender@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515" - integrity sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU= +webdriver-js-extender@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" + integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ== dependencies: - "@types/selenium-webdriver" "^2.53.35" - selenium-webdriver "^2.53.2" + "@types/selenium-webdriver" "^3.0.0" + selenium-webdriver "^3.0.1" webdriver-manager@^12.0.6: version "12.0.6" @@ -8565,35 +8903,20 @@ webpack-core@^0.6.8: source-list-map "~0.1.7" source-map "~0.4.1" -webpack-dev-middleware@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.2.0.tgz#a20ceef194873710052da678f3c6ee0aeed92552" - integrity sha512-YJLMF/96TpKXaEQwaLEo+Z4NDK8aV133ROF6xp9pe3gQoS7sxfpXh4Rv9eC+8vCvWfmDjRQaMSlRPbO+9G6jgA== +webpack-dev-middleware@3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz#1132fecc9026fd90f0ecedac5cbff75d1fb45890" + integrity sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA== dependencies: - loud-rejection "^1.6.0" - memory-fs "~0.4.1" - mime "^2.3.1" - path-is-absolute "^1.0.0" - range-parser "^1.0.3" - url-join "^4.0.0" - webpack-log "^2.0.0" - -webpack-dev-middleware@3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.3.0.tgz#8104daf4d4f65defe06ee2eaaeea612a7c541462" - integrity sha512-5C5gXtOo1I6+0AEg4UPglYEtu3Rai6l5IiO6aUu65scHXz29dc3oIWMiRwvcNLXgL0HwRkRxa9N02ZjFt4hY8w== - dependencies: - loud-rejection "^1.6.0" memory-fs "~0.4.1" mime "^2.3.1" range-parser "^1.0.3" - url-join "^4.0.0" webpack-log "^2.0.0" -webpack-dev-server@3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.8.tgz#eb7a95945d1108170f902604fb3b939533d9daeb" - integrity sha512-c+tcJtDqnPdxCAzEEZKdIPmg3i5i7cAHe+B+0xFNK0BlCc2HF/unYccbU7xTgfGc5xxhCztCQzFmsqim+KhI+A== +webpack-dev-server@3.1.14: + version "3.1.14" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.14.tgz#60fb229b997fc5a0a1fc6237421030180959d469" + integrity sha512-mGXDgz5SlTxcF3hUpfC8hrQ11yhAttuUQWf1Wmb+6zo3x6rb7b9mIfuQvAPLdfDRCGRGvakBWHdHOa0I9p/EVQ== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -8614,13 +8937,15 @@ webpack-dev-server@3.1.8: portfinder "^1.0.9" schema-utils "^1.0.0" selfsigned "^1.9.1" + semver "^5.6.0" serve-index "^1.7.2" sockjs "0.3.19" - sockjs-client "1.1.5" - spdy "^3.4.1" + sockjs-client "1.3.0" + spdy "^4.0.0" strip-ansi "^3.0.0" supports-color "^5.1.0" - webpack-dev-middleware "3.2.0" + url "^0.11.0" + webpack-dev-middleware "3.4.0" webpack-log "^2.0.0" yargs "12.0.2" @@ -8647,18 +8972,18 @@ webpack-sources@1.2.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" - integrity sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw== +webpack-sources@1.3.0, webpack-sources@^1.2.0, webpack-sources@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" - integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== +webpack-sources@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + integrity sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw== dependencies: source-list-map "^2.0.0" source-map "~0.6.1" @@ -8670,15 +8995,15 @@ webpack-subresource-integrity@1.1.0-rc.6: dependencies: webpack-core "^0.6.8" -webpack@4.19.1: - version "4.19.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.19.1.tgz#096674bc3b573f8756c762754366e5b333d6576f" - integrity sha512-j7Q/5QqZRqIFXJvC0E59ipLV5Hf6lAnS3ezC3I4HMUybwEDikQBVad5d+IpPtmaQPQArvgUZLXIN6lWijHBn4g== +webpack@4.28.4: + version "4.28.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.28.4.tgz#1ddae6c89887d7efb752adf0c3cd32b9b07eacd0" + integrity sha512-NxjD61WsK/a3JIdwWjtIpimmvE6UrRi3yG54/74Hk9rwNj5FPkA4DJCf1z4ByDWLkvZhTZE+P3C/eh6UD5lDcw== dependencies: - "@webassemblyjs/ast" "1.7.6" - "@webassemblyjs/helper-module-context" "1.7.6" - "@webassemblyjs/wasm-edit" "1.7.6" - "@webassemblyjs/wasm-parser" "1.7.6" + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/wasm-edit" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" acorn "^5.6.2" acorn-dynamic-import "^3.0.0" ajv "^6.1.0" @@ -8696,9 +9021,9 @@ webpack@4.19.1: node-libs-browser "^2.0.0" schema-utils "^0.4.4" tapable "^1.1.0" - uglifyjs-webpack-plugin "^1.2.4" + terser-webpack-plugin "^1.1.0" watchpack "^1.5.0" - webpack-sources "^1.2.0" + webpack-sources "^1.3.0" websocket-driver@>=0.5.1: version "0.7.0" @@ -8740,6 +9065,13 @@ which@1, which@^1.1.1, which@^1.2.1, which@^1.2.9: dependencies: isexe "^2.0.0" +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -8787,14 +9119,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" - integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w== - dependencies: - options ">=0.0.5" - ultron "1.0.x" - ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -8804,14 +9128,6 @@ ws@~3.3.1: safe-buffer "~5.1.0" ultron "~1.1.0" -xml2js@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d" - integrity sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0= - dependencies: - sax "0.6.x" - xmlbuilder ">=1.0.0" - xml2js@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" @@ -8820,7 +9136,7 @@ xml2js@^0.4.17: sax ">=0.6.0" xmlbuilder "~9.0.1" -xmlbuilder@>=1.0.0, xmlbuilder@~9.0.1: +xmlbuilder@~9.0.1: version "9.0.4" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" integrity sha1-UZy0ymhtAFqEINNJbz8MruzKWA8= diff --git a/integration/dynamic-compiler/package.json b/integration/dynamic-compiler/package.json index 71f48d5a38..3031bf2f21 100644 --- a/integration/dynamic-compiler/package.json +++ b/integration/dynamic-compiler/package.json @@ -10,7 +10,7 @@ "ngc": "ngc -p tsconfig.json", "rollup": "rollup -f iife -c rollup.config.js -o dist/bundle.es2015.js", "rollup:lazy": "rollup -f cjs -c rollup.lazy.config.js -o dist/lazy.bundle.es2015.js", - "postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG", + "postinstall": "webdriver-manager update --gecko false --standalone false $CI_CHROMEDRIVER_VERSION_ARG", "preprotractor": "tsc -p e2e", "protractor": "protractor e2e/protractor.config.js", "serve": "lite-server -c e2e/browser.config.json", diff --git a/integration/dynamic-compiler/rollup.config.js b/integration/dynamic-compiler/rollup.config.js index 0df72458fd..38a6e130e8 100644 --- a/integration/dynamic-compiler/rollup.config.js +++ b/integration/dynamic-compiler/rollup.config.js @@ -1,10 +1,11 @@ import nodeResolve from 'rollup-plugin-node-resolve'; export default { - entry: 'dist/src/main.js', - sourceMap: true, + input: 'dist/src/main.js', + output: { + sourceMap: true, + }, treeshake: true, - moduleName: 'main', plugins: [ nodeResolve() ] diff --git a/integration/dynamic-compiler/rollup.lazy.config.js b/integration/dynamic-compiler/rollup.lazy.config.js index 85b82b9214..94be6e1a48 100644 --- a/integration/dynamic-compiler/rollup.lazy.config.js +++ b/integration/dynamic-compiler/rollup.lazy.config.js @@ -4,10 +4,11 @@ import commonjs from 'rollup-plugin-commonjs'; // a real app should make a common bundle for libraries instead of bundling them // in both the main module & the lazy module, but we don't care about size here export default { - entry: 'dist/src/lazy.module.js', - sourceMap: true, + input: 'dist/src/lazy.module.js', + output: { + sourceMap: true, + }, treeshake: true, - moduleName: 'lazy', plugins: [ nodeResolve() ] diff --git a/integration/dynamic-compiler/yarn.lock b/integration/dynamic-compiler/yarn.lock index b9d169b0b3..9ca3370a8c 100644 --- a/integration/dynamic-compiler/yarn.lock +++ b/integration/dynamic-compiler/yarn.lock @@ -3,64 +3,88 @@ "@angular/animations@file:../../dist/packages-dist/animations": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/common@file:../../dist/packages-dist/common": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: + canonical-path "1.0.0" chokidar "^1.4.2" + convert-source-map "^1.5.1" + dependency-graph "^0.7.2" + magic-string "^0.25.0" minimist "^1.2.0" reflect-metadata "^0.1.2" - tsickle "^0.29.0" + shelljs "^0.8.1" + source-map "^0.6.1" + tslib "^1.9.0" + yargs "9.0.1" "@angular/compiler@file:../../dist/packages-dist/compiler": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/core@file:../../dist/packages-dist/core": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: tslib "^1.9.0" "@angular/platform-server@file:../../dist/packages-dist/platform-server": - version "6.0.0-rc.5" + version "8.0.0-beta.0" dependencies: - domino "^2.0.1" + domino "^2.1.0" tslib "^1.9.0" xhr2 "^0.1.4" -"@types/jasmine@file:../../node_modules/@types/jasmine": - version "2.2.22-alpha" +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== -"@types/node@^6.0.46": - version "6.0.96" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.96.tgz#7bf0bf40d6ce51e93762cc47d010c8cc5ebb2179" +"@types/jasmine@*": + version "3.3.5" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.3.5.tgz#3738ffbf34dffae9ecaac4503d7d969744f0e1d7" + integrity sha512-LJtc52O1PNUffMvH6Q3fS0BOhQWYlkh3SVu/Jc4GoPgJkUytk5Y6YPbw+6lZK2mWWvG62BtVyOFw0ih7r8STsw== + +"@types/jasmine@file:../../node_modules/@types/jasmine": + version "2.8.8" + +"@types/jasminewd2@file:../../node_modules/@types/jasminewd2": + version "2.0.4" + dependencies: + "@types/jasmine" "*" + +"@types/node@*": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== "@types/q@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" -"@types/selenium-webdriver@^2.53.35", "@types/selenium-webdriver@~2.53.39": - version "2.53.43" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz#2de3d718819bc20165754c4a59afb7e9833f6707" +"@types/selenium-webdriver@^3.0.0": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.14.tgz#0b20a2370e6b1b8322c9c3dfcaa409e6c7c0c0a9" + integrity sha512-4GbNCDs98uHCT/OMv40qQC/OpoPbYn9XdXeTiFwHBBFO6eJhYEPUu2zDKirXSbHlvDV8oZ9l8EQ+HrEx/YS9DQ== abbrev@1: version "1.1.1" @@ -84,9 +108,10 @@ acorn@^4.0.1: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -adm-zip@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" +acorn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.5.tgz#81730c0815f3f3b34d8efa95cb7430965f4d887a" + integrity sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg== adm-zip@^0.4.7: version "0.4.7" @@ -96,12 +121,12 @@ after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -agent-base@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" +agent-base@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== dependencies: - extend "~3.0.0" - semver "~5.0.1" + es6-promisify "^5.0.0" ajv@^4.9.1: version "4.11.8" @@ -127,6 +152,11 @@ ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -275,9 +305,10 @@ block-stream@*: dependencies: inherits "~2.0.0" -blocking-proxy@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-0.0.5.tgz#462905e0dcfbea970f41aa37223dda9c07b1912b" +blocking-proxy@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" + integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA== dependencies: minimist "^1.2.0" @@ -314,12 +345,6 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -browser-resolve@^1.11.0: - version "1.11.2" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" - dependencies: - resolve "1.1.7" - browser-sync-ui@v1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/browser-sync-ui/-/browser-sync-ui-1.0.1.tgz#9740527b26d1d7ace259acc0c79e5b5e37d0fdf2" @@ -363,14 +388,26 @@ browser-sync@^2.12.3: ua-parser-js "0.7.12" yargs "6.4.0" +browserstack@^1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.2.tgz#17d8bb76127a1cc0ea416424df80d218f803673f" + integrity sha512-+6AFt9HzhKykcPF79W6yjEUJcdvZOV0lIXdkORXMJftGrDl0OKWqRF4GHqpDNkxiceDT/uB7Fb/aDwktvXX7dg== + dependencies: + https-proxy-agent "^2.2.1" + bs-recipes@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/bs-recipes/-/bs-recipes-1.3.4.tgz#0d2d4d48a718c8c044769fdc4f89592dc8b69585" -builtin-modules@^1.0.0, builtin-modules@^1.1.0: +builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" +builtin-modules@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.0.0.tgz#1e587d44b006620d90286cc7a9238bbc6129cab1" + integrity sha512-hMIeU4K2ilbXV6Uv93ZZ0Avg/M91RaKXucQ+4me2Do1txxBDyDZWCBa5bJSLqoNTRpXTLwEzIk1KmloenDDjhg== + callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" @@ -383,6 +420,16 @@ camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +canonical-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" + integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -504,17 +551,38 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" +convert-source-map@^1.5.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" "core-js@file:../../node_modules/core-js": - version "2.5.1" + version "2.5.7" + +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" @@ -537,12 +605,6 @@ date-fns@^1.23.0: version "1.29.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" -debug@2, debug@^2.2.0, debug@~2.6.4, debug@~2.6.6, debug@~2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - debug@2.6.4: version "2.6.4" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" @@ -555,6 +617,19 @@ debug@2.6.8: dependencies: ms "2.0.0" +debug@^2.2.0, debug@~2.6.4, debug@~2.6.6, debug@~2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" @@ -597,6 +672,11 @@ depd@~1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" +dependency-graph@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" + integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -609,9 +689,10 @@ dev-ip@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0" -domino@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domino/-/domino-2.0.1.tgz#9e1d63215d0fe8dcb8202bff07effa1a216db504" +domino@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.1.tgz#cd5c639940db72bb7cde1cdb5beea466a4113136" + integrity sha512-fqoTi6oQ881wYRENIEmz78hKVoc3X9HqVpklo419yxzebys6dtU5c83iVh3UYvvexPFdAuwlDYCsUM9//CrMMg== easy-extender@2.3.2: version "2.3.2" @@ -694,6 +775,23 @@ es6-module-loader@^0.17.4: dependencies: when "^3.7.2" +es6-promise@^4.0.3: + version "4.2.5" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" + integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg== + +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -714,6 +812,19 @@ eventemitter3@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.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@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -730,7 +841,7 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -extend@3, extend@~3.0.0, extend@~3.0.1: +extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -787,6 +898,13 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" +find-up@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -878,6 +996,11 @@ get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -897,6 +1020,18 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +glob@^7.0.0: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.0.3, glob@^7.0.5, glob@^7.0.6: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" @@ -1045,13 +1180,18 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-proxy-agent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== dependencies: - agent-base "2" - debug "2" - extend "3" + agent-base "^4.1.0" + debug "^3.1.0" + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= immutable@3.8.2, immutable@^3.7.6: version "3.8.2" @@ -1068,7 +1208,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -1076,6 +1216,11 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +interpret@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -1124,6 +1269,11 @@ is-fullwidth-code-point@^1.0.0: dependencies: number-is-nan "^1.0.0" +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -1176,6 +1326,11 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -1192,6 +1347,11 @@ isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -1206,9 +1366,10 @@ jasmine-core@~2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" -jasmine@^2.5.3: +jasmine@2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" + integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4= dependencies: exit "^0.1.2" glob "^7.0.6" @@ -1259,6 +1420,17 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + kind-of@^3.0.2: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -1277,6 +1449,13 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + limiter@^1.0.5: version "1.1.2" resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.2.tgz#229d8055891c8b11af9e0ee5200e8e09bb3dcbeb" @@ -1301,6 +1480,16 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + localtunnel@1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.8.3.tgz#dcc5922fd85651037d4bde24fd93248d0b24eb05" @@ -1310,6 +1499,14 @@ localtunnel@1.8.3: request "2.81.0" yargs "3.29.0" +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + lodash.isfinite@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz#fb89b65a9a80281833f0b7478b3a5104f898ebb3" @@ -1322,12 +1519,34 @@ lodash@^4.11.1, lodash@^4.5.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + magic-string@^0.19.0: version "0.19.1" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.19.1.tgz#14d768013caf2ec8fdea16a49af82fc377e75201" dependencies: vlq "^0.2.1" +magic-string@^0.25.0: + version "0.25.1" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.1.tgz#b1c248b399cd7485da0fe7385c2fc7011843266e" + integrity sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg== + dependencies: + sourcemap-codec "^1.4.1" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + micromatch@2.3.11, micromatch@^2.1.5, micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" @@ -1360,6 +1579,11 @@ mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -1404,6 +1628,11 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + nan@^2.3.0: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" @@ -1450,6 +1679,13 @@ normalize-path@^2.0.0, normalize-path@^2.0.1: dependencies: remove-trailing-separator "^1.0.1" +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -1516,10 +1752,6 @@ optimist@~0.6.0: minimist "~0.0.1" wordwrap "~0.0.2" -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -1530,6 +1762,15 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + os-tmpdir@^1.0.0, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -1541,6 +1782,35 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +pako@~1.0.2: + version "1.0.8" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.8.tgz#6844890aab9c635af868ad5fecc62e8acbba3ea4" + integrity sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA== + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -1578,6 +1848,11 @@ path-exists@^2.0.0: dependencies: pinkie-promise "^2.0.0" +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -1586,10 +1861,20 @@ path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -1598,6 +1883,13 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" @@ -1636,24 +1928,29 @@ process-nextick-args@~1.0.6: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" "protractor@file:../../node_modules/protractor": - version "5.1.2" + version "5.4.2" dependencies: - "@types/node" "^6.0.46" "@types/q" "^0.0.32" - "@types/selenium-webdriver" "~2.53.39" - blocking-proxy "0.0.5" + "@types/selenium-webdriver" "^3.0.0" + blocking-proxy "^1.0.0" + browserstack "^1.5.1" chalk "^1.1.3" glob "^7.0.3" - jasmine "^2.5.3" + jasmine "2.8.0" jasminewd2 "^2.1.0" optimist "~0.6.0" q "1.4.1" - saucelabs "~1.3.0" - selenium-webdriver "3.0.1" + saucelabs "^1.5.0" + selenium-webdriver "3.6.0" source-map-support "~0.4.0" - webdriver-js-extender "^1.0.0" + webdriver-js-extender "2.1.0" webdriver-manager "^12.0.6" +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -1705,6 +2002,14 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -1713,6 +2018,15 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" @@ -1725,6 +2039,18 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4: string_decoder "~1.0.3" util-deprecate "~1.0.1" +readable-stream@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -1734,6 +2060,13 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + reflect-metadata@^0.1.2: version "0.1.10" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a" @@ -1822,16 +2155,19 @@ requires-port@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - resolve@^1.1.6, resolve@^1.1.7: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" +resolve@^1.8.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" + integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== + dependencies: + path-parse "^1.0.6" + resp-modifier@6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/resp-modifier/-/resp-modifier-6.0.2.tgz#b124de5c4fbafcba541f48ffa73970f4aa456b4f" @@ -1855,12 +2191,11 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2. rollup-pluginutils "^2.0.1" "rollup-plugin-node-resolve@file:../../node_modules/rollup-plugin-node-resolve": - version "3.0.0" + version "4.0.0" dependencies: - browser-resolve "^1.11.0" - builtin-modules "^1.1.0" + builtin-modules "^3.0.0" is-module "^1.0.0" - resolve "^1.1.6" + resolve "^1.8.1" rollup-pluginutils@^2.0.1: version "2.0.1" @@ -1870,7 +2205,11 @@ rollup-pluginutils@^2.0.1: micromatch "^2.3.11" "rollup@file:../../node_modules/rollup": - version "0.47.4" + version "1.1.0" + dependencies: + "@types/estree" "0.0.39" + "@types/node" "*" + acorn "^6.0.5" rx@2.3.24: version "2.3.24" @@ -1881,7 +2220,7 @@ rx@4.1.0: resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" "rxjs@file:../../node_modules/rxjs": - version "6.0.0" + version "6.3.3" dependencies: tslib "^1.9.0" @@ -1889,47 +2228,31 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -saucelabs@~1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.3.0.tgz#d240e8009df7fa87306ec4578a69ba3b5c424fee" +saucelabs@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" + integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== dependencies: - https-proxy-agent "^1.0.0" - -sax@0.6.x: - version "0.6.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" + https-proxy-agent "^2.2.1" sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -selenium-webdriver@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz#a2dea5da4a97f6672e89e7ca7276cefa365147a7" +selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q== dependencies: - adm-zip "^0.4.7" + jszip "^3.1.3" rimraf "^2.5.4" tmp "0.0.30" xml2js "^0.4.17" -selenium-webdriver@^2.53.2: - version "2.53.3" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz#d29ff5a957dff1a1b49dc457756e4e4bfbdce085" - dependencies: - adm-zip "0.4.4" - rimraf "^2.2.8" - tmp "0.0.24" - ws "^1.0.1" - xml2js "0.4.4" - "semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" -semver@~5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" - send@0.15.2: version "0.15.2" resolved "https://registry.yarnpkg.com/send/-/send-0.15.2.tgz#f91fab4403bcf87e716f70ceb5db2f578bdc17d6" @@ -1989,6 +2312,27 @@ setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shelljs@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" + integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + signal-exit@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -2046,12 +2390,6 @@ socket.io@2.0.4: socket.io-client "2.0.4" socket.io-parser "~3.1.1" -source-map-support@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.3.tgz#2b3d5fff298cfa4d1afd7d4352d569e9a0158e76" - dependencies: - source-map "^0.6.0" - source-map-support@~0.4.0: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" @@ -2062,9 +2400,15 @@ source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@^0.6.0: +source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" + integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg== spawn-command@^0.0.2-1: version "0.0.2" @@ -2121,6 +2465,19 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +string-width@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" @@ -2143,12 +2500,29 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -2201,10 +2575,6 @@ tfunk@^3.0.1: chalk "^1.1.1" object-path "^0.9.0" -tmp@0.0.24: - version "0.0.24" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" - tmp@0.0.30: version "0.0.30" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" @@ -2225,15 +2595,6 @@ tree-kill@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" -tsickle@^0.29.0: - version "0.29.0" - resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.29.0.tgz#812806554bb46c1aa16eb0fe2a051da95ca8f5a4" - dependencies: - minimist "^1.2.0" - mkdirp "^0.5.1" - source-map "^0.6.0" - source-map-support "^0.5.0" - tslib@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" @@ -2249,7 +2610,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" "typescript@file:../../node_modules/typescript": - version "2.7.2" + version "3.2.2" ua-parser-js@0.7.12: version "0.7.12" @@ -2259,10 +2620,6 @@ uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" -ultron@1.0.x: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" @@ -2310,12 +2667,13 @@ vlq@^0.2.1: version "0.2.3" resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" -webdriver-js-extender@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515" +webdriver-js-extender@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" + integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ== dependencies: - "@types/selenium-webdriver" "^2.53.35" - selenium-webdriver "^2.53.2" + "@types/selenium-webdriver" "^3.0.0" + selenium-webdriver "^3.0.1" webdriver-manager@^12.0.6: version "12.0.6" @@ -2341,6 +2699,18 @@ which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -2370,13 +2740,6 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -ws@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" - dependencies: - options ">=0.0.5" - ultron "1.0.x" - ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -2389,13 +2752,6 @@ xhr2@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" -xml2js@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d" - dependencies: - sax "0.6.x" - xmlbuilder ">=1.0.0" - xml2js@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" @@ -2403,7 +2759,7 @@ xml2js@^0.4.17: sax ">=0.6.0" xmlbuilder "~9.0.1" -xmlbuilder@>=1.0.0, xmlbuilder@~9.0.1: +xmlbuilder@~9.0.1: version "9.0.4" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" @@ -2415,12 +2771,24 @@ y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + yargs-parser@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" dependencies: camelcase "^3.0.0" +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= + dependencies: + camelcase "^4.1.0" + yargs@3.29.0: version "3.29.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.29.0.tgz#1aab9660eae79d8b8f675bcaeeab6ee34c2cf69c" @@ -2451,6 +2819,25 @@ yargs@6.4.0: y18n "^3.2.1" yargs-parser "^4.1.0" +yargs@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" + integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" diff --git a/integration/get-sharded-tests.js b/integration/get-sharded-tests.js new file mode 100644 index 0000000000..4039e4dbec --- /dev/null +++ b/integration/get-sharded-tests.js @@ -0,0 +1,100 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/* + * Script that determines the sharded tests for the current CircleCI container. CircleCI starts + * multiple containers if the "parallelism" option has been specified and this script splits up + * the integration tests into shards based on the amount of parallelism. + * + * It's also possible to manually specify tests which should run on a container because some + * integration tests are more complex and take up more time. In order to properly balance the + * duration of each container, we allow manual test shards to be specified. + * + * The output of this script can then be used to only run the tests which are assigned to the + * current CircleCI container. + */ + +const fs = require('fs'); +const path = require('path'); +const minimist = require('minimist'); + +// Parsed command line arguments. +const {shardIndex, maxShards} = minimist(process.argv.slice(2)); + +// Ensure that all CLI options are set properly. +if (shardIndex == null) { + throw new Error('The "--shardIndex" option has not been specified.') +} else if (maxShards == null) { + throw new Error('The "--maxShards" option has not been specified.'); +} + +// List of all integration tests that are available. +const integrationTests = fs.readdirSync(__dirname).filter( + testName => fs.statSync(path.join(__dirname, testName)).isDirectory()); + +// Manual test shards which aren't computed automatically. This is helpful when a specific +// set of integration test takes up *way* more time than all other tests, and we want to +// balance out the duration for all specific shards. +const manualTestShards = [ + // The first shard should only run the bazel integration tests because these take up + // a lot of time and shouldn't be split up automatically. + ['bazel', 'bazel-schematics'] +]; + +// Tests which haven't been assigned manually to a shard. These tests will be automatically +// split across the remaining available shards. +const unassignedTests = stripManualOverrides(integrationTests, manualTestShards); + +if (manualTestShards.length === maxShards && unassignedTests.length) { + throw new Error( + `Tests have been specified manually for all available shards, but there were ` + + `integration tests which haven't been specified and won't run right now. Missing ` + + `tests: ${unassignedTests.join(', ')}`) +} else if (manualTestShards.length > maxShards) { + throw new Error( + `Too many manual shards have been specified. Increase the amount of maximum shards.`); +} + +// In case the shard for the current index has been specified manually, we just output +// the tests for the manual shard. +if (manualTestShards[shardIndex]) { + printTestNames(manualTestShards[shardIndex]); +} else { + const amountManualShards = manualTestShards.length; + // In case there isn't a manual shard specified for this shard index, we just compute the + // tests for this shard. Note that we need to subtract the amount of manual shards because + // we need to split up the unassigned tests across the remaining available shards. + printTestNames(getTestsForShardIndex( + unassignedTests, shardIndex - amountManualShards, maxShards - amountManualShards)); +} + +/** + * Splits the specified tests into a limited amount of shards and returns the tests that should + * run on the given shard. The shards of tests are being created deterministically and therefore + * we get reproducible tests when executing the same script multiple times. + */ +function getTestsForShardIndex(tests, shardIndex, maxShards) { + return tests.filter((n, index) => index % maxShards === shardIndex); +} + +/** + * Strips all manual tests from the list of integration tests. This is necessary because + * when computing the shards automatically we don't want to include manual tests again. This + * would mean that CircleCI runs some integration tests multiple times. + */ +function stripManualOverrides(integrationTests, manualShards) { + const allManualTests = manualShards.reduce((res, manualTests) => res.concat(manualTests), []); + return integrationTests.filter(testName => !allManualTests.includes(testName)) +} + +/** Prints the specified test names to the stdout. */ +function printTestNames(testNames) { + // Print the test names joined with spaces because this allows Bash to easily convert the output + // of this script into an array. + process.stdout.write(testNames.join(' ')); +} diff --git a/integration/hello_world__closure/package.json b/integration/hello_world__closure/package.json index 6e1c9706d7..fd304c7586 100644 --- a/integration/hello_world__closure/package.json +++ b/integration/hello_world__closure/package.json @@ -22,7 +22,7 @@ "protractor": "file:../../node_modules/protractor" }, "scripts": { - "postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG", + "postinstall": "webdriver-manager update --gecko false --standalone false $CI_CHROMEDRIVER_VERSION_ARG", "closure": "java -jar node_modules/google-closure-compiler/compiler.jar --flagfile closure.conf", "test": "ngc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first", "serve": "lite-server -c e2e/browser.config.json", diff --git a/integration/hello_world__systemjs_umd/package.json b/integration/hello_world__systemjs_umd/package.json index 6b53c8326b..aa747f2d86 100644 --- a/integration/hello_world__systemjs_umd/package.json +++ b/integration/hello_world__systemjs_umd/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "license": "MIT", "scripts": { - "postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG", + "postinstall": "webdriver-manager update --gecko false --standalone false $CI_CHROMEDRIVER_VERSION_ARG", "test": "concurrently \"yarn serve\" \"yarn protractor\" --kill-others --success first", "serve": "lite-server -c bs-config.e2e.json", "preprotractor": "tsc -p e2e", diff --git a/integration/i18n/package.json b/integration/i18n/package.json index 8672de9ccb..06ee78bcb0 100644 --- a/integration/i18n/package.json +++ b/integration/i18n/package.json @@ -23,7 +23,7 @@ "protractor": "file:../../node_modules/protractor" }, "scripts": { - "postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG", + "postinstall": "webdriver-manager update --gecko false --standalone false $CI_CHROMEDRIVER_VERSION_ARG", "closure": "java -jar node_modules/google-closure-compiler/compiler.jar --flagfile closure.conf", "test": "ngc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first && npm run test-locale-folder", "test-locale-folder": "node test-locale-folder.js", @@ -31,4 +31,4 @@ "preprotractor": "tsc -p e2e", "protractor": "protractor e2e/protractor.config.js" } -} \ No newline at end of file +} diff --git a/integration/language_service_plugin/.gitignore b/integration/language_service_plugin/.gitignore index 4c43fe68f6..7420cfbcc3 100644 --- a/integration/language_service_plugin/.gitignore +++ b/integration/language_service_plugin/.gitignore @@ -1 +1,3 @@ -*.js \ No newline at end of file +*.js +tsserver.log +ti-*.log diff --git a/integration/language_service_plugin/fixtures/getCompletions-expected-2.3.json b/integration/language_service_plugin/fixtures/getCompletions-expected-2.3.json deleted file mode 100644 index 3560e80927..0000000000 --- a/integration/language_service_plugin/fixtures/getCompletions-expected-2.3.json +++ /dev/null @@ -1,260 +0,0 @@ -[ - { - "type": "response", - "command": "configure", - "success": true - }, - { - "type": "response", - "command": "compilerOptionsForInferredProjects", - "success": true, - "body": true - }, - { - "type": "response", - "command": "completions", - "success": true, - "body": [ - { - "name": "anchor", - "kind": "method", - "kindModifiers": "", - "sortText": "anchor" - }, - { - "name": "big", - "kind": "method", - "kindModifiers": "", - "sortText": "big" - }, - { - "name": "blink", - "kind": "method", - "kindModifiers": "", - "sortText": "blink" - }, - { - "name": "bold", - "kind": "method", - "kindModifiers": "", - "sortText": "bold" - }, - { - "name": "charAt", - "kind": "method", - "kindModifiers": "", - "sortText": "charAt" - }, - { - "name": "charCodeAt", - "kind": "method", - "kindModifiers": "", - "sortText": "charCodeAt" - }, - { - "name": "codePointAt", - "kind": "method", - "kindModifiers": "", - "sortText": "codePointAt" - }, - { - "name": "concat", - "kind": "method", - "kindModifiers": "", - "sortText": "concat" - }, - { - "name": "endsWith", - "kind": "method", - "kindModifiers": "", - "sortText": "endsWith" - }, - { - "name": "fixed", - "kind": "method", - "kindModifiers": "", - "sortText": "fixed" - }, - { - "name": "fontcolor", - "kind": "method", - "kindModifiers": "", - "sortText": "fontcolor" - }, - { - "name": "fontsize", - "kind": "method", - "kindModifiers": "", - "sortText": "fontsize" - }, - { - "name": "includes", - "kind": "method", - "kindModifiers": "", - "sortText": "includes" - }, - { - "name": "indexOf", - "kind": "method", - "kindModifiers": "", - "sortText": "indexOf" - }, - { - "name": "italics", - "kind": "method", - "kindModifiers": "", - "sortText": "italics" - }, - { - "name": "lastIndexOf", - "kind": "method", - "kindModifiers": "", - "sortText": "lastIndexOf" - }, - { - "name": "length", - "kind": "property", - "kindModifiers": "", - "sortText": "length" - }, - { - "name": "link", - "kind": "method", - "kindModifiers": "", - "sortText": "link" - }, - { - "name": "localeCompare", - "kind": "method", - "kindModifiers": "", - "sortText": "localeCompare" - }, - { - "name": "match", - "kind": "method", - "kindModifiers": "", - "sortText": "match" - }, - { - "name": "normalize", - "kind": "method", - "kindModifiers": "", - "sortText": "normalize" - }, - { - "name": "repeat", - "kind": "method", - "kindModifiers": "", - "sortText": "repeat" - }, - { - "name": "replace", - "kind": "method", - "kindModifiers": "", - "sortText": "replace" - }, - { - "name": "search", - "kind": "method", - "kindModifiers": "", - "sortText": "search" - }, - { - "name": "slice", - "kind": "method", - "kindModifiers": "", - "sortText": "slice" - }, - { - "name": "small", - "kind": "method", - "kindModifiers": "", - "sortText": "small" - }, - { - "name": "split", - "kind": "method", - "kindModifiers": "", - "sortText": "split" - }, - { - "name": "startsWith", - "kind": "method", - "kindModifiers": "", - "sortText": "startsWith" - }, - { - "name": "strike", - "kind": "method", - "kindModifiers": "", - "sortText": "strike" - }, - { - "name": "sub", - "kind": "method", - "kindModifiers": "", - "sortText": "sub" - }, - { - "name": "substr", - "kind": "method", - "kindModifiers": "", - "sortText": "substr" - }, - { - "name": "substring", - "kind": "method", - "kindModifiers": "", - "sortText": "substring" - }, - { - "name": "sup", - "kind": "method", - "kindModifiers": "", - "sortText": "sup" - }, - { - "name": "toLocaleLowerCase", - "kind": "method", - "kindModifiers": "", - "sortText": "toLocaleLowerCase" - }, - { - "name": "toLocaleUpperCase", - "kind": "method", - "kindModifiers": "", - "sortText": "toLocaleUpperCase" - }, - { - "name": "toLowerCase", - "kind": "method", - "kindModifiers": "", - "sortText": "toLowerCase" - }, - { - "name": "toString", - "kind": "method", - "kindModifiers": "", - "sortText": "toString" - }, - { - "name": "toUpperCase", - "kind": "method", - "kindModifiers": "", - "sortText": "toUpperCase" - }, - { - "name": "trim", - "kind": "method", - "kindModifiers": "", - "sortText": "trim" - }, - { - "name": "valueOf", - "kind": "method", - "kindModifiers": "", - "sortText": "valueOf" - } - ] - } -] diff --git a/integration/language_service_plugin/fixtures/getCompletions.json b/integration/language_service_plugin/fixtures/getCompletions.json deleted file mode 100644 index 94be1ebe38..0000000000 --- a/integration/language_service_plugin/fixtures/getCompletions.json +++ /dev/null @@ -1,68 +0,0 @@ -[ - { - "seq": 0, - "type": "request", - "command": "configure", - "arguments": { - "hostInfo": "vscode" - } - }, - { - "seq": 1, - "type": "request", - "command": "compilerOptionsForInferredProjects", - "arguments": { - "options": { - "module": "CommonJS", - "target": "ES6", - "allowSyntheticDefaultImports": true, - "allowNonTsExtensions": true, - "allowJs": true, - "jsx": "Preserve" - } - } - }, - { - "seq": 4, - "type": "request", - "command": "open", - "arguments": { - "file": "$$PWD$$/project/app/app.component.ts", - "fileContent": "import { Component } from '@angular/core';\n\n@Component({\n selector: 'my-app',\n template: `

    Hello {{name}}

    `,\n})\nexport class AppComponent { name = 'Angular'; }\n" - } - }, - { - "seq": 7, - "type": "request", - "command": "geterr", - "arguments": { - "delay": 0, - "files": [ - "$$PWD$$/project/app/app.component.ts" - ] - } - }, - { - "seq": 12, - "type": "request", - "command": "change", - "arguments": { - "file": "$$PWD$$/project/app/app.component.ts", - "line": 5, - "offset": 30, - "endLine": 5, - "endOffset": 30, - "insertString": "." - } - }, - { - "seq": 13, - "type": "request", - "command": "completions", - "arguments": { - "file": "$$PWD$$/project/app/app.component.ts", - "line": 5, - "offset": 31 - } - } -] \ No newline at end of file diff --git a/integration/language_service_plugin/fixtures/smokeTest.json b/integration/language_service_plugin/fixtures/smokeTest.json deleted file mode 100644 index 7ddc202c9a..0000000000 --- a/integration/language_service_plugin/fixtures/smokeTest.json +++ /dev/null @@ -1,45 +0,0 @@ -[ - { - "seq": 0, - "type": "request", - "command": "configure", - "arguments": { - "hostInfo": "vscode" - } - }, - { - "seq": 1, - "type": "request", - "command": "compilerOptionsForInferredProjects", - "arguments": { - "options": { - "module": "CommonJS", - "target": "ES6", - "allowSyntheticDefaultImports": true, - "allowNonTsExtensions": true, - "allowJs": true, - "jsx": "Preserve" - } - } - }, - { - "seq": 2, - "type": "request", - "command": "open", - "arguments": { - "file": "$$PWD$$/app/app.module.ts", - "fileContent": "" - } - }, - { - "seq": 3, - "type": "request", - "command": "geterr", - "arguments": { - "delay": 0, - "files": [ - "$$PWD$$/app/app.module.ts" - ] - } - } -] \ No newline at end of file diff --git a/integration/language_service_plugin/generate.ts b/integration/language_service_plugin/generate.ts new file mode 100644 index 0000000000..3db7aa54aa --- /dev/null +++ b/integration/language_service_plugin/generate.ts @@ -0,0 +1,22 @@ +/** + * @fileOverview + * This file serves as the entry point for generating goldens file for the + * language service integration test. It expects each golden file that needs + * to be generated to be passed in as command line arguments. + * For example, to generate golden file for the 'configure' request, run + * `yarn golden configure.json`. + * To generate multiple golden files, run + * `yarn golden configure.json completionInfo.json`. + * + * This is different from just running `yarn jasmine test.js` because this + * allows passing in arbitrary arguments. + */ + +import Jasmine = require('jasmine'); + +function main() { + const jasmine = new Jasmine({}); + jasmine.execute(['test.js']); +} + +main() diff --git a/integration/language_service_plugin/fixtures/smokeTest-expected-2.3.json b/integration/language_service_plugin/goldens/compilerOptionsForInferredProjects.json similarity index 56% rename from integration/language_service_plugin/fixtures/smokeTest-expected-2.3.json rename to integration/language_service_plugin/goldens/compilerOptionsForInferredProjects.json index 55645cf60d..38eaa54b68 100644 --- a/integration/language_service_plugin/fixtures/smokeTest-expected-2.3.json +++ b/integration/language_service_plugin/goldens/compilerOptionsForInferredProjects.json @@ -1,13 +1,8 @@ -[ - { - "type": "response", - "command": "configure", - "success": true - }, - { +{ + "seq": 0, "type": "response", "command": "compilerOptionsForInferredProjects", + "request_seq": 1, "success": true, "body": true - } -] +} diff --git a/integration/language_service_plugin/goldens/completionInfo.json b/integration/language_service_plugin/goldens/completionInfo.json new file mode 100644 index 0000000000..3c503000c8 --- /dev/null +++ b/integration/language_service_plugin/goldens/completionInfo.json @@ -0,0 +1,266 @@ +{ + "seq": 0, + "type": "response", + "command": "completionInfo", + "request_seq": 5, + "success": true, + "body": { + "isGlobalCompletion": false, + "isMemberCompletion": false, + "isNewIdentifierLocation": false, + "entries": [ + { + "name": "anchor", + "kind": "method", + "kindModifiers": "", + "sortText": "anchor" + }, + { + "name": "big", + "kind": "method", + "kindModifiers": "", + "sortText": "big" + }, + { + "name": "blink", + "kind": "method", + "kindModifiers": "", + "sortText": "blink" + }, + { + "name": "bold", + "kind": "method", + "kindModifiers": "", + "sortText": "bold" + }, + { + "name": "charAt", + "kind": "method", + "kindModifiers": "", + "sortText": "charAt" + }, + { + "name": "charCodeAt", + "kind": "method", + "kindModifiers": "", + "sortText": "charCodeAt" + }, + { + "name": "codePointAt", + "kind": "method", + "kindModifiers": "", + "sortText": "codePointAt" + }, + { + "name": "concat", + "kind": "method", + "kindModifiers": "", + "sortText": "concat" + }, + { + "name": "endsWith", + "kind": "method", + "kindModifiers": "", + "sortText": "endsWith" + }, + { + "name": "fixed", + "kind": "method", + "kindModifiers": "", + "sortText": "fixed" + }, + { + "name": "fontcolor", + "kind": "method", + "kindModifiers": "", + "sortText": "fontcolor" + }, + { + "name": "fontsize", + "kind": "method", + "kindModifiers": "", + "sortText": "fontsize" + }, + { + "name": "includes", + "kind": "method", + "kindModifiers": "", + "sortText": "includes" + }, + { + "name": "indexOf", + "kind": "method", + "kindModifiers": "", + "sortText": "indexOf" + }, + { + "name": "italics", + "kind": "method", + "kindModifiers": "", + "sortText": "italics" + }, + { + "name": "lastIndexOf", + "kind": "method", + "kindModifiers": "", + "sortText": "lastIndexOf" + }, + { + "name": "length", + "kind": "property", + "kindModifiers": "", + "sortText": "length" + }, + { + "name": "link", + "kind": "method", + "kindModifiers": "", + "sortText": "link" + }, + { + "name": "localeCompare", + "kind": "method", + "kindModifiers": "", + "sortText": "localeCompare" + }, + { + "name": "match", + "kind": "method", + "kindModifiers": "", + "sortText": "match" + }, + { + "name": "normalize", + "kind": "method", + "kindModifiers": "", + "sortText": "normalize" + }, + { + "name": "repeat", + "kind": "method", + "kindModifiers": "", + "sortText": "repeat" + }, + { + "name": "replace", + "kind": "method", + "kindModifiers": "", + "sortText": "replace" + }, + { + "name": "search", + "kind": "method", + "kindModifiers": "", + "sortText": "search" + }, + { + "name": "slice", + "kind": "method", + "kindModifiers": "", + "sortText": "slice" + }, + { + "name": "small", + "kind": "method", + "kindModifiers": "", + "sortText": "small" + }, + { + "name": "split", + "kind": "method", + "kindModifiers": "", + "sortText": "split" + }, + { + "name": "startsWith", + "kind": "method", + "kindModifiers": "", + "sortText": "startsWith" + }, + { + "name": "strike", + "kind": "method", + "kindModifiers": "", + "sortText": "strike" + }, + { + "name": "sub", + "kind": "method", + "kindModifiers": "", + "sortText": "sub" + }, + { + "name": "substr", + "kind": "method", + "kindModifiers": "", + "sortText": "substr" + }, + { + "name": "substring", + "kind": "method", + "kindModifiers": "", + "sortText": "substring" + }, + { + "name": "sup", + "kind": "method", + "kindModifiers": "", + "sortText": "sup" + }, + { + "name": "toLocaleLowerCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toLocaleLowerCase" + }, + { + "name": "toLocaleUpperCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toLocaleUpperCase" + }, + { + "name": "toLowerCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toLowerCase" + }, + { + "name": "toString", + "kind": "method", + "kindModifiers": "", + "sortText": "toString" + }, + { + "name": "toUpperCase", + "kind": "method", + "kindModifiers": "", + "sortText": "toUpperCase" + }, + { + "name": "trim", + "kind": "method", + "kindModifiers": "", + "sortText": "trim" + }, + { + "name": "trimLeft", + "kind": "method", + "kindModifiers": "", + "sortText": "trimLeft" + }, + { + "name": "trimRight", + "kind": "method", + "kindModifiers": "", + "sortText": "trimRight" + }, + { + "name": "valueOf", + "kind": "method", + "kindModifiers": "", + "sortText": "valueOf" + } + ] + } +} \ No newline at end of file diff --git a/integration/language_service_plugin/goldens/configure.json b/integration/language_service_plugin/goldens/configure.json new file mode 100644 index 0000000000..b4a7a6f32b --- /dev/null +++ b/integration/language_service_plugin/goldens/configure.json @@ -0,0 +1,7 @@ +{ + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 0, + "success": true +} diff --git a/integration/language_service_plugin/matcher.ts b/integration/language_service_plugin/matcher.ts new file mode 100644 index 0000000000..b46edbf3bc --- /dev/null +++ b/integration/language_service_plugin/matcher.ts @@ -0,0 +1,32 @@ +import { writeFileSync } from 'fs'; + +const goldens: string[] = process.argv.slice(2); + +export const goldenMatcher: jasmine.CustomMatcherFactories = { + toMatchGolden(util: jasmine.MatchersUtil): jasmine.CustomMatcher { + return { + compare(actual: {command: string}, golden: string): jasmine.CustomMatcherResult { + const expected = require(`./goldens/${golden}`); + const pass = util.equals(actual, expected); + if (!pass && goldens.indexOf(golden) >= 0) { + console.error(`Writing golden file ${golden}`); + writeFileSync(`./goldens/${golden}`, JSON.stringify(actual, null, 2)); + return { pass : true }; + } + return { + pass, + message: `Expected response for '${actual.command}' to match golden file ${golden}.\n` + + `To generate new golden file, run "yarn golden ${golden}".`, + }; + } + }; + }, +}; + +declare global { + namespace jasmine { + interface Matchers { + toMatchGolden(golden: string): void + } + } +} diff --git a/integration/language_service_plugin/package.json b/integration/language_service_plugin/package.json index c6c91f558f..c5036b18a1 100644 --- a/integration/language_service_plugin/package.json +++ b/integration/language_service_plugin/package.json @@ -4,23 +4,16 @@ "license": "MIT", "description": "Angular Language Service plugin integration test", "dependencies": { - "@angular/animations": "file:../../dist/packages-dist/animations", - "@angular/common": "file:../../dist/packages-dist/common", - "@angular/compiler": "file:../../dist/packages-dist/compiler", - "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@angular/core": "file:../../dist/packages-dist/core", "@angular/language-service": "file:../../dist/packages-dist/language-service", - "@angular/platform-browser": "file:../../dist/packages-dist/platform-browser", - "@angular/platform-server": "file:../../dist/packages-dist/platform-server", - "@types/minimist": "^1.2.0", - "@types/node": "^7.0.5", - "minimist": "^1.2.0", - "rxjs": "file:../../node_modules/rxjs", - "typescript": "file:../../node_modules/typescript", - "zone.js": "file:../../node_modules/zone.js" + "@types/node": "file:../../node_modules/@types/node", + "jasmine": "file:../../node_modules/jasmine", + "typescript": "file:../../node_modules/typescript" }, "scripts": { - "postinstall": "scripts/install.sh", - "test": "tsc -p tools && scripts/test.sh" + "build": "tsc -p tsconfig.json", + "cleanup": "rm -rf ti-*.log tsserver.log", + "golden": "node generate.js", + "test": "yarn cleanup && yarn build && jasmine test.js" } } diff --git a/integration/language_service_plugin/project/tsconfig.json b/integration/language_service_plugin/project/tsconfig.json index 6a81fdd7df..2c7260d1bc 100644 --- a/integration/language_service_plugin/project/tsconfig.json +++ b/integration/language_service_plugin/project/tsconfig.json @@ -8,9 +8,6 @@ "experimentalDecorators": true, "lib": [ "es2015", "dom" ], "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true, - "plugins": [ - { "name": "@angular/language-service" } - ] + "suppressImplicitAnyIndexErrors": true } } diff --git a/integration/language_service_plugin/scripts/env.sh b/integration/language_service_plugin/scripts/env.sh deleted file mode 100755 index 321f42a45c..0000000000 --- a/integration/language_service_plugin/scripts/env.sh +++ /dev/null @@ -1,2 +0,0 @@ -TYPESCRIPTS=2.3 -FIXTURES="smokeTest getCompletions" diff --git a/integration/language_service_plugin/scripts/install.sh b/integration/language_service_plugin/scripts/install.sh deleted file mode 100755 index d835479259..0000000000 --- a/integration/language_service_plugin/scripts/install.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -ex -o pipefail - -cd `dirname $0` -cd .. -source scripts/env.sh - -# Setup TypeScripts -for TYPESCRIPT in ${TYPESCRIPTS[@]} -do - ( - cd typescripts/$TYPESCRIPT - yarn - ) -done \ No newline at end of file diff --git a/integration/language_service_plugin/scripts/test.sh b/integration/language_service_plugin/scripts/test.sh deleted file mode 100755 index 0721da0c45..0000000000 --- a/integration/language_service_plugin/scripts/test.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -set -ex -o pipefail - -cd `dirname $0` -cd .. -source scripts/env.sh - -HOST="node tools/typescript_host.js" -VALIDATE="node tools/typescript_validator.js" - -# Ensure the languages service can load correctly in node before typescript loads it. -# This verifies its dependencies and emits any exceptions, both of which are only -# emitted to the typescript logs (not the validated output). -node tools/load_test.js - -for TYPESCRIPT in ${TYPESCRIPTS[@]} -do - SERVER="node typescripts/$TYPESCRIPT/node_modules/typescript/lib/tsserver.js" - for FIXTURE_BASE in ${FIXTURES[@]} - do - FIXTURE=fixtures/$FIXTURE_BASE.json - EXPECTED=fixtures/$FIXTURE_BASE-expected-$TYPESCRIPT.json - if [[ ${UPDATE_GOLDEN} == true ]]; then - $HOST --file $FIXTURE --pwd $(pwd) | $SERVER | $VALIDATE --golden > $EXPECTED - else - $HOST --file $FIXTURE --pwd $(pwd) | $SERVER | $VALIDATE --expect $EXPECTED - fi - done -done \ No newline at end of file diff --git a/integration/language_service_plugin/scripts/update_golden.sh b/integration/language_service_plugin/scripts/update_golden.sh deleted file mode 100755 index 4fd0d2484d..0000000000 --- a/integration/language_service_plugin/scripts/update_golden.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -ex -o pipefail - -cd `dirname $0` -cd .. - -UPDATE_GOLDEN=true scripts/test.sh \ No newline at end of file diff --git a/integration/language_service_plugin/test.ts b/integration/language_service_plugin/test.ts new file mode 100644 index 0000000000..0147ed1ebb --- /dev/null +++ b/integration/language_service_plugin/test.ts @@ -0,0 +1,104 @@ +import { fork, ChildProcess } from 'child_process'; +import { join } from 'path'; +import { Client } from './tsclient'; +import { goldenMatcher } from './matcher'; + +describe('Angular Language Service', () => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; /* 10 seconds */ + const PWD = process.env.PWD!; + const SERVER_PATH = "./node_modules/typescript/lib/tsserver.js"; + let server: ChildProcess; + let client: Client; + + beforeEach(() => { + jasmine.addMatchers(goldenMatcher); + server = fork(SERVER_PATH, [ + '--globalPlugins', '@angular/language-service', + '--logVerbosity', 'verbose', + '--logFile', join(PWD, 'tsserver.log'), + ], { + stdio: ['pipe', 'pipe', 'inherit', 'ipc'], + }); + client = new Client(server); + client.listen(); + }); + + afterEach(async () => { + client.sendRequest('exit', {}); + + // Give server process some time to flush all messages + await new Promise((resolve) => setTimeout(resolve, 1000)); + }); + + it('should be launched as tsserver plugin', async () => { + let response = await client.sendRequest('configure', { + hostInfo: 'vscode', + }); + expect(response).toMatchGolden('configure.json'); + response = await client.sendRequest('compilerOptionsForInferredProjects', { + "options": { + module: "CommonJS", + target: "ES6", + allowSyntheticDefaultImports: true, + allowNonTsExtensions: true, + allowJs: true, + jsx: "Preserve" + } + }); + expect(response).toMatchGolden('compilerOptionsForInferredProjects.json'); + // Server does not send response to open request + // https://github.com/Microsoft/TypeScript/blob/master/lib/protocol.d.ts#L1055 + client.sendRequest('open', { + file: `${PWD}/project/app/app.module.ts`, + fileContent: "" + }); + // Server does not send response to geterr request + // https://github.com/Microsoft/TypeScript/blob/master/lib/protocol.d.ts#L1770 + client.sendRequest('geterr', { + delay: 0, + files: [`${PWD}/project/app/app.module.ts`] + }); + }); + + it('should perform completions', async () => { + await client.sendRequest('configure', { + hostInfo: 'vscode', + }); + await client.sendRequest('compilerOptionsForInferredProjects', { + "options": { + module: "CommonJS", + target: "ES6", + allowSyntheticDefaultImports: true, + allowNonTsExtensions: true, + allowJs: true, + jsx: "Preserve" + } + }); + + client.sendRequest('open', { + file: `${PWD}/project/app/app.component.ts`, + fileContent: "import { Component } from '@angular/core';\n\n@Component({\n selector: 'my-app',\n template: `

    Hello {{name}}

    `,\n})\nexport class AppComponent { name = 'Angular'; }\n" + }); + + client.sendRequest('geterr', { + delay: 0, + files: [`${PWD}/project/app/app.component.ts`] + }); + + client.sendRequest('change', { + file: `${PWD}/project/app/app.component.ts`, + line: 5, + offset: 30, + endLine: 5, + endOffset: 30, + insertString: '.', + }); + + const response = await client.sendRequest('completionInfo', { + file: `${PWD}/project/app/app.component.ts`, + line: 5, + offset: 31, + }); + expect(response).toMatchGolden('completionInfo.json'); + }); +}); diff --git a/integration/language_service_plugin/tools/load_test.ts b/integration/language_service_plugin/tools/load_test.ts deleted file mode 100644 index 22090f30f6..0000000000 --- a/integration/language_service_plugin/tools/load_test.ts +++ /dev/null @@ -1,35 +0,0 @@ -const ts = require('typescript'); -const Module = require('module'); - -const existingRequire = Module.prototype.require; - -const recordedRequires: string[] = []; - -function recordingRequire(path: string) { - recordedRequires.push(path); - return existingRequire.call(this, path); -} - -Module.prototype.require = recordingRequire; - -try { - const lsf = require('@angular/language-service'); - const ls = lsf({typescript: ts}); - - // Assert that the only module that should have been required are '@angular/language-service', 'fs', and 'path' - - const allowedLoads = new Set(["@angular/language-service", "fs", "path"]); - - const invalidModules = recordedRequires.filter(m => !allowedLoads.has(m)); - - if (invalidModules.length > 0) { - console.error(`FAILED: Loading the language service required: ${invalidModules.join(', ')}`); - process.exit(1); - } -} catch (e) { - console.error(`FAILED: Loading the language service caused the following exception: ${e.stack || e}`); - process.exit(1); -} - -console.log('SUCCESS: Loading passed') -process.exit(0); \ No newline at end of file diff --git a/integration/language_service_plugin/tools/tsconfig.json b/integration/language_service_plugin/tools/tsconfig.json deleted file mode 100644 index fd844f194c..0000000000 --- a/integration/language_service_plugin/tools/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": true, - "skipLibCheck": true, - "sourceMap": false, - "lib": ["es2015", "dom"], - "types": [ - "node", - "minimist" - ] - }, - "files": [ - "typescript_host.ts", - "typescript_validator.ts", - "load_test.ts" - ] -} \ No newline at end of file diff --git a/integration/language_service_plugin/tools/typescript_host.ts b/integration/language_service_plugin/tools/typescript_host.ts deleted file mode 100644 index 4dc2f415c8..0000000000 --- a/integration/language_service_plugin/tools/typescript_host.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as fs from 'fs'; -import * as minimist from 'minimist'; - -const RE_PWD = /\$\$PWD\$\$/g; - -let errorsDetected = false; - -function reportError(arg: string): boolean { - console.error(`Unknown argument: ${arg}`); - errorsDetected = true; - return false; -} - -function help() { - console.log('TypeScript Host') - console.log(`${process.argv[1]} --file [--pwd ]`); - console.log(` - Send JSON message using the JSON RPC protocol to stdout. - `) -} - -let args = minimist(process.argv.slice(2), { string: ['file', 'pwd'], unknown: reportError }); - -if (errorsDetected) { - help(); - process.exit(2); -} - -const file = args['file']; -if (!file) { - console.log('stdin form not supported yet.') - process.exit(1); -} - -// Sender -const pending: string[] = []; -let writing = false; - -function writeMessage(message: string) { - writing = true; - process.stdout.write(message + '\n', checkPending); -} - -function checkPending() { - writing = false; - if (pending.length) { - writeMessage(pending.shift()); - } -} - -function send(message: string) { - if (writing) { - pending.push(message); - } else { - writeMessage(message); - } -} - -try { - let content = fs.readFileSync(file, 'utf8'); - if (args['pwd']) { - content = content.replace(RE_PWD, args['pwd']); - } - - const json = JSON.parse(content); - - if (Array.isArray(json)) { - for (const message of json) { - send(JSON.stringify(message)); - } - } else { - throw Error('Expected an array for input messages.') - } -} catch(e) { - console.error(`Error: ${e.message}`); - process.exit(2); -} \ No newline at end of file diff --git a/integration/language_service_plugin/tools/typescript_validator.ts b/integration/language_service_plugin/tools/typescript_validator.ts deleted file mode 100644 index 0bad6a4d07..0000000000 --- a/integration/language_service_plugin/tools/typescript_validator.ts +++ /dev/null @@ -1,164 +0,0 @@ -import * as fs from 'fs'; -import * as minimist from 'minimist'; - -let errorsDetected = false; - -const start = Date.now(); - -function reportError(arg: string): boolean { - console.error(`Unknown argument: ${arg}`); - errorsDetected = true; - return false; -} - -function help() { - console.log('TypeScript Validator') - console.log(`${process.argv[1]} [--expect | --golden] [--pwd ]`); - console.log(` - Validate that the emitted output produces the expect JSON.`) -} - -let args = minimist(process.argv.slice(2), { string: ['expect', 'pwd'], boolean: ['golden'], unknown: reportError }); - -if (!args.golden && !args.expect) { - console.log('Expected -golden or -expect'); - errorsDetected = true; -} - -if (args.golden && args.expect) { - console.log('Expected -golded or -expect but not both'); - errorsDetected = true; -} - -if (errorsDetected) { - help(); - process.exit(2); -} - -var expected: any; -if (args.expect) { - expected = JSON.parse(fs.readFileSync(args.expect, 'utf8')); -} - -// Reader -let pending = Buffer.alloc(0); - -const prefix = 'Content-Length: '; - -function tryReadMessage(cb: (message: any) => void) { - const firstLine = pending.indexOf(10); - if (firstLine >= 1) { - const line = pending.toString('utf8', 0, firstLine); - if (!line.startsWith(prefix)) { - throw Error(`Unexpected input: ${line}`); - } - const length = +line.substring(prefix.length, firstLine - 1); - const dataStart = firstLine + 2; - const messageText = pending.toString('utf8', dataStart, dataStart + length); - const message = JSON.parse(messageText); - pending = pending.slice(dataStart + length + 1); - cb(message); - tryReadMessage(cb); - } -} - -function collect(cb: (error: any, messages: any[]) => void) { - const result: any[] = []; - - function report(error: any, messages: any[]) { - cb(error, messages); - cb = () => {}; - } - - process.stdin.on('error', report); - process.stdin.on('data', (data: Buffer) => { - try { - pending = Buffer.concat([pending, data], pending.length + data.length); - tryReadMessage((message: any) => { - result.push(message); - }); - } catch (e) { - report(e, []); - } - }); - - process.stdin.on('close', () => { - report(null, result); - }); -} - -function sanitize(messages: any[]): any[] { - return messages.filter((message: any) => { - return message && message.type == 'response'; - }).map((message: any) => { - // Only preserve a fixed set of fields. - const result: any = {}; - if (message.type != null) result.type = message.type; - if (message.command != null) result.command = message.command; - if (message.success != null) result.success = message.success; - if (message.body != null) result.body = message.body; - return result; - }); -} - - -function isPrimitive(value: any): boolean { - return Object(value) !== value; -} - -function expectPrimitive(received: any, expected: any) { - if (received !== expected) { - throw new Error(`Expected ${expected} but received ${received}`); - } -} - -function expectArray(received: any, expected: any[]) { - if (!Array.isArray(received)) { - throw new Error(`Expected an array, received ${JSON.stringify(received)}`); - } - if (received.length != expected.length) { - throw new Error(`Expected an array length ${expected.length}, received ${JSON.stringify(received)}`); - } - for (let i = 0; i < expected.length; i++) { - expect(received[i], expected[i]); - } -} - -function expectObject(received: any, expected: any) { - for (const name of Object.getOwnPropertyNames(expected)) { - if (!received.hasOwnProperty(name)) { - throw new Error(`Expected object an object containing a field ${name}, received ${JSON.stringify(expected)}`); - } - expect(received[name], expected[name]); - } -} - -function expect(received: any, expected: any) { - if (isPrimitive(expected)) { - expectPrimitive(received, expected); - } else if (Array.isArray(expected)) { - expectArray(received, expected); - } else { - expectObject(received, expected); - } -} - - -collect((err: any, messages: any[]) => { - if (err) { - console.error(err.message); - process.exit(1); - } - if (args.golden) { - console.log(JSON.stringify(sanitize(messages), null, ' ')); - } else { - try { - expect(sanitize(messages), expected); - console.log('PASSED:', Date.now() - start, 'ms'); - process.exit(0); - } catch(e) { - console.log('FAILED:', e.message); - process.exit(1); - } - } -}); diff --git a/integration/language_service_plugin/tsclient.ts b/integration/language_service_plugin/tsclient.ts new file mode 100644 index 0000000000..05dd3c0e0d --- /dev/null +++ b/integration/language_service_plugin/tsclient.ts @@ -0,0 +1,70 @@ +import { ChildProcess } from "child_process"; +import { EventEmitter } from "events"; + +/** + * Provides a client for tsserver. Tsserver does not use standard JSON-RPC + * protocol thus the need for this custom client. + */ +export class Client { + private data: Buffer|undefined; + private id = 0; + private responseEmitter = new EventEmitter(); + + constructor(private readonly server: ChildProcess) {} + + listen() { + this.server.stdout.on('data', (data: Buffer) => { + this.data = this.data ? Buffer.concat([this.data, data]) : data; + const CONTENT_LENGTH = 'Content-Length: ' + const index = this.data.indexOf(CONTENT_LENGTH); + if (index < 0) { + return; + } + let start = index + CONTENT_LENGTH.length; + let end = this.data.indexOf('\r\n', start); + if (end < start) { + return; + } + const contentLengthStr = this.data.slice(start, end).toString(); + const contentLength = Number(contentLengthStr); + if (isNaN(contentLength) || contentLength < 0) { + return; + } + start = end + 4; + end = start + contentLength; + if (end > this.data.length) { + return; + } + const content = this.data.slice(start, end).toString(); + this.data = this.data.slice(end); + try { + const payload = JSON.parse(content); + if (payload.type === "event") { + return; + } + this.responseEmitter.emit('response', payload); + } + catch (error) { + this.responseEmitter.emit('error', error); + } + }); + } + + async send(type: string, command: string, params: {}) { + const request = { + seq: this.id++, + type, + command, + arguments: params + }; + this.server.stdin.write(JSON.stringify(request) + '\r\n'); + return new Promise((resolve, reject) => { + this.responseEmitter.once('response', resolve); + this.responseEmitter.once('error', reject); + }); + } + + async sendRequest(command: string, params: {}) { + return this.send('request', command, params); + } +} diff --git a/integration/language_service_plugin/tsconfig.json b/integration/language_service_plugin/tsconfig.json index 2c7260d1bc..9730ac2fe3 100644 --- a/integration/language_service_plugin/tsconfig.json +++ b/integration/language_service_plugin/tsconfig.json @@ -1,13 +1,60 @@ { "compilerOptions": { - "target": "es5", - "module": "commonjs", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": [ "es2015", "dom" ], - "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true - } + /* Basic Options */ + "target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "include": ["*.ts"] } diff --git a/integration/language_service_plugin/typescripts/2.3/package.json b/integration/language_service_plugin/typescripts/2.3/package.json deleted file mode 100644 index a76f86606d..0000000000 --- a/integration/language_service_plugin/typescripts/2.3/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "2.3", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "typescript": "2.3.0" - } -} diff --git a/integration/language_service_plugin/typescripts/2.3/yarn.lock b/integration/language_service_plugin/typescripts/2.3/yarn.lock deleted file mode 100644 index 978ea5c25e..0000000000 --- a/integration/language_service_plugin/typescripts/2.3/yarn.lock +++ /dev/null @@ -1,7 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -typescript@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.0.tgz#2e63e09284392bc8158a2444c33e2093795c0418" diff --git a/integration/language_service_plugin/yarn.lock b/integration/language_service_plugin/yarn.lock index 2e3bc312da..73dcc87276 100644 --- a/integration/language_service_plugin/yarn.lock +++ b/integration/language_service_plugin/yarn.lock @@ -2,391 +2,44 @@ # yarn lockfile v1 -"@angular/animations@file:../../dist/packages-dist/animations": - version "6.0.0-beta.7-8203e0365a" - dependencies: - tslib "^1.9.0" - -"@angular/common@file:../../dist/packages-dist/common": - version "6.0.0-beta.7-8203e0365a" - dependencies: - tslib "^1.9.0" - -"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "6.0.0-beta.7-8203e0365a" - dependencies: - chokidar "^1.4.2" - minimist "^1.2.0" - reflect-metadata "^0.1.2" - tsickle "^0.27.2" - -"@angular/compiler@file:../../dist/packages-dist/compiler": - version "6.0.0-beta.7-8203e0365a" - dependencies: - tslib "^1.9.0" - "@angular/core@file:../../dist/packages-dist/core": - version "6.0.0-beta.7-8203e0365a" + version "7.2.0" dependencies: tslib "^1.9.0" "@angular/language-service@file:../../dist/packages-dist/language-service": - version "6.0.0-beta.7-8203e0365a" + version "7.2.0" -"@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "6.0.0-beta.7-8203e0365a" - dependencies: - tslib "^1.9.0" - -"@angular/platform-server@file:../../dist/packages-dist/platform-server": - version "6.0.0-beta.7-8203e0365a" - dependencies: - domino "^2.0.1" - tslib "^1.9.0" - xhr2 "^0.1.4" - -"@types/minimist@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" - -"@types/node@^7.0.5": - version "7.0.52" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.52.tgz#8990d3350375542b0c21a83cd0331e6a8fc86716" - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - -are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - -arr-flatten@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" +"@types/node@file:../../node_modules/@types/node": + version "10.9.4" balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - -binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -chokidar@^1.4.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -debug@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - -domino@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domino/-/domino-2.0.1.tgz#9e1d63215d0fe8dcb8202bff07effa1a216db504" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -for-in@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -glob@^7.0.5: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" +glob@^7.0.6: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -395,610 +48,58 @@ glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3: +inherits@2: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +jasmine-core@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.1.0.tgz#a4785e135d5df65024dfc9224953df585bd2766c" + integrity sha1-pHheE11d9lAk38kiSVPfWFvSdmw= -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" +"jasmine@file:../../node_modules/jasmine": + version "3.1.0" dependencies: - binary-extensions "^1.0.0" + glob "^7.0.6" + jasmine-core "~3.1.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - dependencies: - kind-of "^3.0.2" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - dependencies: - is-buffer "^1.1.5" - -micromatch@^2.1.5: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - -mime-types@^2.1.12, mime-types@~2.1.7: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - dependencies: - mime-db "~1.30.0" - -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -"mkdirp@>=0.5 0", mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -nan@^2.3.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" - -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - dependencies: - detect-libc "^1.0.2" - hawk "3.1.3" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - -normalize-path@^2.0.0, normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -once@^1.3.0, once@^1.3.3: +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -osenv@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -rc@^1.1.7: - version "1.2.3" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.3.tgz#51575a900f8dd68381c710b4712c2154c3e2035b" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" - -reflect-metadata@^0.1.2: - version "0.1.10" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -"rxjs@file:../../node_modules/rxjs": - version "6.0.0-alpha.4" - dependencies: - tslib "^1.9.0" - -safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -source-map-support@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.3.tgz#2b3d5fff298cfa4d1afd7d4352d569e9a0158e76" - dependencies: - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - -string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -tough-cookie@~2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - dependencies: - punycode "^1.4.1" - -tsickle@^0.27.2: - version "0.27.2" - resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.27.2.tgz#f33d46d046f73dd5c155a37922e422816e878736" - dependencies: - minimist "^1.2.0" - mkdirp "^0.5.1" - source-map "^0.6.0" - source-map-support "^0.5.0" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= tslib@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== "typescript@file:../../node_modules/typescript": - version "2.7.2" - -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -uuid@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" - dependencies: - string-width "^1.0.2" + version "3.2.2" wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -xhr2@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" - -"zone.js@file:../../node_modules/zone.js": - version "0.8.20" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= diff --git a/integration/ng_elements/package.json b/integration/ng_elements/package.json index 5b865031c2..2efcd364ab 100644 --- a/integration/ng_elements/package.json +++ b/integration/ng_elements/package.json @@ -23,7 +23,7 @@ "protractor": "file:../../node_modules/protractor" }, "scripts": { - "postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG", + "postinstall": "webdriver-manager update --gecko false --standalone false $CI_CHROMEDRIVER_VERSION_ARG", "closure": "java -jar node_modules/google-closure-compiler/compiler.jar --flagfile closure.conf", "test": "ngc && yarn run closure && concurrently \"yarn run serve\" \"yarn run protractor\" --kill-others --success first", "serve": "lite-server -c e2e/browser.config.json", diff --git a/integration/ngcc/test.sh b/integration/ngcc/test.sh index efa8901f7a..0e8e17d49e 100755 --- a/integration/ngcc/test.sh +++ b/integration/ngcc/test.sh @@ -39,6 +39,12 @@ ivy-ngcc grep "static ngInjectorDef: ɵngcc0.InjectorDef;" node_modules/@angular/core/src/application_module.d.ts if [[ $? != 0 ]]; then exit 1; fi +# Did it generate a base factory call for synthesized constructors correctly? + grep "const ɵMatTable_BaseFactory = ɵngcc0.ɵgetInheritedFactory(MatTable);" node_modules/@angular/material/esm2015/table.js + if [[ $? != 0 ]]; then exit 1; fi + grep "const ɵMatTable_BaseFactory = ɵngcc0.ɵgetInheritedFactory(MatTable);" node_modules/@angular/material/esm5/table.es5.js + if [[ $? != 0 ]]; then exit 1; fi + # Can it be safely run again (as a noop)? ivy-ngcc diff --git a/integration/ngcc/yarn.lock b/integration/ngcc/yarn.lock index 7f24bb3051..7321233239 100644 --- a/integration/ngcc/yarn.lock +++ b/integration/ngcc/yarn.lock @@ -3,7 +3,7 @@ "@angular/animations@file:../../dist/packages-dist/animations": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" @@ -17,12 +17,12 @@ parse5 "^5.0.0" "@angular/common@file:../../dist/packages-dist/common": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "7.1.0" + version "0.0.0" dependencies: canonical-path "1.0.0" chokidar "^1.4.2" @@ -37,22 +37,22 @@ yargs "9.0.1" "@angular/compiler@file:../../dist/packages-dist/compiler": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" "@angular/core@file:../../dist/packages-dist/core": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/forms@file:../../dist/packages-dist/forms": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/http@file:../../dist/packages-dist/http": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" @@ -66,17 +66,17 @@ parse5 "^5.0.0" "@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": - version "7.1.0" + version "7.2.0-rc.0" dependencies: tslib "^1.9.0" "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" "@angular/router@file:../../dist/packages-dist/router": - version "7.1.0" + version "0.0.0" dependencies: tslib "^1.9.0" @@ -3278,7 +3278,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= "typescript@file:../../node_modules/typescript": - version "3.1.1" + version "3.2.2" ua-parser-js@0.7.17: version "0.7.17" diff --git a/integration/platform-server/package.json b/integration/platform-server/package.json index 074e55772a..dfe007b8d2 100644 --- a/integration/platform-server/package.json +++ b/integration/platform-server/package.json @@ -24,6 +24,7 @@ }, "devDependencies": { "@types/jasmine": "2.5.41", + "@types/node": "10.11.x", "babel-core": "^6.23.1", "babel-loader": "^6.4.0", "babel-preset-es2015": "^6.22.0", @@ -33,7 +34,7 @@ "webpack": "^2.2.1" }, "scripts": { - "postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG", + "postinstall": "webdriver-manager update --gecko false --standalone false $CI_CHROMEDRIVER_VERSION_ARG", "build": "./build.sh", "test": "npm run build && concurrently \"npm run serve\" \"npm run protractor\" --kill-others --success first", "serve": "node built/server-bundle.js", diff --git a/integration/platform-server/yarn.lock b/integration/platform-server/yarn.lock new file mode 100644 index 0000000000..6b97c8eee6 --- /dev/null +++ b/integration/platform-server/yarn.lock @@ -0,0 +1,4528 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@angular/animations@file:../../dist/packages-dist/animations": + version "7.2.0-rc.0" + dependencies: + tslib "^1.9.0" + +"@angular/common@file:../../dist/packages-dist/common": + version "7.2.0-rc.0" + dependencies: + tslib "^1.9.0" + +"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": + version "7.2.0-rc.0" + dependencies: + canonical-path "1.0.0" + chokidar "^1.4.2" + convert-source-map "^1.5.1" + dependency-graph "^0.7.2" + magic-string "^0.25.0" + minimist "^1.2.0" + reflect-metadata "^0.1.2" + shelljs "^0.8.1" + source-map "^0.6.1" + tslib "^1.9.0" + yargs "9.0.1" + +"@angular/compiler@file:../../dist/packages-dist/compiler": + version "7.2.0-rc.0" + dependencies: + tslib "^1.9.0" + +"@angular/core@file:../../dist/packages-dist/core": + version "7.2.0-rc.0" + dependencies: + tslib "^1.9.0" + +"@angular/http@file:../../dist/packages-dist/http": + version "7.2.0-rc.0" + dependencies: + tslib "^1.9.0" + +"@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": + version "7.2.0-rc.0" + dependencies: + tslib "^1.9.0" + +"@angular/platform-browser@file:../../dist/packages-dist/platform-browser": + version "7.2.0-rc.0" + dependencies: + tslib "^1.9.0" + +"@angular/platform-server@file:../../dist/packages-dist/platform-server": + version "7.2.0-rc.0" + dependencies: + domino "^2.1.0" + tslib "^1.9.0" + xhr2 "^0.1.4" + +"@types/jasmine@2.5.41": + version "2.5.41" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.5.41.tgz#d5e86161a0af80d52062b310a33ed65b051a0713" + integrity sha1-1ehhYaCvgNUgYrMQoz7WWwUaBxM= + +"@types/node@10.11.x": + version "10.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.11.7.tgz#0e75ca9357d646ca754016ca1d68a127ad7e7300" + integrity sha512-yOxFfkN9xUFLyvWaeYj90mlqTJ41CsQzWKS3gXdOMOyPVacUsymejKxJ4/pMW7exouubuEeZLJawGgcNGYlTeg== + +"@types/q@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" + integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= + +"@types/selenium-webdriver@^3.0.0": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.14.tgz#0b20a2370e6b1b8322c9c3dfcaa409e6c7c0c0a9" + integrity sha512-4GbNCDs98uHCT/OMv40qQC/OpoPbYn9XdXeTiFwHBBFO6eJhYEPUu2zDKirXSbHlvDV8oZ9l8EQ+HrEx/YS9DQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + integrity sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ= + dependencies: + acorn "^4.0.3" + +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c= + +acorn@^5.0.0: + version "5.7.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + +adm-zip@^0.4.9: + version "0.4.13" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a" + integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw== + +agent-base@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + +ajv-keywords@^1.1.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + integrity sha1-MU3QpLM2j609/NxU7eYXG4htrzw= + +ajv@^4.7.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY= + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^6.5.5: + version "6.6.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.2.tgz#caceccf474bf3fc3ce3b147443711a24063cc30d" + integrity sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +ansi-regex@^0.2.0, ansi-regex@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + integrity sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-styles@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + integrity sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94= + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA== + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + dependencies: + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + +async@^2.1.2: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== + dependencies: + lodash "^4.17.10" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.23.1, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-loader@^6.4.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca" + integrity sha1-CzQRLVsHSKjc2/Uaz2+b1C1QuMo= + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.16" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8= + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs= + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM= + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos= + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ= + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM= + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg= + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40= + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys= + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw= + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek= + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-regenerator@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8= + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-es2015@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" + integrity sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk= + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.24.1" + babel-plugin-transform-es2015-classes "^6.24.1" + babel-plugin-transform-es2015-computed-properties "^6.24.1" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.24.1" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-plugin-transform-es2015-modules-systemjs "^6.24.1" + babel-plugin-transform-es2015-modules-umd "^6.24.1" + babel-plugin-transform-es2015-object-super "^6.24.1" + babel-plugin-transform-es2015-parameters "^6.24.1" + babel-plugin-transform-es2015-shorthand-properties "^6.24.1" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.24.1" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== + +binary-extensions@^1.0.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" + integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== + +blocking-proxy@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-1.0.1.tgz#81d6fd1fe13a4c0d6957df7f91b75e98dac40cb2" + integrity sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA== + dependencies: + minimist "^1.2.0" + +bluebird@2.9.6: + version "2.9.6" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.9.6.tgz#1fc3a6b1685267dc121b5ec89b32ce069d81ab7d" + integrity sha1-H8OmsWhSZ9wSG17ImzLOBp2Bq30= + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.18.3: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserstack@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.1.tgz#e2dfa66ffee940ebad0a07f7e00fd4687c455d66" + integrity sha512-O8VMT64P9NOLhuIoD4YngyxBURefaSdR4QdhG8l6HZ9VxtU7jc3m6jLufFwKA5gaf7fetfB2TnRJnMxyob+heg== + dependencies: + https-proxy-agent "^2.2.1" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +canonical-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" + integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + integrity sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ= + dependencies: + ansi-styles "^1.1.0" + escape-string-regexp "^1.0.0" + has-ansi "^0.1.0" + strip-ansi "^0.3.0" + supports-color "^0.2.0" + +chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.4.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chokidar@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + integrity sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + +commander@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d" + integrity sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0= + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concurrently@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.1.0.tgz#dc5ef0459090012604756668894c04b434ef90d1" + integrity sha1-3F7wRZCQASYEdWZoiUwEtDTvkNE= + dependencies: + bluebird "2.9.6" + chalk "0.5.1" + commander "2.6.0" + lodash "^4.5.1" + moment "^2.11.2" + rx "2.3.24" + spawn-default-shell "^1.1.0" + tree-kill "^1.1.0" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.5.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js@^2.4.0, core-js@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042" + integrity sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg== + +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.0.0, decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +dependency-graph@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" + integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domino@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.1.tgz#cd5c639940db72bb7cde1cdb5beea466a4113136" + integrity sha512-fqoTi6oQ881wYRENIEmz78hKVoc3X9HqVpklo419yxzebys6dtU5c83iVh3UYvvexPFdAuwlDYCsUM9//CrMMg== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +elliptic@^6.0.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +enhanced-resolve@^3.3.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" + integrity sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24= + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.7" + +errno@^0.1.3: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es6-promise@^4.0.3: + version "4.2.5" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054" + integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg== + +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.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@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +express@^4.14.1: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + integrity sha1-yN765XyKUqinhPnjHFfHQumToLk= + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.0.0, fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.6, glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + integrity sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4= + dependencies: + ansi-regex "^0.2.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +interpret@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= + dependencies: + builtin-modules "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= + dependencies: + is-extglob "^2.1.1" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= + dependencies: + path-is-inside "^1.0.1" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +jasmine-core@~2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" + integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= + +jasmine@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.8.0.tgz#6b089c0a11576b1f16df11b80146d91d4e8b8a3e" + integrity sha1-awicChFXax8W3xG4AUbZHU6Lij4= + dependencies: + exit "^0.1.2" + glob "^7.0.6" + jasmine-core "~2.8.0" + +jasminewd2@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" + integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-loader@^0.5.4: + version "0.5.7" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" + integrity sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= + dependencies: + immediate "~3.0.5" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.1.tgz#026f12fe7c3115992896ac02ba022ba92971b979" + integrity sha512-By6ZFY7ETWOc9RFaAIb23IjJVcM4dvJC/N57nmdz9RSkMXvAXGI7SyVlAw3v8vjtDRlqThgVDVmTnr9fqMlxkw== + +loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash@^4.17.10, lodash@^4.17.4, lodash@^4.5.1: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +magic-string@^0.25.0: + version "0.25.1" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.1.tgz#b1c248b399cd7485da0fe7385c2fc7011843266e" + integrity sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg== + dependencies: + sourcemap-codec "^1.4.1" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= + dependencies: + mimic-fn "^1.0.0" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.37.0: + version "1.37.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== + +mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19: + version "2.1.21" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== + dependencies: + mime-db "~1.37.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + +minipass@^2.2.1, minipass@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +moment@^2.11.2: + version "2.23.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.23.0.tgz#759ea491ac97d54bac5ad776996e2a58cc1bc225" + integrity sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +nan@^2.9.2: + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" + integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +neo-async@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + integrity sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +npm-bundled@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" + integrity sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g== + +npm-packlist@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.2.0.tgz#55a60e793e272f00862c7089274439a4cc31fc7f" + integrity sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +optimist@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +pako@~1.0.2, pako@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.7.tgz#2473439021b57f1516c82f58be7275ad8ef1bb27" + integrity sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ== + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + integrity sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q= + dependencies: + find-up "^1.0.0" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +"protractor@file:../../node_modules/protractor": + version "5.4.2" + dependencies: + "@types/q" "^0.0.32" + "@types/selenium-webdriver" "^3.0.0" + blocking-proxy "^1.0.0" + browserstack "^1.5.1" + chalk "^1.1.3" + glob "^7.0.3" + jasmine "2.8.0" + jasminewd2 "^2.1.0" + optimist "~0.6.0" + q "1.4.1" + saucelabs "^1.5.0" + selenium-webdriver "3.6.0" + source-map-support "~0.4.0" + webdriver-js-extender "2.1.0" + webdriver-manager "^12.0.6" + +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.24: + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + integrity sha1-VXBbzZPF82c1MMLCy8DCs63cKG4= + +q@^1.4.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.5.2, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + integrity sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +raw-loader@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" + integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.3, readable-stream@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +reflect-metadata@^0.1.2: + version "0.1.12" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" + integrity sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A== + +regenerate@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA= + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +request@^2.87.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.6: + version "1.9.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" + integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== + dependencies: + path-parse "^1.0.6" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= + dependencies: + align-text "^0.1.1" + +rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rx@2.3.24: + version "2.3.24" + resolved "https://registry.yarnpkg.com/rx/-/rx-2.3.24.tgz#14f950a4217d7e35daa71bbcbe58eff68ea4b2b7" + integrity sha1-FPlQpCF9fjXapxu8vljv9o6ksrc= + +"rxjs@file:../../node_modules/rxjs": + version "6.3.3" + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saucelabs@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" + integrity sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ== + dependencies: + https-proxy-agent "^2.2.1" + +sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + integrity sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q== + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shelljs@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" + integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15, source-map-support@~0.4.0: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" + integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg== + +spawn-default-shell@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/spawn-default-shell/-/spawn-default-shell-1.1.0.tgz#095439d44c4b7c0aff56a53929fbaab87878e7c6" + integrity sha1-CVQ51ExLfAr/VqU5KfuquHh458Y= + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" + integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sshpk@^1.7.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.0.tgz#1d4963a2fbffe58050aa9084ca20be81741c07de" + integrity sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + integrity sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds= + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + integrity sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA= + dependencies: + ansi-regex "^0.2.1" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + integrity sha1-2S3iaU6z9nMjlz1649i1W0wiGQo= + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + dependencies: + has-flag "^1.0.0" + +tapable@^0.2.7, tapable@~0.2.5: + version "0.2.9" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.9.tgz#af2d8bbc9b04f74ee17af2b4d9048f807acd18a8" + integrity sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A== + +tar@^4: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== + dependencies: + setimmediate "^1.0.4" + +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + integrity sha1-ckGdSovn1s51FI/YsyTlk6cRwu0= + dependencies: + os-tmpdir "~1.0.1" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tree-kill@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" + integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q== + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +"typescript@file:../../node_modules/typescript": + version "3.2.2" + +uglify-js@^2.8.27: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM= + dependencies: + indexof "0.0.1" + +watchpack@^1.3.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +webdriver-js-extender@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz#57d7a93c00db4cc8d556e4d3db4b5db0a80c3bb7" + integrity sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ== + dependencies: + "@types/selenium-webdriver" "^3.0.0" + selenium-webdriver "^3.0.1" + +webdriver-manager@^12.0.6: + version "12.1.1" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.1.1.tgz#66c3271f69cefdaa9fdfca617ae95afae41c3c62" + integrity sha512-L9TEQmZs6JbMMRQI1w60mfps265/NCr0toYJl7p/R2OAk6oXAfwI6jqYP7EWae+d7Ad2S2Aj4+rzxoSjqk3ZuA== + dependencies: + adm-zip "^0.4.9" + chalk "^1.1.1" + del "^2.2.0" + glob "^7.0.3" + ini "^1.3.4" + minimist "^1.2.0" + q "^1.4.1" + request "^2.87.0" + rimraf "^2.5.2" + semver "^5.3.0" + xml2js "^0.4.17" + +webpack-sources@^1.0.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85" + integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^2.2.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.7.0.tgz#b2a1226804373ffd3d03ea9c6bd525067034f6b1" + integrity sha512-MjAA0ZqO1ba7ZQJRnoCdbM56mmFpipOPUv/vQpwwfSI42p5PVDdoiuK2AL2FwFUVgT859Jr43bFZXRg/LNsqvg== + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^4.7.0" + ajv-keywords "^1.1.1" + async "^2.1.2" + enhanced-resolve "^3.3.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^0.2.16" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^3.1.0" + tapable "~0.2.5" + uglify-js "^2.8.27" + watchpack "^1.3.1" + webpack-sources "^1.0.1" + yargs "^6.0.0" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +xhr2@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" + integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= + +xml2js@^0.4.17: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + +yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + integrity sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw= + dependencies: + camelcase "^3.0.0" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= + dependencies: + camelcase "^4.1.0" + +yargs@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" + integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + +yargs@^6.0.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + integrity sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +"zone.js@file:../../node_modules/zone.js": + version "0.8.26" diff --git a/integration/run_tests.sh b/integration/run_tests.sh index afc2a72a4c..2137b69d30 100755 --- a/integration/run_tests.sh +++ b/integration/run_tests.sh @@ -10,20 +10,29 @@ cd "$(dirname "$0")" # basedir is the workspace root readonly basedir=$(pwd)/.. -# Track payload size functions +# When running on the CI, we track the payload size of various integration output files. Also +# we shard tests across multiple CI job instances. The script needs to be run with a shard index +# and the maximum amount of shards available for the integration tests on the CI. +# For example: "./run_tests.sh {SHARD_INDEX} {MAX_SHARDS}". if $CI; then - # We don't install this by default because it contains some broken Bazel setup - # and also it's a very big dependency that we never use except when publishing - # payload sizes on CI. - yarn add --silent -D firebase-tools@5.1.1 source ${basedir}/scripts/ci/payload-size.sh + SHARD_INDEX=${1:?"No shard index has been specified."} + MAX_SHARDS=${2:?"The maximum amount of shards has not been specified."} + + # Determines the tests that need to be run for this shard index. + TEST_DIRS=$(node ./get-sharded-tests.js --shardIndex ${SHARD_INDEX} --maxShards ${MAX_SHARDS}) + # NB: we don't run build-packages-dist.sh because we expect that it was done # by an earlier job in the CircleCI workflow. else # Not on CircleCI so let's build the packages-dist directory. # This should be fast on incremental re-build. ${basedir}/scripts/build-packages-dist.sh + + # If we aren't running on CircleCI, we do not shard tests because this would be the job of + # Bazel eventually. For now, we just run all tests sequentially when running locally. + TEST_DIRS=$(ls | grep -v node_modules) fi # Workaround https://github.com/yarnpkg/yarn/issues/2165 @@ -36,7 +45,7 @@ rm_cache mkdir $cache trap rm_cache EXIT -for testDir in $(ls | grep -v node_modules) ; do +for testDir in ${TEST_DIRS}; do [[ -d "$testDir" ]] || continue echo "#################################" echo "Running integration test $testDir" @@ -48,9 +57,10 @@ for testDir in $(ls | grep -v node_modules) ; do yarn install --cache-folder ../$cache yarn test || exit 1 - # Track payload size for cli-hello-world and hello_world__closure and the render3 tests - if $CI && ([[ $testDir == cli-hello-world ]] || [[ $testDir == hello_world__closure ]]); then - if [[ $testDir == cli-hello-world ]]; then + # Track payload size for cli-hello-world, cli-hello-world-ivy-minimal, cli-hello-world-ivy-compat and + # hello_world__closure + if $CI && ([[ $testDir == cli-hello-world ]] || [[ $testDir == cli-hello-world-ivy-minimal ]] || [[ $testDir == cli-hello-world-ivy-compat ]] || [[ $testDir == hello_world__closure ]]); then + if ([[ $testDir == cli-hello-world ]] || [[ $testDir == cli-hello-world-ivy-minimal ]] || [[ $testDir == cli-hello-world-ivy-compat ]]); then yarn build fi diff --git a/integration/typings_test_ts32/tsconfig.json b/integration/typings_test_ts32/tsconfig.json index 4777e1cfa0..5ad151541f 100644 --- a/integration/typings_test_ts32/tsconfig.json +++ b/integration/typings_test_ts32/tsconfig.json @@ -4,7 +4,7 @@ "experimentalDecorators": true, "module": "commonjs", "moduleResolution": "node", - "outDir": "../../dist/typings_test_ts31/", + "outDir": "../../dist/typings_test_ts32/", "rootDir": ".", "target": "es5", "lib": [ diff --git a/karma-js.conf.js b/karma-js.conf.js index e1e44badac..e1575ed0ad 100644 --- a/karma-js.conf.js +++ b/karma-js.conf.js @@ -144,20 +144,19 @@ module.exports = function(config) { browserNoActivityTimeout: 300000, }); - if (process.env.TRAVIS) { - var buildId = - 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')'; - if (process.env.CI_MODE.startsWith('saucelabs')) { - config.sauceLabs.build = buildId; - config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER; + if (process.env.CIRCLECI) { + const tunnelIdentifier = process.env['SAUCE_TUNNEL_IDENTIFIER']; - // Try "websocket" for a faster transmission first. Fallback to "polling" if necessary. - config.transports = ['websocket', 'polling']; - } + // Setup the Saucelabs plugin so that it can launch browsers using the proper tunnel. + config.sauceLabs.build = tunnelIdentifier; + config.sauceLabs.tunnelIdentifier = tunnelIdentifier; - if (process.env.CI_MODE.startsWith('browserstack')) { - config.browserStack.build = buildId; - config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER; - } + // Setup the Browserstack plugin so that it can launch browsers using the proper tunnel. + // TODO: This is currently not used because BS doesn't run on the CI. Consider removing. + config.browserStack.build = tunnelIdentifier; + config.browserStack.tunnelIdentifier = tunnelIdentifier; + + // Try "websocket" for a faster transmission first. Fallback to "polling" if necessary. + config.transports = ['websocket', 'polling']; } }; diff --git a/modules/benchmarks/BUILD.bazel b/modules/benchmarks/BUILD.bazel index 8ef1f366db..7159d1f14b 100644 --- a/modules/benchmarks/BUILD.bazel +++ b/modules/benchmarks/BUILD.bazel @@ -1,8 +1,7 @@ package(default_visibility = ["//visibility:public"]) -filegroup( - name = "favicon", - srcs = [ - "favicon.ico", - ], -) +exports_files([ + "tsconfig-build.json", + "tsconfig-e2e.json", + "start-server.js", +]) diff --git a/modules/benchmarks/README.md b/modules/benchmarks/README.md index 266e7a0a51..2acb18b650 100644 --- a/modules/benchmarks/README.md +++ b/modules/benchmarks/README.md @@ -1,29 +1,25 @@ # How to run the benchmarks locally ## Run in the browser -$ build.sh (only needed 1x to copy over third party resources) -$ cp -r ./modules/benchmarks ./dist/all/ -$ ./node_modules/.bin/tsc -p modules --emitDecoratorMetadata -w -$ gulp serve -$ open http://localhost:8000/all/benchmarks/src/tree/ng2/index.html?bundles=false + +```bash +yarn bazel run modules/benchmarks/src/tree/{name}:devserver + +# e.g. "ng2" tree benchmark: +yarn bazel run modules/benchmarks/src/tree/ng2:devserver +``` ## Run e2e tests -$ export NODE_PATH=$(pwd)/dist/all:$(pwd)/dist/tools -$ ./node_modules/.bin/protractor protractor-e2e.conf.js --specs=dist/all/benchmarks/e2e_test/tree_spec.js -Options for protractor with `protractor-e2e.conf.js`: -- `--bundles=true`: use prebuilt bundles -- `--ng-help`: show all available options +``` +# Run e2e tests of individual applications: +yarn bazel test modules/benchmarks/src/tree/ng2/... -## Run benchmarks tests -$ export NODE_PATH=$(pwd)/dist/all:$(pwd)/dist/tools -$ ./node_modules/.bin/protractor protractor-perf.conf.js --specs=dist/all/benchmarks/e2e_test/tree_perf.js +# Run all e2e tests: +yarn bazel test modules/benchmarks/... +``` -Options for protractor with `protractor-perf.conf.js`: -- `--bundles=true`: use prebuilt bundles -- `--ng-help`: show all available options +## Use of *_aot.ts files -## Compile *_aot.ts files - -These files are compiled as part of the compiler_cli integration tests. -See `@angular/compile_cli/integrationtest/tsconfig.json` +The `*_aot.ts` files are used as entry-points within Google to run the benchmark +tests. These are still built as part of the corresponding `ng_module` rule. diff --git a/modules/benchmarks/benchmark_test.bzl b/modules/benchmarks/benchmark_test.bzl new file mode 100644 index 0000000000..2f068d8f2a --- /dev/null +++ b/modules/benchmarks/benchmark_test.bzl @@ -0,0 +1,24 @@ +load("//packages/bazel:index.bzl", "protractor_web_test_suite") + +""" + Macro that can be used to define a benchmark test. This differentiates from + a normal Protractor test suite because we specify a custom "perf" configuration + that sets up "@angular/benchpress". +""" + +def benchmark_test(name, server, deps, tags = []): + protractor_web_test_suite( + name = name, + configuration = "//:protractor-perf.conf.js", + data = [ + "//packages/bazel/src/protractor/utils", + "//packages/benchpress", + ], + on_prepare = "//modules/benchmarks:start-server.js", + server = server, + tags = tags, + deps = [ + "@ngdeps//protractor", + "@ngdeps//yargs", + ] + deps, + ) diff --git a/modules/benchmarks/e2e_test/largeform_spec.ts b/modules/benchmarks/e2e_test/largeform_spec.ts deleted file mode 100644 index 4a837dd492..0000000000 --- a/modules/benchmarks/e2e_test/largeform_spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {openBrowser, verifyNoBrowserErrors} from 'e2e_util/e2e_util'; -import {$, By, element} from 'protractor'; - -describe('largeform benchmark spec', () => { - - afterEach(verifyNoBrowserErrors); - - it('should work for ng2', () => { - testLargeformBenchmark({ - url: 'all/benchmarks/src/largeform/ng2/index.html', - }); - }); - - function testLargeformBenchmark( - openConfig: {url: string, ignoreBrowserSynchronization?: boolean}) { - openBrowser({ - url: openConfig.url, - params: [{name: 'copies', value: 1}], - ignoreBrowserSynchronization: openConfig.ignoreBrowserSynchronization, - }); - $('#createDom').click(); - expect(element.all(By.css('input[name=value0]')).get(0).getAttribute('value')) - .toBe('someValue0'); - $('#destroyDom').click(); - expect(element.all(By.css('input[name=value0]')).count()).toBe(0); - } -}); diff --git a/modules/benchmarks/e2e_test/largetable_perf.ts b/modules/benchmarks/e2e_test/largetable_perf.ts deleted file mode 100644 index 9dfb1037c6..0000000000 --- a/modules/benchmarks/e2e_test/largetable_perf.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { runBenchmark, verifyNoBrowserErrors } from 'e2e_util/perf_util'; -import { $ } from 'protractor'; - -interface Worker { - id: string; - prepare?(): void; - work(): void; -} - -const CreateOnlyWorker: Worker = { - id: 'createOnly', - prepare: () => $('#destroyDom').click(), - work: () => $('#createDom').click() -}; - -const CreateAndDestroyWorker: Worker = { - id: 'createDestroy', - work: () => { - $('#createDom').click(); - $('#destroyDom').click(); - } -}; - -const UpdateWorker: Worker = { - id: 'update', - work: () => $('#createDom').click() -}; - -describe('largetable benchmark perf', () => { - - afterEach(verifyNoBrowserErrors); - - [CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => { - describe(worker.id, () => { - it('should run for ng2', done => { - runTableBenchmark({ - id: `largeTable.ng2.${worker.id}`, - url: 'all/benchmarks/src/largetable/ng2/index.html', - worker: worker - }).then(done, done.fail); - }); - - it('should run for ng2 with ngSwitch', done => { - runTableBenchmark({ - id: `largeTable.ng2_switch.${worker.id}`, - url: 'all/benchmarks/src/largetable/ng2_switch/index.html', - worker: worker - }).then(done, done.fail); - }); - - it('should run for iv', done => { - runTableBenchmark({ - id: `largeTable.iv.${worker.id}`, - url: 'all/benchmarks/src/largetable/iv/index.html', - ignoreBrowserSynchronization: true, - worker: worker - }).then(done, done.fail); - }); - - it('should run for the baseline', done => { - runTableBenchmark({ - id: `largeTable.baseline.${worker.id}`, - url: 'all/benchmarks/src/largetable/baseline/index.html', - ignoreBrowserSynchronization: true, - worker: worker - }).then(done, done.fail); - }); - - it('should run for incremental-dom', done => { - runTableBenchmark({ - id: `largeTable.incremental_dom.${worker.id}`, - url: 'all/benchmarks/src/largetable/incremental_dom/index.html', - ignoreBrowserSynchronization: true, - worker: worker - }).then(done, done.fail); - }); - }); - }); - - function runTableBenchmark( - config: {id: string, url: string, ignoreBrowserSynchronization?: boolean, worker: Worker}) { - return runBenchmark({ - id: config.id, - url: config.url, - ignoreBrowserSynchronization: config.ignoreBrowserSynchronization, - params: [{name: 'cols', value: 40}, {name: 'rows', value: 200}], - prepare: config.worker.prepare, - work: config.worker.work - }); - } -}); diff --git a/modules/benchmarks/e2e_test/largetable_spec.ts b/modules/benchmarks/e2e_test/largetable_spec.ts deleted file mode 100644 index d002df5a55..0000000000 --- a/modules/benchmarks/e2e_test/largetable_spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { openBrowser, verifyNoBrowserErrors } from 'e2e_util/e2e_util'; -import { $ } from 'protractor'; - -describe('largetable benchmark spec', () => { - - afterEach(verifyNoBrowserErrors); - - it('should work for ng2', () => { - testTableBenchmark({ - url: 'all/benchmarks/src/largetable/ng2/index.html', - }); - }); - - it('should work for ng2 switch', () => { - testTableBenchmark({ - url: 'all/benchmarks/src/largetable/ng2_switch/index.html', - }); - }); - - it('should work for iv', () => { - testTableBenchmark({ - url: 'all/benchmarks/src/largetable/iv/index.html', - ignoreBrowserSynchronization: true, - }); - }); - - it('should work for the baseline', () => { - testTableBenchmark({ - url: 'all/benchmarks/src/largetable/baseline/index.html', - ignoreBrowserSynchronization: true, - }); - }); - - it('should work for the incremental-dom', () => { - testTableBenchmark({ - url: 'all/benchmarks/src/largetable/incremental_dom/index.html', - ignoreBrowserSynchronization: true, - }); - }); - - function testTableBenchmark(openConfig: {url: string, ignoreBrowserSynchronization?: boolean}) { - openBrowser({ - url: openConfig.url, - ignoreBrowserSynchronization: openConfig.ignoreBrowserSynchronization, - params: [{name: 'cols', value: 5}, {name: 'rows', value: 5}], - }); - $('#createDom').click(); - expect($('#root').getText()).toContain('0/0'); - $('#createDom').click(); - expect($('#root').getText()).toContain('A/A'); - $('#destroyDom').click(); - expect($('#root').getText()).toEqual(''); - } -}); diff --git a/modules/benchmarks/e2e_test/tree_data.ts b/modules/benchmarks/e2e_test/tree_data.ts deleted file mode 100644 index d33c597f54..0000000000 --- a/modules/benchmarks/e2e_test/tree_data.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {$} from 'protractor'; - -export const CreateBtn = '#createDom'; -export const DestroyBtn = '#destroyDom'; -export const DetectChangesBtn = '#detectChanges'; -export const RootEl = '#root'; -export const NumberOfChecksEl = '#numberOfChecks'; - -export interface Benchmark { - id: string; - url: string; - buttons: string[]; - ignoreBrowserSynchronization?: boolean; - extraParams?: {name: string, value: any}[]; -} - -const CreateDestroyButtons: string[] = [CreateBtn, DestroyBtn]; -const CreateDestroyDetectChangesButtons: string[] = [...CreateDestroyButtons, DetectChangesBtn]; - -export const Benchmarks: Benchmark[] = [ - { - id: `deepTree.ng2`, - url: 'all/benchmarks/src/tree/ng2/index.html', - buttons: CreateDestroyDetectChangesButtons, - }, - { - id: `deepTree.ng2.next`, - url: 'all/benchmarks/src/tree/ng2_next/index.html', - buttons: CreateDestroyDetectChangesButtons, - ignoreBrowserSynchronization: true, - // Can't use bundles as we use non exported code - extraParams: [{name: 'bundles', value: false}] - }, - { - id: `deepTree.ng2.static`, - url: 'all/benchmarks/src/tree/ng2_static/index.html', - buttons: CreateDestroyButtons, - }, - { - id: `deepTree.ng2_switch`, - url: 'all/benchmarks/src/tree/ng2_switch/index.html', - buttons: CreateDestroyButtons, - }, - { - id: `deepTree.ng2.render3_function`, - url: 'all/benchmarks/src/tree/render3_function/index.html', - buttons: CreateDestroyDetectChangesButtons, - ignoreBrowserSynchronization: true, - }, - { - id: `deepTree.iv`, - url: 'all/benchmarks/src/tree/iv/index.html', - buttons: CreateDestroyDetectChangesButtons, - ignoreBrowserSynchronization: true, - }, - { - id: `deepTree.baseline`, - url: 'all/benchmarks/src/tree/baseline/index.html', - buttons: CreateDestroyButtons, - ignoreBrowserSynchronization: true, - }, - { - id: `deepTree.incremental_dom`, - url: 'all/benchmarks/src/tree/incremental_dom/index.html', - buttons: CreateDestroyButtons, - ignoreBrowserSynchronization: true, - }, - { - id: `deepTree.polymer`, - url: 'all/benchmarks/src/tree/polymer/index.html', - buttons: CreateDestroyButtons, - ignoreBrowserSynchronization: true, - }, - { - id: `deepTree.polymer_leaves`, - url: 'all/benchmarks/src/tree/polymer_leaves/index.html', - buttons: CreateDestroyButtons, - ignoreBrowserSynchronization: true, - }, - { - id: `deepTree.ng1`, - url: 'all/benchmarks/src/tree/ng1/index.html', - buttons: CreateDestroyDetectChangesButtons, - } -]; diff --git a/modules/benchmarks/e2e_test/tree_perf.ts b/modules/benchmarks/e2e_test/tree_perf.ts deleted file mode 100644 index 12034c7e07..0000000000 --- a/modules/benchmarks/e2e_test/tree_perf.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {runBenchmark, verifyNoBrowserErrors} from 'e2e_util/perf_util'; -import {$, browser} from 'protractor'; - -import {Benchmark, Benchmarks, CreateBtn, DestroyBtn, DetectChangesBtn, RootEl} from './tree_data'; - -describe('tree benchmark perf', () => { - - let _oldRootEl: any; - beforeEach(() => _oldRootEl = browser.rootEl); - - afterEach(() => { - browser.rootEl = _oldRootEl; - verifyNoBrowserErrors(); - }); - - Benchmarks.forEach(benchmark => { - describe(benchmark.id, () => { - // This is actually a destroyOnly benchmark - it('should work for createOnly', done => { - runTreeBenchmark({ - id: 'createOnly', - benchmark, - prepare: () => $(CreateBtn).click(), - work: () => $(DestroyBtn).click() - }).then(done, done.fail); - }); - - it('should work for createOnlyForReal', done => { - runTreeBenchmark({ - id: 'createOnlyForReal', - benchmark, - prepare: () => $(DestroyBtn).click(), - work: () => $(CreateBtn).click() - }).then(done, done.fail); - }); - - it('should work for createDestroy', done => { - runTreeBenchmark({ - id: 'createDestroy', - benchmark, - work: () => { - $(DestroyBtn).click(); - $(CreateBtn).click(); - } - }).then(done, done.fail); - }); - - it('should work for update', done => { - runTreeBenchmark({id: 'update', benchmark, work: () => $(CreateBtn).click()}) - .then(done, done.fail); - }); - - if (benchmark.buttons.indexOf(DetectChangesBtn) !== -1) { - it('should work for detectChanges', done => { - runTreeBenchmark({ - id: 'detectChanges', - benchmark, - work: () => $(DetectChangesBtn).click(), - setup: () => $(DestroyBtn).click() - }).then(done, done.fail); - }); - } - - }); - }); -}); - -function runTreeBenchmark({id, benchmark, prepare, setup, work}: { - id: string; benchmark: Benchmark, prepare ? () : void; setup ? () : void; work(): void; -}) { - let params = [{name: 'depth', value: 11}]; - if (benchmark.extraParams) { - params = params.concat(benchmark.extraParams); - } - browser.rootEl = RootEl; - return runBenchmark({ - id: `${benchmark.id}.${id}`, - url: benchmark.url, - ignoreBrowserSynchronization: benchmark.ignoreBrowserSynchronization, - params: params, - work: work, - prepare: prepare, - setup: setup - }); -} diff --git a/modules/benchmarks/e2e_test/tree_spec.ts b/modules/benchmarks/e2e_test/tree_spec.ts deleted file mode 100644 index 6c58fd4b84..0000000000 --- a/modules/benchmarks/e2e_test/tree_spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {openBrowser, verifyNoBrowserErrors} from 'e2e_util/e2e_util'; -import {$, browser} from 'protractor'; - -import {Benchmark, Benchmarks, CreateBtn, DestroyBtn, DetectChangesBtn, NumberOfChecksEl, RootEl} from './tree_data'; - -describe('tree benchmark spec', () => { - - let _oldRootEl: any; - beforeEach(() => _oldRootEl = browser.rootEl); - - afterEach(() => { - browser.rootEl = _oldRootEl; - verifyNoBrowserErrors(); - }); - - Benchmarks.forEach(benchmark => { - describe(benchmark.id, () => { - it('should work for createDestroy', () => { - openTreeBenchmark(benchmark); - $(CreateBtn).click(); - expect($(RootEl).getText()).toContain('0'); - $(DestroyBtn).click(); - expect($(RootEl).getText()).toEqual(''); - }); - - it('should work for update', () => { - openTreeBenchmark(benchmark); - $(CreateBtn).click(); - $(CreateBtn).click(); - expect($(RootEl).getText()).toContain('A'); - }); - - if (benchmark.buttons.indexOf(DetectChangesBtn) !== -1) { - it('should work for detectChanges', () => { - openTreeBenchmark(benchmark); - $(DetectChangesBtn).click(); - expect($(NumberOfChecksEl).getText()).toContain('10'); - }); - } - }); - }); - - function openTreeBenchmark(benchmark: Benchmark) { - let params = [{name: 'depth', value: 4}]; - if (benchmark.extraParams) { - params = params.concat(benchmark.extraParams); - } - browser.rootEl = RootEl; - openBrowser({ - url: benchmark.url, - ignoreBrowserSynchronization: benchmark.ignoreBrowserSynchronization, - params: params, - }); - } -}); diff --git a/modules/benchmarks/src/BUILD.bazel b/modules/benchmarks/src/BUILD.bazel index 45901bd2fa..fd7fb9848a 100644 --- a/modules/benchmarks/src/BUILD.bazel +++ b/modules/benchmarks/src/BUILD.bazel @@ -4,13 +4,7 @@ load("//tools:defaults.bzl", "ts_library") ts_library( name = "util_lib", - srcs = [ - "util.ts", - ], - deps = [ - "//packages:types", - "//packages/core", - ], + srcs = ["util.ts"], ) ts_library( diff --git a/modules/benchmarks/src/largeform/BUILD.bazel b/modules/benchmarks/src/largeform/BUILD.bazel new file mode 100644 index 0000000000..0bfbe75e36 --- /dev/null +++ b/modules/benchmarks/src/largeform/BUILD.bazel @@ -0,0 +1,15 @@ +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "tests_lib", + testonly = 1, + srcs = ["largeform_perf.spec.ts"], + tsconfig = "//modules/benchmarks:tsconfig-e2e.json", + deps = [ + "//modules/e2e_util", + "@ngdeps//@types/jasminewd2", + "@ngdeps//protractor", + ], +) diff --git a/modules/benchmarks/e2e_test/largeform_perf.ts b/modules/benchmarks/src/largeform/largeform_perf.spec.ts similarity index 54% rename from modules/benchmarks/e2e_test/largeform_perf.ts rename to modules/benchmarks/src/largeform/largeform_perf.spec.ts index 42165a0358..1210745425 100644 --- a/modules/benchmarks/e2e_test/largeform_perf.ts +++ b/modules/benchmarks/src/largeform/largeform_perf.spec.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {runBenchmark, verifyNoBrowserErrors} from 'e2e_util/perf_util'; -import {$} from 'protractor'; +import {$, By, element} from 'protractor'; + +import {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; +import {runBenchmark} from '../../../e2e_util/perf_util'; interface Worker { id: string; @@ -15,7 +17,7 @@ interface Worker { work(): void; } -const CreateAndDestroyWorker: Worker = { +const CreateAndDestroyWorker = { id: 'createDestroy', work: () => { $('#createDom').click(); @@ -23,18 +25,28 @@ const CreateAndDestroyWorker: Worker = { } }; -describe('largeform benchmark perf', () => { +describe('largeform benchmark spec', () => { afterEach(verifyNoBrowserErrors); + it('should work for ng2', () => { + openBrowser({ + url: '/', + params: [{name: 'copies', value: 1}], + ignoreBrowserSynchronization: true, + }); + $('#createDom').click(); + expect(element.all(By.css('input[name=value0]')).get(0).getAttribute('value')) + .toBe('someValue0'); + $('#destroyDom').click(); + expect(element.all(By.css('input[name=value0]')).count()).toBe(0); + }); + [CreateAndDestroyWorker].forEach((worker) => { describe(worker.id, () => { it('should run for ng2', done => { - runLargeFormBenchmark({ - id: `largeform.ng2.${worker.id}`, - url: 'all/benchmarks/src/largeform/ng2/index.html', - worker: worker - }).then(done, done.fail); + runLargeFormBenchmark({url: '/', id: `largeform.ng2.${worker.id}`, worker: worker}) + .then(done, done.fail); }); }); }); diff --git a/modules/benchmarks/src/largeform/ng2/BUILD.bazel b/modules/benchmarks/src/largeform/ng2/BUILD.bazel new file mode 100644 index 0000000000..741b3cf264 --- /dev/null +++ b/modules/benchmarks/src/largeform/ng2/BUILD.bazel @@ -0,0 +1,45 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +# Note that this benchmark has been designed for Angular with ViewEngine, but once ViewEngine is +# removed, we should keep this benchmark and run it with Ivy (potentially rename it to "render3") +ng_module( + name = "ng2", + srcs = glob(["*.ts"]), + # FIXME-IVY(FW-998): ExpressionTranslatorVisitor#visitWriteKeyExpr is not implemented. + tags = ["fixme-ivy-aot"], + tsconfig = "//modules/benchmarks:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//modules/benchmarks/src:util_lib", + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/largeform/ng2/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + tags = ["fixme-ivy-aot"], + deps = [":ng2"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + tags = ["fixme-ivy-aot"], + deps = ["//modules/benchmarks/src/largeform:tests_lib"], +) diff --git a/modules/benchmarks/src/largeform/ng2/index.html b/modules/benchmarks/src/largeform/ng2/index.html index 02796b44c6..8e327a95d3 100644 --- a/modules/benchmarks/src/largeform/ng2/index.html +++ b/modules/benchmarks/src/largeform/ng2/index.html @@ -19,11 +19,5 @@
    Loading...
    - - diff --git a/modules/benchmarks/src/largeform/ng2/index.ts b/modules/benchmarks/src/largeform/ng2/index.ts index d630106729..8ceaaf04ba 100644 --- a/modules/benchmarks/src/largeform/ng2/index.ts +++ b/modules/benchmarks/src/largeform/ng2/index.ts @@ -12,7 +12,5 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {AppModule} from './app'; import {init} from './init'; -export function main() { - enableProdMode(); - platformBrowserDynamic().bootstrapModule(AppModule).then(init); -} +enableProdMode(); +platformBrowserDynamic().bootstrapModule(AppModule).then(init); diff --git a/modules/benchmarks/src/largetable/BUILD.bazel b/modules/benchmarks/src/largetable/BUILD.bazel index a03fd4fe0c..85706c9c97 100644 --- a/modules/benchmarks/src/largetable/BUILD.bazel +++ b/modules/benchmarks/src/largetable/BUILD.bazel @@ -4,25 +4,16 @@ load("//tools:defaults.bzl", "ts_library") ts_library( name = "util_lib", - srcs = [ - "util.ts", - ], - deps = [ - "//modules/benchmarks/src:util_lib", - "//packages:types", - "//packages/core", - ], + srcs = ["util.ts"], + deps = ["//modules/benchmarks/src:util_lib"], ) ts_library( name = "perf_lib", testonly = 1, - srcs = [ - "largetable_perf.spec.ts", - ], + srcs = ["largetable_perf.spec.ts"], deps = [ - "//modules/e2e_util:lib", - "//packages:types", + "//modules/e2e_util", "@ngdeps//protractor", ], ) diff --git a/modules/benchmarks/src/largetable/baseline/BUILD.bazel b/modules/benchmarks/src/largetable/baseline/BUILD.bazel new file mode 100644 index 0000000000..bcdbc22a1f --- /dev/null +++ b/modules/benchmarks/src/largetable/baseline/BUILD.bazel @@ -0,0 +1,29 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_library( + name = "baseline", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/largetable:util_lib", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/largetable/baseline/index", + index_html = "index.html", + port = 4200, + deps = [":baseline"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:perf_lib"], +) diff --git a/modules/benchmarks/src/largetable/baseline/index.html b/modules/benchmarks/src/largetable/baseline/index.html index 6c922ffe49..0095fb92ec 100644 --- a/modules/benchmarks/src/largetable/baseline/index.html +++ b/modules/benchmarks/src/largetable/baseline/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -24,11 +28,5 @@
    Loading...
    - - - \ No newline at end of file + diff --git a/modules/benchmarks/src/largetable/incremental_dom/BUILD.bazel b/modules/benchmarks/src/largetable/incremental_dom/BUILD.bazel new file mode 100644 index 0000000000..fc94da3175 --- /dev/null +++ b/modules/benchmarks/src/largetable/incremental_dom/BUILD.bazel @@ -0,0 +1,32 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_library( + name = "incremental_dom", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/largetable:util_lib", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/largetable/incremental_dom/index", + index_html = "index.html", + port = 4200, + static_files = [ + "@ngdeps//node_modules/incremental-dom:dist/incremental-dom.js", + ], + deps = [":incremental_dom"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:perf_lib"], +) diff --git a/modules/benchmarks/src/largetable/incremental_dom/index.html b/modules/benchmarks/src/largetable/incremental_dom/index.html index 9688ff7156..b2a38bcca1 100644 --- a/modules/benchmarks/src/largetable/incremental_dom/index.html +++ b/modules/benchmarks/src/largetable/incremental_dom/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -24,7 +28,5 @@
    - - - \ No newline at end of file + diff --git a/modules/benchmarks/src/largetable/incremental_dom/index.ts b/modules/benchmarks/src/largetable/incremental_dom/index.ts index 62f48e1a83..1b32df57c1 100644 --- a/modules/benchmarks/src/largetable/incremental_dom/index.ts +++ b/modules/benchmarks/src/largetable/incremental_dom/index.ts @@ -10,24 +10,26 @@ import {bindAction, profile} from '../../util'; import {buildTable, emptyTable} from '../util'; import {TableComponent} from './table'; -export function main() { - let table: TableComponent; +let table: TableComponent; - function destroyDom() { table.data = emptyTable; } - - function createDom() { table.data = buildTable(); } - - function noop() {} - - function init() { - table = new TableComponent(document.querySelector('largetable')); - - bindAction('#destroyDom', destroyDom); - bindAction('#createDom', createDom); - - bindAction('#updateDomProfile', profile(createDom, noop, 'update')); - bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); - } - - init(); +function destroyDom() { + table.data = emptyTable; } + +function createDom() { + table.data = buildTable(); +} + +function noop() {} + +function init() { + table = new TableComponent(document.querySelector('largetable')); + + bindAction('#destroyDom', destroyDom); + bindAction('#createDom', createDom); + + bindAction('#updateDomProfile', profile(createDom, noop, 'update')); + bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); +} + +init(); diff --git a/modules/benchmarks/src/largetable/incremental_dom/table.ts b/modules/benchmarks/src/largetable/incremental_dom/table.ts index 6abf149534..7d50f8ff27 100644 --- a/modules/benchmarks/src/largetable/incremental_dom/table.ts +++ b/modules/benchmarks/src/largetable/incremental_dom/table.ts @@ -7,8 +7,12 @@ */ import {TableCell} from '../util'; + +// We load "IncrementalDOM" as a AMD global because the "incremental-dom" NPM package does not +// come with a named UMD module, and it's easier to just import the AMD file and use it globally. +declare const IncrementalDOM: any; const {patch, elementOpen, elementClose, elementOpenStart, elementOpenEnd, attr, text} = - require('incremental-dom'); + IncrementalDOM; export class TableComponent { constructor(private _rootEl: any) {} diff --git a/modules/benchmarks/src/largetable/iv/BUILD.bazel b/modules/benchmarks/src/largetable/iv/BUILD.bazel new file mode 100644 index 0000000000..a58fcd7a59 --- /dev/null +++ b/modules/benchmarks/src/largetable/iv/BUILD.bazel @@ -0,0 +1,18 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_devserver( + name = "devserver", + index_html = "index.html", + port = 4200, + static_files = ["largetable.js"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:perf_lib"], +) diff --git a/modules/benchmarks/src/largetable/iv/index.html b/modules/benchmarks/src/largetable/iv/index.html index e4423c8493..77b2962159 100644 --- a/modules/benchmarks/src/largetable/iv/index.html +++ b/modules/benchmarks/src/largetable/iv/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -24,8 +28,5 @@
    - - - diff --git a/modules/benchmarks/src/largetable/largetable_perf.spec.ts b/modules/benchmarks/src/largetable/largetable_perf.spec.ts index 71552f688b..6e9bdfe788 100644 --- a/modules/benchmarks/src/largetable/largetable_perf.spec.ts +++ b/modules/benchmarks/src/largetable/largetable_perf.spec.ts @@ -36,11 +36,19 @@ const UpdateWorker: Worker = { work: () => $('#createDom').click() }; +// In order to make sure that we don't change the ids of the benchmarks, we need to +// determine the current test package name from the Bazel target. This is necessary +// because previous to the Bazel conversion, the benchmark test ids contained the test +// name. e.g. "largeTable.ng2_switch.createDestroy". We determine the name of the +// Bazel package where this test runs from the current test target. The Bazel target +// looks like: "//modules/benchmarks/src/largetable/{pkg_name}:{target_name}". +const testPackageName = process.env['BAZEL_TARGET'] !.split(':')[0].split('/').pop(); + describe('largetable benchmark perf', () => { afterEach(verifyNoBrowserErrors); - it('should render the table for render3', () => { + it(`should render the table for ${testPackageName}`, () => { openBrowser({ url: '', ignoreBrowserSynchronization: true, @@ -56,26 +64,26 @@ describe('largetable benchmark perf', () => { [CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => { describe(worker.id, () => { - it('should run benchmark for render3', done => { + it(`should run benchmark for ${testPackageName}`, done => { runTableBenchmark({ - id: `largeTable.render3.${worker.id}`, - url: 'index.html', + id: `largeTable.${testPackageName}.${worker.id}`, + url: '/', ignoreBrowserSynchronization: true, worker: worker }).then(done, done.fail); }); }); }); - - function runTableBenchmark( - config: {id: string, url: string, ignoreBrowserSynchronization?: boolean, worker: Worker}) { - return runBenchmark({ - id: config.id, - url: config.url, - ignoreBrowserSynchronization: config.ignoreBrowserSynchronization, - params: [{name: 'cols', value: 40}, {name: 'rows', value: 200}], - prepare: config.worker.prepare, - work: config.worker.work - }); - } }); + +function runTableBenchmark( + config: {id: string, url: string, ignoreBrowserSynchronization?: boolean, worker: Worker}) { + return runBenchmark({ + id: config.id, + url: config.url, + ignoreBrowserSynchronization: config.ignoreBrowserSynchronization, + params: [{name: 'cols', value: 40}, {name: 'rows', value: 200}], + prepare: config.worker.prepare, + work: config.worker.work + }); +} diff --git a/modules/benchmarks/src/largetable/ng2/BUILD.bazel b/modules/benchmarks/src/largetable/ng2/BUILD.bazel new file mode 100644 index 0000000000..18ad59f723 --- /dev/null +++ b/modules/benchmarks/src/largetable/ng2/BUILD.bazel @@ -0,0 +1,42 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +# Note that this benchmark has been designed for Angular with ViewEngine, but once +# ViewEngine is removed, we should should consider removing this one since there +# already is a "render3" benchmark. +ng_module( + name = "ng2", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/largetable:util_lib", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/largetable/ng2/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":ng2"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:perf_lib"], +) diff --git a/modules/benchmarks/src/largetable/ng2/index.html b/modules/benchmarks/src/largetable/ng2/index.html index 3842f86625..f854962b57 100644 --- a/modules/benchmarks/src/largetable/ng2/index.html +++ b/modules/benchmarks/src/largetable/ng2/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -24,11 +28,5 @@
    Loading...
    - - diff --git a/modules/benchmarks/src/largetable/ng2/index.ts b/modules/benchmarks/src/largetable/ng2/index.ts index c7d73eb3f2..b0a0bfec83 100644 --- a/modules/benchmarks/src/largetable/ng2/index.ts +++ b/modules/benchmarks/src/largetable/ng2/index.ts @@ -12,7 +12,5 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {init} from './init'; import {AppModule} from './table'; -export function main() { - enableProdMode(); - platformBrowserDynamic().bootstrapModule(AppModule).then(init); -} +enableProdMode(); +platformBrowserDynamic().bootstrapModule(AppModule).then(init); diff --git a/modules/benchmarks/src/largetable/ng2_switch/BUILD.bazel b/modules/benchmarks/src/largetable/ng2_switch/BUILD.bazel new file mode 100644 index 0000000000..72a4c1bc2d --- /dev/null +++ b/modules/benchmarks/src/largetable/ng2_switch/BUILD.bazel @@ -0,0 +1,39 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ng_module( + name = "ng2_switch", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/largetable:util_lib", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/largetable/ng2_switch/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":ng2_switch"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:perf_lib"], +) diff --git a/modules/benchmarks/src/largetable/ng2_switch/index.html b/modules/benchmarks/src/largetable/ng2_switch/index.html index 9cd629ebc2..5db094975b 100644 --- a/modules/benchmarks/src/largetable/ng2_switch/index.html +++ b/modules/benchmarks/src/largetable/ng2_switch/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -24,11 +28,5 @@
    Loading...
    - - diff --git a/modules/benchmarks/src/largetable/ng2_switch/index.ts b/modules/benchmarks/src/largetable/ng2_switch/index.ts index c7d73eb3f2..b0a0bfec83 100644 --- a/modules/benchmarks/src/largetable/ng2_switch/index.ts +++ b/modules/benchmarks/src/largetable/ng2_switch/index.ts @@ -12,7 +12,5 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {init} from './init'; import {AppModule} from './table'; -export function main() { - enableProdMode(); - platformBrowserDynamic().bootstrapModule(AppModule).then(init); -} +enableProdMode(); +platformBrowserDynamic().bootstrapModule(AppModule).then(init); diff --git a/modules/benchmarks/src/largetable/render3/BUILD.bazel b/modules/benchmarks/src/largetable/render3/BUILD.bazel index df6a24d3a5..f8ae700c47 100644 --- a/modules/benchmarks/src/largetable/render3/BUILD.bazel +++ b/modules/benchmarks/src/largetable/render3/BUILD.bazel @@ -1,17 +1,12 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle") -load("//packages/bazel:index.bzl", "protractor_web_test_suite") load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") ng_module( name = "largetable_lib", - srcs = glob( - [ - "**/*.ts", - ], - exclude = ["protractor.on-prepare.ts"], - ), + srcs = glob(["**/*.ts"]), tags = ["ivy-only"], deps = [ "//modules/benchmarks/src:util_lib", @@ -32,41 +27,19 @@ ng_rollup_bundle( ], ) -genrule( - name = "favicon", - srcs = ["//modules/benchmarks:favicon"], - outs = ["favicon.ico"], - cmd = "cp $< $@", -) - ts_devserver( name = "devserver", static_files = [ ":bundle.min_debug.js", ":bundle.min.js", "index.html", - ":favicon", ], tags = ["ivy-only"], ) -protractor_web_test_suite( +benchmark_test( name = "perf", - configuration = "//:protractor-perf.conf.js", - data = [ - "//packages/bazel/src/protractor/utils", - "//packages/benchpress", - "@ngdeps//node-uuid", - "@ngdeps//protractor", - "@ngdeps//reflect-metadata", - "@ngdeps//yargs", - ], - on_prepare = ":protractor.on_prepare.js", server = ":devserver", - tags = [ - "ivy-only", - ], - deps = [ - "//modules/benchmarks/src/largetable:perf_lib", - ], + tags = ["ivy-only"], + deps = ["//modules/benchmarks/src/largetable:perf_lib"], ) diff --git a/modules/benchmarks/src/largetable/render3/index.html b/modules/benchmarks/src/largetable/render3/index.html index 87de79a691..41684174e7 100644 --- a/modules/benchmarks/src/largetable/render3/index.html +++ b/modules/benchmarks/src/largetable/render3/index.html @@ -1,6 +1,9 @@ - + + + +

    Params

    diff --git a/modules/benchmarks/src/largetable/render3/index.ts b/modules/benchmarks/src/largetable/render3/index.ts index bcecbc0fdf..caa6f2370d 100644 --- a/modules/benchmarks/src/largetable/render3/index.ts +++ b/modules/benchmarks/src/largetable/render3/index.ts @@ -27,10 +27,4 @@ export function main() { } } -const isBazel = location.pathname.indexOf('/all/') !== 0; -// isBazel needed while 'scripts/ci/test-e2e.sh test.e2e.protractor-e2e' is run -// on Travis -// TODO: port remaining protractor e2e tests to bazel protractor_web_test_suite rule -if (isBazel) { - main(); -} +main(); diff --git a/modules/benchmarks/src/largetable/render3/tsconfig.json b/modules/benchmarks/src/largetable/render3/tsconfig.json deleted file mode 100644 index 8f3c656796..0000000000 --- a/modules/benchmarks/src/largetable/render3/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "lib": ["es2015"] - } -} diff --git a/modules/benchmarks/src/tree/BUILD.bazel b/modules/benchmarks/src/tree/BUILD.bazel index 64f64eef6d..05d485954b 100644 --- a/modules/benchmarks/src/tree/BUILD.bazel +++ b/modules/benchmarks/src/tree/BUILD.bazel @@ -4,25 +4,36 @@ load("//tools:defaults.bzl", "ts_library") ts_library( name = "util_lib", - srcs = [ - "util.ts", - ], + srcs = ["util.ts"], + deps = ["//modules/benchmarks/src:util_lib"], +) + +ts_library( + name = "test_utils_lib", + testonly = 1, + srcs = ["tree_perf_test_utils.ts"], deps = [ - "//modules/benchmarks/src:util_lib", - "//packages:types", - "//packages/core", + "//modules/e2e_util", + "@ngdeps//protractor", ], ) ts_library( name = "perf_lib", testonly = 1, - srcs = [ - "tree_perf.spec.ts", - ], + srcs = ["tree_perf.spec.ts"], deps = [ - "//modules/e2e_util:lib", - "//packages:types", + ":test_utils_lib", + "@ngdeps//protractor", + ], +) + +ts_library( + name = "perf_detect_changes_lib", + testonly = 1, + srcs = ["tree_perf_detect_changes.spec.ts"], + deps = [ + ":test_utils_lib", "@ngdeps//protractor", ], ) diff --git a/modules/benchmarks/src/tree/baseline/BUILD.bazel b/modules/benchmarks/src/tree/baseline/BUILD.bazel new file mode 100644 index 0000000000..9450d53c15 --- /dev/null +++ b/modules/benchmarks/src/tree/baseline/BUILD.bazel @@ -0,0 +1,29 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_library( + name = "baseline", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/tree:util_lib", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/baseline/index", + index_html = "index.html", + port = 4200, + deps = [":baseline"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:perf_lib"], +) diff --git a/modules/benchmarks/src/tree/baseline/index.html b/modules/benchmarks/src/tree/baseline/index.html index 3bfb634097..5e6983d0fc 100644 --- a/modules/benchmarks/src/tree/baseline/index.html +++ b/modules/benchmarks/src/tree/baseline/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -21,11 +25,5 @@
    Loading...
    - - - \ No newline at end of file + diff --git a/modules/benchmarks/src/tree/incremental_dom/BUILD.bazel b/modules/benchmarks/src/tree/incremental_dom/BUILD.bazel new file mode 100644 index 0000000000..da172f9d6e --- /dev/null +++ b/modules/benchmarks/src/tree/incremental_dom/BUILD.bazel @@ -0,0 +1,33 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_library( + name = "incremental_dom", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/tree:util_lib", + "@ngdeps//@types/node", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/incremental_dom/index", + index_html = "index.html", + port = 4200, + static_files = [ + "@ngdeps//node_modules/incremental-dom:dist/incremental-dom.js", + ], + deps = [":incremental_dom"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:perf_lib"], +) diff --git a/modules/benchmarks/src/tree/incremental_dom/index.html b/modules/benchmarks/src/tree/incremental_dom/index.html index 99335bd3e4..0853f8d5c0 100644 --- a/modules/benchmarks/src/tree/incremental_dom/index.html +++ b/modules/benchmarks/src/tree/incremental_dom/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -21,7 +25,5 @@
    - - - \ No newline at end of file + diff --git a/modules/benchmarks/src/tree/incremental_dom/index.ts b/modules/benchmarks/src/tree/incremental_dom/index.ts index d730a47c66..a14ccc7221 100644 --- a/modules/benchmarks/src/tree/incremental_dom/index.ts +++ b/modules/benchmarks/src/tree/incremental_dom/index.ts @@ -9,26 +9,27 @@ import {bindAction, profile} from '../../util'; import {buildTree, emptyTree} from '../util'; import {TreeComponent} from './tree'; -const {patch} = require('incremental-dom'); -export function main() { - let tree: TreeComponent; +let tree: TreeComponent; - function destroyDom() { tree.data = emptyTree; } - - function createDom() { tree.data = buildTree(); } - - function noop() {} - - function init() { - tree = new TreeComponent(document.querySelector('tree')); - - bindAction('#destroyDom', destroyDom); - bindAction('#createDom', createDom); - - bindAction('#updateDomProfile', profile(createDom, noop, 'update')); - bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); - } - - init(); +function destroyDom() { + tree.data = emptyTree; } + +function createDom() { + tree.data = buildTree(); +} + +function noop() {} + +function init() { + tree = new TreeComponent(document.querySelector('tree')); + + bindAction('#destroyDom', destroyDom); + bindAction('#createDom', createDom); + + bindAction('#updateDomProfile', profile(createDom, noop, 'update')); + bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); +} + +init(); diff --git a/modules/benchmarks/src/tree/incremental_dom/tree.ts b/modules/benchmarks/src/tree/incremental_dom/tree.ts index 3915288cec..0a5a23ab6b 100644 --- a/modules/benchmarks/src/tree/incremental_dom/tree.ts +++ b/modules/benchmarks/src/tree/incremental_dom/tree.ts @@ -7,8 +7,12 @@ */ import {TreeNode} from '../util'; + +// We load "IncrementalDOM" as a AMD global because the "incremental-dom" NPM package does not +// come with a named UMD module, and it's easier to just import the AMD file and use it globally. +declare const IncrementalDOM: any; const {patch, elementOpen, elementClose, elementOpenStart, elementOpenEnd, text, attr} = - require('incremental-dom'); + IncrementalDOM; export class TreeComponent { constructor(private _rootEl: any) {} diff --git a/modules/benchmarks/src/tree/iv/BUILD.bazel b/modules/benchmarks/src/tree/iv/BUILD.bazel new file mode 100644 index 0000000000..b6c88e036a --- /dev/null +++ b/modules/benchmarks/src/tree/iv/BUILD.bazel @@ -0,0 +1,20 @@ +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_devserver( + name = "devserver", + index_html = "index.html", + port = 4200, + static_files = ["tree.js"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:perf_detect_changes_lib", + "//modules/benchmarks/src/tree:perf_lib", + ], +) diff --git a/modules/benchmarks/src/tree/iv/index.html b/modules/benchmarks/src/tree/iv/index.html index fd0d7f85a7..5d9ef00dfd 100644 --- a/modules/benchmarks/src/tree/iv/index.html +++ b/modules/benchmarks/src/tree/iv/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -24,7 +28,5 @@ Change detection runs:
  • - - diff --git a/modules/benchmarks/src/tree/ng1/BUILD.bazel b/modules/benchmarks/src/tree/ng1/BUILD.bazel new file mode 100644 index 0000000000..6bdc2c4ce8 --- /dev/null +++ b/modules/benchmarks/src/tree/ng1/BUILD.bazel @@ -0,0 +1,35 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_library( + name = "ng1", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/tree:util_lib", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/ng1/index", + index_html = "index.html", + port = 4200, + static_files = [ + "@ngdeps//node_modules/angular:angular.js", + ], + deps = [":ng1"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:perf_detect_changes_lib", + "//modules/benchmarks/src/tree:perf_lib", + ], +) diff --git a/modules/benchmarks/src/tree/ng1/index.html b/modules/benchmarks/src/tree/ng1/index.html index ee7c5b37e6..a522c3002c 100644 --- a/modules/benchmarks/src/tree/ng1/index.html +++ b/modules/benchmarks/src/tree/ng1/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -26,19 +30,5 @@
    Loading...
    - - - \ No newline at end of file + diff --git a/modules/benchmarks/src/tree/ng2/BUILD.bazel b/modules/benchmarks/src/tree/ng2/BUILD.bazel new file mode 100644 index 0000000000..4a8eb58635 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2/BUILD.bazel @@ -0,0 +1,45 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +# Note that this benchmark has been designed for Angular with ViewEngine, but once +# ViewEngine is removed, we should should consider removing this one since there +# already is a "render3" benchmark. +ng_module( + name = "ng2", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/tree:util_lib", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/ng2/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":ng2"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:perf_detect_changes_lib", + "//modules/benchmarks/src/tree:perf_lib", + ], +) diff --git a/modules/benchmarks/src/tree/ng2/index.html b/modules/benchmarks/src/tree/ng2/index.html index 266162c0a4..fee0d1588e 100644 --- a/modules/benchmarks/src/tree/ng2/index.html +++ b/modules/benchmarks/src/tree/ng2/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -26,11 +30,5 @@
    Loading...
    - - diff --git a/modules/benchmarks/src/tree/ng2/index.ts b/modules/benchmarks/src/tree/ng2/index.ts index 3dc8eab927..9e3d67c59b 100644 --- a/modules/benchmarks/src/tree/ng2/index.ts +++ b/modules/benchmarks/src/tree/ng2/index.ts @@ -12,7 +12,5 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {init} from './init'; import {AppModule} from './tree'; -export function main() { - enableProdMode(); - platformBrowserDynamic().bootstrapModule(AppModule).then(init); -} +enableProdMode(); +platformBrowserDynamic().bootstrapModule(AppModule).then(init); diff --git a/modules/benchmarks/src/tree/ng2_next/BUILD.bazel b/modules/benchmarks/src/tree/ng2_next/BUILD.bazel new file mode 100644 index 0000000000..585674c2cc --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_next/BUILD.bazel @@ -0,0 +1,36 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_library( + name = "ng2_next", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/tree:util_lib", + "//packages/common", + "//packages/core", + "//packages/platform-browser", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/ng2_next/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + deps = [":ng2_next"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:perf_detect_changes_lib", + "//modules/benchmarks/src/tree:perf_lib", + ], +) diff --git a/modules/benchmarks/src/tree/ng2_next/index.html b/modules/benchmarks/src/tree/ng2_next/index.html index 69fcee27da..7057fe1268 100644 --- a/modules/benchmarks/src/tree/ng2_next/index.html +++ b/modules/benchmarks/src/tree/ng2_next/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -26,11 +30,5 @@
    Loading...
    - - diff --git a/modules/benchmarks/src/tree/ng2_next/index.ts b/modules/benchmarks/src/tree/ng2_next/index.ts index 1de8c0041c..0a4416796a 100644 --- a/modules/benchmarks/src/tree/ng2_next/index.ts +++ b/modules/benchmarks/src/tree/ng2_next/index.ts @@ -13,42 +13,40 @@ import {buildTree, emptyTree} from '../util'; import {AppModule, TreeComponent} from './tree'; -export function main() { - let tree: TreeComponent; - let appMod: AppModule; - let detectChangesRuns = 0; +let tree: TreeComponent; +let appMod: AppModule; +let detectChangesRuns = 0; - function destroyDom() { - tree.data = emptyTree; - appMod.tick(); - } - - function createDom() { - tree.data = buildTree(); - appMod.tick(); - } - - function detectChanges() { - for (let i = 0; i < 10; i++) { - appMod.tick(); - } - detectChangesRuns += 10; - numberOfChecksEl.textContent = `${detectChangesRuns}`; - } - - function noop() {} - - const numberOfChecksEl = document.getElementById('numberOfChecks'); - - enableProdMode(); - appMod = new AppModule(); - appMod.bootstrap(); - tree = appMod.componentRef.instance; - - bindAction('#destroyDom', destroyDom); - bindAction('#createDom', createDom); - bindAction('#detectChanges', detectChanges); - bindAction('#detectChangesProfile', profile(detectChanges, noop, 'detectChanges')); - bindAction('#updateDomProfile', profile(createDom, noop, 'update')); - bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); +function destroyDom() { + tree.data = emptyTree; + appMod.tick(); } + +function createDom() { + tree.data = buildTree(); + appMod.tick(); +} + +function detectChanges() { + for (let i = 0; i < 10; i++) { + appMod.tick(); + } + detectChangesRuns += 10; + numberOfChecksEl.textContent = `${detectChangesRuns}`; +} + +function noop() {} + +const numberOfChecksEl = document.getElementById('numberOfChecks'); + +enableProdMode(); +appMod = new AppModule(); +appMod.bootstrap(); +tree = appMod.componentRef.instance; + +bindAction('#destroyDom', destroyDom); +bindAction('#createDom', createDom); +bindAction('#detectChanges', detectChanges); +bindAction('#detectChangesProfile', profile(detectChanges, noop, 'detectChanges')); +bindAction('#updateDomProfile', profile(createDom, noop, 'update')); +bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); diff --git a/modules/benchmarks/src/tree/ng2_static/BUILD.bazel b/modules/benchmarks/src/tree/ng2_static/BUILD.bazel new file mode 100644 index 0000000000..4bed4314a6 --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_static/BUILD.bazel @@ -0,0 +1,37 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ts_library( + name = "ng2_static", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/tree:util_lib", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/ng2_static/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":ng2_static"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:perf_lib"], +) diff --git a/modules/benchmarks/src/tree/ng2_static/index.html b/modules/benchmarks/src/tree/ng2_static/index.html index 3b4659e1d2..91be35f9a4 100644 --- a/modules/benchmarks/src/tree/ng2_static/index.html +++ b/modules/benchmarks/src/tree/ng2_static/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -20,7 +24,5 @@
    - - - \ No newline at end of file + diff --git a/modules/benchmarks/src/tree/ng2_static/index.ts b/modules/benchmarks/src/tree/ng2_static/index.ts index f4f34cb546..e28ba1ab8c 100644 --- a/modules/benchmarks/src/tree/ng2_static/index.ts +++ b/modules/benchmarks/src/tree/ng2_static/index.ts @@ -14,35 +14,33 @@ import {buildTree, emptyTree} from '../util'; import {AppModule, RootTreeComponent} from './tree'; -export function main() { - let tree: RootTreeComponent; - let appRef: ApplicationRef; +let tree: RootTreeComponent; +let appRef: ApplicationRef; - function destroyDom() { - tree.data = emptyTree; - appRef.tick(); - } - - function createDom() { - tree.data = buildTree(); - appRef.tick(); - } - - function noop() {} - - function init() { - enableProdMode(); - platformBrowserDynamic().bootstrapModule(AppModule).then((ref) => { - const injector = ref.injector; - appRef = injector.get(ApplicationRef); - - tree = appRef.components[0].instance; - bindAction('#destroyDom', destroyDom); - bindAction('#createDom', createDom); - bindAction('#updateDomProfile', profile(createDom, noop, 'update')); - bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); - }); - } - - init(); +function destroyDom() { + tree.data = emptyTree; + appRef.tick(); } + +function createDom() { + tree.data = buildTree(); + appRef.tick(); +} + +function noop() {} + +function init() { + enableProdMode(); + platformBrowserDynamic().bootstrapModule(AppModule).then((ref) => { + const injector = ref.injector; + appRef = injector.get(ApplicationRef); + + tree = appRef.components[0].instance; + bindAction('#destroyDom', destroyDom); + bindAction('#createDom', createDom); + bindAction('#updateDomProfile', profile(createDom, noop, 'update')); + bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); + }); +} + +init(); diff --git a/modules/benchmarks/src/tree/ng2_switch/BUILD.bazel b/modules/benchmarks/src/tree/ng2_switch/BUILD.bazel new file mode 100644 index 0000000000..bfbe8565da --- /dev/null +++ b/modules/benchmarks/src/tree/ng2_switch/BUILD.bazel @@ -0,0 +1,39 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ng_module( + name = "ng2_switch", + srcs = glob(["*.ts"]), + tsconfig = "//modules/benchmarks:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//modules/benchmarks/src:util_lib", + "//modules/benchmarks/src/tree:util_lib", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/ng2_switch/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":ng2_switch"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:perf_lib"], +) diff --git a/modules/benchmarks/src/tree/ng2_switch/index.html b/modules/benchmarks/src/tree/ng2_switch/index.html index 2f3d6a3d7b..2eef92aa4f 100644 --- a/modules/benchmarks/src/tree/ng2_switch/index.html +++ b/modules/benchmarks/src/tree/ng2_switch/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -21,11 +25,5 @@
    Loading...
    - - diff --git a/modules/benchmarks/src/tree/ng2_switch/index.ts b/modules/benchmarks/src/tree/ng2_switch/index.ts index 3dc8eab927..9e3d67c59b 100644 --- a/modules/benchmarks/src/tree/ng2_switch/index.ts +++ b/modules/benchmarks/src/tree/ng2_switch/index.ts @@ -12,7 +12,5 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {init} from './init'; import {AppModule} from './tree'; -export function main() { - enableProdMode(); - platformBrowserDynamic().bootstrapModule(AppModule).then(init); -} +enableProdMode(); +platformBrowserDynamic().bootstrapModule(AppModule).then(init); diff --git a/modules/benchmarks/src/tree/polymer/binary_tree.html b/modules/benchmarks/src/tree/polymer/binary_tree.html deleted file mode 100644 index ebab874dfa..0000000000 --- a/modules/benchmarks/src/tree/polymer/binary_tree.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/modules/benchmarks/src/tree/polymer/index.html b/modules/benchmarks/src/tree/polymer/index.html deleted file mode 100644 index ce2c79c35f..0000000000 --- a/modules/benchmarks/src/tree/polymer/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - -

    Params

    - - Depth: - -
    - -
    - -

    Polymer Tree Benchmark

    -

    - - - - -

    - -
    - -
    - - - - - - \ No newline at end of file diff --git a/modules/benchmarks/src/tree/polymer/index.ts b/modules/benchmarks/src/tree/polymer/index.ts deleted file mode 100644 index 5f1ee89984..0000000000 --- a/modules/benchmarks/src/tree/polymer/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {bindAction, profile} from '../../util'; -import {buildTree, emptyTree} from '../util'; - -declare var Polymer: any; - -export function main() { - const rootEl: any = document.querySelector('binary-tree'); - rootEl.data = emptyTree; - - function destroyDom() { rootEl.data = emptyTree; } - - function createDom() { rootEl.data = buildTree(); } - - function noop() {} - - bindAction('#destroyDom', destroyDom); - bindAction('#createDom', createDom); - - bindAction('#updateDomProfile', profile(createDom, noop, 'update')); - bindAction('#createDomProfile', profile(createDom, destroyDom, 'create')); -} diff --git a/modules/benchmarks/src/tree/polymer_leaves/index.html b/modules/benchmarks/src/tree/polymer_leaves/index.html deleted file mode 100644 index fe51d79feb..0000000000 --- a/modules/benchmarks/src/tree/polymer_leaves/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - -

    Params

    -
    - Depth: - -
    - -
    - -

    Polymer Leaves Benchmark

    -

    - - - - -

    - -
    - -
    - - - - - - diff --git a/modules/benchmarks/src/tree/polymer_leaves/index.ts b/modules/benchmarks/src/tree/polymer_leaves/index.ts deleted file mode 100644 index 6c2549197a..0000000000 --- a/modules/benchmarks/src/tree/polymer_leaves/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {bindAction} from '../../util'; -import {buildTree, flattenTree} from '../util'; - -declare var Polymer: any; - -export function main() { - const rootEl: any = document.querySelector('binary-tree'); - - function destroyDom() { - while (rootEl.firstChild) rootEl.removeChild(rootEl.firstChild); - } - - function createDom() { - const flatTree = flattenTree(buildTree(), []); - for (let i = 0; i < flatTree.length; i++) { - const el: any = document.createElement('tree-leaf'); - el.data = flatTree[i]; - rootEl.appendChild(el); - } - } - - bindAction('#destroyDom', destroyDom); - bindAction('#createDom', createDom); -} diff --git a/modules/benchmarks/src/tree/polymer_leaves/tree_leaf.html b/modules/benchmarks/src/tree/polymer_leaves/tree_leaf.html deleted file mode 100644 index 28f3fce8ff..0000000000 --- a/modules/benchmarks/src/tree/polymer_leaves/tree_leaf.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/modules/benchmarks/src/tree/render3/BUILD.bazel b/modules/benchmarks/src/tree/render3/BUILD.bazel index e9cb5f1d09..7e6564a6c6 100644 --- a/modules/benchmarks/src/tree/render3/BUILD.bazel +++ b/modules/benchmarks/src/tree/render3/BUILD.bazel @@ -1,16 +1,12 @@ -package(default_visibility = ["//visibility:public"]) +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle") -load("//packages/bazel:index.bzl", "protractor_web_test_suite") load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") ng_module( name = "tree_lib", - srcs = glob( - [ - "**/*.ts", - ], - ), + srcs = glob(["**/*.ts"]), tags = ["ivy-only"], deps = [ "//modules/benchmarks/src/tree:util_lib", @@ -30,40 +26,22 @@ ng_rollup_bundle( ], ) -genrule( - name = "favicon", - srcs = ["//modules/benchmarks:favicon"], - outs = ["favicon.ico"], - cmd = "cp $< $@", -) - ts_devserver( name = "devserver", static_files = [ ":bundle.min_debug.js", ":bundle.min.js", "index.html", - ":favicon", ], tags = ["ivy-only"], ) -protractor_web_test_suite( +benchmark_test( name = "perf", - configuration = "//:protractor-perf.conf.js", - data = [ - "//packages/bazel/src/protractor/utils", - "//packages/benchpress", - ], - on_prepare = ":protractor.on_prepare.js", server = ":devserver", - tags = [ - "ivy-only", - ], + tags = ["ivy-only"], deps = [ + "//modules/benchmarks/src/tree:perf_detect_changes_lib", "//modules/benchmarks/src/tree:perf_lib", - "@ngdeps//node-uuid", - "@ngdeps//protractor", - "@ngdeps//yargs", ], ) diff --git a/modules/benchmarks/src/tree/render3/index.html b/modules/benchmarks/src/tree/render3/index.html index b5b1ea3614..0f86ab6ac4 100644 --- a/modules/benchmarks/src/tree/render3/index.html +++ b/modules/benchmarks/src/tree/render3/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    diff --git a/modules/benchmarks/src/tree/render3_function/BUILD.bazel b/modules/benchmarks/src/tree/render3_function/BUILD.bazel index 1e8adc00de..69760e79ea 100644 --- a/modules/benchmarks/src/tree/render3_function/BUILD.bazel +++ b/modules/benchmarks/src/tree/render3_function/BUILD.bazel @@ -1,19 +1,34 @@ -package(default_visibility = ["//visibility:public"]) +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("//tools:defaults.bzl", "ts_library") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") -load("//tools:defaults.bzl", "ng_module") +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) -ng_module( +ts_library( name = "render3_function_lib", - srcs = glob( - [ - "**/*.ts", - ], - ), + srcs = glob(["**/*.ts"]), deps = [ + "//modules/benchmarks/src:util_lib", "//modules/benchmarks/src/tree:util_lib", "//modules/benchmarks/src/tree/render3:tree_lib", - "//packages:types", "//packages/core", - "@rxjs", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/benchmarks/src/tree/render3_function/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + deps = [":render3_function_lib"], +) + +benchmark_test( + name = "perf", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:perf_detect_changes_lib", + "//modules/benchmarks/src/tree:perf_lib", ], ) diff --git a/modules/benchmarks/src/tree/render3_function/index.html b/modules/benchmarks/src/tree/render3_function/index.html index d71594cf18..96284c3dbe 100644 --- a/modules/benchmarks/src/tree/render3_function/index.html +++ b/modules/benchmarks/src/tree/render3_function/index.html @@ -1,5 +1,9 @@ + + + +

    Params

    @@ -30,9 +34,6 @@ diff --git a/modules/benchmarks/src/tree/render3_function/index.ts b/modules/benchmarks/src/tree/render3_function/index.ts index afb084ac76..a4e4785632 100644 --- a/modules/benchmarks/src/tree/render3_function/index.ts +++ b/modules/benchmarks/src/tree/render3_function/index.ts @@ -14,23 +14,6 @@ import {TreeNode, emptyTree} from '../util'; function noop() {} -export function main() { - let component: TreeFunction; - if (typeof window !== 'undefined') { - component = renderComponent(TreeFunction); - bindAction('#createDom', () => createDom(component as any)); - bindAction('#destroyDom', () => destroyDom(component as any)); - bindAction('#detectChanges', () => detectChanges(component as any)); - bindAction( - '#detectChangesProfile', - profile(() => detectChanges(component as any), noop, 'detectChanges')); - bindAction('#updateDomProfile', profile(() => createDom(component as any), noop, 'update')); - bindAction( - '#createDomProfile', - profile(() => createDom(component as any), () => destroyDom(component as any), 'create')); - } -} - export class TreeFunction { data: TreeNode = emptyTree; @@ -86,3 +69,18 @@ export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { ɵcontainerRefreshEnd(); } } + +let component: TreeFunction; +if (typeof window !== 'undefined') { + component = renderComponent(TreeFunction); + bindAction('#createDom', () => createDom(component as any)); + bindAction('#destroyDom', () => destroyDom(component as any)); + bindAction('#detectChanges', () => detectChanges(component as any)); + bindAction( + '#detectChangesProfile', + profile(() => detectChanges(component as any), noop, 'detectChanges')); + bindAction('#updateDomProfile', profile(() => createDom(component as any), noop, 'update')); + bindAction( + '#createDomProfile', + profile(() => createDom(component as any), () => destroyDom(component as any), 'create')); +} diff --git a/modules/benchmarks/src/tree/tree_perf.spec.ts b/modules/benchmarks/src/tree/tree_perf.spec.ts index 25df3f8632..1b4881c5e3 100644 --- a/modules/benchmarks/src/tree/tree_perf.spec.ts +++ b/modules/benchmarks/src/tree/tree_perf.spec.ts @@ -6,10 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {$, browser} from 'protractor'; - -import {openBrowser} from '../../../e2e_util/e2e_util'; -import {runBenchmark} from '../../../e2e_util/perf_util'; +import {$} from 'protractor'; +import {openTreeBenchmark, runTreeBenchmark} from './tree_perf_test_utils'; describe('benchmark render', () => { it('should work for createDestroy', () => { @@ -26,20 +24,15 @@ describe('benchmark render', () => { $('#createDom').click(); expect($('#root').getText()).toContain('A'); }); - - it('should work for detectChanges', () => { - openTreeBenchmark(); - $('#detectChanges').click(); - expect($('#numberOfChecks').getText()).toContain('10'); - }); - }); describe('benchmarks', () => { it('should work for createOnly', done => { runTreeBenchmark({ - id: 'createOnly', + // This cannot be called "createOnly" because the actual destroy benchmark + // has the "createOnly" id already. See: https://github.com/angular/angular/pull/21503 + id: 'createOnlyForReal', prepare: () => $('#destroyDom').click(), work: () => $('#createDom').click() }).then(done, done.fail); @@ -47,6 +40,8 @@ describe('benchmarks', () => { it('should work for destroy', done => { runTreeBenchmark({ + // This is actually a benchmark for destroying the dom, but it has been accidentally + // named "createOnly". See https://github.com/angular/angular/pull/21503. id: 'createOnly', prepare: () => $('#createDom').click(), work: () => $('#destroyDom').click() @@ -66,36 +61,4 @@ describe('benchmarks', () => { it('should work for update', done => { runTreeBenchmark({id: 'update', work: () => $('#createDom').click()}).then(done, done.fail); }); - - it('should work for detectChanges', done => { - runTreeBenchmark({ - id: 'detectChanges', - work: () => $('#detectChanges').click(), - setup: () => $('#destroyDom').click() - }).then(done, done.fail); - }); - }); - -function runTreeBenchmark({id, prepare, setup, work}: - {id: string; prepare ? () : void; setup ? () : void; work(): void;}) { - browser.rootEl = '#root'; - return runBenchmark({ - id: id, - url: '', - ignoreBrowserSynchronization: true, - params: [{name: 'depth', value: 11}], - work: work, - prepare: prepare, - setup: setup - }); -} - -function openTreeBenchmark() { - browser.rootEl = '#root'; - openBrowser({ - url: '', - ignoreBrowserSynchronization: true, - params: [{name: 'depth', value: 4}], - }); -} diff --git a/modules/benchmarks/src/tree/tree_perf_detect_changes.spec.ts b/modules/benchmarks/src/tree/tree_perf_detect_changes.spec.ts new file mode 100644 index 0000000000..9b744d2bac --- /dev/null +++ b/modules/benchmarks/src/tree/tree_perf_detect_changes.spec.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {$} from 'protractor'; +import {openTreeBenchmark, runTreeBenchmark} from './tree_perf_test_utils'; + +describe('benchmark render', () => { + it('should work for detectChanges', () => { + openTreeBenchmark(); + $('#detectChanges').click(); + expect($('#numberOfChecks').getText()).toContain('10'); + }); +}); + +describe('benchmarks', () => { + it('should work for detectChanges', async() => { + await runTreeBenchmark({ + id: 'detectChanges', + work: () => $('#detectChanges').click(), + setup: () => $('#destroyDom').click() + }); + }); +}); diff --git a/modules/benchmarks/src/tree/tree_perf_test_utils.ts b/modules/benchmarks/src/tree/tree_perf_test_utils.ts new file mode 100644 index 0000000000..b2fa21b138 --- /dev/null +++ b/modules/benchmarks/src/tree/tree_perf_test_utils.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {browser} from 'protractor'; + +import {openBrowser} from '../../../e2e_util/e2e_util'; +import {runBenchmark} from '../../../e2e_util/perf_util'; + +export function runTreeBenchmark({id, prepare, setup, work}: { + id: string; prepare ? () : void; setup ? () : void; work(): void; +}) { + browser.rootEl = '#root'; + return runBenchmark({ + id: id, + url: '', + ignoreBrowserSynchronization: true, + params: [{name: 'depth', value: 11}], + work: work, + prepare: prepare, + setup: setup + }); +} + +export function openTreeBenchmark() { + browser.rootEl = '#root'; + openBrowser({ + url: '', + ignoreBrowserSynchronization: true, + params: [{name: 'depth', value: 4}], + }); +} diff --git a/modules/benchmarks/src/largetable/render3/protractor.on_prepare.js b/modules/benchmarks/start-server.js similarity index 50% rename from modules/benchmarks/src/largetable/render3/protractor.on_prepare.js rename to modules/benchmarks/start-server.js index 509208c84e..98fbaf25f8 100644 --- a/modules/benchmarks/src/largetable/render3/protractor.on_prepare.js +++ b/modules/benchmarks/start-server.js @@ -10,13 +10,9 @@ const protractorUtils = require('@angular/bazel/protractor-utils'); const protractor = require('protractor'); module.exports = async function(config) { - const serverSpec = await protractorUtils.runServer(config.workspace, config.server, '-port', []); - - const serverUrl = `http://localhost:${serverSpec.port}`; - // Since the browser restarts in this benchmark we need to set both the browser.baseUrl - // for the first test and the protractor config.baseUrl for the subsequent tests - protractor.browser.baseUrl = serverUrl; - + const {port} = await protractorUtils.runServer(config.workspace, config.server, '-port', []); const processedConfig = await protractor.browser.getProcessedConfig(); - return processedConfig.baseUrl = serverUrl; + const serverUrl = `http://localhost:${port}`; + + return processedConfig.baseUrl = protractor.browser.baseUrl = serverUrl; }; diff --git a/modules/benchmarks/tsconfig-build.json b/modules/benchmarks/tsconfig-build.json new file mode 100644 index 0000000000..d18dc325cc --- /dev/null +++ b/modules/benchmarks/tsconfig-build.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["dom", "es2015"], + "types": [] + } +} diff --git a/modules/benchmarks/tsconfig-e2e.json b/modules/benchmarks/tsconfig-e2e.json new file mode 100644 index 0000000000..ed38112bb4 --- /dev/null +++ b/modules/benchmarks/tsconfig-e2e.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["es2015"], + "types": ["node", "jasminewd2"] + } +} diff --git a/modules/benchmarks_external/e2e_test/polymer_tree_perf.ts b/modules/benchmarks_external/e2e_test/polymer_tree_perf.ts deleted file mode 100644 index 731abd8c4a..0000000000 --- a/modules/benchmarks_external/e2e_test/polymer_tree_perf.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {runClickBenchmark, verifyNoBrowserErrors} from '@angular/testing/src/perf_util'; - -describe('polymer tree benchmark', function() { - - const URL = 'benchmarks_external/src/tree/polymer/index.html'; - - afterEach(verifyNoBrowserErrors); - - it('should log the stats (create)', function(done) { - runClickBenchmark({ - url: URL, - buttons: ['#destroyDom', '#createDom'], - id: 'polymer.tree.create', - params: [{name: 'depth', value: 9, scale: 'log2'}], - waitForAngular2: false - }).then(done, done.fail); - }); - - it('should log the stats (update)', function(done) { - runClickBenchmark({ - url: URL, - buttons: ['#createDom'], - id: 'polymer.tree.update', - params: [{name: 'depth', value: 9, scale: 'log2'}], - waitForAngular2: false - }).then(done, done.fail); - }); - -}); diff --git a/modules/benchmarks_external/src/index.html b/modules/benchmarks_external/src/index.html index d9c74f9c2e..7a9640adcc 100644 --- a/modules/benchmarks_external/src/index.html +++ b/modules/benchmarks_external/src/index.html @@ -11,9 +11,6 @@
  • Static tree benchmark
  • -
  • - Polymer Tree benchmark -
  • React Tree benchmark
  • diff --git a/modules/e2e_util/BUILD.bazel b/modules/e2e_util/BUILD.bazel index 6209f07cf1..647b53205e 100644 --- a/modules/e2e_util/BUILD.bazel +++ b/modules/e2e_util/BUILD.bazel @@ -3,7 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "ts_library") ts_library( - name = "lib", + name = "e2e_util", testonly = 1, srcs = glob(["*.ts"]), deps = [ @@ -12,6 +12,7 @@ ts_library( "@ngdeps//@types/fs-extra", "@ngdeps//@types/selenium-webdriver", "@ngdeps//fs-extra", + "@ngdeps//node-uuid", "@ngdeps//protractor", "@ngdeps//selenium-webdriver", ], diff --git a/modules/es6-subset.d.ts b/modules/es6-subset.d.ts deleted file mode 100644 index caef53e496..0000000000 --- a/modules/es6-subset.d.ts +++ /dev/null @@ -1,65 +0,0 @@ - -/** - * Subset of lib.es2015.core.d.ts typings. - * Angular should not require use of ES6 runtime but some API usages are already present. - * See https://github.com/angular/angular/issues/5242 - * TODO(alexeagle): remove methods below which may not be present in targeted browser - */ - -interface String { - /** - * Returns true if the sequence of elements of searchString converted to a String is the - * same as the corresponding elements of this object (converted to a String) starting at - * position. Otherwise returns false. - */ - startsWith(searchString: string, position?: number): boolean; - - /** - * Returns true if the sequence of elements of searchString converted to a String is the - * same as the corresponding elements of this object (converted to a String) starting at - * endPosition – length(this). Otherwise returns false. - */ - endsWith(searchString: string, endPosition?: number): boolean; -} - -interface Array { - /** - * Returns the value of the first element in the array where predicate is true, and undefined - * otherwise. - * @param predicate find calls predicate once for each element of the array, in ascending - * order, until it finds one where predicate returns true. If such an element is found, find - * immediately returns that element value. Otherwise, find returns undefined. - * @param thisArg If provided, it will be used as the this value for each invocation of - * predicate. If it is not provided, undefined is used instead. - */ - find(predicate: (value: T, index: number, obj: Array) => boolean, thisArg?: any): T; - /** - * Returns the this object after filling the section identified by start and end with value - * @param value value to fill array section with - * @param start index to start filling the array at. If start is negative, it is treated as - * length+start where length is the length of the array. - * @param end index to stop filling the array at. If end is negative, it is treated as - * length+end. - */ - fill(value: T, start?: number, end?: number): T[]; -} - -interface NumberConstructor { - /** - * Returns true if the value passed is an integer, false otherwise. - * @param number A numeric value. - */ - isInteger(number: number): boolean; -} - -// Workaround https://github.com/Microsoft/TypeScript/issues/9193 -interface PromiseConstructor { - all(values: (T|PromiseLike)[]): Promise; -} - -interface Function { - /** - * Returns the name of the function. Function names are read-only and can not be changed. - */ - readonly name: string; -} diff --git a/modules/playground/BUILD.bazel b/modules/playground/BUILD.bazel new file mode 100644 index 0000000000..45e5be832f --- /dev/null +++ b/modules/playground/BUILD.bazel @@ -0,0 +1,6 @@ +exports_files([ + "tsconfig-build.json", + "tsconfig-e2e.json", + "systemjs-config.js", + "systemjs-rxjs-operators.js", +]) diff --git a/modules/playground/README.md b/modules/playground/README.md index 213a5faafb..50172f008d 100644 --- a/modules/playground/README.md +++ b/modules/playground/README.md @@ -1,8 +1,12 @@ -# How to run the examples locally +## How to serve the examples -``` -$ cp -r ./modules/playground ./dist/all/ -$ ./node_modules/.bin/tsc -p modules --emitDecoratorMetadata -w -$ gulp serve -$ open http://localhost:8000/all/playground/src/hello_world/index.html?bundles=false +All playground examples are built and served with Bazel. Below is an example that +demonstrates how a specific example can be built and served with Bazel: + +```bash +# e.g. src/zippy_component +yarn bazel run modules/playground/src/zippy_component:devserver + +# e.g. src/upgrade +yarn bazel run modules/playground/src/upgrade:devserver ``` \ No newline at end of file diff --git a/modules/playground/e2e_test/BUILD.bazel b/modules/playground/e2e_test/BUILD.bazel new file mode 100644 index 0000000000..b8c5b364b1 --- /dev/null +++ b/modules/playground/e2e_test/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["start-server.js"]) diff --git a/modules/playground/e2e_test/async/BUILD.bazel b/modules/playground/e2e_test/async/BUILD.bazel new file mode 100644 index 0000000000..90ff687e3e --- /dev/null +++ b/modules/playground/e2e_test/async/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "async", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/async:devserver", +) diff --git a/modules/playground/e2e_test/async/async_spec.ts b/modules/playground/e2e_test/async/async_spec.ts index d2afab7542..c67993f581 100644 --- a/modules/playground/e2e_test/async/async_spec.ts +++ b/modules/playground/e2e_test/async/async_spec.ts @@ -6,12 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {$, browser} from 'protractor'; import {promise} from 'selenium-webdriver'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('async', () => { - const URL = 'all/playground/src/async/index.html'; + const URL = '/'; beforeEach(() => browser.get(URL)); diff --git a/modules/playground/e2e_test/example_test.bzl b/modules/playground/e2e_test/example_test.bzl new file mode 100644 index 0000000000..b9f1b018e0 --- /dev/null +++ b/modules/playground/e2e_test/example_test.bzl @@ -0,0 +1,32 @@ +load("//packages/bazel:index.bzl", "protractor_web_test_suite") +load("//tools:defaults.bzl", "ts_library") + +def example_test(name, srcs, server, data = [], **kwargs): + ts_library( + name = "%s_lib" % name, + testonly = True, + srcs = srcs, + tsconfig = "//modules/playground:tsconfig-e2e.json", + deps = [ + "//modules/e2e_util", + "//packages/private/testing", + "@ngdeps//@types/jasminewd2", + "@ngdeps//@types/selenium-webdriver", + "@ngdeps//protractor", + ], + ) + + protractor_web_test_suite( + name = "protractor_tests", + data = ["//packages/bazel/src/protractor/utils"] + data, + on_prepare = "//modules/playground/e2e_test:start-server.js", + server = server, + deps = [ + ":%s_lib" % name, + "@ngdeps//protractor", + "@ngdeps//selenium-webdriver", + "@ngdeps//yargs", + "@ngdeps//source-map", + ], + **kwargs + ) diff --git a/modules/playground/e2e_test/hello_world/BUILD.bazel b/modules/playground/e2e_test/hello_world/BUILD.bazel new file mode 100644 index 0000000000..c1010cab13 --- /dev/null +++ b/modules/playground/e2e_test/hello_world/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "hello_world", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/hello_world:devserver", +) diff --git a/modules/playground/e2e_test/hello_world/hello_world_spec.ts b/modules/playground/e2e_test/hello_world/hello_world_spec.ts index 1d6bb3fab8..7e20b09b74 100644 --- a/modules/playground/e2e_test/hello_world/hello_world_spec.ts +++ b/modules/playground/e2e_test/hello_world/hello_world_spec.ts @@ -6,15 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('hello world', function() { afterEach(verifyNoBrowserErrors); describe('hello world app', function() { - const URL = 'all/playground/src/hello_world/index.html'; + const URL = '/'; it('should greet', function() { browser.get(URL); diff --git a/modules/playground/e2e_test/http/BUILD.bazel b/modules/playground/e2e_test/http/BUILD.bazel new file mode 100644 index 0000000000..3d64eb56f0 --- /dev/null +++ b/modules/playground/e2e_test/http/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "http", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/http:devserver", +) diff --git a/modules/playground/e2e_test/http/http_spec.ts b/modules/playground/e2e_test/http/http_spec.ts index 441400fb5d..58d4ecb0db 100644 --- a/modules/playground/e2e_test/http/http_spec.ts +++ b/modules/playground/e2e_test/http/http_spec.ts @@ -6,15 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('http', function() { afterEach(verifyNoBrowserErrors); describe('fetching', function() { - const URL = 'all/playground/src/http/index.html'; + const URL = '/'; it('should fetch and display people', function() { browser.get(URL); diff --git a/modules/playground/e2e_test/jsonp/BUILD.bazel b/modules/playground/e2e_test/jsonp/BUILD.bazel new file mode 100644 index 0000000000..3372078e11 --- /dev/null +++ b/modules/playground/e2e_test/jsonp/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "jsonp", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/jsonp:devserver", +) diff --git a/modules/playground/e2e_test/jsonp/jsonp_spec.ts b/modules/playground/e2e_test/jsonp/jsonp_spec.ts index b4fcda164a..71c6734ea4 100644 --- a/modules/playground/e2e_test/jsonp/jsonp_spec.ts +++ b/modules/playground/e2e_test/jsonp/jsonp_spec.ts @@ -6,15 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('jsonp', function() { afterEach(verifyNoBrowserErrors); describe('fetching', function() { - const URL = 'all/playground/src/jsonp/index.html'; + const URL = '/'; it('should fetch and display people', function() { browser.get(URL); diff --git a/modules/playground/e2e_test/key_events/BUILD.bazel b/modules/playground/e2e_test/key_events/BUILD.bazel new file mode 100644 index 0000000000..b5963a7b65 --- /dev/null +++ b/modules/playground/e2e_test/key_events/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "key_events", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/key_events:devserver", +) diff --git a/modules/playground/e2e_test/key_events/key_events_spec.ts b/modules/playground/e2e_test/key_events/key_events_spec.ts index 5552e03bd0..f98d087df4 100644 --- a/modules/playground/e2e_test/key_events/key_events_spec.ts +++ b/modules/playground/e2e_test/key_events/key_events_spec.ts @@ -6,14 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element, protractor} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + const Key = protractor.Key; describe('key_events', function() { - const URL = 'all/playground/src/key_events/index.html?bundles=false'; + const URL = '/'; afterEach(verifyNoBrowserErrors); beforeEach(() => { browser.get(URL); }); diff --git a/modules/playground/e2e_test/model_driven_forms/BUILD.bazel b/modules/playground/e2e_test/model_driven_forms/BUILD.bazel new file mode 100644 index 0000000000..848cd4bdf0 --- /dev/null +++ b/modules/playground/e2e_test/model_driven_forms/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "model_driven_forms", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/model_driven_forms:devserver", +) diff --git a/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts b/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts index a3b3aaaca6..8fd35bea15 100644 --- a/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts +++ b/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts @@ -6,14 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('Model-Driven Forms', function() { afterEach(verifyNoBrowserErrors); - const URL = 'all/playground/src/model_driven_forms/index.html'; + const URL = '/'; it('should display errors', function() { browser.get(URL); diff --git a/modules/playground/e2e_test/order_management/BUILD.bazel b/modules/playground/e2e_test/order_management/BUILD.bazel new file mode 100644 index 0000000000..b0f523a2a3 --- /dev/null +++ b/modules/playground/e2e_test/order_management/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "order_management", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/order_management:devserver", +) diff --git a/modules/playground/e2e_test/order_management/order_management_spec.ts b/modules/playground/e2e_test/order_management/order_management_spec.ts index 7750eeda44..970f71ae9f 100644 --- a/modules/playground/e2e_test/order_management/order_management_spec.ts +++ b/modules/playground/e2e_test/order_management/order_management_spec.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('Order Management CRUD', function() { - const URL = 'all/playground/src/order_management/index.html'; + const URL = '/'; it('should work', function() { browser.get(URL); diff --git a/modules/playground/e2e_test/person_management/BUILD.bazel b/modules/playground/e2e_test/person_management/BUILD.bazel new file mode 100644 index 0000000000..3a441d2895 --- /dev/null +++ b/modules/playground/e2e_test/person_management/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "person_management", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/person_management:devserver", +) diff --git a/modules/playground/e2e_test/person_management/person_management_spec.ts b/modules/playground/e2e_test/person_management/person_management_spec.ts index b1d5dad6c6..3fddf0638e 100644 --- a/modules/playground/e2e_test/person_management/person_management_spec.ts +++ b/modules/playground/e2e_test/person_management/person_management_spec.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('Person Management CRUD', function() { - const URL = 'all/playground/src/person_management/index.html'; + const URL = '/'; it('should work', function() { browser.get(URL); diff --git a/modules/playground/e2e_test/relative_assets/BUILD.bazel b/modules/playground/e2e_test/relative_assets/BUILD.bazel new file mode 100644 index 0000000000..5159c74498 --- /dev/null +++ b/modules/playground/e2e_test/relative_assets/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "relative_assets", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/relative_assets:devserver", +) diff --git a/modules/playground/e2e_test/relative_assets/assets_spec.ts b/modules/playground/e2e_test/relative_assets/assets_spec.ts index 99dcb7f1ec..1b777c6d2d 100644 --- a/modules/playground/e2e_test/relative_assets/assets_spec.ts +++ b/modules/playground/e2e_test/relative_assets/assets_spec.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + function waitForElement(selector: string) { // Waits for the element with id 'abc' to be present on the dom. browser.wait(ExpectedConditions.presenceOf($(selector)), 20000); @@ -18,7 +19,7 @@ describe('relative assets relative-app', () => { afterEach(verifyNoBrowserErrors); - const URL = 'all/playground/src/relative_assets/'; + const URL = '/'; it('should load in the templateUrl relative to the my-cmp component', () => { browser.get(URL); diff --git a/modules/playground/e2e_test/routing/BUILD.bazel b/modules/playground/e2e_test/routing/BUILD.bazel new file mode 100644 index 0000000000..049f348561 --- /dev/null +++ b/modules/playground/e2e_test/routing/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "routing", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/routing:devserver", +) diff --git a/modules/playground/e2e_test/routing/routing_spec.ts b/modules/playground/e2e_test/routing/routing_spec.ts index d86efa17af..9e28ba0d41 100644 --- a/modules/playground/e2e_test/routing/routing_spec.ts +++ b/modules/playground/e2e_test/routing/routing_spec.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + function waitForElement(selector: string) { // Waits for the element with id 'abc' to be present on the dom. browser.wait(ExpectedConditions.presenceOf($(selector)), 20000); @@ -19,7 +20,7 @@ describe('routing inbox-app', () => { afterEach(verifyNoBrowserErrors); describe('index view', () => { - const URL = 'all/playground/src/routing/'; + const URL = '/'; it('should list out the current collection of items', () => { browser.get(URL); diff --git a/modules/playground/e2e_test/sourcemap/BUILD.bazel b/modules/playground/e2e_test/sourcemap/BUILD.bazel new file mode 100644 index 0000000000..943adc8d2a --- /dev/null +++ b/modules/playground/e2e_test/sourcemap/BUILD.bazel @@ -0,0 +1,11 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "sourcemap", + srcs = glob(["**/*.ts"]), + data = [ + "//modules/playground/src/sourcemap", + "//modules/playground/src/sourcemap:index.ts", + ], + server = "//modules/playground/src/sourcemap:devserver", +) diff --git a/modules/playground/e2e_test/sourcemap/sourcemap_spec.ts b/modules/playground/e2e_test/sourcemap/sourcemap_spec.ts index 0de005d2e7..2110fd372b 100644 --- a/modules/playground/e2e_test/sourcemap/sourcemap_spec.ts +++ b/modules/playground/e2e_test/sourcemap/sourcemap_spec.ts @@ -13,16 +13,13 @@ const fs = require('fs'); const sourceMap = require('source-map'); describe('sourcemaps', function() { - const URL = 'all/playground/src/sourcemap/index.html'; + const URL = '/'; it('should map sources', function() { browser.get(URL); $('error-app .errorButton').click(); - // TODO(tbosch): Bug in ChromeDriver: Need to execute at least one command - // so that the browser logs can be read out! - browser.executeScript('1+1'); browser.manage().logs().get(logging.Type.BROWSER).then(function(logs: any) { let errorLine: number = null; let errorColumn: number = null; @@ -39,7 +36,7 @@ describe('sourcemaps', function() { const content = - fs.readFileSync('dist/all/playground/src/sourcemap/index.js').toString('utf8'); + fs.readFileSync(require.resolve('../../src/sourcemap/index.js')).toString('utf8'); const marker = '//# sourceMappingURL=data:application/json;base64,'; const index = content.indexOf(marker); const sourceMapData = @@ -49,7 +46,7 @@ describe('sourcemaps', function() { const originalPosition = decoder.originalPositionFor({line: errorLine, column: errorColumn}); - const sourceCodeLines = fs.readFileSync('modules/playground/src/sourcemap/index.ts', { + const sourceCodeLines = fs.readFileSync(require.resolve('../../src/sourcemap/index.ts'), { encoding: 'UTF-8' }).split('\n'); expect(sourceCodeLines[originalPosition.line - 1]) diff --git a/modules/playground/e2e_test/start-server.js b/modules/playground/e2e_test/start-server.js new file mode 100644 index 0000000000..e7d432281a --- /dev/null +++ b/modules/playground/e2e_test/start-server.js @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const protractorUtils = require('@angular/bazel/protractor-utils'); +const protractor = require('protractor'); + +module.exports = async function(config) { + const {port} = await protractorUtils.runServer(config.workspace, config.server, '-port', []); + const serverUrl = `http://localhost:${port}`; + + protractor.browser.baseUrl = serverUrl; +}; diff --git a/modules/playground/e2e_test/svg/BUILD.bazel b/modules/playground/e2e_test/svg/BUILD.bazel new file mode 100644 index 0000000000..3bba6c3b1e --- /dev/null +++ b/modules/playground/e2e_test/svg/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "svg", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/svg:devserver", +) diff --git a/modules/playground/e2e_test/svg/svg_spec.ts b/modules/playground/e2e_test/svg/svg_spec.ts index 464f8d0afc..0c58cab353 100644 --- a/modules/playground/e2e_test/svg/svg_spec.ts +++ b/modules/playground/e2e_test/svg/svg_spec.ts @@ -6,12 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('SVG', function() { - const URL = 'all/playground/src/svg/index.html'; + const URL = '/'; afterEach(verifyNoBrowserErrors); beforeEach(() => { browser.get(URL); }); diff --git a/modules/playground/e2e_test/template_driven_forms/BUILD.bazel b/modules/playground/e2e_test/template_driven_forms/BUILD.bazel new file mode 100644 index 0000000000..31a512dbf6 --- /dev/null +++ b/modules/playground/e2e_test/template_driven_forms/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "template_driven_forms", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/template_driven_forms:devserver", +) diff --git a/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts b/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts index ae2eab5958..b822ad49cd 100644 --- a/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts +++ b/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts @@ -6,14 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('Template-Driven Forms', function() { afterEach(verifyNoBrowserErrors); - const URL = 'all/playground/src/template_driven_forms/index.html'; + const URL = '/'; it('should display errors', function() { browser.get(URL); diff --git a/modules/playground/e2e_test/upgrade/BUILD.bazel b/modules/playground/e2e_test/upgrade/BUILD.bazel new file mode 100644 index 0000000000..e7dfac39ef --- /dev/null +++ b/modules/playground/e2e_test/upgrade/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "upgrade", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/upgrade:devserver", +) diff --git a/modules/playground/e2e_test/upgrade/upgrade_spec.ts b/modules/playground/e2e_test/upgrade/upgrade_spec.ts index eb5a86520d..0a568a1a30 100644 --- a/modules/playground/e2e_test/upgrade/upgrade_spec.ts +++ b/modules/playground/e2e_test/upgrade/upgrade_spec.ts @@ -6,23 +6,20 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element} from 'protractor'; -// TODO(i): re-enable once we are using a version of protractor containing the -// change in https://github.com/angular/protractor/pull/3403 -xdescribe('ngUpgrade', function() { - const URL = 'all/playground/src/upgrade/index.html'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + +describe('ngUpgrade', function() { + const URL = '/'; beforeEach(function() { browser.rootEl = 'body'; - (browser).ng12Hybrid = true; browser.get(URL); }); afterEach(function() { - (browser).useAllAngular2AppRoots(); - (browser).ng12Hybrid = false; + browser.useAllAngular2AppRoots(); verifyNoBrowserErrors(); }); @@ -30,7 +27,10 @@ xdescribe('ngUpgrade', function() { const ng1NameInput = element(by.css('input[ng-model="name"]')); expect(ng1NameInput.getAttribute('value')).toEqual('World'); - const userSpan = element(by.css('user span')); - expect(userSpan.getText()).toMatch(/World$/); + const projectedGreetingEl = element(by.css('.projected-content .greeting')); + const upgradedNg1ComponentEl = element(by.css('ng1-user')); + + expect(projectedGreetingEl.getText()).toMatch(/World!$/); + expect(upgradedNg1ComponentEl.getText()).toMatch(/^User: World/); }); }); diff --git a/modules/playground/e2e_test/web_workers/animations/BUILD.bazel b/modules/playground/e2e_test/web_workers/animations/BUILD.bazel new file mode 100644 index 0000000000..2bd6e176d7 --- /dev/null +++ b/modules/playground/e2e_test/web_workers/animations/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "animations", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/web_workers/animations:devserver", +) diff --git a/modules/playground/e2e_test/web_workers/animations/animations_spec.ts b/modules/playground/e2e_test/web_workers/animations/animations_spec.ts index d3590ff9fe..9e148d5d63 100644 --- a/modules/playground/e2e_test/web_workers/animations/animations_spec.ts +++ b/modules/playground/e2e_test/web_workers/animations/animations_spec.ts @@ -6,10 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element, protractor} from 'protractor'; -// TODO(matsko): make this test work again with new view engine. +import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; + + +// Disabled because with ViewEngine animations within webworkers is not supported. +// See: https://github.com/angular/angular/issues/18610 xdescribe('WebWorkers Animations', function() { afterEach(() => { verifyNoBrowserErrors(); diff --git a/modules/playground/e2e_test/web_workers/input/BUILD.bazel b/modules/playground/e2e_test/web_workers/input/BUILD.bazel new file mode 100644 index 0000000000..ae90a5daa4 --- /dev/null +++ b/modules/playground/e2e_test/web_workers/input/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "input", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/web_workers/input:devserver", +) diff --git a/modules/playground/e2e_test/web_workers/input/input_spec.ts b/modules/playground/e2e_test/web_workers/input/input_spec.ts index 833af282a2..0659ba5adf 100644 --- a/modules/playground/e2e_test/web_workers/input/input_spec.ts +++ b/modules/playground/e2e_test/web_workers/input/input_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {ExpectedConditions, browser, by, element, protractor} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; describe('WebWorkers Input', function() { afterEach(() => { @@ -16,7 +16,7 @@ describe('WebWorkers Input', function() { browser.ignoreSynchronization = false; }); const selector = 'input-app'; - const URL = 'all/playground/src/web_workers/input/index.html'; + const URL = '/'; const VALUE = 'test val'; it('should bootstrap', () => { diff --git a/modules/playground/e2e_test/web_workers/kitchen_sink/BUILD.bazel b/modules/playground/e2e_test/web_workers/kitchen_sink/BUILD.bazel new file mode 100644 index 0000000000..a764d7b479 --- /dev/null +++ b/modules/playground/e2e_test/web_workers/kitchen_sink/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "kitchen_sink", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/web_workers/kitchen_sink:devserver", +) diff --git a/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts b/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts index a081abb8d4..a271f82ce5 100644 --- a/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts +++ b/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts @@ -6,16 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {ExpectedConditions, browser, by, element, protractor} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; + describe('WebWorkers Kitchen Sink', function() { afterEach(() => { verifyNoBrowserErrors(); browser.ignoreSynchronization = false; }); const selector = 'hello-app .greeting'; - const URL = 'all/playground/src/web_workers/kitchen_sink/index.html'; + const URL = '/'; it('should greet', () => { // This test can't wait for Angular as Testability is not available when using WebWorker diff --git a/modules/playground/e2e_test/web_workers/message_broker/BUILD.bazel b/modules/playground/e2e_test/web_workers/message_broker/BUILD.bazel new file mode 100644 index 0000000000..74b19d9060 --- /dev/null +++ b/modules/playground/e2e_test/web_workers/message_broker/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "message_broker", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/web_workers/message_broker:devserver", +) diff --git a/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts b/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts index cc06d59156..d5c1ec34ca 100644 --- a/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts +++ b/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {ExpectedConditions, browser, by, element, protractor} from 'protractor'; -const URL = 'all/playground/src/web_workers/message_broker/index.html'; +import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; + +const URL = '/'; describe('MessageBroker', function() { diff --git a/modules/playground/e2e_test/web_workers/router/BUILD.bazel b/modules/playground/e2e_test/web_workers/router/BUILD.bazel new file mode 100644 index 0000000000..e6c55fae25 --- /dev/null +++ b/modules/playground/e2e_test/web_workers/router/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "router", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/web_workers/router:devserver", +) diff --git a/modules/playground/e2e_test/web_workers/router/router_spec.ts b/modules/playground/e2e_test/web_workers/router/router_spec.ts index 3d5863e10d..736e01fc54 100644 --- a/modules/playground/e2e_test/web_workers/router/router_spec.ts +++ b/modules/playground/e2e_test/web_workers/router/router_spec.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element, protractor} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; + describe('WebWorker Router', () => { beforeEach(() => { // This test can't wait for Angular as Testability is not available when using WebWorker @@ -23,7 +24,7 @@ describe('WebWorker Router', () => { const contentSelector = 'app main h1'; const navSelector = 'app nav ul'; - const baseUrl = 'all/playground/src/web_workers/router/index.html'; + const baseUrl = '/'; it('should route on click', () => { browser.get(baseUrl); diff --git a/modules/playground/e2e_test/web_workers/todo/BUILD.bazel b/modules/playground/e2e_test/web_workers/todo/BUILD.bazel new file mode 100644 index 0000000000..907933a699 --- /dev/null +++ b/modules/playground/e2e_test/web_workers/todo/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "todo", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/web_workers/todo:devserver", +) diff --git a/modules/playground/e2e_test/web_workers/todo/todo_spec.ts b/modules/playground/e2e_test/web_workers/todo/todo_spec.ts index d9c8416575..f1a5415866 100644 --- a/modules/playground/e2e_test/web_workers/todo/todo_spec.ts +++ b/modules/playground/e2e_test/web_workers/todo/todo_spec.ts @@ -6,16 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element, protractor} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; + describe('WebWorkers Todo', function() { afterEach(() => { verifyNoBrowserErrors(); browser.ignoreSynchronization = false; }); - const URL = 'all/playground/src/web_workers/todo/index.html'; + const URL = '/'; it('should bootstrap', () => { // This test can't wait for Angular as Testability is not available when using WebWorker diff --git a/modules/playground/e2e_test/zippy_component/BUILD.bazel b/modules/playground/e2e_test/zippy_component/BUILD.bazel new file mode 100644 index 0000000000..acded1138e --- /dev/null +++ b/modules/playground/e2e_test/zippy_component/BUILD.bazel @@ -0,0 +1,7 @@ +load("//modules/playground/e2e_test:example_test.bzl", "example_test") + +example_test( + name = "zippy_component", + srcs = glob(["**/*.ts"]), + server = "//modules/playground/src/zippy_component:devserver", +) diff --git a/modules/playground/e2e_test/zippy_component/zippy_spec.ts b/modules/playground/e2e_test/zippy_component/zippy_spec.ts index fc339a12e3..e3d7f25043 100644 --- a/modules/playground/e2e_test/zippy_component/zippy_spec.ts +++ b/modules/playground/e2e_test/zippy_component/zippy_spec.ts @@ -6,15 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {verifyNoBrowserErrors} from 'e2e_util/e2e_util'; import {browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + describe('Zippy Component', function() { afterEach(verifyNoBrowserErrors); describe('zippy', function() { - const URL = 'all/playground/src/zippy_component/index.html'; + const URL = '/'; beforeEach(function() { browser.get(URL); }); diff --git a/modules/playground/src/animate/BUILD.bazel b/modules/playground/src/animate/BUILD.bazel new file mode 100644 index 0000000000..de99d38015 --- /dev/null +++ b/modules/playground/src/animate/BUILD.bazel @@ -0,0 +1,32 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "animate", + srcs = glob(["**/*.ts"]), + assets = glob(["**/*.css"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/animations", + "//packages/core", + "//packages/platform-browser-dynamic", + "//packages/platform-browser/animations", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/animate/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":animate"], +) diff --git a/modules/playground/src/animate/app/animate-app.ts b/modules/playground/src/animate/app/animate-app.ts index 0dba74ec69..273fa54415 100644 --- a/modules/playground/src/animate/app/animate-app.ts +++ b/modules/playground/src/animate/app/animate-app.ts @@ -16,7 +16,7 @@ import {Component} from '@angular/core'; '(@backgroundAnimation.done)': 'bgStatusChanged($event, "completed")' }, selector: 'animate-app', - styleUrls: ['css/animate-app.css'], + styleUrls: ['../css/animate-app.css'], template: ` diff --git a/modules/playground/src/animate/index.html b/modules/playground/src/animate/index.html index acaaacef31..f4591b33e0 100644 --- a/modules/playground/src/animate/index.html +++ b/modules/playground/src/animate/index.html @@ -15,6 +15,5 @@ Loading... - diff --git a/modules/playground/src/animate/index.ts b/modules/playground/src/animate/index.ts index 68ef663588..8d9e09bd2c 100644 --- a/modules/playground/src/animate/index.ts +++ b/modules/playground/src/animate/index.ts @@ -12,9 +12,7 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {AnimateApp} from './app/animate-app'; @NgModule({declarations: [AnimateApp], bootstrap: [AnimateApp], imports: [BrowserAnimationsModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/async/BUILD.bazel b/modules/playground/src/async/BUILD.bazel new file mode 100644 index 0000000000..7d81f1bd66 --- /dev/null +++ b/modules/playground/src/async/BUILD.bazel @@ -0,0 +1,30 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "async", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/async/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":async"], +) diff --git a/modules/playground/src/async/index.html b/modules/playground/src/async/index.html index 64f40da63a..5d56cfbef2 100644 --- a/modules/playground/src/async/index.html +++ b/modules/playground/src/async/index.html @@ -8,7 +8,5 @@ Loading... - - diff --git a/modules/playground/src/async/index.ts b/modules/playground/src/async/index.ts index a476f9da80..d3405212e0 100644 --- a/modules/playground/src/async/index.ts +++ b/modules/playground/src/async/index.ts @@ -103,6 +103,4 @@ class AsyncApplication { class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/benchpress/BUILD.bazel b/modules/playground/src/benchpress/BUILD.bazel new file mode 100644 index 0000000000..3816a88355 --- /dev/null +++ b/modules/playground/src/benchpress/BUILD.bazel @@ -0,0 +1,9 @@ +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ts_devserver( + name = "devserver", + index_html = "index.html", + port = 4200, +) diff --git a/modules/playground/src/bootstrap.ts b/modules/playground/src/bootstrap.ts deleted file mode 100644 index 92daa49b1d..0000000000 --- a/modules/playground/src/bootstrap.ts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - - -(function(global: any) { - writeScriptTag('/all/playground/vendor/core.js'); - writeScriptTag('/all/playground/vendor/zone.js'); - writeScriptTag('/all/playground/vendor/long-stack-trace-zone.js'); - writeScriptTag('/all/playground/vendor/system.src.js'); - writeScriptTag('/all/playground/vendor/Reflect.js', 'playgroundBootstrap()'); - - global.playgroundBootstrap = playgroundBootstrap; - - function playgroundBootstrap() { - // check query param - const useBundles = location.search.indexOf('bundles=false') == -1; - - if (useBundles) { - System.config({ - map: { - 'index': 'index.js', - '@angular/common': '/packages-dist/common/bundles/common.umd.js', - '@angular/animations': '/packages-dist/animation/bundles/animations.umd.js', - '@angular/platform-browser/animations': - '/packages-dist/platform-browser/animations/bundles/platform-browser-animations.umd.js', - '@angular/compiler': '/packages-dist/compiler/bundles/compiler.umd.js', - '@angular/core': '/packages-dist/core/bundles/core.umd.js', - '@angular/forms': '/packages-dist/forms/bundles/forms.umd.js', - '@angular/http': '/packages-dist/http/bundles/http.umd.js', - '@angular/platform-browser': - '/packages-dist/platform-browser/bundles/platform-browser.umd.js', - '@angular/platform-browser-dynamic': - '/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', - '@angular/platform-webworker': - '/packages-dist/platform-webworker/bundles/platform-webworker.umd.js', - '@angular/platform-webworker-dynamic': - '/packages-dist/platform-webworker-dynamic/bundles/platform-webworker-dynamic.umd.js', - '@angular/router': '/packages-dist/router/bundles/router.umd.js', - '@angular/upgrade': '/packages-dist/upgrade/bundles/upgrade.umd.js', - '@angular/upgrade/static': '/packages-dist/upgrade/bundles/upgrade-static.umd.js', - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - 'app': {defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - - } - }); - } else { - console.warn( - 'Not using the Angular bundles. Don\'t use this configuration for e2e/performance tests!'); - - System.config({ - map: { - 'index': 'index.js', - '@angular': '/all/@angular', - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - 'app': {defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/animations': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/forms': {main: 'index.js', defaultExtension: 'js'}, - '@angular/http': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/router': {main: 'index.js', defaultExtension: 'js'}, - '@angular/upgrade': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - } - }); - } - - - // BOOTSTRAP the app! - System.import('index').then(function(m: {main: Function}) { - m.main(); - }, console.error.bind(console)); - } - - - function writeScriptTag(scriptUrl: string, onload?: string) { - document.write(``); - } -}(window)); diff --git a/modules/playground/src/gestures/BUILD.bazel b/modules/playground/src/gestures/BUILD.bazel new file mode 100644 index 0000000000..877a085205 --- /dev/null +++ b/modules/playground/src/gestures/BUILD.bazel @@ -0,0 +1,33 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "gestures", + srcs = glob(["**/*.ts"]), + assets = ["template.html"], + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + "@ngdeps//@types/hammerjs", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/gestures/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/hammerjs:hammer.js", + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":gestures"], +) diff --git a/modules/playground/src/gestures/index.html b/modules/playground/src/gestures/index.html index 746684c1e9..fe941f1e00 100644 --- a/modules/playground/src/gestures/index.html +++ b/modules/playground/src/gestures/index.html @@ -14,8 +14,5 @@ - - - diff --git a/modules/playground/src/gestures/index.ts b/modules/playground/src/gestures/index.ts index 29d099f5e7..2dbc531eb6 100644 --- a/modules/playground/src/gestures/index.ts +++ b/modules/playground/src/gestures/index.ts @@ -27,6 +27,4 @@ class GesturesCmp { class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/hello_world/BUILD.bazel b/modules/playground/src/hello_world/BUILD.bazel new file mode 100644 index 0000000000..1a89868573 --- /dev/null +++ b/modules/playground/src/hello_world/BUILD.bazel @@ -0,0 +1,30 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "hello_world", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/hello_world/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":hello_world"], +) diff --git a/modules/playground/src/hello_world/index.html b/modules/playground/src/hello_world/index.html index 6e75312ae1..3bac186b20 100644 --- a/modules/playground/src/hello_world/index.html +++ b/modules/playground/src/hello_world/index.html @@ -5,7 +5,5 @@ Loading... - - diff --git a/modules/playground/src/hello_world/index.ts b/modules/playground/src/hello_world/index.ts index 2478447c93..5a449f7f3e 100644 --- a/modules/playground/src/hello_world/index.ts +++ b/modules/playground/src/hello_world/index.ts @@ -6,14 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Directive, ElementRef, Injectable, NgModule, Renderer} from '@angular/core'; +import {Component, Directive, ElementRef, Injectable, NgModule, Renderer2} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} - // A service available to the Injector, used by the HelloCmp component. @Injectable() export class GreetingService { @@ -26,8 +22,8 @@ export class GreetingService { export class RedDec { // ElementRef is always injectable and it wraps the element on which the // directive was found by the compiler. - constructor(el: ElementRef, renderer: Renderer) { - renderer.setElementStyle(el.nativeElement, 'color', 'red'); + constructor(el: ElementRef, renderer: Renderer2) { + renderer.setStyle(el.nativeElement, 'color', 'red'); } } @@ -58,5 +54,7 @@ export class HelloCmp { } @NgModule({declarations: [HelloCmp, RedDec], bootstrap: [HelloCmp], imports: [BrowserModule]}) -class ExampleModule { +export class ExampleModule { } + +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/http/BUILD.bazel b/modules/playground/src/http/BUILD.bazel new file mode 100644 index 0000000000..676990e4e2 --- /dev/null +++ b/modules/playground/src/http/BUILD.bazel @@ -0,0 +1,32 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "http", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/http", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = ["people.json"], + entry_module = "angular/modules/playground/src/http/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":http"], +) diff --git a/modules/playground/src/http/index.html b/modules/playground/src/http/index.html index fa19f65ec4..229d9303f3 100644 --- a/modules/playground/src/http/index.html +++ b/modules/playground/src/http/index.html @@ -5,7 +5,5 @@ Loading... - - diff --git a/modules/playground/src/http/index.ts b/modules/playground/src/http/index.ts index 9fbc084118..19672e8b54 100644 --- a/modules/playground/src/http/index.ts +++ b/modules/playground/src/http/index.ts @@ -14,9 +14,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {HttpCmp} from './app/http_comp'; @NgModule({declarations: [HttpCmp], bootstrap: [HttpCmp], imports: [BrowserModule, HttpModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/jsonp/BUILD.bazel b/modules/playground/src/jsonp/BUILD.bazel new file mode 100644 index 0000000000..2cf58c5573 --- /dev/null +++ b/modules/playground/src/jsonp/BUILD.bazel @@ -0,0 +1,32 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "jsonp", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/http", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = ["people.json"], + entry_module = "angular/modules/playground/src/jsonp/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":jsonp"], +) diff --git a/modules/playground/src/jsonp/index.html b/modules/playground/src/jsonp/index.html index e4fadcf643..5ea6a289d7 100644 --- a/modules/playground/src/jsonp/index.html +++ b/modules/playground/src/jsonp/index.html @@ -5,7 +5,5 @@ Loading... - - diff --git a/modules/playground/src/jsonp/index.ts b/modules/playground/src/jsonp/index.ts index b840bf025f..c9e6501b8a 100644 --- a/modules/playground/src/jsonp/index.ts +++ b/modules/playground/src/jsonp/index.ts @@ -14,9 +14,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {JsonpCmp} from './app/jsonp_comp'; @NgModule({bootstrap: [JsonpCmp], declarations: [JsonpCmp], imports: [BrowserModule, JsonpModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/key_events/BUILD.bazel b/modules/playground/src/key_events/BUILD.bazel new file mode 100644 index 0000000000..08b0584912 --- /dev/null +++ b/modules/playground/src/key_events/BUILD.bazel @@ -0,0 +1,30 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "key_events", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/key_events/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":key_events"], +) diff --git a/modules/playground/src/key_events/index.html b/modules/playground/src/key_events/index.html index 70b7f5fc43..99d1babc80 100644 --- a/modules/playground/src/key_events/index.html +++ b/modules/playground/src/key_events/index.html @@ -20,7 +20,5 @@ Loading... - - diff --git a/modules/playground/src/key_events/index.ts b/modules/playground/src/key_events/index.ts index 116c3ce4be..e73aaf437b 100644 --- a/modules/playground/src/key_events/index.ts +++ b/modules/playground/src/key_events/index.ts @@ -22,7 +22,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; tabindex="0" >{{shiftEnter ? 'You pressed shift.enter!' : ''}}
    ` }) -class KeyEventsApp { +export class KeyEventsApp { lastKey: string = '(none)'; shiftEnter: boolean = false; @@ -71,9 +71,7 @@ class KeyEventsApp { } @NgModule({declarations: [KeyEventsApp], bootstrap: [KeyEventsApp], imports: [BrowserModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/model_driven_forms/BUILD.bazel b/modules/playground/src/model_driven_forms/BUILD.bazel new file mode 100644 index 0000000000..24058d1e94 --- /dev/null +++ b/modules/playground/src/model_driven_forms/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "model_driven_forms", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/model_driven_forms/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":model_driven_forms"], +) diff --git a/modules/playground/src/model_driven_forms/index.html b/modules/playground/src/model_driven_forms/index.html index 366507deef..fcc8603b8d 100644 --- a/modules/playground/src/model_driven_forms/index.html +++ b/modules/playground/src/model_driven_forms/index.html @@ -13,7 +13,5 @@ Loading... - - diff --git a/modules/playground/src/model_driven_forms/index.ts b/modules/playground/src/model_driven_forms/index.ts index ebb78850a3..b71d22cf76 100644 --- a/modules/playground/src/model_driven_forms/index.ts +++ b/modules/playground/src/model_driven_forms/index.ts @@ -47,7 +47,7 @@ function creditCardValidator(c: AbstractControl): {[key: string]: boolean} { {{errorMessage}} ` }) -class ShowError { +export class ShowError { formDir: FormGroupDirective; controlPath: string; errorTypes: string[]; @@ -136,7 +136,7 @@ class ShowError { ` }) -class ReactiveForms { +export class ReactiveForms { form: FormGroup; countries = ['US', 'Canada']; @@ -164,9 +164,7 @@ class ReactiveForms { declarations: [ShowError, ReactiveForms], imports: [BrowserModule, ReactiveFormsModule] }) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/order_management/BUILD.bazel b/modules/playground/src/order_management/BUILD.bazel new file mode 100644 index 0000000000..12b0eed56d --- /dev/null +++ b/modules/playground/src/order_management/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "order_management", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/order_management/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":order_management"], +) diff --git a/modules/playground/src/order_management/index.html b/modules/playground/src/order_management/index.html index 52098d69d0..21a1f48317 100644 --- a/modules/playground/src/order_management/index.html +++ b/modules/playground/src/order_management/index.html @@ -13,7 +13,5 @@ Loading... - - diff --git a/modules/playground/src/order_management/index.ts b/modules/playground/src/order_management/index.ts index ad1a247503..b83b10b9f1 100644 --- a/modules/playground/src/order_management/index.ts +++ b/modules/playground/src/order_management/index.ts @@ -41,7 +41,7 @@ class Order { let _nextId = 1000; @Injectable() -class DataService { +export class DataService { orderItems: OrderItem[]; orders: Order[]; currentOrder: Order = null; @@ -104,7 +104,7 @@ class DataService {
    ` }) -class OrderListComponent { +export class OrderListComponent { orders: Order[]; constructor(private _service: DataService) { this.orders = _service.orders; } @@ -137,7 +137,7 @@ class OrderListComponent {
    ` }) -class OrderItemComponent { +export class OrderItemComponent { @Input() item: OrderItem; @Output() delete = new EventEmitter(); @@ -173,7 +173,7 @@ class OrderItemComponent {
    ` }) -class OrderDetailsComponent { +export class OrderDetailsComponent { constructor(private _service: DataService) {} get order(): Order { return this._service.currentOrder; } @@ -191,7 +191,7 @@ class OrderDetailsComponent { ` }) -class OrderManagementApplication { +export class OrderManagementApplication { } @NgModule({ @@ -200,9 +200,7 @@ class OrderManagementApplication { [OrderManagementApplication, OrderListComponent, OrderDetailsComponent, OrderItemComponent], imports: [BrowserModule, FormsModule] }) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/person_management/BUILD.bazel b/modules/playground/src/person_management/BUILD.bazel new file mode 100644 index 0000000000..55d66aa41c --- /dev/null +++ b/modules/playground/src/person_management/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "person_management", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/person_management/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":person_management"], +) diff --git a/modules/playground/src/person_management/index.html b/modules/playground/src/person_management/index.html index 905b2b2577..13569410aa 100644 --- a/modules/playground/src/person_management/index.html +++ b/modules/playground/src/person_management/index.html @@ -13,7 +13,5 @@ Loading... - - diff --git a/modules/playground/src/person_management/index.ts b/modules/playground/src/person_management/index.ts index bc867189c3..d981acad14 100644 --- a/modules/playground/src/person_management/index.ts +++ b/modules/playground/src/person_management/index.ts @@ -45,7 +45,7 @@ class Person { // ---- services @Injectable() -class DataService { +export class DataService { currentPerson: Person; persons: Person[]; @@ -85,13 +85,15 @@ class DataService {
    @@ -102,7 +104,7 @@ class DataService {
    ` }) -class FullNameComponent { +export class FullNameComponent { constructor(private _service: DataService) {} get person(): Person { return this._service.currentPerson; } } @@ -115,29 +117,34 @@ class FullNameComponent {
    - +
    - +
    - + Age: {{person.age}}
    \
    - - + + {{person.mom.fullName}}
    - - + + {{person.dad.fullName}}
    @@ -149,7 +156,7 @@ class FullNameComponent {
    ` }) -class PersonsDetailComponent { +export class PersonsDetailComponent { constructor(private _service: DataService) {} get person(): Person { return this._service.currentPerson; } } @@ -169,7 +176,7 @@ class PersonsDetailComponent {
    ` }) -class PersonsComponent { +export class PersonsComponent { persons: Person[]; constructor(private _service: DataService) { this.persons = _service.persons; } @@ -189,7 +196,7 @@ class PersonsComponent { ` }) -class PersonManagementApplication { +export class PersonManagementApplication { mode: string; switchToEditName(): void { this.mode = 'editName'; } @@ -202,9 +209,7 @@ class PersonManagementApplication { [PersonManagementApplication, FullNameComponent, PersonsComponent, PersonsDetailComponent], imports: [BrowserModule, FormsModule] }) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/relative_assets/BUILD.bazel b/modules/playground/src/relative_assets/BUILD.bazel new file mode 100644 index 0000000000..faa1534bfb --- /dev/null +++ b/modules/playground/src/relative_assets/BUILD.bazel @@ -0,0 +1,39 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "relative_assets", + srcs = glob(["**/*.ts"]), + # This example demonstrates how external resources can be loaded relatively, so we + # need to disable resource inlining. + inline_resources = False, + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + # Needed because the example uses "module.id" in order to load assets relatively. + "@ngdeps//@types/node", + ], +) + +ts_devserver( + name = "devserver", + data = [ + "app/style.css", + "app/tpl.html", + ], + entry_module = "angular/modules/playground/src/relative_assets/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":relative_assets"], +) diff --git a/modules/playground/src/relative_assets/app/my_cmp.ts b/modules/playground/src/relative_assets/app/my_cmp.ts index 77e6fb1092..e7d1b4c8ad 100644 --- a/modules/playground/src/relative_assets/app/my_cmp.ts +++ b/modules/playground/src/relative_assets/app/my_cmp.ts @@ -6,7 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ +// Declare the AMD dependency on "module" because otherwise the generated AMD module will +// try to reference "module.id" from the globals, while we want the one from RequireJS. +/// + +// We use the "node" type here because "module.id" is part of "CommonJS" and Bazel compiles +// with "umd" module resolution which means that "module.id" is not a defined global variable. +/// + import {Component} from '@angular/core'; + @Component( {selector: 'my-cmp', templateUrl: 'tpl.html', styleUrls: ['style.css'], moduleId: module.id}) export class MyCmp { diff --git a/modules/playground/src/relative_assets/index.html b/modules/playground/src/relative_assets/index.html index 20bd353c1f..2bebbe2b2e 100644 --- a/modules/playground/src/relative_assets/index.html +++ b/modules/playground/src/relative_assets/index.html @@ -5,7 +5,5 @@ Loading... - - diff --git a/modules/playground/src/relative_assets/index.ts b/modules/playground/src/relative_assets/index.ts index 43894d02a7..91aa4e1c78 100644 --- a/modules/playground/src/relative_assets/index.ts +++ b/modules/playground/src/relative_assets/index.ts @@ -12,10 +12,6 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {MyCmp} from './app/my_cmp'; -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} - @Component({ selector: 'relative-app', template: `component = `, @@ -24,5 +20,7 @@ export class RelativeApp { } @NgModule({declarations: [RelativeApp, MyCmp], bootstrap: [RelativeApp], imports: [BrowserModule]}) -class ExampleModule { +export class ExampleModule { } + +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/routing/BUILD.bazel b/modules/playground/src/routing/BUILD.bazel new file mode 100644 index 0000000000..2186c1130d --- /dev/null +++ b/modules/playground/src/routing/BUILD.bazel @@ -0,0 +1,41 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "routing", + srcs = glob(["**/*.ts"]), + assets = glob(["**/*.html"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + "//packages/router", + ], +) + +ts_devserver( + name = "devserver", + data = [ + # This is temporarily needed because Angular imports from "rxjs/operators/index", while + # there is only one RxJS UMD bundle that re-exports everything at the root. + "//modules/playground:systemjs-rxjs-operators.js", + "//third_party/fonts.google.com/open-sans", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + ] + glob(["**/*.css"]), + port = 4200, + static_files = [ + "index.html", + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + "@ngdeps//node_modules/systemjs:dist/system.js", + "//modules/playground:systemjs-config.js", + "load-app.js", + ], + deps = [":routing"], +) diff --git a/modules/playground/src/routing/app/inbox-app.ts b/modules/playground/src/routing/app/inbox-app.ts index 86bf0cb7f6..2d87ef3719 100644 --- a/modules/playground/src/routing/app/inbox-app.ts +++ b/modules/playground/src/routing/app/inbox-app.ts @@ -84,9 +84,9 @@ export class DbService { } } -@Component({selector: 'inbox', templateUrl: 'app/inbox.html'}) +@Component({selector: 'inbox', templateUrl: './inbox.html'}) export class InboxCmp { - private items: InboxRecord[] = []; + items: InboxRecord[] = []; private ready: boolean = false; constructor(public router: Router, db: DbService, route: ActivatedRoute) { @@ -107,9 +107,9 @@ export class InboxCmp { } -@Component({selector: 'drafts', templateUrl: 'app/drafts.html'}) +@Component({selector: 'drafts', templateUrl: './drafts.html'}) export class DraftsCmp { - private items: InboxRecord[] = []; + items: InboxRecord[] = []; private ready: boolean = false; constructor(private router: Router, db: DbService) { @@ -125,6 +125,6 @@ export const ROUTER_CONFIG = [ {path: 'drafts', component: DraftsCmp}, {path: 'detail', loadChildren: 'app/inbox-detail.js'} ]; -@Component({selector: 'inbox-app', templateUrl: 'app/inbox-app.html'}) +@Component({selector: 'inbox-app', templateUrl: './inbox-app.html'}) export class InboxApp { } diff --git a/modules/playground/src/routing/app/inbox-detail.ts b/modules/playground/src/routing/app/inbox-detail.ts index 584ccc9e80..d59ccd0e0c 100644 --- a/modules/playground/src/routing/app/inbox-detail.ts +++ b/modules/playground/src/routing/app/inbox-detail.ts @@ -11,9 +11,9 @@ import {ActivatedRoute, RouterModule} from '@angular/router'; import {DbService, InboxRecord} from './inbox-app'; -@Component({selector: 'inbox-detail', templateUrl: 'app/inbox-detail.html'}) +@Component({selector: 'inbox-detail', templateUrl: './inbox-detail.html'}) export class InboxDetailCmp { - private record: InboxRecord = new InboxRecord(); + record: InboxRecord = new InboxRecord(); private ready: boolean = false; constructor(db: DbService, route: ActivatedRoute) { diff --git a/modules/playground/src/routing/css/gumby.css b/modules/playground/src/routing/css/gumby.css index af8373bec0..c9ac543657 100644 --- a/modules/playground/src/routing/css/gumby.css +++ b/modules/playground/src/routing/css/gumby.css @@ -1,15 +1,7 @@ -/** - * Angular note: local copy downloaded from https://cdnjs.cloudflare.com/ajax/libs/gumby/2.6.0/css/gumby.css - * local modification: - * - forced google fonts to be fetched via http in order to avoid SSL error - * https://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700 - Failed to load resource: net::ERR_SSL_PROTOCOL_ERROR - * it's unclear why the CI tries to fetch the font via SSL when the base url is http - * example broken build: https://travis-ci.org/angular/angular/jobs/204456086#L2355 - * - */ - @charset "UTF-8"; -@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700); + +@import url("/angular/third_party/fonts.google.com/open-sans/open-sans.css"); + /** * Gumby Framework * --------------- diff --git a/modules/playground/src/routing/index.html b/modules/playground/src/routing/index.html index 7d066f8cf3..414edae61c 100644 --- a/modules/playground/src/routing/index.html +++ b/modules/playground/src/routing/index.html @@ -3,12 +3,20 @@ Routing Example - + Loading... - - + + + + + + diff --git a/modules/playground/src/routing/load-app.js b/modules/playground/src/routing/load-app.js new file mode 100644 index 0000000000..2be58f2f55 --- /dev/null +++ b/modules/playground/src/routing/load-app.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/* + * Normally the "ts_devserver" bundles all specified source files into a bundle and uses + * Require.JS, but for this example we need to use SystemJS as module loader since this + * example uses lazy loading and we want to ensure that the default SystemJS factory loader + * works as expected. + */ + +System.config({ + packages: { + 'angular/modules/playground/src/routing': {defaultExtension: 'js'}, + } +}); + +System.import('./main.js').catch(e => console.error(e)); diff --git a/modules/playground/src/routing/index.ts b/modules/playground/src/routing/main.ts similarity index 60% rename from modules/playground/src/routing/index.ts rename to modules/playground/src/routing/main.ts index df1c7280a6..17620bf5cf 100644 --- a/modules/playground/src/routing/index.ts +++ b/modules/playground/src/routing/main.ts @@ -13,14 +13,13 @@ import {RouterModule} from '@angular/router'; import {DbService, DraftsCmp, InboxApp, InboxCmp, ROUTER_CONFIG} from './app/inbox-app'; -export function main() { - @NgModule({ - providers: [DbService], - declarations: [InboxCmp, DraftsCmp, InboxApp], - imports: [RouterModule.forRoot(ROUTER_CONFIG, {useHash: true}), BrowserModule], - bootstrap: [InboxApp] - }) - class RoutingExampleModule { - } - platformBrowserDynamic().bootstrapModule(RoutingExampleModule); +@NgModule({ + providers: [DbService], + declarations: [InboxCmp, DraftsCmp, InboxApp], + imports: [RouterModule.forRoot(ROUTER_CONFIG, {useHash: true}), BrowserModule], + bootstrap: [InboxApp], +}) +export class RoutingExampleModule { } + +platformBrowserDynamic().bootstrapModule(RoutingExampleModule); diff --git a/modules/playground/src/sourcemap/BUILD.bazel b/modules/playground/src/sourcemap/BUILD.bazel new file mode 100644 index 0000000000..0865ca9ceb --- /dev/null +++ b/modules/playground/src/sourcemap/BUILD.bazel @@ -0,0 +1,34 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +# Exported since the e2e test needs to read the source file in order to +# ensure that the source map properly maps back to the source file. +exports_files(["index.ts"]) + +ng_module( + name = "sourcemap", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/sourcemap/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":sourcemap"], +) diff --git a/modules/playground/src/sourcemap/index.html b/modules/playground/src/sourcemap/index.html index d1981b2a7e..b16b2d6006 100644 --- a/modules/playground/src/sourcemap/index.html +++ b/modules/playground/src/sourcemap/index.html @@ -10,7 +10,5 @@ Please look into the console and check whether the stack trace is mapped via source maps!

    - - diff --git a/modules/playground/src/sourcemap/index.ts b/modules/playground/src/sourcemap/index.ts index 497f88e2d9..2a0622683d 100644 --- a/modules/playground/src/sourcemap/index.ts +++ b/modules/playground/src/sourcemap/index.ts @@ -20,9 +20,7 @@ export class ErrorComponent { } @NgModule({declarations: [ErrorComponent], bootstrap: [ErrorComponent], imports: [BrowserModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/svg/BUILD.bazel b/modules/playground/src/svg/BUILD.bazel new file mode 100644 index 0000000000..b7da7a0c7f --- /dev/null +++ b/modules/playground/src/svg/BUILD.bazel @@ -0,0 +1,30 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "svg", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/svg/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":svg"], +) diff --git a/modules/playground/src/svg/index.html b/modules/playground/src/svg/index.html index f74683b943..fb0d1490d9 100644 --- a/modules/playground/src/svg/index.html +++ b/modules/playground/src/svg/index.html @@ -5,6 +5,5 @@ Loading... - diff --git a/modules/playground/src/svg/index.ts b/modules/playground/src/svg/index.ts index 82fa5bcc48..a914351711 100644 --- a/modules/playground/src/svg/index.ts +++ b/modules/playground/src/svg/index.ts @@ -11,7 +11,7 @@ import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; @Component({selector: '[svg-group]', template: `Hello`}) -class SvgGroup { +export class SvgGroup { } @Component({ @@ -20,13 +20,11 @@ class SvgGroup { ` }) -class SvgApp { +export class SvgApp { } @NgModule({bootstrap: [SvgApp], declarations: [SvgApp, SvgGroup], imports: [BrowserModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/template_driven_forms/BUILD.bazel b/modules/playground/src/template_driven_forms/BUILD.bazel new file mode 100644 index 0000000000..23d1a5d73f --- /dev/null +++ b/modules/playground/src/template_driven_forms/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "template_driven_forms", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/template_driven_forms/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":template_driven_forms"], +) diff --git a/modules/playground/src/template_driven_forms/index.html b/modules/playground/src/template_driven_forms/index.html index 19eb778b98..76bb1fdb79 100644 --- a/modules/playground/src/template_driven_forms/index.html +++ b/modules/playground/src/template_driven_forms/index.html @@ -13,7 +13,5 @@ Loading... - - diff --git a/modules/playground/src/template_driven_forms/index.ts b/modules/playground/src/template_driven_forms/index.ts index eae084b6f2..e5c316370b 100644 --- a/modules/playground/src/template_driven_forms/index.ts +++ b/modules/playground/src/template_driven_forms/index.ts @@ -33,7 +33,7 @@ class CheckoutModel { /** * Custom validator. */ -function creditCardValidator(c: FormControl): {[key: string]: boolean} { +export function creditCardValidator(c: FormControl): {[key: string]: boolean} { if (c.value && /^\d{16}$/.test(c.value)) { return null; } else { @@ -41,14 +41,14 @@ function creditCardValidator(c: FormControl): {[key: string]: boolean} { } } -const creditCardValidatorBinding = { +export const creditCardValidatorBinding = { provide: NG_VALIDATORS, useValue: creditCardValidator, multi: true }; @Directive({selector: '[credit-card]', providers: [creditCardValidatorBinding]}) -class CreditCardValidator { +export class CreditCardValidator { } /** @@ -73,7 +73,7 @@ class CreditCardValidator { {{errorMessage}} ` }) -class ShowError { +export class ShowError { formDir: NgForm; controlPath: string; errorTypes: string[]; @@ -161,7 +161,7 @@ class ShowError { ` }) -class TemplateDrivenForms { +export class TemplateDrivenForms { model = new CheckoutModel(); countries = ['US', 'Canada']; @@ -175,9 +175,7 @@ class TemplateDrivenForms { bootstrap: [TemplateDrivenForms], imports: [BrowserModule, FormsModule] }) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/todo/BUILD.bazel b/modules/playground/src/todo/BUILD.bazel new file mode 100644 index 0000000000..024754cb60 --- /dev/null +++ b/modules/playground/src/todo/BUILD.bazel @@ -0,0 +1,32 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "todo", + srcs = glob(["**/*.ts"]), + assets = ["todo.html"], + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = glob(["**/*.css"]), + entry_module = "angular/modules/playground/src/todo/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":todo"], +) diff --git a/modules/playground/src/todo/css/base.css b/modules/playground/src/todo/css/base.css index 8abb353e87..78a42f1434 100644 --- a/modules/playground/src/todo/css/base.css +++ b/modules/playground/src/todo/css/base.css @@ -13,10 +13,6 @@ button { -webkit-appearance: none; -ms-appearance: none; appearance: none; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - -ms-font-smoothing: antialiased; - font-smoothing: antialiased; } button, @@ -89,10 +85,6 @@ input[type="checkbox"] { box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); -ms-box-sizing: border-box; box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - -ms-font-smoothing: antialiased; - font-smoothing: antialiased; } #new-todo { diff --git a/modules/playground/src/todo/css/main.css b/modules/playground/src/todo/css/main.css index 6177782da2..62c68be738 100644 --- a/modules/playground/src/todo/css/main.css +++ b/modules/playground/src/todo/css/main.css @@ -11,9 +11,4 @@ body { color: #4d4d4d; width: 550px; margin: 0 auto; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - -ms-font-smoothing: antialiased; - -o-font-smoothing: antialiased; - font-smoothing: antialiased; } diff --git a/modules/playground/src/todo/index.html b/modules/playground/src/todo/index.html index 7f38ed0bf6..9a519073ef 100644 --- a/modules/playground/src/todo/index.html +++ b/modules/playground/src/todo/index.html @@ -7,8 +7,5 @@ Loading... - - - diff --git a/modules/playground/src/todo/index.ts b/modules/playground/src/todo/index.ts index 6e8d91773a..3e6526cf94 100644 --- a/modules/playground/src/todo/index.ts +++ b/modules/playground/src/todo/index.ts @@ -13,7 +13,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {Store, Todo, TodoFactory} from './app/TodoStore'; @Component({selector: 'todo-app', viewProviders: [Store, TodoFactory], templateUrl: 'todo.html'}) -class TodoApp { +export class TodoApp { todoEdit: Todo = null; constructor(public todoStore: Store, public factory: TodoFactory) {} @@ -52,9 +52,7 @@ class TodoApp { } @NgModule({declarations: [TodoApp], bootstrap: [TodoApp], imports: [BrowserModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/todo/todo.html b/modules/playground/src/todo/todo.html index 6799ec7569..1a1b8d2cbb 100644 --- a/modules/playground/src/todo/todo.html +++ b/modules/playground/src/todo/todo.html @@ -67,5 +67,5 @@ diff --git a/modules/playground/src/upgrade/BUILD.bazel b/modules/playground/src/upgrade/BUILD.bazel new file mode 100644 index 0000000000..c30cbc0089 --- /dev/null +++ b/modules/playground/src/upgrade/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +# Since this test uses the AOT-incompatible version of "@angular/upgrade", we cannot +# use the "ng_module" rule here unless we switch this example to "upgrade/static". +ts_library( + name = "upgrade", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/upgrade", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/upgrade/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + "@ngdeps//node_modules/angular:angular.js", + ], + deps = [":upgrade"], +) diff --git a/modules/playground/src/upgrade/index.html b/modules/playground/src/upgrade/index.html index 499a7be8fa..0851d9079d 100644 --- a/modules/playground/src/upgrade/index.html +++ b/modules/playground/src/upgrade/index.html @@ -16,7 +16,5 @@
    Greetings from {{name}}! - - diff --git a/modules/playground/src/upgrade/index.ts b/modules/playground/src/upgrade/index.ts index 7eb2fffa9d..7b737ebeab 100644 --- a/modules/playground/src/upgrade/index.ts +++ b/modules/playground/src/upgrade/index.ts @@ -50,7 +50,7 @@ ng1module.directive('ng1User', function() {
    `, styles: styles }) -class Pane { +export class Pane { @Input() title: string; } @@ -61,7 +61,7 @@ class Pane { - +
    @@ -69,7 +69,7 @@ class Pane {
    `, styles: styles }) -class UpgradeApp { +export class UpgradeApp { @Input() user: string; @Output() reset = new EventEmitter(); constructor() {} @@ -77,14 +77,12 @@ class UpgradeApp { @NgModule({ declarations: [Pane, UpgradeApp, adapter.upgradeNg1Component('ng1User')], - imports: [BrowserModule] + imports: [BrowserModule], }) -class Ng2AppModule { +export class Ng2AppModule { } ng1module.directive('upgradeApp', adapter.downgradeNg2Component(UpgradeApp)); -export function main() { - adapter.bootstrap(document.body, ['myExample']); -} +adapter.bootstrap(document.body, ['myExample']); diff --git a/modules/playground/src/web_workers/BUILD.bazel b/modules/playground/src/web_workers/BUILD.bazel new file mode 100644 index 0000000000..03a0fd21d9 --- /dev/null +++ b/modules/playground/src/web_workers/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "worker-config", + srcs = ["worker-configure.js"], + data = [ + "//modules/playground:systemjs-config.js", + "//modules/playground:systemjs-rxjs-operators.js", + "@ngdeps//reflect-metadata", + "@ngdeps//systemjs", + "@ngdeps//zone.js", + ], +) diff --git a/modules/playground/src/web_workers/animations/BUILD.bazel b/modules/playground/src/web_workers/animations/BUILD.bazel new file mode 100644 index 0000000000..35138500ea --- /dev/null +++ b/modules/playground/src/web_workers/animations/BUILD.bazel @@ -0,0 +1,34 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "animations", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/animations", + "//packages/core", + "//packages/platform-webworker", + "//packages/platform-webworker-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = [ + "loader.js", + "//modules/playground/src/web_workers:worker-config", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + ], + entry_module = "angular/modules/playground/src/web_workers/animations/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = ["@ngdeps//node_modules/zone.js:dist/zone.js"], + deps = [":animations"], +) diff --git a/modules/playground/src/web_workers/animations/background_index.ts b/modules/playground/src/web_workers/animations/background_index.ts index 7f541be763..d6beeee175 100644 --- a/modules/playground/src/web_workers/animations/background_index.ts +++ b/modules/playground/src/web_workers/animations/background_index.ts @@ -13,9 +13,7 @@ import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic'; import {AnimationCmp} from './index_common'; @NgModule({imports: [WorkerAppModule], bootstrap: [AnimationCmp], declarations: [AnimationCmp]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformWorkerAppDynamic().bootstrapModule(ExampleModule); -} +platformWorkerAppDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/web_workers/animations/index.html b/modules/playground/src/web_workers/animations/index.html index 83a75c9deb..c4c0c25eb1 100644 --- a/modules/playground/src/web_workers/animations/index.html +++ b/modules/playground/src/web_workers/animations/index.html @@ -7,8 +7,5 @@ Loading... - - - diff --git a/modules/playground/src/web_workers/animations/index.ts b/modules/playground/src/web_workers/animations/index.ts index b45021b6fc..c43aa4aaff 100644 --- a/modules/playground/src/web_workers/animations/index.ts +++ b/modules/playground/src/web_workers/animations/index.ts @@ -8,6 +8,4 @@ import {bootstrapWorkerUi} from '@angular/platform-webworker'; -export function main() { - bootstrapWorkerUi('loader.js'); -} +bootstrapWorkerUi('loader.js'); diff --git a/modules/playground/src/web_workers/animations/loader.js b/modules/playground/src/web_workers/animations/loader.js index 7f9b18aed2..b400e24f64 100644 --- a/modules/playground/src/web_workers/animations/loader.js +++ b/modules/playground/src/web_workers/animations/loader.js @@ -6,43 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -importScripts( - '../../../vendor/core.js', '../../../vendor/zone.js', - '../../../vendor/long-stack-trace-zone.js', '../../../vendor/system.src.js', - '../../../vendor/Reflect.js'); +importScripts('angular/modules/playground/src/web_workers/worker-configure.js'); +System.config({packages: {'angular/modules/playground/src/web_workers': {defaultExtension: 'js'}}}); -System.config({ - baseURL: '/all', - - map: { - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, - - defaultJSExtensions: true -}); - -System.import('playground/src/web_workers/animations/background_index') - .then( - function(m) { - try { - m.main(); - } catch (e) { - console.error(e); - } - }, - function(error) { console.error('error loading background', error); }); +System.import('./background_index.js') + .catch(error => console.error('error loading background', error)); diff --git a/modules/playground/src/web_workers/images/BUILD.bazel b/modules/playground/src/web_workers/images/BUILD.bazel new file mode 100644 index 0000000000..e53583a85d --- /dev/null +++ b/modules/playground/src/web_workers/images/BUILD.bazel @@ -0,0 +1,44 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "images", + srcs = glob(["**/*.ts"]), + assets = ["image_demo.html"], + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-webworker", + "//packages/platform-webworker-dynamic", + "@ngdeps//@types/base64-js", + ], +) + +ts_devserver( + name = "devserver", + # Workaround for: https://github.com/bazelbuild/rules_typescript/issues/409 + additional_root_paths = ["angular"], + data = [ + "//modules/playground/src/web_workers:worker-config", + "@ngdeps//node_modules/base64-js:base64js.min.js", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + "loader.js", + ] + glob(["**/*.css"]), + entry_module = "angular/modules/playground/src/web_workers/images/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/materialize-css:dist/js/materialize.min.js", + "@ngdeps//node_modules/materialize-css:dist/css/materialize.min.css", + "@ngdeps//node_modules/jquery:dist/jquery.min.js", + "//third_party/github.com/google/material-design-icons", + ], + deps = [":images"], +) diff --git a/modules/playground/src/web_workers/images/background_index.ts b/modules/playground/src/web_workers/images/background_index.ts index 8f9459e418..564d9bad8e 100644 --- a/modules/playground/src/web_workers/images/background_index.ts +++ b/modules/playground/src/web_workers/images/background_index.ts @@ -13,9 +13,7 @@ import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic'; import {ImageDemo} from './index_common'; @NgModule({imports: [WorkerAppModule], bootstrap: [ImageDemo], declarations: [ImageDemo]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformWorkerAppDynamic().bootstrapModule(ExampleModule); -} +platformWorkerAppDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/web_workers/images/image_demo.html b/modules/playground/src/web_workers/images/image_demo.html index 83c25c1226..e1ae692b98 100644 --- a/modules/playground/src/web_workers/images/image_demo.html +++ b/modules/playground/src/web_workers/images/image_demo.html @@ -24,10 +24,13 @@
    -
    +
    Select Images
    +
    + +
    diff --git a/modules/playground/src/web_workers/images/index.html b/modules/playground/src/web_workers/images/index.html index 68736e91b7..bb31e90ca4 100644 --- a/modules/playground/src/web_workers/images/index.html +++ b/modules/playground/src/web_workers/images/index.html @@ -1,18 +1,8 @@ - - - - - - - - - - - + diff --git a/modules/playground/src/web_workers/images/index.ts b/modules/playground/src/web_workers/images/index.ts index b45021b6fc..c43aa4aaff 100644 --- a/modules/playground/src/web_workers/images/index.ts +++ b/modules/playground/src/web_workers/images/index.ts @@ -8,6 +8,4 @@ import {bootstrapWorkerUi} from '@angular/platform-webworker'; -export function main() { - bootstrapWorkerUi('loader.js'); -} +bootstrapWorkerUi('loader.js'); diff --git a/modules/playground/src/web_workers/images/loader.js b/modules/playground/src/web_workers/images/loader.js index 374be14033..3612f5426f 100644 --- a/modules/playground/src/web_workers/images/loader.js +++ b/modules/playground/src/web_workers/images/loader.js @@ -6,46 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -importScripts( - '../../../vendor/core.js', '../../../vendor/zone.js', - '../../../vendor/long-stack-trace-zone.js', '../../../vendor/system.src.js', - '../../../vendor/Reflect.js'); - +importScripts('angular/modules/playground/src/web_workers/worker-configure.js'); System.config({ - baseURL: '/all', - map: { - 'base64-js': '/all/playground/vendor/base64-js', - 'rxjs': '/all/playground/vendor/rxjs', + 'base64-js': 'ngdeps/node_modules/base64-js/base64js.min.js', }, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/router': {main: 'index.js', defaultExtension: 'js'}, - 'base64-js': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, - - defaultJSExtensions: true + packages: {'angular/modules/playground/src/web_workers': {defaultExtension: 'js'}} }); -System.import('playground/src/web_workers/images/background_index') - .then( - function(m) { - try { - m.main(); - } catch (e) { - console.error(e); - } - }, - function(error) { console.error('error loading background', error); }); +System.import('./background_index.js') + .catch(error => console.error('error loading background', error)); diff --git a/modules/playground/src/web_workers/images/services/bitmap.ts b/modules/playground/src/web_workers/images/services/bitmap.ts index 89e551b946..6c03ab8b41 100644 --- a/modules/playground/src/web_workers/images/services/bitmap.ts +++ b/modules/playground/src/web_workers/images/services/bitmap.ts @@ -35,7 +35,7 @@ export class BitmapService { toDataUri(imageData: ImageData): string { const header = this._createBMPHeader(imageData); imageData = this._imageDataToBMP(imageData); - return 'data:image/bmp;base64,' + btoa(header) + fromByteArray(imageData.data); + return 'data:image/bmp;base64,' + btoa(header) + fromByteArray(Uint8Array.from(imageData.data)); } // converts a .bmp file ArrayBuffer to a dataURI diff --git a/modules/playground/src/web_workers/images/single_thread.html b/modules/playground/src/web_workers/images/single_thread.html index 98dcfcbb43..ec3da632a5 100644 --- a/modules/playground/src/web_workers/images/single_thread.html +++ b/modules/playground/src/web_workers/images/single_thread.html @@ -1,18 +1,17 @@ - + - - - + - - + + diff --git a/modules/playground/src/web_workers/input/BUILD.bazel b/modules/playground/src/web_workers/input/BUILD.bazel new file mode 100644 index 0000000000..2d714d76f1 --- /dev/null +++ b/modules/playground/src/web_workers/input/BUILD.bazel @@ -0,0 +1,33 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "input", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-webworker", + "//packages/platform-webworker-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = [ + "loader.js", + "//modules/playground/src/web_workers:worker-config", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + ], + entry_module = "angular/modules/playground/src/web_workers/input/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = ["@ngdeps//node_modules/zone.js:dist/zone.js"], + deps = [":input"], +) diff --git a/modules/playground/src/web_workers/input/background_index.ts b/modules/playground/src/web_workers/input/background_index.ts index d05ec70439..b820bbd85f 100644 --- a/modules/playground/src/web_workers/input/background_index.ts +++ b/modules/playground/src/web_workers/input/background_index.ts @@ -13,9 +13,7 @@ import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic'; import {InputCmp} from './index_common'; @NgModule({imports: [WorkerAppModule], bootstrap: [InputCmp], declarations: [InputCmp]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformWorkerAppDynamic().bootstrapModule(ExampleModule); -} +platformWorkerAppDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/web_workers/input/index.html b/modules/playground/src/web_workers/input/index.html index 80dfbcbc72..ffa2e1662f 100644 --- a/modules/playground/src/web_workers/input/index.html +++ b/modules/playground/src/web_workers/input/index.html @@ -7,7 +7,5 @@ Loading... - - diff --git a/modules/playground/src/web_workers/input/index.ts b/modules/playground/src/web_workers/input/index.ts index b45021b6fc..c43aa4aaff 100644 --- a/modules/playground/src/web_workers/input/index.ts +++ b/modules/playground/src/web_workers/input/index.ts @@ -8,6 +8,4 @@ import {bootstrapWorkerUi} from '@angular/platform-webworker'; -export function main() { - bootstrapWorkerUi('loader.js'); -} +bootstrapWorkerUi('loader.js'); diff --git a/modules/playground/src/web_workers/input/loader.js b/modules/playground/src/web_workers/input/loader.js index 13b703e219..b400e24f64 100644 --- a/modules/playground/src/web_workers/input/loader.js +++ b/modules/playground/src/web_workers/input/loader.js @@ -6,43 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -importScripts( - '../../../vendor/core.js', '../../../vendor/zone.js', - '../../../vendor/long-stack-trace-zone.js', '../../../vendor/system.src.js', - '../../../vendor/Reflect.js'); +importScripts('angular/modules/playground/src/web_workers/worker-configure.js'); +System.config({packages: {'angular/modules/playground/src/web_workers': {defaultExtension: 'js'}}}); -System.config({ - baseURL: '/all', - - map: { - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, - - defaultJSExtensions: true -}); - -System.import('playground/src/web_workers/input/background_index') - .then( - function(m) { - try { - m.main(); - } catch (e) { - console.error(e); - } - }, - function(error) { console.error('error loading background', error); }); +System.import('./background_index.js') + .catch(error => console.error('error loading background', error)); diff --git a/modules/playground/src/web_workers/kitchen_sink/BUILD.bazel b/modules/playground/src/web_workers/kitchen_sink/BUILD.bazel new file mode 100644 index 0000000000..768d4dec31 --- /dev/null +++ b/modules/playground/src/web_workers/kitchen_sink/BUILD.bazel @@ -0,0 +1,33 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "kitchen_sink", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-webworker", + "//packages/platform-webworker-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = [ + "loader.js", + "//modules/playground/src/web_workers:worker-config", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + ], + entry_module = "angular/modules/playground/src/web_workers/kitchen_sink/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = ["@ngdeps//node_modules/zone.js:dist/zone.js"], + deps = [":kitchen_sink"], +) diff --git a/modules/playground/src/web_workers/kitchen_sink/background_index.ts b/modules/playground/src/web_workers/kitchen_sink/background_index.ts index a2ea51650c..e23048eeb1 100644 --- a/modules/playground/src/web_workers/kitchen_sink/background_index.ts +++ b/modules/playground/src/web_workers/kitchen_sink/background_index.ts @@ -10,12 +10,14 @@ import {NgModule} from '@angular/core'; import {WorkerAppModule} from '@angular/platform-webworker'; import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic'; -import {HelloCmp} from './index_common'; +import {HelloCmp, RedDec} from './index_common'; -@NgModule({imports: [WorkerAppModule], bootstrap: [HelloCmp], declarations: [HelloCmp]}) -class ExampleModule { +@NgModule({ + imports: [WorkerAppModule], + bootstrap: [HelloCmp], + declarations: [HelloCmp, RedDec], +}) +export class ExampleModule { } -export function main() { - platformWorkerAppDynamic().bootstrapModule(ExampleModule); -} +platformWorkerAppDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/web_workers/kitchen_sink/index.html b/modules/playground/src/web_workers/kitchen_sink/index.html index 793df34e11..aab3329a43 100644 --- a/modules/playground/src/web_workers/kitchen_sink/index.html +++ b/modules/playground/src/web_workers/kitchen_sink/index.html @@ -20,7 +20,5 @@ Loading... - - diff --git a/modules/playground/src/web_workers/kitchen_sink/index.ts b/modules/playground/src/web_workers/kitchen_sink/index.ts index b45021b6fc..c43aa4aaff 100644 --- a/modules/playground/src/web_workers/kitchen_sink/index.ts +++ b/modules/playground/src/web_workers/kitchen_sink/index.ts @@ -8,6 +8,4 @@ import {bootstrapWorkerUi} from '@angular/platform-webworker'; -export function main() { - bootstrapWorkerUi('loader.js'); -} +bootstrapWorkerUi('loader.js'); diff --git a/modules/playground/src/web_workers/kitchen_sink/index_common.ts b/modules/playground/src/web_workers/kitchen_sink/index_common.ts index fd7c9b3373..387c95d599 100644 --- a/modules/playground/src/web_workers/kitchen_sink/index_common.ts +++ b/modules/playground/src/web_workers/kitchen_sink/index_common.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Directive, ElementRef, Injectable, Renderer} from '@angular/core'; +import {Component, Directive, ElementRef, Injectable, Renderer2} from '@angular/core'; // A service available to the Injector, used by the HelloCmp component. @Injectable() @@ -20,8 +20,8 @@ export class GreetingService { export class RedDec { // ElementRef is always injectable and it wraps the element on which the // directive was found by the compiler. - constructor(el: ElementRef, renderer: Renderer) { - renderer.setElementStyle(el.nativeElement, 'color', 'red'); + constructor(el: ElementRef, renderer: Renderer2) { + renderer.setStyle(el.nativeElement, 'color', 'red'); } } diff --git a/modules/playground/src/web_workers/kitchen_sink/loader.js b/modules/playground/src/web_workers/kitchen_sink/loader.js index d5bf332e04..b400e24f64 100644 --- a/modules/playground/src/web_workers/kitchen_sink/loader.js +++ b/modules/playground/src/web_workers/kitchen_sink/loader.js @@ -6,44 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -importScripts( - '../../../vendor/core.js', '../../../vendor/zone.js', - '../../../vendor/long-stack-trace-zone.js', '../../../vendor/system.src.js', - '../../../vendor/Reflect.js'); +importScripts('angular/modules/playground/src/web_workers/worker-configure.js'); +System.config({packages: {'angular/modules/playground/src/web_workers': {defaultExtension: 'js'}}}); -System.config({ - baseURL: '/all', - - map: { - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/router': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, - - defaultJSExtensions: true -}); - -System.import('playground/src/web_workers/kitchen_sink/background_index') - .then( - function(m) { - try { - m.main(); - } catch (e) { - console.error(e); - } - }, - function(error) { console.error('error loading background', error); }); +System.import('./background_index.js') + .catch(error => console.error('error loading background', error)); diff --git a/modules/playground/src/web_workers/message_broker/BUILD.bazel b/modules/playground/src/web_workers/message_broker/BUILD.bazel new file mode 100644 index 0000000000..0f2dda548d --- /dev/null +++ b/modules/playground/src/web_workers/message_broker/BUILD.bazel @@ -0,0 +1,33 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "message_broker", + srcs = glob(["**/*.ts"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-webworker", + "//packages/platform-webworker-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = [ + "loader.js", + "//modules/playground/src/web_workers:worker-config", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + ], + entry_module = "angular/modules/playground/src/web_workers/message_broker/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = ["@ngdeps//node_modules/zone.js:dist/zone.js"], + deps = [":message_broker"], +) diff --git a/modules/playground/src/web_workers/message_broker/background_index.ts b/modules/playground/src/web_workers/message_broker/background_index.ts index df555d60a3..8ca4ba8578 100644 --- a/modules/playground/src/web_workers/message_broker/background_index.ts +++ b/modules/playground/src/web_workers/message_broker/background_index.ts @@ -13,9 +13,7 @@ import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic'; import {App} from './index_common'; @NgModule({imports: [WorkerAppModule], bootstrap: [App], declarations: [App]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformWorkerAppDynamic().bootstrapModule(ExampleModule); -} +platformWorkerAppDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/web_workers/message_broker/index.html b/modules/playground/src/web_workers/message_broker/index.html index 40450e78dd..61d08aec07 100644 --- a/modules/playground/src/web_workers/message_broker/index.html +++ b/modules/playground/src/web_workers/message_broker/index.html @@ -7,6 +7,5 @@

    - diff --git a/modules/playground/src/web_workers/message_broker/index.ts b/modules/playground/src/web_workers/message_broker/index.ts index 4d14bd5d62..0f6979eece 100644 --- a/modules/playground/src/web_workers/message_broker/index.ts +++ b/modules/playground/src/web_workers/message_broker/index.ts @@ -11,10 +11,6 @@ import {ClientMessageBrokerFactory, FnArg, SerializerTypes, UiArguments, bootstr const ECHO_CHANNEL = 'ECHO'; -export function main() { - bootstrapWorkerUi('loader.js').then(afterBootstrap); -} - function afterBootstrap(ref: PlatformRef) { const brokerFactory: ClientMessageBrokerFactory = ref.injector.get(ClientMessageBrokerFactory); const broker = brokerFactory.createMessageBroker(ECHO_CHANNEL, false); @@ -32,3 +28,5 @@ function afterBootstrap(ref: PlatformRef) { }); }); } + +bootstrapWorkerUi('loader.js').then(afterBootstrap); diff --git a/modules/playground/src/web_workers/message_broker/loader.js b/modules/playground/src/web_workers/message_broker/loader.js index 5d69da02db..b400e24f64 100644 --- a/modules/playground/src/web_workers/message_broker/loader.js +++ b/modules/playground/src/web_workers/message_broker/loader.js @@ -6,44 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -importScripts( - '../../../vendor/core.js', '../../../vendor/zone.js', - '../../../vendor/long-stack-trace-zone.js', '../../../vendor/system.src.js', - '../../../vendor/Reflect.js'); +importScripts('angular/modules/playground/src/web_workers/worker-configure.js'); +System.config({packages: {'angular/modules/playground/src/web_workers': {defaultExtension: 'js'}}}); -System.config({ - baseURL: '/all', - - map: { - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/router': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, - - defaultJSExtensions: true -}); - -System.import('playground/src/web_workers/message_broker/background_index') - .then( - function(m) { - try { - m.main(); - } catch (e) { - console.error(e); - } - }, - function(error) { console.error('error loading background', error); }); +System.import('./background_index.js') + .catch(error => console.error('error loading background', error)); diff --git a/modules/playground/src/web_workers/router/BUILD.bazel b/modules/playground/src/web_workers/router/BUILD.bazel new file mode 100644 index 0000000000..d9b6385cd3 --- /dev/null +++ b/modules/playground/src/web_workers/router/BUILD.bazel @@ -0,0 +1,35 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "router", + srcs = glob(["**/*.ts"]), + assets = ["app.html"], + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-webworker", + "//packages/platform-webworker-dynamic", + "//packages/router", + ], +) + +ts_devserver( + name = "devserver", + data = [ + "loader.js", + "//modules/playground/src/web_workers:worker-config", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + ], + entry_module = "angular/modules/playground/src/web_workers/router/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = ["@ngdeps//node_modules/zone.js:dist/zone.js"], + deps = [":router"], +) diff --git a/modules/playground/src/web_workers/router/background_index.ts b/modules/playground/src/web_workers/router/background_index.ts index c60355187d..60bf59440c 100644 --- a/modules/playground/src/web_workers/router/background_index.ts +++ b/modules/playground/src/web_workers/router/background_index.ts @@ -7,9 +7,6 @@ */ import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic'; - import {AppModule} from './index_common'; -export function main() { - platformWorkerAppDynamic().bootstrapModule(AppModule); -} +platformWorkerAppDynamic().bootstrapModule(AppModule); diff --git a/modules/playground/src/web_workers/router/index.html b/modules/playground/src/web_workers/router/index.html index 36d69ed15f..64395a0733 100644 --- a/modules/playground/src/web_workers/router/index.html +++ b/modules/playground/src/web_workers/router/index.html @@ -3,6 +3,5 @@ Web Worker Router Example - diff --git a/modules/playground/src/web_workers/router/index.ts b/modules/playground/src/web_workers/router/index.ts index bc138f7a99..7885532472 100644 --- a/modules/playground/src/web_workers/router/index.ts +++ b/modules/playground/src/web_workers/router/index.ts @@ -8,6 +8,4 @@ import {WORKER_UI_LOCATION_PROVIDERS, bootstrapWorkerUi} from '@angular/platform-webworker'; -export function main() { - bootstrapWorkerUi('loader.js', WORKER_UI_LOCATION_PROVIDERS); -} +bootstrapWorkerUi('loader.js', WORKER_UI_LOCATION_PROVIDERS); diff --git a/modules/playground/src/web_workers/router/loader.js b/modules/playground/src/web_workers/router/loader.js index c5123e2c3e..b400e24f64 100644 --- a/modules/playground/src/web_workers/router/loader.js +++ b/modules/playground/src/web_workers/router/loader.js @@ -6,44 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -importScripts( - '../../../vendor/core.js', '../../../vendor/zone.js', - '../../../vendor/long-stack-trace-zone.js', '../../../vendor/system.src.js', - '../../../vendor/Reflect.js'); +importScripts('angular/modules/playground/src/web_workers/worker-configure.js'); +System.config({packages: {'angular/modules/playground/src/web_workers': {defaultExtension: 'js'}}}); -System.config({ - baseURL: '/all', - - map: { - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/router': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, - - defaultJSExtensions: true -}); - -System.import('playground/src/web_workers/router/background_index') - .then( - function(m) { - try { - m.main(); - } catch (e) { - console.error(e); - } - }, - function(error) { console.error('error loading background', error); }); +System.import('./background_index.js') + .catch(error => console.error('error loading background', error)); diff --git a/modules/playground/src/web_workers/todo/BUILD.bazel b/modules/playground/src/web_workers/todo/BUILD.bazel new file mode 100644 index 0000000000..aaba201256 --- /dev/null +++ b/modules/playground/src/web_workers/todo/BUILD.bazel @@ -0,0 +1,36 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "todo", + srcs = glob(["**/*.ts"]), + assets = ["todo.html"], + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/forms", + "//packages/platform-webworker", + "//packages/platform-webworker-dynamic", + ], +) + +ts_devserver( + name = "devserver", + data = [ + "css/main.css", + "loader.js", + "//modules/playground/src/web_workers:worker-config", + "@ngdeps//node_modules/rxjs:bundles/rxjs.umd.js", + "@ngdeps//node_modules/tslib:tslib.js", + ], + entry_module = "angular/modules/playground/src/web_workers/todo/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = ["@ngdeps//node_modules/zone.js:dist/zone.js"], + deps = [":todo"], +) diff --git a/modules/playground/src/web_workers/todo/background_index.ts b/modules/playground/src/web_workers/todo/background_index.ts index 190431081a..77d1882b3a 100644 --- a/modules/playground/src/web_workers/todo/background_index.ts +++ b/modules/playground/src/web_workers/todo/background_index.ts @@ -14,9 +14,7 @@ import {platformWorkerAppDynamic} from '@angular/platform-webworker-dynamic'; import {TodoApp} from './index_common'; @NgModule({imports: [WorkerAppModule, FormsModule], bootstrap: [TodoApp], declarations: [TodoApp]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformWorkerAppDynamic().bootstrapModule(ExampleModule); -} +platformWorkerAppDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/src/web_workers/todo/css/main.css b/modules/playground/src/web_workers/todo/css/main.css index a87b28d934..2b3220292b 100644 --- a/modules/playground/src/web_workers/todo/css/main.css +++ b/modules/playground/src/web_workers/todo/css/main.css @@ -13,11 +13,6 @@ body { color: #4d4d4d; width: 550px; margin: 0 auto; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - -ms-font-smoothing: antialiased; - -o-font-smoothing: antialiased; - font-smoothing: antialiased; } button { @@ -33,10 +28,6 @@ button { -webkit-appearance: none; -ms-appearance: none; appearance: none; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - -ms-font-smoothing: antialiased; - font-smoothing: antialiased; } button, @@ -109,10 +100,6 @@ input[type="checkbox"] { box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); -ms-box-sizing: border-box; box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - -ms-font-smoothing: antialiased; - font-smoothing: antialiased; } #new-todo { diff --git a/modules/playground/src/web_workers/todo/index.html b/modules/playground/src/web_workers/todo/index.html index 699655ded7..e4fac7623f 100644 --- a/modules/playground/src/web_workers/todo/index.html +++ b/modules/playground/src/web_workers/todo/index.html @@ -6,8 +6,5 @@ Loading... - - - diff --git a/modules/playground/src/web_workers/todo/index.ts b/modules/playground/src/web_workers/todo/index.ts index b45021b6fc..c43aa4aaff 100644 --- a/modules/playground/src/web_workers/todo/index.ts +++ b/modules/playground/src/web_workers/todo/index.ts @@ -8,6 +8,4 @@ import {bootstrapWorkerUi} from '@angular/platform-webworker'; -export function main() { - bootstrapWorkerUi('loader.js'); -} +bootstrapWorkerUi('loader.js'); diff --git a/modules/playground/src/web_workers/todo/index_web_socket.html b/modules/playground/src/web_workers/todo/index_web_socket.html index ef39c45a5f..e4fac7623f 100644 --- a/modules/playground/src/web_workers/todo/index_web_socket.html +++ b/modules/playground/src/web_workers/todo/index_web_socket.html @@ -6,8 +6,5 @@ Loading... - - - diff --git a/modules/playground/src/web_workers/todo/loader.js b/modules/playground/src/web_workers/todo/loader.js index f559e52ba7..b400e24f64 100644 --- a/modules/playground/src/web_workers/todo/loader.js +++ b/modules/playground/src/web_workers/todo/loader.js @@ -6,45 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -importScripts( - '../../../vendor/core.js', '../../../vendor/zone.js', - '../../../vendor/long-stack-trace-zone.js', '../../../vendor/system.src.js', - '../../../vendor/Reflect.js'); +importScripts('angular/modules/playground/src/web_workers/worker-configure.js'); +System.config({packages: {'angular/modules/playground/src/web_workers': {defaultExtension: 'js'}}}); -System.config({ - baseURL: '/all', - - map: { - 'rxjs': '/all/playground/vendor/rxjs', - }, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/forms': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/router': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, - - defaultJSExtensions: true -}); - -System.import('playground/src/web_workers/todo/background_index') - .then( - function(m) { - try { - m.main(); - } catch (e) { - console.error(e); - } - }, - function(error) { console.error('error loading background', error); }); +System.import('./background_index.js') + .catch(error => console.error('error loading background', error)); diff --git a/modules/playground/src/web_workers/worker-configure.js b/modules/playground/src/web_workers/worker-configure.js new file mode 100644 index 0000000000..96041039ec --- /dev/null +++ b/modules/playground/src/web_workers/worker-configure.js @@ -0,0 +1,14 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +importScripts('ngdeps/node_modules/reflect-metadata/Reflect.js'); +importScripts('ngdeps/node_modules/zone.js/dist/zone.js'); +importScripts('ngdeps/node_modules/zone.js/dist/long-stack-trace-zone.js'); +importScripts('ngdeps/node_modules/systemjs/dist/system.js'); + +importScripts('angular/modules/playground/systemjs-config.js'); diff --git a/modules/playground/src/zippy_component/BUILD.bazel b/modules/playground/src/zippy_component/BUILD.bazel new file mode 100644 index 0000000000..da9d9396f2 --- /dev/null +++ b/modules/playground/src/zippy_component/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//modules/playground:__subpackages__"]) + +ng_module( + name = "zippy_component", + srcs = glob(["**/*.ts"]), + assets = glob(["app/zippy.html"]), + tsconfig = "//modules/playground:tsconfig-build.json", + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "angular/modules/playground/src/zippy_component/index", + index_html = "index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":zippy_component"], +) diff --git a/modules/playground/src/zippy_component/app/zippy.ts b/modules/playground/src/zippy_component/app/zippy.ts index dd738bae1d..e005090fa8 100644 --- a/modules/playground/src/zippy_component/app/zippy.ts +++ b/modules/playground/src/zippy_component/app/zippy.ts @@ -8,7 +8,7 @@ import {Component, EventEmitter, Input, Output} from '@angular/core'; -@Component({selector: 'zippy', templateUrl: 'app/zippy.html'}) +@Component({selector: 'zippy', templateUrl: './zippy.html'}) export class Zippy { visible: boolean = true; @Input() title: string = ''; diff --git a/modules/playground/src/zippy_component/index.html b/modules/playground/src/zippy_component/index.html index 3310e15eb0..de656ac666 100644 --- a/modules/playground/src/zippy_component/index.html +++ b/modules/playground/src/zippy_component/index.html @@ -5,7 +5,5 @@ Loading... - - diff --git a/modules/playground/src/zippy_component/index.ts b/modules/playground/src/zippy_component/index.ts index 5e17f1b225..00ede4cd6c 100644 --- a/modules/playground/src/zippy_component/index.ts +++ b/modules/playground/src/zippy_component/index.ts @@ -23,16 +23,14 @@ import {Zippy} from './app/zippy'; ` }) -class ZippyApp { +export class ZippyApp { logs: string[] = []; pushLog(log: string) { this.logs.push(log); } } @NgModule({declarations: [ZippyApp, Zippy], bootstrap: [ZippyApp], imports: [BrowserModule]}) -class ExampleModule { +export class ExampleModule { } -export function main() { - platformBrowserDynamic().bootstrapModule(ExampleModule); -} +platformBrowserDynamic().bootstrapModule(ExampleModule); diff --git a/modules/playground/systemjs-config.js b/modules/playground/systemjs-config.js new file mode 100644 index 0000000000..a9f4c0b75d --- /dev/null +++ b/modules/playground/systemjs-config.js @@ -0,0 +1,49 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// Normally the Bazel "ts_devserver" automatically handles the module resolution of +// dependencies in the browser using RequireJS, but there are various examples that +// use SystemJS (e.g. for lazy loading, web workers) and therefore we want to avoid +// repeating the basic configuration by providing this as a general SystemJS config. + +const angularPackages = [ + 'common', + 'animations', + 'platform-browser/animations', + 'compiler', + 'core', + 'forms', + 'http', + 'platform-browser', + 'platform-browser-dynamic', + 'platform-webworker', + 'platform-webworker-dynamic', + 'router', + 'upgrade', + 'upgrade/static', +]; + +const packagesConfig = {}; +const mapConfig = { + 'tslib': 'ngdeps/node_modules/tslib/tslib.js', + 'rxjs': 'ngdeps/node_modules/rxjs/bundles/rxjs.umd.js', + 'rxjs/operators': 'angular/modules/playground/systemjs-rxjs-operators.js', +}; + +angularPackages.forEach(pkgName => { + mapConfig[`@angular/${pkgName}`] = `angular/packages/${pkgName}`; + packagesConfig[`@angular/${pkgName}`] = { + main: 'index.js', + defaultExtension: 'js', + }; +}); + +System.config({ + map: mapConfig, + packages: packagesConfig, +}); diff --git a/modules/playground/systemjs-rxjs-operators.js b/modules/playground/systemjs-rxjs-operators.js new file mode 100644 index 0000000000..eddff38471 --- /dev/null +++ b/modules/playground/systemjs-rxjs-operators.js @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// Workaround for an issue where RxJS cannot be used with UMD bundles only. This is because +// rxjs only ships one UMD bundle and expects everyone to only use the named "rxjs" AMD module. +// Since our code internally loads operators from "rxjs/operators/index", we need to make sure +// that we re-export all operators from the UMD module. This is a small trade-off for not loading +// all rxjs files individually. + +if (typeof define === 'function' && define.amd) { + define(['exports', 'rxjs'], (exports, rxjs) => { + // Re-export all operators in this AMD module. + Object.assign(exports, rxjs.operators); + }); +} diff --git a/modules/playground/tsconfig-build.json b/modules/playground/tsconfig-build.json new file mode 100644 index 0000000000..d18dc325cc --- /dev/null +++ b/modules/playground/tsconfig-build.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["dom", "es2015"], + "types": [] + } +} diff --git a/modules/playground/tsconfig-e2e.json b/modules/playground/tsconfig-e2e.json new file mode 100644 index 0000000000..16123f3cc4 --- /dev/null +++ b/modules/playground/tsconfig-e2e.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["es2015", "dom"], + "types": ["node", "jasminewd2", "selenium-webdriver"] + } +} diff --git a/modules/tsconfig.json b/modules/tsconfig.json index 5dedb93d0e..67c1ff7253 100644 --- a/modules/tsconfig.json +++ b/modules/tsconfig.json @@ -24,11 +24,10 @@ }, "exclude": [ "angular1_router", - "benchmarks/e2e_test/old", - "benchmarks/src/old", - "benchmarks/src/**/index_aot.ts", "benchmarks_external", - "payload_tests" + "payload_tests", + "playground/", + "benchmarks/" ], "angularCompilerOptions": { "skipTemplateCodegen": true diff --git a/modules/types.d.ts b/modules/types.d.ts index 7d0eb482b2..1084916097 100644 --- a/modules/types.d.ts +++ b/modules/types.d.ts @@ -13,5 +13,5 @@ /// /// /// -/// +/// /// diff --git a/package.json b/package.json index afe8815ab0..f4340a285e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-srcs", - "version": "7.2.0-rc.0", + "version": "8.0.0-beta.4", "private": true, "branchPattern": "2.0.*", "description": "Angular - a web framework for modern web apps", @@ -9,7 +9,7 @@ "license": "MIT", "engines": { "node": ">=10.9.0 <11.0.0", - "yarn": ">=1.10.1 <1.13.0" + "yarn": ">=1.12.1 <=1.14.0" }, "repository": { "type": "git", @@ -21,7 +21,7 @@ "bazel:lint-fix": "yarn bazel:format --lint=fix", "preinstall": "node tools/yarn/check-yarn.js", "postinstall": "yarn update-webdriver && node --preserve-symlinks --preserve-symlinks-main ./tools/postinstall-patches.js", - "update-webdriver": "webdriver-manager update --gecko false $CHROMEDRIVER_VERSION_ARG", + "update-webdriver": "webdriver-manager update --gecko false $CI_CHROMEDRIVER_VERSION_ARG", "check-env": "gulp check-env", "commitmsg": "node ./scripts/git/commit-msg.js", "test-ivy-aot": "bazel test --define=compile=aot --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot", @@ -32,17 +32,22 @@ "// 1": "dependencies are used locally and by bazel", "dependencies": { "@angular-devkit/architect": "^0.10.6", + "@angular-devkit/build-optimizer": "0.13.0-rc.0", "@angular-devkit/core": "^7.0.4", - "@angular-devkit/schematics": "^7.0.4", - "@bazel/karma": "~0.22.0", - "@bazel/typescript": "~0.22.0", + "@angular-devkit/schematics": "^7.3.0-rc.0", + "@bazel/karma": "0.23.2", + "@bazel/typescript": "0.23.2", + "@microsoft/api-extractor": "^7.0.17", "@schematics/angular": "^7.0.4", + "@types/angular": "^1.6.47", + "@types/base64-js": "1.2.5", "@types/chokidar": "1.7.3", "@types/convert-source-map": "^1.5.1", "@types/diff": "^3.2.2", "@types/fs-extra": "4.0.2", "@types/hammerjs": "2.0.35", "@types/jasmine": "^2.8.8", + "@types/jasminewd2": "^2.0.6", "@types/mock-fs": "^3.6.30", "@types/node": "^10.9.4", "@types/selenium-webdriver": "3.0.7", @@ -61,21 +66,30 @@ "chokidar": "1.7.0", "convert-source-map": "^1.5.1", "dependency-graph": "^0.7.2", + "diff": "^3.5.0", "domino": "2.1.0", "fs-extra": "4.0.2", + "hammerjs": "2.0.8", + "incremental-dom": "0.4.1", "jasmine": "^3.1.0", "jasmine-core": "^3.1.0", + "jquery": "3.0.0", "karma": "^3.1.4", "magic-string": "^0.25.0", + "materialize-css": "1.0.0", "minimist": "1.2.0", "mock-fs": "^4.5.0", "node-uuid": "1.4.8", - "protractor": "5.1.2", + "protractor": "^5.4.2", "reflect-metadata": "^0.1.3", + "rollup": "^1.1.0", + "rollup-plugin-node-resolve": "^4.0.0", + "rollup-plugin-sourcemaps": "^0.4.2", "selenium-webdriver": "3.5.0", "shelljs": "^0.8.1", "source-map": "^0.6.1", "source-map-support": "0.5.9", + "systemjs": "0.18.10", "tsickle": "0.34.0", "tslib": "^1.9.0", "typescript": "~3.2.2", @@ -87,16 +101,14 @@ "fsevents": "2.0.1" }, "// 2": "devDependencies are not used under Bazel. Many can be removed after test.sh is deleted.", + "// 3": "when updating @bazel/bazel version you also need to update the RBE settings in .bazelrc (see https://github.com/angular/angular/pull/27935)", "devDependencies": { - "@bazel/bazel": "~0.20.0", + "@angular/cli": "^7.3.0-rc.0", + "@bazel/bazel": "~0.22.0", "@bazel/buildifier": "^0.19.2", "@bazel/ibazel": "~0.9.0", - "@types/angular": "^1.6.47", - "@types/base64-js": "1.2.5", - "@types/jasminewd2": "^2.0.4", "@types/minimist": "^1.2.0", "@types/systemjs": "0.19.32", - "bower": "1.8.2", "browserstacktunnel-wrapper": "2.0.1", "clang-format": "1.0.41", "cldr": "4.10.0", @@ -105,8 +117,8 @@ "conventional-changelog": "^2.0.3", "core-js": "^2.4.1", "cors": "2.8.4", - "diff": "^3.5.0", "entities": "1.1.1", + "firebase-tools": "5.1.1", "firefox-profile": "1.0.3", "glob": "7.1.2", "gulp": "3.9.1", @@ -116,9 +128,7 @@ "gulp-filter": "^5.1.0", "gulp-git": "^2.7.0", "gulp-tslint": "8.1.2", - "hammerjs": "2.0.8", "husky": "^0.14.3", - "incremental-dom": "0.4.1", "jpm": "1.3.1", "karma-browserstack-launcher": "^1.3.0", "karma-chrome-launcher": "^2.2.0", @@ -128,13 +138,10 @@ "madge": "0.5.0", "mutation-observer": "^1.0.3", "rewire": "2.5.2", - "rollup": "0.47.4", "rollup-plugin-commonjs": "8.1.0", - "rollup-plugin-node-resolve": "3.0.0", - "rollup-plugin-sourcemaps": "0.4.2", "rxjs": "^6.3.0", + "sauce-connect": "https://saucelabs.com/downloads/sc-4.5.1-linux.tar.gz", "semver": "5.4.1", - "systemjs": "0.18.10", "tslint": "5.7.0", "tslint-eslint-rules": "4.1.1", "tsutils": "2.27.2", @@ -143,5 +150,9 @@ "vlq": "0.2.2", "vrsource-tslint-rules": "5.1.1", "webpack": "1.12.9" + }, + "// 4": "natives is needed for gulp to work with node >= 10.13, see #28213", + "resolutions": { + "natives": "1.1.6" } } diff --git a/packages/animations/BUILD.bazel b/packages/animations/BUILD.bazel index 1cd92b5aa8..b104693eb8 100644 --- a/packages/animations/BUILD.bazel +++ b/packages/animations/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/animations", deps = [ "//packages/core", ], @@ -30,6 +29,7 @@ ng_package( # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", "//packages/compiler/test:__pkg__", ], deps = [ diff --git a/packages/animations/browser/BUILD.bazel b/packages/animations/browser/BUILD.bazel index b3bb295b03..e2cba30158 100644 --- a/packages/animations/browser/BUILD.bazel +++ b/packages/animations/browser/BUILD.bazel @@ -12,7 +12,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/animations/browser", deps = [ "//packages/animations", "//packages/core", diff --git a/packages/animations/browser/rollup.config.js b/packages/animations/browser/rollup.config.js deleted file mode 100644 index 3ffb6d5a6a..0000000000 --- a/packages/animations/browser/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/animations': 'ng.animations' -}; - -module.exports = { - entry: '../../../dist/packages-dist/animations/fesm5/browser.js', - dest: '../../../dist/packages-dist/animations/bundles/animations-browser.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/animations/browser'}, - moduleName: 'ng.animations.browser', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/animations/browser/src/dsl/animation_ast_builder.ts b/packages/animations/browser/src/dsl/animation_ast_builder.ts index 841bfd378b..f225491baf 100644 --- a/packages/animations/browser/src/dsl/animation_ast_builder.ts +++ b/packages/animations/browser/src/dsl/animation_ast_builder.ts @@ -26,7 +26,7 @@ const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g'); * * 1. Overlap of animations * Given that a CSS property cannot be animated in more than one place at the same time, it's - * important that this behaviour is detected and validated. The way in which this occurs is that + * important that this behavior is detected and validated. The way in which this occurs is that * each time a style property is examined, a string-map containing the property will be updated with * the start and end times for when the property is used within an animation step. * diff --git a/packages/animations/browser/src/render/animation_engine_next.ts b/packages/animations/browser/src/render/animation_engine_next.ts index 753d8b52ae..fe458b7611 100644 --- a/packages/animations/browser/src/render/animation_engine_next.ts +++ b/packages/animations/browser/src/render/animation_engine_next.ts @@ -66,8 +66,8 @@ export class AnimationEngine { this._transitionEngine.insertNode(namespaceId, element, parent, insertBefore); } - onRemove(namespaceId: string, element: any, context: any): void { - this._transitionEngine.removeNode(namespaceId, element, context); + onRemove(namespaceId: string, element: any, context: any, isHostElement?: boolean): void { + this._transitionEngine.removeNode(namespaceId, element, isHostElement || false, context); } disableAnimations(element: any, disable: boolean) { diff --git a/packages/animations/browser/src/render/transition_animation_engine.ts b/packages/animations/browser/src/render/transition_animation_engine.ts index 0feacd5de4..b44f54446b 100644 --- a/packages/animations/browser/src/render/transition_animation_engine.ts +++ b/packages/animations/browser/src/render/transition_animation_engine.ts @@ -708,17 +708,23 @@ export class TransitionAnimationEngine { } } - removeNode(namespaceId: string, element: any, context: any): void { - if (!isElementNode(element)) { - this._onRemovalComplete(element, context); - return; - } + removeNode(namespaceId: string, element: any, isHostElement: boolean, context: any): void { + if (isElementNode(element)) { + const ns = namespaceId ? this._fetchNamespace(namespaceId) : null; + if (ns) { + ns.removeNode(element, context); + } else { + this.markElementAsRemoved(namespaceId, element, false, context); + } - const ns = namespaceId ? this._fetchNamespace(namespaceId) : null; - if (ns) { - ns.removeNode(element, context); + if (isHostElement) { + const hostNS = this.namespacesByHostElement.get(element); + if (hostNS && hostNS.id !== namespaceId) { + hostNS.removeNode(element, context); + } + } } else { - this.markElementAsRemoved(namespaceId, element, false, context); + this._onRemovalComplete(element, context); } } diff --git a/packages/animations/browser/test/render/css_keyframes/shared.ts b/packages/animations/browser/test/render/css_keyframes/shared.ts index e7055d1186..e60a4f50ad 100644 --- a/packages/animations/browser/test/render/css_keyframes/shared.ts +++ b/packages/animations/browser/test/render/css_keyframes/shared.ts @@ -23,7 +23,7 @@ export function supportsAnimationEventCreation() { try { makeAnimationEvent('end', 'test', 0); supported = true; - } catch (e) { + } catch { } return supported; } diff --git a/packages/animations/browser/test/render/transition_animation_engine_spec.ts b/packages/animations/browser/test/render/transition_animation_engine_spec.ts index 8090f81e00..1ad40b001f 100644 --- a/packages/animations/browser/test/render/transition_animation_engine_spec.ts +++ b/packages/animations/browser/test/render/transition_animation_engine_spec.ts @@ -111,7 +111,7 @@ const DEFAULT_NAMESPACE_ID = 'id'; expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy(); - engine.removeNode(DEFAULT_NAMESPACE_ID, element, true); + engine.removeNode(DEFAULT_NAMESPACE_ID, element, true, true); engine.flush(); expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy(); diff --git a/packages/animations/browser/testing/BUILD.bazel b/packages/animations/browser/testing/BUILD.bazel index c8a98f45fb..f14f49c1d1 100644 --- a/packages/animations/browser/testing/BUILD.bazel +++ b/packages/animations/browser/testing/BUILD.bazel @@ -7,7 +7,6 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "testing", srcs = glob(["**/*.ts"]), - module_name = "@angular/animations/browser/testing", deps = [ "//packages/animations", "//packages/animations/browser", diff --git a/packages/animations/browser/testing/rollup.config.js b/packages/animations/browser/testing/rollup.config.js deleted file mode 100644 index 8380bc9d35..0000000000 --- a/packages/animations/browser/testing/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/animations': 'ng.animations', - '@angular/animations/browser': 'ng.animations.browser', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../../../dist/packages-dist/animations/fesm5/browser/testing.js', - dest: '../../../../dist/packages-dist/animations/bundles/animations-browser-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/animations/browser/testing'}, - moduleName: 'ng.animations.browser.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/animations/rollup.config.js b/packages/animations/rollup.config.js deleted file mode 100644 index 5a1aa1f7f2..0000000000 --- a/packages/animations/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/animations': 'ng.animations', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../dist/packages-dist/animations/fesm5/animations.js', - dest: '../../dist/packages-dist/animations/bundles/animations.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/animations'}, - moduleName: 'ng.animations', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/animations/src/animation_metadata.ts b/packages/animations/src/animation_metadata.ts index b549bd426e..6200226cfc 100755 --- a/packages/animations/src/animation_metadata.ts +++ b/packages/animations/src/animation_metadata.ts @@ -979,8 +979,8 @@ export function animate( * * ```typescript * group([ - * animate("1s", { background: "black" })) - * animate("2s", { color: "white" })) + * animate("1s", style({ background: "black" })), + * animate("2s", style({ color: "white" })) * ]) * ``` * @@ -1034,7 +1034,7 @@ export function group( * ```typescript * sequence([ * style({ opacity: 0 })), - * animate("1s", { opacity: 1 })) + * animate("1s", style({ opacity: 1 })) * ]) * ``` * @@ -1603,7 +1603,7 @@ export function animation( * 每当 Angular 触发动画时,总是父动画优先,而子动画被阻塞。 * 为了执行子动画,父动画必须查询每个包含子动画的元素,并使用该函数运行它们。 * - * Note that this feature designed to be used with `query()` and it will only work + * Note that this feature is designed to be used with `query()` and it will only work * with animations that are assigned using the Angular animation library. CSS keyframes * and transitions are not handled by this API. * diff --git a/packages/bazel/BUILD.bazel b/packages/bazel/BUILD.bazel index 03f97b9fe0..31c10a2cde 100644 --- a/packages/bazel/BUILD.bazel +++ b/packages/bazel/BUILD.bazel @@ -23,6 +23,7 @@ npm_package( "//packages/bazel/src/ngc-wrapped:ngc_lib", "//packages/bazel/src/protractor/utils", "//packages/bazel/src/schematics/bazel-workspace", + "//packages/bazel/src/schematics/ng-add", "//packages/bazel/src/schematics/ng-new", ], ) diff --git a/packages/bazel/package.bzl b/packages/bazel/package.bzl index c21c99af50..3027727957 100644 --- a/packages/bazel/package.bzl +++ b/packages/bazel/package.bzl @@ -9,42 +9,12 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") def rules_angular_dependencies(): - """ - Fetch our transitive dependencies. - - If the user wants to get a different version of these, they can just fetch it - from their WORKSPACE before calling this function, or not call this function at all. - """ - - # - # Download Bazel toolchain dependencies as needed by build actions - # Use a SHA to get fix for needing symlink_prefix during npm publishing - # TODO(alexeagle): updated to next tagged rules_typescript release - _maybe( - http_archive, - name = "build_bazel_rules_nodejs", - url = "https://github.com/bazelbuild/rules_nodejs/archive/ee218e2a98b9f09ba07cecac8496a5918c47bc5d.zip", - strip_prefix = "rules_nodejs-ee218e2a98b9f09ba07cecac8496a5918c47bc5d", - ) - - _maybe( - http_archive, - name = "build_bazel_rules_typescript", - url = "https://github.com/bazelbuild/rules_typescript/archive/0.22.0.zip", - strip_prefix = "rules_typescript-0.22.0", - ) - - # Needed for Remote Execution - _maybe( - http_archive, - name = "bazel_toolchains", - sha256 = "07a81ee03f5feae354c9f98c884e8e886914856fb2b6a63cba4619ef10aaaf0b", - strip_prefix = "bazel-toolchains-31b5dc8c4e9c7fd3f5f4d04c6714f2ce87b126c1", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/31b5dc8c4e9c7fd3f5f4d04c6714f2ce87b126c1.tar.gz", - "https://github.com/bazelbuild/bazel-toolchains/archive/31b5dc8c4e9c7fd3f5f4d04c6714f2ce87b126c1.tar.gz", - ], - ) + print("""DEPRECATION WARNING: + rules_angular_dependencies is no longer needed, and will be removed in a future release. + We assume you will fetch rules_nodejs in your WORKSPACE file, and no other dependencies remain here. + Simply remove any calls to this function and the corresponding call to + load("@angular//:package.bzl", "rules_angular_dependencies") + """) def rules_angular_dev_dependencies(): """ @@ -54,19 +24,6 @@ def rules_angular_dev_dependencies(): shorter. """ - # We have a source dependency on the Devkit repository, because it's built with - # Bazel. - # This allows us to edit sources and have the effect appear immediately without - # re-packaging or "npm link"ing. - # Even better, things like aspects will visit the entire graph including - # ts_library rules in the devkit repository. - http_archive( - name = "angular_cli", - sha256 = "8cf320ea58c321e103f39087376feea502f20eaf79c61a4fdb05c7286c8684fd", - strip_prefix = "angular-cli-6.1.0-rc.0", - url = "https://github.com/angular/angular-cli/archive/v6.1.0-rc.0.zip", - ) - http_archive( name = "org_brotli", sha256 = "774b893a0700b0692a76e2e5b7e7610dbbe330ffbe3fe864b4b52ca718061d5a", @@ -74,6 +31,18 @@ def rules_angular_dev_dependencies(): url = "https://github.com/google/brotli/archive/v1.0.5.zip", ) + # Needed for Remote Execution + _maybe( + http_archive, + name = "bazel_toolchains", + sha256 = "ee854b5de299138c1f4a2edb5573d22b21d975acfc7aa938f36d30b49ef97498", + strip_prefix = "bazel-toolchains-37419a124bdb9af2fec5b99a973d359b6b899b61", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/37419a124bdb9af2fec5b99a973d359b6b899b61.tar.gz", + "https://github.com/bazelbuild/bazel-toolchains/archive/37419a124bdb9af2fec5b99a973d359b6b899b61.tar.gz", + ], + ) + ############################################# # Dependencies for generating documentation # ############################################# diff --git a/packages/bazel/package.json b/packages/bazel/package.json index 80fa0431fe..473fa766bc 100644 --- a/packages/bazel/package.json +++ b/packages/bazel/package.json @@ -14,8 +14,9 @@ "dependencies": { "@angular-devkit/architect": "^0.10.6", "@angular-devkit/core": "^7.0.4", - "@angular-devkit/schematics": "^7.0.4", - "@bazel/typescript": "^0.21.0", + "@angular-devkit/schematics": "^7.3.0-rc.0", + "@bazel/typescript": "^0.23.2", + "@microsoft/api-extractor": "^7.0.17", "@schematics/angular": "^7.0.4", "@types/node": "6.0.84", "semver": "^5.6.0", diff --git a/packages/bazel/src/BUILD.bazel b/packages/bazel/src/BUILD.bazel index eb11c4201d..4ca155ee46 100644 --- a/packages/bazel/src/BUILD.bazel +++ b/packages/bazel/src/BUILD.bazel @@ -13,13 +13,15 @@ load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary") nodejs_binary( name = "rollup_with_build_optimizer", - data = ["@angular_cli//packages/angular_devkit/build_optimizer:lib"], - # Since our rule extends the one in rules_nodejs, we use the same runtime - # dependency @build_bazel_rules_nodejs_rollup_deps. We don't need any - # additional npm dependencies when we run rollup or uglify. - entry_point = "build_bazel_rules_nodejs_rollup_deps/node_modules/rollup/bin/rollup", + data = [ + "@ngdeps//@angular-devkit/build-optimizer", + "@ngdeps//is-builtin-module", + "@ngdeps//rollup", + "@ngdeps//rollup-plugin-node-resolve", + "@ngdeps//rollup-plugin-sourcemaps", + ], + entry_point = "ngdeps/node_modules/rollup/bin/rollup", install_source_map_support = False, - node_modules = "@build_bazel_rules_nodejs_rollup_deps//:node_modules", ) nodejs_binary( diff --git a/packages/bazel/src/api-extractor/BUILD.bazel b/packages/bazel/src/api-extractor/BUILD.bazel new file mode 100644 index 0000000000..b0a9bf207d --- /dev/null +++ b/packages/bazel/src/api-extractor/BUILD.bazel @@ -0,0 +1,27 @@ +package(default_visibility = ["//packages:__subpackages__"]) + +load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary") +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "lib", + srcs = [ + "index.ts", + ], + deps = [ + "@ngdeps//@bazel/typescript", + "@ngdeps//@microsoft/api-extractor", + "@ngdeps//@types/node", + ], +) + +nodejs_binary( + name = "api_extractor", + data = [ + ":lib", + "@ngdeps//@bazel/typescript", + "@ngdeps//@microsoft/api-extractor", + ], + entry_point = "angular/packages/bazel/src/api-extractor/index.js", + visibility = ["//visibility:public"], +) diff --git a/packages/bazel/src/api-extractor/index.ts b/packages/bazel/src/api-extractor/index.ts new file mode 100644 index 0000000000..c895891c96 --- /dev/null +++ b/packages/bazel/src/api-extractor/index.ts @@ -0,0 +1,115 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/// +/// + +import {format, parseTsconfig} from '@bazel/typescript'; +import {Extractor, ExtractorValidationRulePolicy, IExtractorConfig, IExtractorOptions} from '@microsoft/api-extractor'; +import * as fs from 'fs'; +import * as path from 'path'; + +const DEBUG = false; + +export function runMain( + tsConfig: string, entryPoint: string, dtsBundleOut?: string, apiReviewFolder?: string, + acceptApiUpdates = false): 1|0 { + const [parsedConfig, errors] = parseTsconfig(tsConfig); + if (errors && errors.length) { + console.error(format('', errors)); + + return 1; + } + + const pkgJson = path.resolve(path.dirname(entryPoint), 'package.json'); + if (!fs.existsSync(pkgJson)) { + fs.writeFileSync(pkgJson, JSON.stringify({ + 'name': 'GENERATED-BY-BAZEL', + 'version': '0.0.0', + 'description': 'This is a dummy package.json as API Extractor always requires one.', + })); + } + + // API extractor doesn't always support the version of TypeScript used in the repo + // example: at the moment it is not compatable with 3.2 + // to use the internal TypeScript we shall not create a program but rather pass a parsed tsConfig. + const parsedTsConfig = parsedConfig !.config as any; + const compilerOptions = parsedTsConfig.compilerOptions; + for (const [key, values] of Object.entries(compilerOptions.paths)) { + if (key === '*') { + continue; + } + + // we shall not pass ts files as this will need to be parsed, and for example rxjs, + // cannot be compiled with our tsconfig, as ours is more strict + // hence amend the paths to point always to the '.d.ts' files. + compilerOptions.paths[key] = values.map(path => { + const pathSuffix = /(\*|index)$/.test(path) ? '.d.ts' : '/index.d.ts'; + + return path + pathSuffix; + }); + } + + const extractorOptions: IExtractorOptions = { + localBuild: acceptApiUpdates, + customLogger: DEBUG ? undefined : { + // don't log verbose messages when not in debug mode + logVerbose: _message => {} + } + }; + + const extractorConfig: IExtractorConfig = { + compiler: { + configType: 'tsconfig', + overrideTsconfig: parsedTsConfig, + rootFolder: path.resolve(path.dirname(tsConfig)) + }, + project: { + entryPointSourceFile: path.resolve(entryPoint), + }, + apiReviewFile: { + enabled: !!apiReviewFolder, + apiReviewFolder: apiReviewFolder && path.resolve(apiReviewFolder), + }, + apiJsonFile: { + enabled: false, + }, + policies: { + namespaceSupport: 'permissive', + }, + validationRules: { + missingReleaseTags: ExtractorValidationRulePolicy.allow, + }, + dtsRollup: { + enabled: !!dtsBundleOut, + publishFolder: dtsBundleOut && path.resolve(path.dirname(dtsBundleOut)), + mainDtsRollupPath: dtsBundleOut && path.basename(dtsBundleOut), + } + }; + + const extractor = new Extractor(extractorConfig, extractorOptions); + const isSuccessful = extractor.processProject(); + + // API extractor errors are emitted by it's logger. + return isSuccessful ? 0 : 1; +} + +// Entry point +if (require.main === module) { + if (DEBUG) { + console.error(` +api-extractor: running with + cwd: ${process.cwd()} + argv: + ${process.argv.join('\n ')} + `); + } + + const [tsConfig, entryPoint, dtsBundleOut] = process.argv.slice(2); + process.exitCode = runMain(tsConfig, entryPoint, dtsBundleOut); +} diff --git a/packages/bazel/src/builders/bazel.ts b/packages/bazel/src/builders/bazel.ts index 24c5369a8d..d1fe2cdbfb 100644 --- a/packages/bazel/src/builders/bazel.ts +++ b/packages/bazel/src/builders/bazel.ts @@ -17,7 +17,8 @@ export function runBazel( projectDir: string, executable: Executable, command: Command, workspaceTarget: string, flags: string[]): Observable { const doneSubject = new Subject(); - const buildProcess = spawn(executable, [command, workspaceTarget, ...flags], { + const bin = require.resolve(`@bazel/${executable}`); + const buildProcess = spawn(bin, [command, workspaceTarget, ...flags], { cwd: projectDir, stdio: 'inherit', shell: false, @@ -35,7 +36,13 @@ export function runBazel( } export function checkInstallation(executable: Executable, projectDir: string) { - const child = spawnSync(executable, ['version'], { + let bin: string; + try { + bin = require.resolve(`@bazel/${executable}`); + } catch { + return false; + } + const child = spawnSync(bin, ['version'], { cwd: projectDir, shell: false, }); diff --git a/packages/bazel/src/builders/index.ts b/packages/bazel/src/builders/index.ts index 42785c8c34..cf268067fc 100644 --- a/packages/bazel/src/builders/index.ts +++ b/packages/bazel/src/builders/index.ts @@ -11,7 +11,7 @@ import {BuildEvent, Builder, BuilderConfiguration, BuilderContext} from '@angular-devkit/architect'; import {getSystemPath, resolve} from '@angular-devkit/core'; import {Observable, of } from 'rxjs'; -import {catchError, map, tap} from 'rxjs/operators'; +import {catchError, map} from 'rxjs/operators'; import {checkInstallation, runBazel} from './bazel'; import {Schema} from './schema'; @@ -28,7 +28,8 @@ class BazelBuilder implements Builder { if (!checkInstallation(executable, projectRoot)) { throw new Error( `Could not run ${executable}. Please make sure that the ` + - `"${executable}" command is available in the $PATH.`); + `"${executable}" command is installed by running ` + + `"npm install" or "yarn install".`); } // TODO: Support passing flags. diff --git a/packages/bazel/src/esm5.bzl b/packages/bazel/src/esm5.bzl index 450200e4c0..43c6ff03fe 100644 --- a/packages/bazel/src/esm5.bzl +++ b/packages/bazel/src/esm5.bzl @@ -12,6 +12,8 @@ However we need to publish this flavor on NPM, so it's necessary to be able to produce it. """ +load(":external.bzl", "DEFAULT_NG_COMPILER") + # The provider downstream rules use to access the outputs ESM5Info = provider( doc = "Typescript compilation outputs in ES5 syntax with ES Modules", @@ -84,13 +86,23 @@ def _esm5_outputs_aspect(target, ctx): ], ) - replay_compiler = target.typescript.replay_params.compiler.path.split("/")[-1] + replay_compiler_path = target.typescript.replay_params.compiler.short_path + replay_compiler_name = replay_compiler_path.split("/")[-1] # in windows replay_compiler path end with '.exe' - if replay_compiler.startswith("tsc_wrapped"): + if replay_compiler_name.startswith("tsc_wrapped"): compiler = ctx.executable._tsc_wrapped - elif replay_compiler.startswith("ngc-wrapped"): + elif replay_compiler_name.startswith("ngc-wrapped"): compiler = ctx.executable._ngc_wrapped + + # BEGIN-INTERNAL + # If the "replay_compiler" path does not refer to "ngc_wrapped" from the "@npm" workspace, + # we use "ngc_wrapped" from within the Angular workspace. This is necessary because we + # don't have a "npm" workspace with the "@angular/bazel" NPM package installed. + if replay_compiler_path != ctx.executable._ngc_wrapped.short_path: + compiler = ctx.executable._internal_ngc_wrapped + + # END-INTERNAL else: fail("Unknown replay compiler", target.typescript.replay_params.compiler.path) @@ -131,6 +143,14 @@ esm5_outputs_aspect = aspect( # Recurse to the deps of any target we visit attr_aspects = ["deps"], attrs = { + # This is only used if the replay_compiler refers to the "angular" workspace. In that + # case we need to use "ngc_wrapped" from its source location because we can't have + # the "npm" workspace that has the "@angular/bazel" NPM package installed. + "_internal_ngc_wrapped": attr.label( + default = Label("//packages/bazel/src/ngc-wrapped"), + executable = True, + cfg = "host", + ), "_modify_tsconfig": attr.label( default = Label("//packages/bazel/src:modify_tsconfig"), executable = True, @@ -141,8 +161,12 @@ esm5_outputs_aspect = aspect( executable = True, cfg = "host", ), + # This is the default "ngc_wrapped" executable that will be used to replay the compilation + # for ESM5 mode. The default compiler consumes "ngc_wrapped" from the "@npm" workspace. + # This is needed for downstream Bazel users that can have a different TypeScript + # version installed. "_ngc_wrapped": attr.label( - default = Label("//packages/bazel/src/ngc-wrapped"), + default = Label(DEFAULT_NG_COMPILER), executable = True, cfg = "host", ), diff --git a/packages/bazel/src/external.bzl b/packages/bazel/src/external.bzl index a054142fa2..af5c6bd007 100644 --- a/packages/bazel/src/external.bzl +++ b/packages/bazel/src/external.bzl @@ -30,3 +30,4 @@ ts_providers_dict_to_struct = _ts_providers_dict_to_struct DEFAULT_NG_COMPILER = "@angular//:@angular/bazel/ngc-wrapped" DEFAULT_NG_XI18N = "@npm//@angular/bazel/bin:xi18n" +FLAT_DTS_FILE_SUFFIX = ".bundle.d.ts" diff --git a/packages/bazel/src/ng_module.bzl b/packages/bazel/src/ng_module.bzl index 9a4e651d40..444bb58567 100644 --- a/packages/bazel/src/ng_module.bzl +++ b/packages/bazel/src/ng_module.bzl @@ -19,6 +19,8 @@ load( "tsc_wrapped_tsconfig", ) +_FLAT_DTS_FILE_SUFFIX = ".bundle.d.ts" + def compile_strategy(ctx): """Detect which strategy should be used to implement ng_module. @@ -121,6 +123,24 @@ def _flat_module_out_file(ctx): return ctx.attr.flat_module_out_file return "%s_public_index" % ctx.label.name +def _should_produce_dts_bundle(ctx): + """Should we produce dts bundles. + + We only produce flatten dts outs when we expect the ng_module is meant to be published, + based on the value of the bundle_dts attribute. + + Args: + ctx: skylark rule execution context + + Returns: + true when we should produce bundled dts. + """ + + # At the moment we cannot use this with ngtsc compiler since it emits + # import * as ___ from local modules which is not supported + # see: https://github.com/Microsoft/web-build-tools/issues/1029 + return _is_legacy_ngc(ctx) and hasattr(ctx.attr, "bundle_dts") and ctx.attr.bundle_dts + def _should_produce_flat_module_outs(ctx): """Should we produce flat module outputs. @@ -200,6 +220,14 @@ def _expected_outs(ctx): if not _is_bazel(): metadata_files += [ctx.actions.declare_file(basename + ext) for ext in metadata] + dts_bundle = None + if _should_produce_dts_bundle(ctx): + # We need to add a suffix to bundle as it might collide with the flat module dts. + # The flat module dts out contains several other exports + # https://github.com/angular/angular/blob/master/packages/compiler-cli/src/metadata/index_writer.ts#L18 + # the file name will be like 'core.bundle.d.ts' + dts_bundle = ctx.actions.declare_file(ctx.label.name + _FLAT_DTS_FILE_SUFFIX) + # We do this just when producing a flat module index for a publishable ng_module if _should_produce_flat_module_outs(ctx): flat_module_out = _flat_module_out_file(ctx) @@ -225,6 +253,7 @@ def _expected_outs(ctx): declarations = declaration_files, summaries = summary_files, metadata = metadata_files, + dts_bundle = dts_bundle, bundle_index_typings = bundle_index_typings, i18n_messages = i18n_messages_files, ) @@ -245,8 +274,16 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs): "enableSummariesForJit": is_legacy_ngc, "enableIvy": _enable_ivy_value(ctx), "fullTemplateTypeCheck": ctx.attr.type_check, + # In Google3 we still want to use the symbol factory re-exports in order to + # not break existing apps inside Google. Unlike Bazel, Google3 does not only + # enforce strict dependencies of source files, but also for generated files + # (such as the factory files). Therefore in order to avoid that generated files + # introduce new module dependencies (which aren't explicitly declared), we need + # to enable external symbol re-exports by default when running with Blaze. + "createExternalSymbolFactoryReexports": (not _is_bazel()), # FIXME: wrong place to de-dupe "expectedOut": depset([o.path for o in expected_outs]).to_list(), + "_useHostForImportGeneration": (not _is_bazel()), } if _should_produce_flat_module_outs(ctx): @@ -285,6 +322,8 @@ _EXTRA_NODE_OPTIONS_FLAGS = [ "--node_options=--expose-gc", # Show ~full stack traces, instead of cutting off after 10 items. "--node_options=--stack-trace-limit=100", + # Give 2 GB RAM to node to make bigger google3 modules to compile, we should be able to drop this after Ivy/ngtsc is the default in g3 + "--node_options=--max-old-space-size=2048", ] def ngc_compile_action( @@ -296,7 +335,8 @@ def ngc_compile_action( tsconfig_file, node_opts, locale = None, - i18n_args = []): + i18n_args = [], + dts_bundle_out = None): """Helper function to create the ngc action. This is exposed for google3 to wire up i18n replay rules, and is not intended @@ -312,6 +352,7 @@ def ngc_compile_action( node_opts: list of strings, extra nodejs options. locale: i18n locale, or None i18n_args: additional command-line arguments to ngc + dts_bundle_out: produced flattened dts file Returns: the parameters of the compilation which will be used to replay the ngc action for i18N. @@ -370,6 +411,28 @@ def ngc_compile_action( mnemonic = "Angular2MessageExtractor", ) + if dts_bundle_out != None: + # combine the inputs and outputs and filter .d.ts and json files + filter_inputs = [f for f in inputs + outputs if f.path.endswith(".d.ts") or f.path.endswith(".json")] + + if _should_produce_flat_module_outs(ctx): + dts_entry_point = "%s.d.ts" % _flat_module_out_file(ctx) + else: + dts_entry_point = ctx.attr.entry_point.replace(".ts", ".d.ts") + + ctx.actions.run( + progress_message = "Bundling DTS %s" % str(ctx.label), + mnemonic = "APIExtractor", + executable = ctx.executable._api_extractor, + inputs = filter_inputs, + outputs = [dts_bundle_out], + arguments = [ + tsconfig_file.path, + "/".join([ctx.bin_dir.path, ctx.label.package, dts_entry_point]), + dts_bundle_out.path, + ], + ) + if not locale and not ctx.attr.no_i18n: return struct( label = label, @@ -390,7 +453,7 @@ def _filter_ts_inputs(all_inputs): if f.path.endswith(".js") or f.path.endswith(".ts") or f.path.endswith(".json") ] -def _compile_action(ctx, inputs, outputs, messages_out, tsconfig_file, node_opts): +def _compile_action(ctx, inputs, outputs, dts_bundle_out, messages_out, tsconfig_file, node_opts): # Give the Angular compiler all the user-listed assets file_inputs = list(ctx.files.assets) @@ -417,16 +480,16 @@ def _compile_action(ctx, inputs, outputs, messages_out, tsconfig_file, node_opts ], ) - return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, tsconfig_file, node_opts) + return ngc_compile_action(ctx, ctx.label, action_inputs, outputs, messages_out, tsconfig_file, node_opts, None, [], dts_bundle_out) def _prodmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts): outs = _expected_outs(ctx) - return _compile_action(ctx, inputs, outputs + outs.closure_js, outs.i18n_messages, tsconfig_file, node_opts) + return _compile_action(ctx, inputs, outputs + outs.closure_js, None, outs.i18n_messages, tsconfig_file, node_opts) def _devmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts): outs = _expected_outs(ctx) compile_action_outputs = outputs + outs.devmode_js + outs.declarations + outs.summaries + outs.metadata - _compile_action(ctx, inputs, compile_action_outputs, None, tsconfig_file, node_opts) + _compile_action(ctx, inputs, compile_action_outputs, outs.dts_bundle, None, tsconfig_file, node_opts) def _ts_expected_outs(ctx, label, srcs_files = []): # rules_typescript expects a function with two or more arguments, but our @@ -487,6 +550,9 @@ def ng_module_impl(ctx, ts_compile_actions): flat_module_out_file = _flat_module_out_file(ctx), ) + if outs.dts_bundle != None: + providers["dts_bundle"] = outs.dts_bundle + return providers def _ng_module_impl(ctx): @@ -620,6 +686,12 @@ NG_MODULE_RULE_ATTRS = dict(dict(COMMON_ATTRIBUTES, **NG_MODULE_ATTRIBUTES), **{ # See the flatModuleOutFile documentation in # https://github.com/angular/angular/blob/master/packages/compiler-cli/src/transformers/api.ts "flat_module_out_file": attr.string(), + "bundle_dts": attr.bool(default = False), + "_api_extractor": attr.label( + default = Label("//packages/bazel/src/api-extractor:api_extractor"), + executable = True, + cfg = "host", + ), }) ng_module = rule( diff --git a/packages/bazel/src/ng_package/BUILD.bazel b/packages/bazel/src/ng_package/BUILD.bazel index ed5307737d..cacb014d35 100644 --- a/packages/bazel/src/ng_package/BUILD.bazel +++ b/packages/bazel/src/ng_package/BUILD.bazel @@ -3,10 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary") load("@build_bazel_rules_typescript//:defs.bzl", "ts_library") -exports_files([ - "rollup.config.js", - "ng_package.bzl", -]) +exports_files(["ng_package.bzl"]) ts_library( name = "lib", diff --git a/packages/bazel/src/ng_package/ng_package.bzl b/packages/bazel/src/ng_package/ng_package.bzl index f84d0471fc..c1b4c64492 100644 --- a/packages/bazel/src/ng_package/ng_package.bzl +++ b/packages/bazel/src/ng_package/ng_package.bzl @@ -13,7 +13,9 @@ It packages your library following the Angular Package Format, see the specification of this format at https://goo.gl/jB3GVv """ -load("@build_bazel_rules_nodejs//:internal/collect_es6_sources.bzl", "collect_es6_sources") +load("@build_bazel_rules_nodejs//internal/common:collect_es6_sources.bzl", "collect_es6_sources") +load("@build_bazel_rules_nodejs//internal/common:node_module_info.bzl", "NodeModuleInfo") +load("@build_bazel_rules_nodejs//internal/common:sources_aspect.bzl", "sources_aspect") load( "@build_bazel_rules_nodejs//:internal/rollup/rollup_bundle.bzl", "ROLLUP_ATTRS", @@ -27,8 +29,7 @@ load( "NPM_PACKAGE_OUTPUTS", "create_package", ) -load("@build_bazel_rules_nodejs//:internal/node.bzl", "sources_aspect") -load("@build_bazel_rules_nodejs//internal/common:node_module_info.bzl", "NodeModuleInfo") +load("//packages/bazel/src:external.bzl", "FLAT_DTS_FILE_SUFFIX") load("//packages/bazel/src:esm5.bzl", "esm5_outputs_aspect", "esm5_root_dir", "flatten_esm5") load("//packages/bazel/src/ng_package:collect-type-definitions.bzl", "collect_type_definitions") @@ -188,15 +189,6 @@ def _ng_package_impl(ctx): esm_2015_files = _filter_out_generated_files(collect_es6_sources(ctx), "js") esm5_sources = _filter_out_generated_files(flatten_esm5(ctx), "js") - # Filter out all TypeScript definitions generated by NGC as well as definition files - # that do not belong to the current package. We only want to package types that belong - # to the current package. - type_definitions = _filter_out_generated_files( - collect_type_definitions(ctx), - "d.ts", - ctx.label.package, - ) - # These accumulators match the directory names where the files live in the # Angular package format. fesm2015 = [] @@ -204,6 +196,8 @@ def _ng_package_impl(ctx): esm2015 = [] esm5 = [] bundles = [] + bundled_type_definitions = [] + type_definitions = [] # For Angular Package Format v6, we put all the individual .js files in the # esm5/ and esm2015/ folders. @@ -235,6 +229,22 @@ def _ng_package_impl(ctx): # fallback to a reasonable default flat_module_out_file = "index.js" + if hasattr(dep, "dts_bundle"): + bundled_type_definitions.append(dep.dts_bundle) + elif len(type_definitions) == 0: + # Filter out all TypeScript definitions generated by NGC as well as definition files + # that do not belong to the current package. We only want to package types that belong + # to the current package. + type_definitions = _filter_out_generated_files( + collect_type_definitions(ctx), + "d.ts", + ctx.label.package, + ).to_list() + + if len(type_definitions) > 0 and len(bundled_type_definitions) > 0: + # bundle_dts needs to be enabled/disabled for all ng module packages. + fail("Expected all or none of the 'ng_module' dependencies to have 'bundle_dts' enabled.") + es2015_entry_point = "/".join([p for p in [ ctx.bin_dir.path, ctx.label.package, @@ -304,7 +314,8 @@ def _ng_package_impl(ctx): ctx.files.srcs + ctx.files.data + esm5_sources.to_list() + - type_definitions.to_list() + + type_definitions + + bundled_type_definitions + [f.js for f in fesm2015 + fesm5 + esm2015 + esm5 + bundles] + [f.map for f in fesm2015 + fesm5 + esm2015 + esm5 + bundles if f.map] ) @@ -355,6 +366,9 @@ def _ng_package_impl(ctx): # placeholder packager_args.add("") + packager_args.add_joined([d.path for d in bundled_type_definitions], join_with = ",", omit_if_empty = False) + packager_args.add(FLAT_DTS_FILE_SUFFIX) + ctx.actions.run( progress_message = "Angular Packaging: building npm package %s" % str(ctx.label), mnemonic = "AngularPackage", @@ -393,7 +407,7 @@ NG_PACKAGE_ATTRS = dict(NPM_PACKAGE_ATTRS, **dict(ROLLUP_ATTRS, **{ allow_files = True, ), "include_devmode_srcs": attr.bool(default = False), - "readme_md": attr.label(allow_single_file = FileType([".md"])), + "readme_md": attr.label(allow_single_file = [".md"]), "globals": attr.string_dict(default = {}), "entry_point_name": attr.string( doc = "Name to use when generating bundle files for the primary entry-point.", diff --git a/packages/bazel/src/ng_package/packager.ts b/packages/bazel/src/ng_package/packager.ts index b9d7692a3d..deb6b432ce 100644 --- a/packages/bazel/src/ng_package/packager.ts +++ b/packages/bazel/src/ng_package/packager.ts @@ -45,7 +45,7 @@ function main(args: string[]): number { // flat module metadata, for example // {"@angular/core": { // "index": "bazel-bin/packages/core/core.js", - // "typing": "bazel-bin/packages/core/core.d.ts", + // "typings": "bazel-bin/packages/core/core.d.ts", // "metadata": "bazel-bin/packages/core/core.metadata.json" // }, // ... @@ -81,6 +81,12 @@ function main(args: string[]): number { // Path to the package's LICENSE. licenseFile, + + // List of all dts bundles generated by the API extractor. + dtsBundleArg, + + // The dts bundle file suffix example: '.bundle.d.ts' + dtsBundleFileSuffix, ] = params; const fesm2015 = fesm2015Arg.split(',').filter(s => !!s); @@ -92,6 +98,7 @@ function main(args: string[]): number { const srcs = srcsArg.split(',').filter(s => !!s); const dataFiles: string[] = dataArg.split(',').filter(s => !!s); const modulesManifest = JSON.parse(modulesManifestArg); + const dtsBundles: string[] = dtsBundleArg.split(',').filter(s => !!s); if (readmeMd) { copyFile(readmeMd, out); @@ -155,12 +162,7 @@ function main(args: string[]): number { // Copy all type definitions into the package. This is necessary so that developers can use // the package with type definitions. - typeDefinitions.forEach((f: string) => { - const content = fs.readFileSync(f, 'utf-8') - // Strip the named AMD module for compatibility with non-bazel users - .replace(/^\/\/\/ \n/gm, ''); - writeFileFromInputPath(f, content); - }); + typeDefinitions.forEach(f => writeFileFromInputPath(f, readTypingsAndStripAmdModule(f))); // Copy all `data` files into the package. These are files that aren't built by the ng_package // rule, but instead are just straight copied into the package, e.g. global CSS assets. @@ -176,7 +178,30 @@ function main(args: string[]): number { moduleFiles['esm5_index'] = path.join(binDir, 'esm5', relative); moduleFiles['esm2015_index'] = path.join(binDir, 'esm2015', relative); - copyFileFromInputPath(moduleFiles['metadata']); + const metadataFile = moduleFiles['metadata']; + const typingsOutFile = moduleFiles['typings']; + + // We only support all modules within a package to be dts bundled + // ie: if @angular/common/http has flat dts, so should @angular/common + if (dtsBundles.length) { + const metadataContent = rewireMetadata(metadataFile, typingsOutFile); + writeFileFromInputPath(metadataFile, metadataContent); + } else { + copyFileFromInputPath(metadataFile); + } + }); + + const licenseBanner = licenseFile ? fs.readFileSync(licenseFile, 'utf-8') : ''; + + dtsBundles.forEach(bundleFile => { + const cleanDistPath = bundleFile.replace(dtsBundleFileSuffix, '.d.ts'); + // API extractor will not dedupe license comments from various files + // this will remove all the license comments and append the license banner. + const content = licenseBanner + '\n' + + readTypingsAndStripAmdModule(bundleFile) + .replace(/(\/\*\*\s+\*\s\@license(((?!\*\/).|\s)*)\*\/)/gm, ''); + + writeFileFromInputPath(cleanDistPath, content); }); // Root package name (e.g. '@angular/common'), captures as we iterate through sources below. @@ -210,8 +235,6 @@ function main(args: string[]): number { writeFileFromInputPath(src, content); } - const licenseBanner = licenseFile ? fs.readFileSync(licenseFile, 'utf-8') : ''; - // Generate extra files for secondary entry-points. Object.keys(modulesManifest).forEach(entryPointPackageName => { const entryPointName = entryPointPackageName.substr(rootPackageName.length + 1); @@ -235,8 +258,8 @@ function main(args: string[]): number { * @param file path to a file under the binDir, like bazel-bin/core/testing/generated.js */ function srcDirRelative(from: string, file: string) { - const result = - path.relative(path.dirname(from), path.join(srcDir, path.relative(binDir, file))); + const result = normalizeSeparators( + path.relative(path.dirname(from), path.join(srcDir, path.relative(binDir, file)))); if (result.startsWith('..')) return result; return `./${result}`; } @@ -346,8 +369,8 @@ function main(args: string[]): number { function createTypingsReexportFile(entryPointName: string, license: string, typingsFile: string) { const inputPath = path.join(srcDir, `${entryPointName}.d.ts`); const content = `${license} - export * from '${srcDirRelative(inputPath, typingsFile.replace(/\.d\.tsx?$/, ''))}'; - `; +export * from '${srcDirRelative(inputPath, typingsFile.replace(/\.d\.tsx?$/, ''))}'; +`; writeFileFromInputPath(inputPath, content); } @@ -362,6 +385,45 @@ function main(args: string[]): number { const content = amendPackageJson(pkgJson, {name: entryPointPackageName}); writeFileFromInputPath(pkgJson, content); } + + /** + * Normalizes the specified path by replacing backslash separators with Posix + * forward slash separators. + */ + function normalizeSeparators(path: string): string { return path.replace(/\\/g, '/'); } + + /** + * Rewires metadata to point to the flattened dts file. + * + * @param metadataPath the metadata file path + * @param typingsPath the typings bundle entrypoint + */ + function rewireMetadata(metadataPath: string, typingsPath: string): string { + const metadata = fs.readFileSync(metadataPath, 'utf-8'); + + let typingsRelativePath = + normalizeSeparators(path.relative(path.dirname(metadataPath), typingsPath)); + if (!typingsRelativePath.startsWith('..')) { + typingsRelativePath = `./${typingsRelativePath}`; + } + + typingsRelativePath = typingsRelativePath.replace('.d.ts', ''); + + // the regexp here catches all relative paths such as: + // ./src/core/foo.d.ts and ../src/core/foo.d.ts + return metadata.replace(/\.?\.\/[\w\.\-_\/]+/g, typingsRelativePath); + } + + /** + * Strip the named AMD module for compatibility with non-bazel users from typings content + * @param filePath dts file path + */ + function readTypingsAndStripAmdModule(filePath: string): string { + return fs + .readFileSync(filePath, 'utf-8') + // Strip the named AMD module for compatibility with non-bazel users + .replace(/^\/\/\/ [\r\n]+/gm, ''); + } } if (require.main === module) { diff --git a/packages/bazel/src/ng_rollup_bundle.bzl b/packages/bazel/src/ng_rollup_bundle.bzl index 7ce493a373..0905ff49aa 100644 --- a/packages/bazel/src/ng_rollup_bundle.bzl +++ b/packages/bazel/src/ng_rollup_bundle.bzl @@ -24,14 +24,26 @@ load( "run_uglify", "write_rollup_config", ) -load("@build_bazel_rules_nodejs//internal:collect_es6_sources.bzl", collect_es2015_sources = "collect_es6_sources") +load("@build_bazel_rules_nodejs//internal/common:collect_es6_sources.bzl", collect_es2015_sources = "collect_es6_sources") load(":esm5.bzl", "esm5_outputs_aspect", "esm5_root_dir", "flatten_esm5") -PACKAGES = ["packages/core/src", "packages/common/src", "packages/compiler/src", "external/rxjs"] +PACKAGES = [ + # Generated paths when using ng_rollup_bundle outside this monorepo. + "external/angular/packages/core/src", + "external/angular/packages/common/src", + "external/angular/packages/compiler/src", + "external/angular/packages/platform-browser/src", + "external/rxjs", + # Generated paths when using ng_rollup_bundle inside this monorepo. + "packages/core/src", + "packages/common/src", + "packages/compiler/src", + "packages/platform-browser/src", +] PLUGIN_CONFIG = "{sideEffectFreeModules: [\n%s]}" % ",\n".join( [" '.esm5/{0}'".format(p) for p in PACKAGES], ) -BO_ROLLUP = "angular_cli/packages/angular_devkit/build_optimizer/src/build-optimizer/rollup-plugin.js" +BO_ROLLUP = "ngdeps/node_modules/@angular-devkit/build-optimizer/src/build-optimizer/rollup-plugin.js" BO_PLUGIN = "require('%s').default(%s)" % (BO_ROLLUP, PLUGIN_CONFIG) def _use_plain_rollup(ctx): @@ -95,6 +107,8 @@ def _plain_rollup_bundle(ctx): run_uglify(ctx, ctx.outputs.build_es5, ctx.outputs.build_es5_min_debug, debug = True) umd_rollup_config = write_rollup_config(ctx, filename = "_%s_umd.rollup.conf.js", output_format = "umd") run_rollup(ctx, collect_es2015_sources(ctx), umd_rollup_config, ctx.outputs.build_umd) + cjs_rollup_config = write_rollup_config(ctx, filename = "_%s_cjs.rollup.conf.js", output_format = "cjs") + run_rollup(ctx, collect_es2015_sources(ctx), cjs_rollup_config, ctx.outputs.build_cjs) run_sourcemapexplorer(ctx, ctx.outputs.build_es5_min, source_map, ctx.outputs.explore_html) run_brotli(ctx, ctx.outputs.build_es5_min, ctx.outputs.build_es5_min_compressed) @@ -134,6 +148,8 @@ def _ng_rollup_bundle(ctx): umd_rollup_config = write_rollup_config(ctx, filename = "_%s_umd.rollup.conf.js", output_format = "umd") run_rollup(ctx, collect_es2015_sources(ctx), umd_rollup_config, ctx.outputs.build_umd) + cjs_rollup_config = write_rollup_config(ctx, filename = "_%s_cjs.rollup.conf.js", output_format = "cjs") + run_rollup(ctx, collect_es2015_sources(ctx), cjs_rollup_config, ctx.outputs.build_cjs) run_brotli(ctx, ctx.outputs.build_es5_min, ctx.outputs.build_es5_min_compressed) diff --git a/packages/bazel/src/ng_setup_workspace.bzl b/packages/bazel/src/ng_setup_workspace.bzl index 1926aaf393..4845f7b701 100644 --- a/packages/bazel/src/ng_setup_workspace.bzl +++ b/packages/bazel/src/ng_setup_workspace.bzl @@ -5,17 +5,9 @@ "Install toolchain dependencies" -load("@build_bazel_rules_typescript//:defs.bzl", "check_rules_typescript_version") - def ng_setup_workspace(): """This repository rule should be called from your WORKSPACE file. It creates some additional Bazel external repositories that are used internally by the Angular rules. """ - - # 0.16.0: minimal version required to work with ng_module - # 0.16.2: bazel type resolution for zone.js types - # 0.20.1: fine grained deps - # 0.20.2: version check fix - check_rules_typescript_version("0.20.2") diff --git a/packages/bazel/src/ngc-wrapped/index.ts b/packages/bazel/src/ngc-wrapped/index.ts index d875cd0bbe..636d8db08e 100644 --- a/packages/bazel/src/ngc-wrapped/index.ts +++ b/packages/bazel/src/ngc-wrapped/index.ts @@ -199,25 +199,27 @@ export function compile({allDepsCompiledWithBazel = true, compilerOpts, tsHost, }; const origBazelHostShouldNameModule = bazelHost.shouldNameModule.bind(bazelHost); bazelHost.shouldNameModule = (fileName: string) => { + const flatModuleOutPath = + path.posix.join(bazelOpts.package, compilerOpts.flatModuleOutFile + '.ts'); + // The bundle index file is synthesized in bundle_index_host so it's not in the // compilationTargetSrc. // However we still want to give it an AMD module name for devmode. // We can't easily tell which file is the synthetic one, so we build up the path we expect // it to have and compare against that. - if (fileName === - path.join(compilerOpts.baseUrl, bazelOpts.package, compilerOpts.flatModuleOutFile + '.ts')) - return true; + if (fileName === path.posix.join(compilerOpts.baseUrl, flatModuleOutPath)) return true; + // Also handle the case the target is in an external repository. // Pull the workspace name from the target which is formatted as `@wksp//package:target` // if it the target is from an external workspace. If the target is from the local // workspace then it will be formatted as `//package:target`. const targetWorkspace = bazelOpts.target.split('/')[0].replace(/^@/, ''); + if (targetWorkspace && fileName === - path.join( - compilerOpts.baseUrl, 'external', targetWorkspace, bazelOpts.package, - compilerOpts.flatModuleOutFile + '.ts')) + path.posix.join(compilerOpts.baseUrl, 'external', targetWorkspace, flatModuleOutPath)) return true; + return origBazelHostShouldNameModule(fileName) || NGC_GEN_FILES.test(fileName); }; @@ -290,6 +292,7 @@ export function compile({allDepsCompiledWithBazel = true, compilerOpts, tsHost, cancellationToken, emitOnlyDtsFiles, { beforeTs: customTransformers.before, afterTs: customTransformers.after, + afterDeclarations: customTransformers.afterDeclarations, }); if (!gatherDiagnostics) { diff --git a/packages/bazel/src/protractor/protractor.conf.js b/packages/bazel/src/protractor/protractor.conf.js index 1c26660bcb..3eaef57197 100644 --- a/packages/bazel/src/protractor/protractor.conf.js +++ b/packages/bazel/src/protractor/protractor.conf.js @@ -88,7 +88,8 @@ if (onPreparePath) { // ts_web_test_suite & rules_webtesting WEB_TEST_METADATA attributes setConf(conf, 'framework', 'jasmine2', 'is set to jasmine2'); -const specs = [TMPL_specs].map(s => require.resolve(s)).filter(s => /\b(spec|test)\.js$/.test(s)); +const specs = + [TMPL_specs].map(s => require.resolve(s)).filter(s => /(\b|_)(spec|test)\.js$/.test(s)); setConf(conf, 'specs', specs, 'are determined by the srcs and deps attribute'); @@ -128,22 +129,22 @@ if (process.env['WEB_TEST_METADATA']) { if (webTestNamedFiles['CHROMIUM']) { const chromeBin = require.resolve(webTestNamedFiles['CHROMIUM']); const chromeDriver = require.resolve(webTestNamedFiles['CHROMEDRIVER']); - const args = []; + + // The sandbox needs to be disabled, because it causes Chrome to crash on some environments. + // See: http://chromedriver.chromium.org/help/chrome-doesn-t-start + const args = ['--no-sandbox']; if (headless) { - args.push('--headless'); - args.push('--disable-gpu'); + args.push('--headless', '--disable-gpu'); } setConf(conf, 'directConnect', true, 'is set to true for chrome'); setConf(conf, 'chromeDriver', chromeDriver, 'is determined by the browsers attribute'); - mergeCapabilities( - conf, { - browserName: 'chrome', - chromeOptions: { - binary: chromeBin, - args: args, - } - }, - 'is determined by the browsers attribute'); + mergeCapabilities(conf, { + browserName: 'chrome', + chromeOptions: { + binary: chromeBin, + args: args, + } + }); } if (webTestNamedFiles['FIREFOX']) { // TODO(gmagolan): implement firefox support for protractor diff --git a/packages/bazel/src/protractor/protractor_web_test.bzl b/packages/bazel/src/protractor/protractor_web_test.bzl index 0dc4784535..eb2fc06914 100644 --- a/packages/bazel/src/protractor/protractor_web_test.bzl +++ b/packages/bazel/src/protractor/protractor_web_test.bzl @@ -4,14 +4,11 @@ # found in the LICENSE file at https://angular.io/license "Run end-to-end tests with Protractor" -load( - "@build_bazel_rules_nodejs//internal:node.bzl", - "expand_path_into_runfiles", - "sources_aspect", -) load("@io_bazel_rules_webtesting//web:web.bzl", "web_test_suite") load("@io_bazel_rules_webtesting//web/internal:constants.bzl", "DEFAULT_WRAPPED_TEST_TAGS") load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary") +load("@build_bazel_rules_nodejs//internal/common:expand_into_runfiles.bzl", "expand_path_into_runfiles") +load("@build_bazel_rules_nodejs//internal/common:sources_aspect.bzl", "sources_aspect") _CONF_TMPL = "//packages/bazel/src/protractor:protractor.conf.js" @@ -77,7 +74,10 @@ def _protractor_web_test_impl(ctx): output = ctx.outputs.executable, is_executable = True, content = """#!/usr/bin/env bash -if [ -e "$RUNFILE_MANIFEST_FILE" ]; then +# Immediately exit if any command fails. +set -e + +if [ -e "$RUNFILES_MANIFEST_FILE" ]; then while read line; do declare -a PARTS=($line) if [ "${{PARTS[0]}}" == "{TMPL_protractor}" ]; then @@ -85,7 +85,7 @@ if [ -e "$RUNFILE_MANIFEST_FILE" ]; then elif [ "${{PARTS[0]}}" == "{TMPL_conf}" ]; then readonly CONF=${{PARTS[1]}} fi - done < $RUNFILE_MANIFEST_FILE + done < $RUNFILES_MANIFEST_FILE else readonly PROTRACTOR=../{TMPL_protractor} readonly CONF=../{TMPL_conf} diff --git a/packages/bazel/src/protractor/utils/index.ts b/packages/bazel/src/protractor/utils/index.ts index 666119d516..424d2a21bb 100644 --- a/packages/bazel/src/protractor/utils/index.ts +++ b/packages/bazel/src/protractor/utils/index.ts @@ -71,24 +71,31 @@ export interface ServerSpec { port: number; } -export function runServer( - workspace: string, binary: string, portFlag: string, args: string[], +/** + * Runs the specified server binary from a given workspace and waits for the server + * being ready. The server binary will be resolved from the Bazel runfiles. Note that + * the server will be launched with a random free port in order to support test concurrency + * with Bazel. + */ +export async function runServer( + workspace: string, serverTarget: string, portFlag: string, serverArgs: string[], timeout = 5000): Promise { - return findFreeTcpPort().then(function(port) { - const runfiles_path = process.env.TEST_SRCDIR; - const cmd = path.join(runfiles_path, workspace, binary); + const serverPath = require.resolve(`${workspace}/${serverTarget}`); + const port = await findFreeTcpPort(); - args = args.concat([portFlag, port.toString()]); + // Start the Bazel server binary with a random free TCP port. + const serverProcess = child_process.spawn( + serverPath, serverArgs.concat([portFlag, port.toString()]), {stdio: 'inherit'}); - const child = child_process.spawn( - cmd, args, {cwd: path.join(runfiles_path, workspace), stdio: 'inherit'}); - - child.on('exit', function(code) { - if (code != 0) { - throw new Error(`non-zero exit code ${code} from server`); - } - }); - - return waitForServer(port, timeout).then(() => { return {port}; }); + // In case the process exited with an error, we want to propagate the error. + serverProcess.on('exit', exitCode => { + if (exitCode !== 0) { + throw new Error(`Server exited with error code: ${exitCode}`); + } }); + + // Wait for the server to be bound to the given port. + await waitForServer(port, timeout); + + return {port}; } diff --git a/packages/bazel/src/schematics/BUILD.bazel b/packages/bazel/src/schematics/BUILD.bazel index 5770199cc3..fe90035725 100644 --- a/packages/bazel/src/schematics/BUILD.bazel +++ b/packages/bazel/src/schematics/BUILD.bazel @@ -15,7 +15,9 @@ jasmine_node_test( bootstrap = ["angular/tools/testing/init_node_spec.js"], deps = [ "//packages/bazel/src/schematics/bazel-workspace:test", + "//packages/bazel/src/schematics/ng-add:test", "//packages/bazel/src/schematics/ng-new:test", + "//packages/bazel/src/schematics/utility:test", "//tools/testing:node", ], ) diff --git a/packages/bazel/src/schematics/README.md b/packages/bazel/src/schematics/README.md index 741a6952f0..02099c9620 100644 --- a/packages/bazel/src/schematics/README.md +++ b/packages/bazel/src/schematics/README.md @@ -1,5 +1,109 @@ # Schematics for Bazel +## WARNING + +Schematics in `@angular/bazel` is still highly experimental as of January 2019, +please use with caution. For feedbacks and comments, please open an issue on +GitHub and ping [@mgechev](https://github.com/mgechev) or +[@kyliau](https://github.com/kyliau). + +## Requirements + +To create a new Angular project that builds with Bazel + CLI, the following +packages have to be installed. + +Package | Minimum Version +--------|---------------- +@angular/cli | v7.3.x +@angular/bazel | v8.0.x + +The `@angular/bazel` package contains schematics to generate necessary Bazel +build files. + +If the packages are not on your system yet, install them with the following +commands: + +``` +yarn global add @angular/cli@latest @angular/bazel@next +``` + +It is very *important* to meet the minimum version requirement of `@angular/cli` +because Bazel schematics rely on some of the new APIs that are missing in older +versions of the CLI. Invoking `@angular/bazel` schematics with an older version +of CLI would very likely result in unexpected errors. + +
    + +More details + +Bazel schematics rely on the new + +ScopedTree in @angular-devkit/schematics. +There is currently no way for a schematic to mandate a minimum +"schematic runtime" version. The version of @angular-devkit/schematics +that is installed with the CLI is used to run the schematic even though a different +version is used in the schematic itself. +
    + +## Create a Bazel-managed Angular project + +Create a new project using `@angular/bazel` schematics for `ng new`. + +``` +$ ng new demo --collection=@angular/bazel --defaults +``` + +In addition to the regular files generated by CLI, the following files that are +specific to a Bazel workspace are also created. + +``` +... +CREATE demo/BUILD.bazel (190 bytes) +CREATE demo/WORKSPACE (2951 bytes) +CREATE demo/.bazelignore (18 bytes) +CREATE demo/.bazelrc (828 bytes) +CREATE demo/e2e/BUILD.bazel (1230 bytes) +CREATE demo/e2e/protractor.on-prepare.js (1101 bytes) +CREATE demo/src/BUILD.bazel (2626 bytes) +CREATE demo/src/initialize_testbed.ts (432 bytes) +CREATE demo/src/main.dev.ts (185 bytes) +CREATE demo/src/main.prod.ts (249 bytes) +``` + +Note that in a Bazel-managed project, there is a Bazel WORKSPACE file and a few BUILD.bazel files. +There are also some files specific to a Bazel-managed project, namely `main.dev.ts` and `main.prod.ts`. +This is because all Angular projects built with Bazel must be AOT only. +In a Bazel project, `main.ts` generated by CLI is not used. + +By default, `ng new` for Bazel does not perform `yarn install`. +This is because the `node_modules` are managed by Bazel and it is Bazel's +responsibility to perform the install. + +Next, let's try to build the project using Bazel. +All existing `ng` commands would work as before. + +``` +cd demo +# The following yarn step is needed so that `ng build` works correctly. +# Alternatively, you can skip this step if you choose to not use `ng` commands. +# In which case, you'd execute `yarn bazel build //src:bundle`. This is +# equivalent to running `ng build`. +yarn +ng build +ng serve +``` + +If you encounter a warning about version mismatch, update `ANGULAR_VERSION` in +the WORKSPACE file to match the version of `@angular/bazel` installed from NPM. + +Bring up the dev server using `ibazel run` command. + +``` +yarn ibazel run //src:devserver +``` + +Make some changes to the code, and verify that the dev server automatically refreshes. + ## Development notes To test any local changes, run diff --git a/packages/bazel/src/schematics/bazel-workspace/files/WORKSPACE.template b/packages/bazel/src/schematics/bazel-workspace/files/WORKSPACE.template index 393f2947d1..101f133610 100644 --- a/packages/bazel/src/schematics/bazel-workspace/files/WORKSPACE.template +++ b/packages/bazel/src/schematics/bazel-workspace/files/WORKSPACE.template @@ -12,8 +12,15 @@ workspace(name = "<%= utils.underscore(name) %>") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +RULES_NODEJS_VERSION = "<%= RULES_NODEJS_VERSION %>" +RULES_NODEJS_SHA256 = "<%= RULES_NODEJS_SHA256 %>" +http_archive( + name = "build_bazel_rules_nodejs", + sha256 = "%s" % RULES_NODEJS_SHA256, + url = "https://github.com/bazelbuild/rules_nodejs/releases/download/%s/rules_nodejs-%s.tar.gz" % (RULES_NODEJS_VERSION, RULES_NODEJS_VERSION), +) + # The @angular repo contains rule for building Angular applications -# Provides "build_bazel_rules_typescript" ANGULAR_VERSION = "<%= ANGULAR_VERSION %>" http_archive( name = "angular", @@ -28,7 +35,7 @@ http_archive( url = "https://registry.yarnpkg.com/rxjs/-/rxjs-%s.tgz" % RXJS_VERSION, strip_prefix = "package/src", ) - +<% if (sass) { %> # Rules for compiling sass RULES_SASS_VERSION = "<%= RULES_SASS_VERSION %>" http_archive( @@ -36,33 +43,28 @@ http_archive( url = "https://github.com/bazelbuild/rules_sass/archive/%s.zip" % RULES_SASS_VERSION, strip_prefix = "rules_sass-%s" % RULES_SASS_VERSION, ) - +<% } %> #################################### # Load and install our dependencies downloaded above. -load("@angular//packages/bazel:package.bzl", "rules_angular_dependencies") -rules_angular_dependencies() - -load("@build_bazel_rules_typescript//:package.bzl", "rules_typescript_dependencies") -rules_typescript_dependencies() -# build_bazel_rules_nodejs is loaded transitively through rules_typescript_dependencies. - -load("@build_bazel_rules_nodejs//:package.bzl", "rules_nodejs_dependencies") -rules_nodejs_dependencies() - load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories", "yarn_install") # 0.18.0 is needed for .bazelignore check_bazel_version("0.18.0") node_repositories() yarn_install( name = "npm", + # Need a reference to @angular here so that Bazel sets up the + # external repository before calling yarn_install + data = ["@angular//:LICENSE"], package_json = "//:package.json", yarn_lock = "//:yarn.lock", ) -load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains") -go_rules_dependencies() -go_register_toolchains() +load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies") +install_bazel_dependencies() + +load("@build_bazel_rules_karma//:package.bzl", "rules_karma_dependencies") +rules_karma_dependencies() load("@io_bazel_rules_webtesting//web:repositories.bzl", "browser_repositories", "web_test_repositories") web_test_repositories() @@ -71,11 +73,11 @@ browser_repositories( firefox = True, ) -load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace", "check_rules_typescript_version") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace") ts_setup_workspace() - +<% if (sass) { %> load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories") sass_repositories() - +<% } %> load("@angular//:index.bzl", "ng_setup_workspace") ng_setup_workspace() diff --git a/packages/bazel/src/schematics/bazel-workspace/files/__dot__bazelrc.template b/packages/bazel/src/schematics/bazel-workspace/files/__dot__bazelrc.template index a40483eeac..1b544399da 100644 --- a/packages/bazel/src/schematics/bazel-workspace/files/__dot__bazelrc.template +++ b/packages/bazel/src/schematics/bazel-workspace/files/__dot__bazelrc.template @@ -13,6 +13,16 @@ build --strategy=AngularTemplateCompile=worker # `bazel-out` directory that is created in the workspace root. build --symlink_prefix=dist/ +# Turn on --incompatible_strict_action_env which was on by default +# in Bazel 0.21.0 but turned off again in 0.22.0. Follow +# https://github.com/bazelbuild/bazel/issues/7026 for more details. +# This flag is needed to so that the bazel cache is not invalidated +# when running bazel via `yarn bazel`. +# See https://github.com/angular/angular/issues/27514. +build --incompatible_strict_action_env +run --incompatible_strict_action_env +test --incompatible_strict_action_env + test --test_output=errors # Use the Angular 6 compiler diff --git a/packages/bazel/src/schematics/bazel-workspace/files/e2e/BUILD.bazel.template b/packages/bazel/src/schematics/bazel-workspace/files/e2e/BUILD.bazel.template index 25995db21e..b58aaac891 100644 --- a/packages/bazel/src/schematics/bazel-workspace/files/e2e/BUILD.bazel.template +++ b/packages/bazel/src/schematics/bazel-workspace/files/e2e/BUILD.bazel.template @@ -12,6 +12,7 @@ ts_library( "@npm//@types/node", "@npm//jasmine", "@npm//protractor", + "@npm//tslib", ], data = [ "//:tsconfig.json", diff --git a/packages/bazel/src/schematics/bazel-workspace/files/src/BUILD.bazel.template b/packages/bazel/src/schematics/bazel-workspace/files/src/BUILD.bazel.template index f3ce9dec8f..172bfedb04 100644 --- a/packages/bazel/src/schematics/bazel-workspace/files/src/BUILD.bazel.template +++ b/packages/bazel/src/schematics/bazel-workspace/files/src/BUILD.bazel.template @@ -1,10 +1,17 @@ package(default_visibility = ["//visibility:public"]) load("@angular//:index.bzl", "ng_module") -load("@build_bazel_rules_typescript//:defs.bzl", "ts_library", "ts_web_test_suite") +load("@build_bazel_rules_karma//:defs.bzl", "ts_web_test_suite") load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle", "history_server") -load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") +load("@build_bazel_rules_nodejs//internal/web_package:web_package.bzl", "web_package") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver", "ts_library") +<% if (sass) { %>load("@io_bazel_rules_sass//:defs.bzl", "multi_sass_binary") +multi_sass_binary( + name = "styles", + srcs = glob(["**/*.scss"]), +) +<% } %> ng_module( name = "src", srcs = glob( @@ -19,10 +26,11 @@ ng_module( assets = glob([ "**/*.css", "**/*.html", - ]), + ])<% if (sass) { %> + [":styles"]<% } %>, deps = [ "@angular//packages/core", - "@angular//packages/platform-browser", + "@angular//packages/platform-browser",<% if (routing) { %> + "@angular//packages/router",<% } %> "@npm//@types", ], ) @@ -33,22 +41,23 @@ rollup_bundle( deps = ["//src"], ) -# Needed because the prodserver only loads static files that appear under this -# package. -genrule( - name = "zonejs", - srcs = ["@npm//node_modules/zone.js:dist/zone.min.js"], - outs = ["zone.min.js"], - cmd = "cp $< $@", +web_package( + name = "prodapp", + assets = [ + # do not sort + "@npm//node_modules/zone.js:dist/zone.min.js", + ":bundle.min.js", + ], + data = [ + ":bundle", + ], + index_html = "index.html", ) history_server( name = "prodserver", - data = [ - "index.html", - ":bundle", - ":zonejs", - ], + data = [":prodapp"], + templated_args = ["src/prodapp"], ) ts_devserver( @@ -63,8 +72,8 @@ ts_devserver( static_files = [ "@npm//node_modules/zone.js:dist/zone.min.js", "@npm//node_modules/tslib:tslib.js", - "index.html", ], + index_html = "index.html", deps = [":src"], ) diff --git a/packages/bazel/src/schematics/bazel-workspace/index.ts b/packages/bazel/src/schematics/bazel-workspace/index.ts index 5045971576..de65eead65 100644 --- a/packages/bazel/src/schematics/bazel-workspace/index.ts +++ b/packages/bazel/src/schematics/bazel-workspace/index.ts @@ -21,21 +21,15 @@ import {Schema as BazelWorkspaceOptions} from './schema'; * Look for package.json file for package with `packageName` in node_modules and * extract its version. */ -function findVersion(projectName: string, packageName: string, host: Tree): string|null { - // Need to look in multiple locations because we could be working in a subtree. - const candidates = [ - `node_modules/${packageName}/package.json`, - `${projectName}/node_modules/${packageName}/package.json`, - ]; - for (const candidate of candidates) { - if (host.exists(candidate)) { - try { - const packageJson = JSON.parse(host.read(candidate).toString()); - if (packageJson.name === packageName && packageJson.version) { - return packageJson.version; - } - } catch { +function findVersion(packageName: string, host: Tree): string|null { + const candidate = `node_modules/${packageName}/package.json`; + if (host.exists(candidate)) { + try { + const packageJson = JSON.parse(host.read(candidate).toString()); + if (packageJson.name === packageName && packageJson.version) { + return packageJson.version; } + } catch { } } return null; @@ -51,25 +45,38 @@ export function clean(version: string): string|null { return matches && matches.pop() || null; } +/** + * Returns true if project contains routing module, false otherwise. + */ +function hasRoutingModule(host: Tree) { + let hasRouting = false; + host.visit((file: string) => { hasRouting = hasRouting || file.endsWith('-routing.module.ts'); }); + return hasRouting; +} + +/** + * Returns true if project uses SASS stylesheets, false otherwise. + */ +function hasSassStylesheet(host: Tree) { + let hasSass = false; + // The proper extension for SASS is .scss + host.visit((file: string) => { hasSass = hasSass || file.endsWith('.scss'); }); + return hasSass; +} + export default function(options: BazelWorkspaceOptions): Rule { return (host: Tree, context: SchematicContext) => { - if (!options.name) { - throw new SchematicsException(`Invalid options, "name" is required.`); + const name = options.name || getWorkspace(host).defaultProject; + if (!name) { + throw new Error('Please provide a name for Bazel workspace'); } - validateProjectName(options.name); - let newProjectRoot = ''; - try { - const workspace = getWorkspace(host); - newProjectRoot = workspace.newProjectRoot || ''; - } catch { - } - const appDir = `${newProjectRoot}/${options.name}`; + validateProjectName(name); // If the project already has some deps installed, Bazel should use existing // versions. const existingVersions = { - Angular: findVersion(options.name, '@angular/core', host), - RxJs: findVersion(options.name, 'rxjs', host), + Angular: findVersion('@angular/core', host), + RxJs: findVersion('rxjs', host), }; Object.keys(existingVersions).forEach((name: 'Angular' | 'RxJs') => { @@ -79,20 +86,27 @@ export default function(options: BazelWorkspaceOptions): Rule { } }); + if (!host.exists('yarn.lock')) { + host.create('yarn.lock', ''); + } + const workspaceVersions = { + 'RULES_NODEJS_VERSION': '0.18.6', + 'RULES_NODEJS_SHA256': '1416d03823fed624b49a0abbd9979f7c63bbedfd37890ddecedd2fe25cccebc6', 'ANGULAR_VERSION': existingVersions.Angular || clean(latestVersions.Angular), 'RXJS_VERSION': existingVersions.RxJs || clean(latestVersions.RxJs), // TODO(kyliau): Consider moving this to latest-versions.ts - 'RULES_SASS_VERSION': '1.15.1', + 'RULES_SASS_VERSION': '1.17.0', }; return mergeWith(apply(url('./files'), [ applyTemplates({ utils: strings, - ...options, + name, 'dot': '.', ...workspaceVersions, + routing: hasRoutingModule(host), + sass: hasSassStylesheet(host), }), - move(appDir), ])); }; } diff --git a/packages/bazel/src/schematics/bazel-workspace/index_spec.ts b/packages/bazel/src/schematics/bazel-workspace/index_spec.ts index bf0efa4771..085fb7a952 100644 --- a/packages/bazel/src/schematics/bazel-workspace/index_spec.ts +++ b/packages/bazel/src/schematics/bazel-workspace/index_spec.ts @@ -12,7 +12,7 @@ import {clean} from './index'; describe('Bazel-workspace Schematic', () => { const schematicRunner = - new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json'), ); + new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json')); const defaultOptions = { name: 'demo', }; @@ -21,53 +21,91 @@ describe('Bazel-workspace Schematic', () => { const options = {...defaultOptions}; const host = schematicRunner.runSchematic('bazel-workspace', options); const files = host.files; - expect(files).toContain('/demo/.bazelignore'); - expect(files).toContain('/demo/.bazelrc'); - expect(files).toContain('/demo/BUILD.bazel'); - expect(files).toContain('/demo/src/BUILD.bazel'); - expect(files).toContain('/demo/WORKSPACE'); - expect(files).toContain('/demo/yarn.lock'); + expect(files).toContain('/.bazelignore'); + expect(files).toContain('/.bazelrc'); + expect(files).toContain('/BUILD.bazel'); + expect(files).toContain('/src/BUILD.bazel'); + expect(files).toContain('/WORKSPACE'); + expect(files).toContain('/yarn.lock'); }); - it('should find existing Angular version', () => { - let host = new UnitTestTree(new HostTree); - host.create('/demo/node_modules/@angular/core/package.json', JSON.stringify({ - name: '@angular/core', - version: '6.6.6', - })); - const options = {...defaultOptions}; - host = schematicRunner.runSchematic('bazel-workspace', options, host); - expect(host.files).toContain('/demo/WORKSPACE'); - const workspace = host.readContent('/demo/WORKSPACE'); - expect(workspace).toMatch('ANGULAR_VERSION = "6.6.6"'); + it('should generate empty yarn.lock file', () => { + const host = schematicRunner.runSchematic('bazel-workspace', defaultOptions); + expect(host.files).toContain('/yarn.lock'); + expect(host.readContent('/yarn.lock')).toBe(''); + }); + + it('should not replace yarn.lock if it exists', () => { + let host = new UnitTestTree(new HostTree()); + host.create('yarn.lock', 'some content'); + expect(host.files).toContain('/yarn.lock'); + host = schematicRunner.runSchematic('bazel-workspace', defaultOptions, host); + expect(host.files).toContain('/yarn.lock'); + expect(host.readContent('/yarn.lock')).toBe('some content'); }); it('should have the correct entry_module for devserver', () => { const options = {...defaultOptions, name: 'demo-app'}; const host = schematicRunner.runSchematic('bazel-workspace', options); const {files} = host; - expect(files).toContain('/demo-app/src/BUILD.bazel'); - const content = host.readContent('/demo-app/src/BUILD.bazel'); + expect(files).toContain('/src/BUILD.bazel'); + const content = host.readContent('/src/BUILD.bazel'); expect(content).toContain('entry_module = "demo_app/src/main.dev"'); }); + it('should add router if project contains routing module', () => { + let host = new UnitTestTree(new HostTree); + host.create('/src/app/app-routing.module.ts', ''); + expect(host.files).toContain('/src/app/app-routing.module.ts'); + const options = {...defaultOptions}; + host = schematicRunner.runSchematic('bazel-workspace', options, host); + expect(host.files).toContain('/src/BUILD.bazel'); + const content = host.readContent('/src/BUILD.bazel'); + expect(content).toContain('@angular//packages/router'); + }); + describe('WORKSPACE', () => { it('should contain project name', () => { const options = {...defaultOptions}; const host = schematicRunner.runSchematic('bazel-workspace', options); - expect(host.files).toContain('/demo/WORKSPACE'); - const content = host.readContent('/demo/WORKSPACE'); + expect(host.files).toContain('/WORKSPACE'); + const content = host.readContent('/WORKSPACE'); expect(content).toContain('workspace(name = "demo")'); }); it('should convert dashes in name to underscore', () => { const options = {...defaultOptions, name: 'demo-project'}; const host = schematicRunner.runSchematic('bazel-workspace', options); - expect(host.files).toContain('/demo-project/WORKSPACE'); - const content = host.readContent('/demo-project/WORKSPACE'); + expect(host.files).toContain('/WORKSPACE'); + const content = host.readContent('/WORKSPACE'); expect(content).toContain('workspace(name = "demo_project"'); }); }); + + describe('SASS', () => { + let host = new UnitTestTree(new HostTree); + beforeAll(() => { + host.create('/src/app/app.component.scss', ''); + expect(host.files).toContain('/src/app/app.component.scss'); + const options = {...defaultOptions}; + host = schematicRunner.runSchematic('bazel-workspace', options, host); + expect(host.files).toContain('/WORKSPACE'); + expect(host.files).toContain('/src/BUILD.bazel'); + }); + + it('should download and load rules_sass in WORKSPACE', () => { + const content = host.readContent('/WORKSPACE'); + expect(content).toContain('RULES_SASS_VERSION'); + expect(content).toContain( + 'load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")'); + }); + + it('should add multi_sass_binary rule in src/BUILD', () => { + const content = host.readContent('/src/BUILD.bazel'); + expect(content).toContain('load("@io_bazel_rules_sass//:defs.bzl", "multi_sass_binary")'); + expect(content).toContain('glob(["**/*.scss"])'); + }); + }); }); describe('clean', () => { diff --git a/packages/bazel/src/schematics/bazel-workspace/schema.d.ts b/packages/bazel/src/schematics/bazel-workspace/schema.d.ts index 4e0ad890ab..4006879eb3 100644 --- a/packages/bazel/src/schematics/bazel-workspace/schema.d.ts +++ b/packages/bazel/src/schematics/bazel-workspace/schema.d.ts @@ -9,5 +9,5 @@ export interface Schema { /** * The name of the project. */ - name: string; + name?: string; } diff --git a/packages/bazel/src/schematics/bazel-workspace/schema.json b/packages/bazel/src/schematics/bazel-workspace/schema.json index 794abf9115..173e464b2d 100644 --- a/packages/bazel/src/schematics/bazel-workspace/schema.json +++ b/packages/bazel/src/schematics/bazel-workspace/schema.json @@ -15,6 +15,5 @@ } }, "required": [ - "name" ] } diff --git a/packages/bazel/src/schematics/collection.json b/packages/bazel/src/schematics/collection.json index 5e5d5eff46..534f02cd62 100644 --- a/packages/bazel/src/schematics/collection.json +++ b/packages/bazel/src/schematics/collection.json @@ -1,17 +1,22 @@ { - "name": "@angular/bazel", - "version": "0.1", - "schematics": { - "ng-new": { - "factory": "./ng-new", - "schema": "./ng-new/schema.json", - "description": "Create an Angular project that builds with Bazel." - }, - "bazel-workspace": { - "factory": "./bazel-workspace", - "schema": "./bazel-workspace/schema.json", - "description": "Setup Bazel workspace", - "hidden": true - } + "name": "@angular/bazel", + "version": "0.1", + "schematics": { + "ng-add": { + "factory": "./ng-add", + "schema": "ng-add/schema.json", + "description": "Add Bazel build files and configurations to a project" + }, + "ng-new": { + "factory": "./ng-new", + "schema": "./ng-new/schema.json", + "description": "Create an Angular project that builds with Bazel." + }, + "bazel-workspace": { + "factory": "./bazel-workspace", + "schema": "./bazel-workspace/schema.json", + "description": "Setup Bazel workspace", + "hidden": true } } +} diff --git a/packages/bazel/src/schematics/ng-add/BUILD.bazel b/packages/bazel/src/schematics/ng-add/BUILD.bazel new file mode 100644 index 0000000000..461a1cd924 --- /dev/null +++ b/packages/bazel/src/schematics/ng-add/BUILD.bazel @@ -0,0 +1,37 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "ng-add", + srcs = [ + "index.ts", + "schema.d.ts", + ], + data = glob(["files/**/*"]) + [ + "schema.json", + ], + deps = [ + "//packages/bazel/src/schematics/bazel-workspace", + "//packages/bazel/src/schematics/utility", + "@ngdeps//@angular-devkit/core", + "@ngdeps//@angular-devkit/schematics", + "@ngdeps//@schematics/angular", + "@ngdeps//typescript", + ], +) + +ts_library( + name = "test", + testonly = True, + srcs = [ + "index_spec.ts", + ], + data = [ + "//packages/bazel/src/schematics:package_assets", + ], + deps = [ + ":ng-add", + "@ngdeps//@angular-devkit/schematics", + ], +) diff --git a/packages/bazel/src/schematics/ng-new/files/main.dev.ts.template b/packages/bazel/src/schematics/ng-add/files/main.dev.ts.template similarity index 100% rename from packages/bazel/src/schematics/ng-new/files/main.dev.ts.template rename to packages/bazel/src/schematics/ng-add/files/main.dev.ts.template diff --git a/packages/bazel/src/schematics/ng-new/files/main.prod.ts.template b/packages/bazel/src/schematics/ng-add/files/main.prod.ts.template similarity index 100% rename from packages/bazel/src/schematics/ng-new/files/main.prod.ts.template rename to packages/bazel/src/schematics/ng-add/files/main.prod.ts.template diff --git a/packages/bazel/src/schematics/ng-add/index.ts b/packages/bazel/src/schematics/ng-add/index.ts new file mode 100755 index 0000000000..1dfba68596 --- /dev/null +++ b/packages/bazel/src/schematics/ng-add/index.ts @@ -0,0 +1,275 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + * + * @fileoverview Schematics for ng-new project that builds with Bazel. + */ + +import {JsonAstObject, parseJsonAst, strings} from '@angular-devkit/core'; +import {Rule, SchematicContext, SchematicsException, Tree, apply, applyTemplates, chain, mergeWith, move, schematic, url} from '@angular-devkit/schematics'; +import {getWorkspacePath} from '@schematics/angular/utility/config'; +import {findPropertyInAstObject, insertPropertyInAstObjectInOrder} from '@schematics/angular/utility/json-utils'; +import {validateProjectName} from '@schematics/angular/utility/validation'; +import {isJsonAstObject, removeKeyValueInAstObject as removeKeyValueInAstObject, replacePropertyInAstObject} from '../utility/json-utils'; +import {Schema} from './schema'; + +/** + * Packages that build under Bazel require additional dev dependencies. This + * function adds those dependencies to "devDependencies" section in + * package.json. + */ +function addDevDependenciesToPackageJson(options: Schema) { + return (host: Tree) => { + const packageJson = 'package.json'; + if (!host.exists(packageJson)) { + throw new Error(`Could not find ${packageJson}`); + } + const packageJsonContent = host.read(packageJson); + if (!packageJsonContent) { + throw new Error('Failed to read package.json content'); + } + const jsonAst = parseJsonAst(packageJsonContent.toString()) as JsonAstObject; + const deps = findPropertyInAstObject(jsonAst, 'dependencies') as JsonAstObject; + const devDeps = findPropertyInAstObject(jsonAst, 'devDependencies') as JsonAstObject; + + const angularCoreNode = findPropertyInAstObject(deps, '@angular/core'); + if (!angularCoreNode) { + throw new Error('@angular/core dependency not found in package.json'); + } + const angularCoreVersion = angularCoreNode.value as string; + + const devDependencies: {[k: string]: string} = { + '@angular/bazel': angularCoreVersion, + // TODO(kyliau): Consider moving this to latest-versions.ts + '@bazel/bazel': '^0.22.1', + '@bazel/ibazel': '^0.9.0', + '@bazel/karma': '^0.23.2', + '@bazel/typescript': '^0.23.2', + }; + + const recorder = host.beginUpdate(packageJson); + for (const packageName of Object.keys(devDependencies)) { + const version = devDependencies[packageName]; + const indent = 4; + insertPropertyInAstObjectInOrder(recorder, devDeps, packageName, version, indent); + } + host.commitUpdate(recorder); + return host; + }; +} + +/** + * Append main.dev.ts and main.prod.ts to src directory. These files are needed + * by Bazel for devserver and prodserver, respectively. They are different from + * main.ts generated by CLI because they use platformBrowser (AOT) instead of + * platformBrowserDynamic (JIT). + */ +function addDevAndProdMainForAot(options: Schema) { + return (host: Tree) => { + return mergeWith(apply(url('./files'), [ + applyTemplates({ + utils: strings, + ...options, + 'dot': '.', + }), + move('/src'), + ])); + }; +} + +/** + * Append '/bazel-out' to the gitignore file. + */ +function updateGitignore() { + return (host: Tree) => { + const gitignore = '/.gitignore'; + if (!host.exists(gitignore)) { + return host; + } + const gitIgnoreContent = host.read(gitignore).toString(); + if (gitIgnoreContent.includes('\n/bazel-out\n')) { + return host; + } + const compiledOutput = '# compiled output\n'; + const index = gitIgnoreContent.indexOf(compiledOutput); + const insertionIndex = index >= 0 ? index + compiledOutput.length : gitIgnoreContent.length; + const recorder = host.beginUpdate(gitignore); + recorder.insertRight(insertionIndex, '/bazel-out\n'); + host.commitUpdate(recorder); + return host; + }; +} + +function updateAngularJsonToUseBazelBuilder(options: Schema): Rule { + return (host: Tree, context: SchematicContext) => { + const {name} = options; + const workspacePath = getWorkspacePath(host); + if (!workspacePath) { + throw new Error('Could not find angular.json'); + } + const workspaceContent = host.read(workspacePath).toString(); + const workspaceJsonAst = parseJsonAst(workspaceContent) as JsonAstObject; + const projects = findPropertyInAstObject(workspaceJsonAst, 'projects'); + if (!projects) { + throw new SchematicsException('Expect projects in angular.json to be an Object'); + } + const project = findPropertyInAstObject(projects as JsonAstObject, name); + if (!project) { + throw new SchematicsException(`Expected projects to contain ${name}`); + } + const recorder = host.beginUpdate(workspacePath); + const indent = 8; + const architect = + findPropertyInAstObject(project as JsonAstObject, 'architect') as JsonAstObject; + replacePropertyInAstObject( + recorder, architect, 'build', { + builder: '@angular/bazel:build', + options: { + targetLabel: '//src:bundle.js', + bazelCommand: 'build', + }, + configurations: { + production: { + targetLabel: '//src:bundle', + }, + }, + }, + indent); + replacePropertyInAstObject( + recorder, architect, 'serve', { + builder: '@angular/bazel:build', + options: { + targetLabel: '//src:devserver', + bazelCommand: 'run', + }, + configurations: { + production: { + targetLabel: '//src:prodserver', + }, + }, + }, + indent); + replacePropertyInAstObject( + recorder, architect, 'test', { + builder: '@angular/bazel:build', + options: {'bazelCommand': 'test', 'targetLabel': '//src/...'}, + }, + indent); + + const e2e = `${options.name}-e2e`; + const e2eNode = findPropertyInAstObject(projects as JsonAstObject, e2e); + if (e2eNode) { + const architect = + findPropertyInAstObject(e2eNode as JsonAstObject, 'architect') as JsonAstObject; + replacePropertyInAstObject( + recorder, architect, 'e2e', { + builder: '@angular/bazel:build', + options: { + bazelCommand: 'test', + targetLabel: '//e2e:devserver_test', + }, + configurations: { + production: { + targetLabel: '//e2e:prodserver_test', + }, + } + }, + indent); + } + + host.commitUpdate(recorder); + return host; + }; +} + +/** + * Create a backup for the original angular.json file in case user wants to + * eject Bazel and revert to the original workflow. + */ +function backupAngularJson(): Rule { + return (host: Tree, context: SchematicContext) => { + const workspacePath = getWorkspacePath(host); + if (!workspacePath) { + return; + } + host.create( + `${workspacePath}.bak`, '// This is a backup file of the original angular.json. ' + + 'This file is needed in case you want to revert to the workflow without Bazel.\n\n' + + host.read(workspacePath)); + }; +} + +/** + * Create a backup for the original tsconfig.json file in case user wants to + * eject Bazel and revert to the original workflow. + */ +function backupTsconfigJson(): Rule { + return (host: Tree, context: SchematicContext) => { + const tsconfigPath = 'tsconfig.json'; + if (!host.exists(tsconfigPath)) { + return; + } + host.create( + `${tsconfigPath}.bak`, '// This is a backup file of the original tsconfig.json. ' + + 'This file is needed in case you want to revert to the workflow without Bazel.\n\n' + + host.read(tsconfigPath)); + }; +} + +/** + * Bazel controls the compilation options of tsc, so many options in + * tsconfig.json generated by the default CLI schematics are not applicable. + * This function updates the tsconfig.json to remove Bazel-controlled + * parameters. This prevents Bazel from printing out warnings about overriden + * settings. + */ +function updateTsconfigJson(): Rule { + return (host: Tree, context: SchematicContext) => { + const tsconfigPath = 'tsconfig.json'; + if (!host.exists(tsconfigPath)) { + return host; + } + const content = host.read(tsconfigPath).toString(); + const ast = parseJsonAst(content); + if (!isJsonAstObject(ast)) { + return host; + } + const compilerOptions = findPropertyInAstObject(ast, 'compilerOptions'); + if (!isJsonAstObject(compilerOptions)) { + return host; + } + const recorder = host.beginUpdate(tsconfigPath); + // target and module are controlled by downstream dependencies, such as + // ts_devserver + removeKeyValueInAstObject(recorder, content, compilerOptions, 'target'); + removeKeyValueInAstObject(recorder, content, compilerOptions, 'module'); + // typeRoots is always set to the @types subdirectory of the node_modules + // attribute + removeKeyValueInAstObject(recorder, content, compilerOptions, 'typeRoots'); + // rootDir and baseUrl are always the workspace root directory + removeKeyValueInAstObject(recorder, content, compilerOptions, 'rootDir'); + removeKeyValueInAstObject(recorder, content, compilerOptions, 'baseUrl'); + host.commitUpdate(recorder); + return host; + }; +} + +export default function(options: Schema): Rule { + return (host: Tree) => { + validateProjectName(options.name); + + return chain([ + schematic('bazel-workspace', options), + addDevAndProdMainForAot(options), + addDevDependenciesToPackageJson(options), + backupAngularJson(), + backupTsconfigJson(), + updateAngularJsonToUseBazelBuilder(options), + updateGitignore(), + updateTsconfigJson(), + ]); + }; +} diff --git a/packages/bazel/src/schematics/ng-add/index_spec.ts b/packages/bazel/src/schematics/ng-add/index_spec.ts new file mode 100644 index 0000000000..9f426bf5ed --- /dev/null +++ b/packages/bazel/src/schematics/ng-add/index_spec.ts @@ -0,0 +1,201 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {HostTree} from '@angular-devkit/schematics'; +import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; + +describe('ng-add schematic', () => { + + const defaultOptions = {name: 'demo'}; + let host: UnitTestTree; + let schematicRunner: SchematicTestRunner; + + beforeEach(() => { + host = new UnitTestTree(new HostTree()); + host.create('package.json', JSON.stringify({ + name: 'demo', + dependencies: { + '@angular/core': '1.2.3', + }, + devDependencies: { + 'typescript': '3.2.2', + }, + })); + host.create('tsconfig.json', JSON.stringify({ + compileOnSave: false, + compilerOptions: { + baseUrl: './', + outDir: './dist/out-tsc', + } + })); + host.create('angular.json', JSON.stringify({ + projects: { + 'demo': { + architect: { + build: {}, + serve: {}, + test: {}, + 'extract-i18n': { + builder: '@angular-devkit/build-angular:extract-i18n', + }, + }, + }, + 'demo-e2e': { + architect: { + e2e: {}, + lint: { + builder: '@angular-devkit/build-angular:tslint', + }, + }, + }, + }, + })); + schematicRunner = + new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json')); + }); + + it('throws if package.json is not found', () => { + expect(host.files).toContain('/package.json'); + host.delete('/package.json'); + expect(() => schematicRunner.runSchematic('ng-add', defaultOptions)) + .toThrowError('Could not find package.json'); + }); + + it('throws if angular.json is not found', () => { + expect(host.files).toContain('/angular.json'); + host.delete('/angular.json'); + expect(() => schematicRunner.runSchematic('ng-add', defaultOptions, host)) + .toThrowError('Could not find angular.json'); + }); + + it('should add @angular/bazel to package.json dependencies', () => { + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const {files} = host; + expect(files).toContain('/package.json'); + const content = host.readContent('/package.json'); + expect(() => JSON.parse(content)).not.toThrow(); + const json = JSON.parse(content); + const core = '@angular/core'; + const bazel = '@angular/bazel'; + expect(Object.keys(json)).toContain('dependencies'); + expect(Object.keys(json)).toContain('devDependencies'); + expect(Object.keys(json.dependencies)).toContain(core); + expect(Object.keys(json.devDependencies)).toContain(bazel); + expect(json.dependencies[core]).toBe(json.devDependencies[bazel]); + }); + + it('should add @bazel/* dev dependencies', () => { + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const content = host.readContent('/package.json'); + const json = JSON.parse(content); + const devDeps = Object.keys(json.devDependencies); + expect(devDeps).toContain('@bazel/bazel'); + expect(devDeps).toContain('@bazel/ibazel'); + expect(devDeps).toContain('@bazel/karma'); + expect(devDeps).toContain('@bazel/typescript'); + }); + + it('should create Bazel workspace file', () => { + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const {files} = host; + expect(files).toContain('/WORKSPACE'); + expect(files).toContain('/BUILD.bazel'); + }); + + it('should produce main.dev.ts and main.prod.ts for AOT', () => { + host.create('/src/main.ts', 'generated by CLI'); + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const {files} = host; + // main.dev.ts and main.prod.ts are used by Bazel for AOT + expect(files).toContain('/src/main.dev.ts'); + expect(files).toContain('/src/main.prod.ts'); + // main.ts is produced by original ng-add schematics + // This file should be present for backwards compatibility. + expect(files).toContain('/src/main.ts'); + }); + + it('should not overwrite index.html with script tags', () => { + host.create('/src/index.html', 'Hello World'); + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const {files} = host; + expect(files).toContain('/src/index.html'); + const content = host.readContent('/src/index.html'); + expect(content).not.toMatch(''); + expect(content).not.toMatch(''); + }); + + it('should generate main.dev.ts and main.prod.ts', () => { + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const {files} = host; + expect(files).toContain('/src/main.dev.ts'); + expect(files).toContain('/src/main.prod.ts'); + }); + + it('should overwrite .gitignore for bazel-out directory', () => { + host.create('.gitignore', '\n# compiled output\n'); + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const {files} = host; + expect(files).toContain('/.gitignore'); + const content = host.readContent('/.gitignore'); + expect(content).toMatch('\n# compiled output\n/bazel-out\n'); + }); + + it('should create a backup for original angular.json', () => { + expect(host.files).toContain('/angular.json'); + const original = host.readContent('/angular.json'); + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + expect(host.files).toContain('/angular.json.bak'); + const content = host.readContent('/angular.json.bak'); + expect(content.startsWith('// This is a backup file')).toBe(true); + expect(content).toMatch(original); + }); + + it('should update angular.json to use Bazel builder', () => { + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + const {files} = host; + expect(files).toContain('/angular.json'); + const content = host.readContent('/angular.json'); + expect(() => JSON.parse(content)).not.toThrow(); + const json = JSON.parse(content); + const demo = json.projects.demo; + const demo_e2e = json.projects['demo-e2e']; + const {build, serve, test} = demo.architect; + expect(build.builder).toBe('@angular/bazel:build'); + expect(serve.builder).toBe('@angular/bazel:build'); + expect(test.builder).toBe('@angular/bazel:build'); + const {e2e, lint} = demo_e2e.architect; + expect(e2e.builder).toBe('@angular/bazel:build'); + // it should leave non-Bazel commands unmodified + expect(demo.architect['extract-i18n'].builder) + .toBe('@angular-devkit/build-angular:extract-i18n'); + expect(lint.builder).toBe('@angular-devkit/build-angular:tslint'); + }); + + it('should create a backup for original tsconfig.json', () => { + expect(host.files).toContain('/tsconfig.json'); + const original = host.readContent('/tsconfig.json'); + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + expect(host.files).toContain('/tsconfig.json.bak'); + const content = host.readContent('/tsconfig.json.bak'); + expect(content.startsWith('// This is a backup file')).toBe(true); + expect(content).toMatch(original); + }); + + it('should remove Bazel-controlled options from tsconfig.json', () => { + host = schematicRunner.runSchematic('ng-add', defaultOptions, host); + expect(host.files).toContain('/tsconfig.json'); + const content = host.readContent('/tsconfig.json'); + expect(() => JSON.parse(content)).not.toThrow(); + expect(JSON.parse(content)).toEqual({ + compileOnSave: false, + compilerOptions: { + outDir: './dist/out-tsc', + } + }); + }); +}); diff --git a/packages/bazel/src/schematics/ng-add/schema.d.ts b/packages/bazel/src/schematics/ng-add/schema.d.ts new file mode 100644 index 0000000000..4e0ad890ab --- /dev/null +++ b/packages/bazel/src/schematics/ng-add/schema.d.ts @@ -0,0 +1,13 @@ + +// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE +// THE CORRESPONDING JSON SCHEMA FILE. See README.md. + +// tslint:disable:no-global-tslint-disable +// tslint:disable + +export interface Schema { + /** + * The name of the project. + */ + name: string; +} diff --git a/packages/bazel/src/schematics/ng-add/schema.json b/packages/bazel/src/schematics/ng-add/schema.json new file mode 100755 index 0000000000..dbfb4ab203 --- /dev/null +++ b/packages/bazel/src/schematics/ng-add/schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "SchematicsAngularBazelNgAdd", + "title": "Angular Bazel Ng Add Schema", + "type": "object", + "properties": { + "name": { + "description": "The name of the project.", + "type": "string", + "format": "html-selector", + "$default": { + "$source": "argv", + "index": 0 + } + } + }, + "required": [ + "name" + ] +} diff --git a/packages/bazel/src/schematics/ng-new/BUILD.bazel b/packages/bazel/src/schematics/ng-new/BUILD.bazel index d70cab250f..6227329322 100644 --- a/packages/bazel/src/schematics/ng-new/BUILD.bazel +++ b/packages/bazel/src/schematics/ng-new/BUILD.bazel @@ -12,11 +12,9 @@ ts_library( "schema.json", ], deps = [ - "//packages/bazel/src/schematics/bazel-workspace", - "@ngdeps//@angular-devkit/core", + "//packages/bazel/src/schematics/ng-add", "@ngdeps//@angular-devkit/schematics", "@ngdeps//@schematics/angular", - "@ngdeps//typescript", ], ) diff --git a/packages/bazel/src/schematics/ng-new/index.ts b/packages/bazel/src/schematics/ng-new/index.ts old mode 100755 new mode 100644 index 3701f1c648..e132ffec6f --- a/packages/bazel/src/schematics/ng-new/index.ts +++ b/packages/bazel/src/schematics/ng-new/index.ts @@ -8,174 +8,19 @@ * @fileoverview Schematics for ng-new project that builds with Bazel. */ -import {SchematicContext, apply, applyTemplates, chain, externalSchematic, MergeStrategy, mergeWith, move, Rule, schematic, Tree, url, SchematicsException, UpdateRecorder,} from '@angular-devkit/schematics'; -import {parseJsonAst, JsonAstObject, strings, JsonValue} from '@angular-devkit/core'; -import {findPropertyInAstObject, insertPropertyInAstObjectInOrder} from '@schematics/angular/utility/json-utils'; +import {Rule, Tree, chain, externalSchematic, schematic} from '@angular-devkit/schematics'; import {validateProjectName} from '@schematics/angular/utility/validation'; -import {getWorkspace} from '@schematics/angular/utility/config'; import {Schema} from './schema'; -function addDevDependenciesToPackageJson(options: Schema) { - return (host: Tree) => { - const packageJson = `${options.name}/package.json`; - - if (!host.exists(packageJson)) { - throw new Error(`Could not find ${packageJson}`); - } - const packageJsonContent = host.read(packageJson); - if (!packageJsonContent) { - throw new Error('Failed to read package.json content'); - } - const jsonAst = parseJsonAst(packageJsonContent.toString()) as JsonAstObject; - const deps = findPropertyInAstObject(jsonAst, 'dependencies') as JsonAstObject; - const devDeps = findPropertyInAstObject(jsonAst, 'devDependencies') as JsonAstObject; - - const angularCoreNode = findPropertyInAstObject(deps, '@angular/core'); - const angularCoreVersion = angularCoreNode !.value as string; - - const devDependencies: {[k: string]: string} = { - '@angular/bazel': angularCoreVersion, - // TODO(kyliau): Consider moving this to latest-versions.ts - '@bazel/karma': '^0.22.0', - '@bazel/typescript': '^0.22.0', - }; - - const recorder = host.beginUpdate(packageJson); - for (const packageName of Object.keys(devDependencies)) { - const version = devDependencies[packageName]; - const indent = 4; - insertPropertyInAstObjectInOrder(recorder, devDeps, packageName, version, indent); - } - host.commitUpdate(recorder); - return host; - }; -} - -function overwriteMainAndIndex(options: Schema) { - return (host: Tree) => { - let newProjectRoot = ''; - try { - const workspace = getWorkspace(host); - newProjectRoot = workspace.newProjectRoot || ''; - } catch { - } - const srcDir = `${newProjectRoot}/${options.name}/src`; - - return mergeWith( - apply( - url('./files'), - [ - applyTemplates({ - utils: strings, - ...options, - 'dot': '.', - }), - move(srcDir), - ]), - MergeStrategy.Overwrite); - }; -} - -function replacePropertyInAstObject( - recorder: UpdateRecorder, node: JsonAstObject, propertyName: string, value: JsonValue, - indent: number) { - const property = findPropertyInAstObject(node, propertyName); - if (property === null) { - throw new Error(`Property ${propertyName} does not exist in JSON object`); - } - const {start, text} = property; - recorder.remove(start.offset, text.length); - const indentStr = '\n' + - ' '.repeat(indent); - const content = JSON.stringify(value, null, ' ').replace(/\n/g, indentStr); - recorder.insertLeft(start.offset, content); -} - -function updateWorkspaceFileToUseBazelBuilder(options: Schema): Rule { - return (host: Tree, context: SchematicContext) => { - const {name} = options; - const workspacePath = `${name}/angular.json`; - if (!host.exists(workspacePath)) { - throw new SchematicsException(`Workspace file ${workspacePath} not found.`); - } - const workspaceBuffer = host.read(workspacePath) !; - const workspaceJsonAst = parseJsonAst(workspaceBuffer.toString()) as JsonAstObject; - const projects = findPropertyInAstObject(workspaceJsonAst, 'projects'); - if (!projects) { - throw new SchematicsException('Expect projects in angular.json to be an Object'); - } - const project = findPropertyInAstObject(projects as JsonAstObject, name); - if (!project) { - throw new SchematicsException(`Expected projects to contain ${name}`); - } - const recorder = host.beginUpdate(workspacePath); - const indent = 6; - replacePropertyInAstObject( - recorder, project as JsonAstObject, 'architect', { - 'build': { - 'builder': '@angular/bazel:build', - 'options': {'targetLabel': '//src:bundle.js', 'bazelCommand': 'build'}, - 'configurations': {'production': {'targetLabel': '//src:bundle'}} - }, - 'serve': { - 'builder': '@angular/bazel:build', - 'options': {'targetLabel': '//src:devserver', 'bazelCommand': 'run'}, - 'configurations': {'production': {'targetLabel': '//src:prodserver'}} - }, - 'extract-i18n': { - 'builder': '@angular-devkit/build-angular:extract-i18n', - 'options': {'browserTarget': `${name}:build`} - }, - 'test': { - 'builder': '@angular/bazel:build', - 'options': {'bazelCommand': 'test', 'targetLabel': '//src/...'} - }, - 'lint': { - 'builder': '@angular-devkit/build-angular:tslint', - 'options': { - 'tsConfig': ['src/tsconfig.app.json', 'src/tsconfig.spec.json'], - 'exclude': ['**/node_modules/**'] - } - } - }, - indent); - - const e2e = `${options.name}-e2e`; - const e2eNode = findPropertyInAstObject(projects as JsonAstObject, e2e); - if (e2eNode) { - replacePropertyInAstObject( - recorder, e2eNode as JsonAstObject, 'architect', { - 'e2e': { - 'builder': '@angular/bazel:build', - 'options': {'bazelCommand': 'test', 'targetLabel': '//e2e:devserver_test'}, - 'configurations': {'production': {'targetLabel': '//e2e:prodserver_test'}} - }, - 'lint': { - 'builder': '@angular-devkit/build-angular:tslint', - 'options': {'tsConfig': 'e2e/tsconfig.e2e.json', 'exclude': ['**/node_modules/**']} - } - }, - indent); - } - - host.commitUpdate(recorder); - return host; - }; -} - export default function(options: Schema): Rule { return (host: Tree) => { validateProjectName(options.name); return chain([ - externalSchematic('@schematics/angular', 'ng-new', { - ...options, - skipInstall: true, + externalSchematic('@schematics/angular', 'ng-new', options), + schematic('ng-add', options, { + scope: options.name, }), - addDevDependenciesToPackageJson(options), - schematic('bazel-workspace', options), - overwriteMainAndIndex(options), - updateWorkspaceFileToUseBazelBuilder(options), ]); }; } diff --git a/packages/bazel/src/schematics/ng-new/index_spec.ts b/packages/bazel/src/schematics/ng-new/index_spec.ts index f28811ddc8..66177ea67c 100644 --- a/packages/bazel/src/schematics/ng-new/index_spec.ts +++ b/packages/bazel/src/schematics/ng-new/index_spec.ts @@ -8,7 +8,7 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; -describe('Ng-new Schematic', () => { +describe('ng-new schematic', () => { const schematicRunner = new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json'), ); const defaultOptions = { @@ -22,77 +22,15 @@ describe('Ng-new Schematic', () => { const {files} = host; // External schematic should produce workspace file angular.json expect(files).toContain('/demo/angular.json'); - }); - - it('should add @angular/bazel to package.json dependencies', () => { - const options = {...defaultOptions}; - const host = schematicRunner.runSchematic('ng-new', options); - const {files} = host; expect(files).toContain('/demo/package.json'); - const content = host.readContent('/demo/package.json'); - expect(() => JSON.parse(content)).not.toThrow(); - const json = JSON.parse(content); - const core = '@angular/core'; - const bazel = '@angular/bazel'; - expect(Object.keys(json)).toContain('dependencies'); - expect(Object.keys(json)).toContain('devDependencies'); - expect(Object.keys(json.dependencies)).toContain(core); - expect(Object.keys(json.devDependencies)).toContain(bazel); - expect(json.dependencies[core]).toBe(json.devDependencies[bazel]); }); - it('should add @bazel/* dev dependencies', () => { - const options = {...defaultOptions}; - const host = schematicRunner.runSchematic('ng-new', options); - const content = host.readContent('/demo/package.json'); - const json = JSON.parse(content); - const devDeps = Object.keys(json.devDependencies); - expect(devDeps).toContain('@bazel/karma'); - expect(devDeps).toContain('@bazel/typescript'); - }); - - it('should create Bazel workspace file', () => { + it('should call ng-add to generate Bazel files', () => { const options = {...defaultOptions}; const host = schematicRunner.runSchematic('ng-new', options); const {files} = host; expect(files).toContain('/demo/WORKSPACE'); expect(files).toContain('/demo/BUILD.bazel'); - }); - - it('should produce main.prod.ts for AOT', () => { - const options = {...defaultOptions}; - const host = schematicRunner.runSchematic('ng-new', options); - const {files} = host; - // main.prod.ts is used by Bazel for AOT - expect(files).toContain('/demo/src/main.prod.ts'); - // main.ts is produced by original ng-new schematics - // This file should be present for backwards compatibility. - expect(files).toContain('/demo/src/main.ts'); - }); - - it('should overwrite index.html with script tags', () => { - const options = {...defaultOptions}; - const host = schematicRunner.runSchematic('ng-new', options); - const {files} = host; - expect(files).toContain('/demo/src/index.html'); - const content = host.readContent('/demo/src/index.html'); - expect(content).toMatch(''); - expect(content).toMatch(''); - }); - - it('should update angular.json to use Bazel builder', () => { - const options = {...defaultOptions}; - const host = schematicRunner.runSchematic('ng-new', options); - const {files} = host; - expect(files).toContain('/demo/angular.json'); - const content = host.readContent('/demo/angular.json'); - expect(() => JSON.parse(content)).not.toThrow(); - const json = JSON.parse(content); - let {architect} = json.projects.demo; - expect(architect.build.builder).toBe('@angular/bazel:build'); - expect(architect.serve.builder).toBe('@angular/bazel:build'); - expect(architect.test.builder).toBe('@angular/bazel:build'); - architect = json.projects['demo-e2e'].architect; - expect(architect.e2e.builder).toBe('@angular/bazel:build'); + expect(files).toContain('/demo/src/BUILD.bazel'); }); }); diff --git a/packages/bazel/src/schematics/ng-new/schema.json b/packages/bazel/src/schematics/ng-new/schema.json old mode 100755 new mode 100644 index e80bc82bc3..ba82f2c628 --- a/packages/bazel/src/schematics/ng-new/schema.json +++ b/packages/bazel/src/schematics/ng-new/schema.json @@ -43,7 +43,9 @@ "commit": { "description": "Initial repository commit information.", "oneOf": [ - { "type": "boolean" }, + { + "type": "boolean" + }, { "type": "object", "properties": { @@ -85,7 +87,12 @@ }, "viewEncapsulation": { "description": "Specifies the view encapsulation strategy.", - "enum": ["Emulated", "Native", "None", "ShadowDom"], + "enum": [ + "Emulated", + "Native", + "None", + "ShadowDom" + ], "type": "string" }, "version": { @@ -118,11 +125,22 @@ "message": "Which stylesheet format would you like to use?", "type": "list", "items": [ - { "value": "css", "label": "CSS" }, - { "value": "scss", "label": "SCSS [ http://sass-lang.com ]" }, - { "value": "sass", "label": "SASS [ http://sass-lang.com ]" }, - { "value": "less", "label": "LESS [ http://lesscss.org ]" }, - { "value": "styl", "label": "Stylus [ http://stylus-lang.com ]" } + { + "value": "css", + "label": "CSS" + }, + { + "value": "sass", + "label": "Sass [ http://sass-lang.com ]" + }, + { + "value": "less", + "label": "Less [ http://lesscss.org ]" + }, + { + "value": "styl", + "label": "Stylus [ http://stylus-lang.com ]" + } ] } }, diff --git a/packages/bazel/src/schematics/utility/BUILD.bazel b/packages/bazel/src/schematics/utility/BUILD.bazel new file mode 100644 index 0000000000..2c82c9ae28 --- /dev/null +++ b/packages/bazel/src/schematics/utility/BUILD.bazel @@ -0,0 +1,30 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "utility", + srcs = [ + "json-utils.ts", + ], + module_name = "@angular/bazel/src/schematics/utility", + deps = [ + "@ngdeps//@angular-devkit/core", + "@ngdeps//@angular-devkit/schematics", + "@ngdeps//@schematics/angular", + "@ngdeps//typescript", + ], +) + +ts_library( + name = "test", + testonly = True, + srcs = [ + "json-utils_spec.ts", + ], + deps = [ + ":utility", + "@ngdeps//@angular-devkit/core", + "@ngdeps//@angular-devkit/schematics", + ], +) diff --git a/packages/bazel/src/schematics/utility/json-utils.ts b/packages/bazel/src/schematics/utility/json-utils.ts new file mode 100644 index 0000000000..37526b5f6e --- /dev/null +++ b/packages/bazel/src/schematics/utility/json-utils.ts @@ -0,0 +1,65 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {JsonAstNode, JsonAstObject, JsonValue} from '@angular-devkit/core'; +import {UpdateRecorder} from '@angular-devkit/schematics'; +import {findPropertyInAstObject} from '@schematics/angular/utility/json-utils'; + +/** + * Replace the value of the key-value pair in the 'node' object with a different + * 'value' and record the update using the specified 'recorder'. + */ +export function replacePropertyInAstObject( + recorder: UpdateRecorder, node: JsonAstObject, propertyName: string, value: JsonValue, + indent: number = 0) { + const property = findPropertyInAstObject(node, propertyName); + if (property === null) { + throw new Error(`Property '${propertyName}' does not exist in JSON object`); + } + const {start, text} = property; + recorder.remove(start.offset, text.length); + const indentStr = '\n' + + ' '.repeat(indent); + const content = JSON.stringify(value, null, ' ').replace(/\n/g, indentStr); + recorder.insertLeft(start.offset, content); +} + +/** + * Remove the key-value pair with the specified 'key' in the specified 'node' + * object and record the update using the specified 'recorder'. + */ +export function removeKeyValueInAstObject( + recorder: UpdateRecorder, content: string, node: JsonAstObject, key: string) { + for (const [i, prop] of node.properties.entries()) { + if (prop.key.value === key) { + const start = prop.start.offset; + const end = prop.end.offset; + let length = end - start; + const match = content.slice(end).match(/[,\s]+/); + if (match) { + length += match.pop() !.length; + } + recorder.remove(start, length); + if (i === node.properties.length - 1) { // last property + let offset = 0; + while (/(,|\s)/.test(content.charAt(start - offset - 1))) { + offset++; + } + recorder.remove(start - offset, offset); + } + return; + } + } +} + +/** + * Returns true if the specified 'node' is a JsonAstObject, false otherwise. + */ +export function isJsonAstObject(node: JsonAstNode | null): node is JsonAstObject { + return !!node && node.kind === 'object'; +} diff --git a/packages/bazel/src/schematics/utility/json-utils_spec.ts b/packages/bazel/src/schematics/utility/json-utils_spec.ts new file mode 100644 index 0000000000..0f7e2d24aa --- /dev/null +++ b/packages/bazel/src/schematics/utility/json-utils_spec.ts @@ -0,0 +1,109 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {JsonAstObject, parseJsonAst} from '@angular-devkit/core'; +import {HostTree} from '@angular-devkit/schematics'; +import {UnitTestTree} from '@angular-devkit/schematics/testing'; +import {isJsonAstObject, removeKeyValueInAstObject, replacePropertyInAstObject} from './json-utils'; + +describe('JsonUtils', () => { + + let tree: UnitTestTree; + beforeEach(() => { tree = new UnitTestTree(new HostTree()); }); + + describe('replacePropertyInAstObject', () => { + it('should replace property', () => { + const content = JSON.stringify({foo: {bar: 'baz'}}); + tree.create('tmp', content); + const ast = parseJsonAst(content) as JsonAstObject; + const recorder = tree.beginUpdate('tmp'); + replacePropertyInAstObject(recorder, ast, 'foo', [1, 2, 3]); + tree.commitUpdate(recorder); + const value = tree.readContent('tmp'); + expect(JSON.parse(value)).toEqual({ + foo: [1, 2, 3], + }); + expect(value).toBe(`{"foo":[ + 1, + 2, + 3 +]}`); + }); + + it('should respect the indent parameter', () => { + const content = JSON.stringify({hello: 'world'}, null, 2); + tree.create('tmp', content); + const ast = parseJsonAst(content) as JsonAstObject; + const recorder = tree.beginUpdate('tmp'); + replacePropertyInAstObject(recorder, ast, 'hello', 'world!', 2); + tree.commitUpdate(recorder); + const value = tree.readContent('tmp'); + expect(JSON.parse(value)).toEqual({ + hello: 'world!', + }); + expect(value).toBe(`{ + "hello": "world!" +}`); + }); + + it('should throw error if property is not found', () => { + const content = JSON.stringify({}); + tree.create('tmp', content); + const ast = parseJsonAst(content) as JsonAstObject; + const recorder = tree.beginUpdate('tmp'); + expect(() => replacePropertyInAstObject(recorder, ast, 'foo', 'bar')) + .toThrowError(`Property 'foo' does not exist in JSON object`); + }); + }); + + describe('removeKeyValueInAstObject', () => { + it('should remove key-value pair', () => { + const content = JSON.stringify({hello: 'world', foo: 'bar'}); + tree.create('tmp', content); + const ast = parseJsonAst(content) as JsonAstObject; + let recorder = tree.beginUpdate('tmp'); + removeKeyValueInAstObject(recorder, content, ast, 'foo'); + tree.commitUpdate(recorder); + const tmp = tree.readContent('tmp'); + expect(JSON.parse(tmp)).toEqual({ + hello: 'world', + }); + expect(tmp).toBe('{"hello":"world"}'); + recorder = tree.beginUpdate('tmp'); + const newContent = tree.readContent('tmp'); + removeKeyValueInAstObject(recorder, newContent, ast, 'hello'); + tree.commitUpdate(recorder); + const value = tree.readContent('tmp'); + expect(JSON.parse(value)).toEqual({}); + expect(value).toBe('{}'); + }); + + it('should be a noop if key is not found', () => { + const content = JSON.stringify({foo: 'bar'}); + tree.create('tmp', content); + const ast = parseJsonAst(content) as JsonAstObject; + let recorder = tree.beginUpdate('tmp'); + expect(() => removeKeyValueInAstObject(recorder, content, ast, 'hello')).not.toThrow(); + tree.commitUpdate(recorder); + const value = tree.readContent('tmp'); + expect(JSON.parse(value)).toEqual({foo: 'bar'}); + expect(value).toBe('{"foo":"bar"}'); + }); + }); + + describe('isJsonAstObject', () => { + it('should return true for an object', () => { + const ast = parseJsonAst(JSON.stringify({})); + expect(isJsonAstObject(ast)).toBe(true); + }); + it('should return false for a non-object', () => { + const ast = parseJsonAst(JSON.stringify([])); + expect(isJsonAstObject(ast)).toBe(false); + }); + }); +}); diff --git a/packages/bazel/test/ng_package/BUILD.bazel b/packages/bazel/test/ng_package/BUILD.bazel index dd4d1d57b0..0925aa37f6 100644 --- a/packages/bazel/test/ng_package/BUILD.bazel +++ b/packages/bazel/test/ng_package/BUILD.bazel @@ -33,6 +33,7 @@ ts_library( srcs = ["common_package.spec.ts"], deps = [ "//packages:types", + "//packages/private/testing", "@ngdeps//@types/shelljs", ], ) @@ -63,9 +64,10 @@ jasmine_node_test( "example_package.golden", "//packages/bazel/test/ng_package/example:npm_package", ], - # TODO(alexeagle): re-enable this test - # see https://github.com/angular/angular/pull/22933 - tags = ["manual"], + # We don't want to run the example_package golden test with Ivy yet. Currently the golden + # file is based on non-ivy output and therefore won't work for ngc and Ivy at the same time. + # TODO: We should be able to have another golden for ivy-aot as well. + tags = ["no-ivy-aot"], deps = ["@ngdeps//diff"], ) @@ -76,6 +78,7 @@ nodejs_binary( "example_package.golden", ":example_spec_lib", "//packages/bazel/test/ng_package/example:npm_package", + "@ngdeps//diff", ], entry_point = "angular/packages/bazel/test/ng_package/example_package.spec.js", templated_args = ["--accept"], diff --git a/packages/bazel/test/ng_package/common_package.spec.ts b/packages/bazel/test/ng_package/common_package.spec.ts index b73d3ff7b1..e929a9fd41 100644 --- a/packages/bazel/test/ng_package/common_package.spec.ts +++ b/packages/bazel/test/ng_package/common_package.spec.ts @@ -6,11 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ +import {obsoleteInIvy} from '@angular/private/testing'; import * as fs from 'fs'; import * as path from 'path'; import * as shx from 'shelljs'; -shx.cd(path.join(process.env['TEST_SRCDIR'] !, 'angular', 'packages', 'common', 'npm_package')); +// Resolve the "npm_package" directory by using the runfile resolution. Note that we need to +// resolve the "package.json" of the package since otherwise NodeJS would resolve the "main" +// file, which is not necessarily at the root of the "npm_package". +shx.cd(path.dirname(require.resolve('angular/packages/common/npm_package/package.json'))); describe('@angular/common ng_package', () => { describe('should have the locales files', () => { @@ -89,6 +93,14 @@ describe('@angular/common ng_package', () => { .toMatch('//# sourceMappingURL=testing.js.map'); }); + describe('secondary entry-point', () => { + obsoleteInIvy( + `now that we don't need metadata files, we don't need these redirects to help resolve paths to them`) + .it('should contain a root type definition re-export', () => { + expect(shx.cat('./testing.d.ts')).toContain(`export * from './testing/testing';`); + }); + }); + describe('should have module resolution properties in the package.json file for', () => { // https://github.com/angular/common-builds/blob/master/package.json diff --git a/packages/bazel/test/ng_package/core_package.spec.ts b/packages/bazel/test/ng_package/core_package.spec.ts index f5f349f57b..7d231884fe 100644 --- a/packages/bazel/test/ng_package/core_package.spec.ts +++ b/packages/bazel/test/ng_package/core_package.spec.ts @@ -10,9 +10,10 @@ import {fixmeIvy, ivyEnabled, obsoleteInIvy} from '@angular/private/testing'; import * as path from 'path'; import * as shx from 'shelljs'; -const corePackagePath = - path.join(process.env['TEST_SRCDIR'] !, 'angular', 'packages', 'core', 'npm_package'); -shx.cd(corePackagePath); +// Resolve the "npm_package" directory by using the runfile resolution. Note that we need to +// resolve the "package.json" of the package since otherwise NodeJS would resolve the "main" +// file, which is not necessarily at the root of the "npm_package". +shx.cd(path.dirname(require.resolve('angular/packages/core/npm_package/package.json'))); /** * Utility functions that allows me to create fs paths @@ -223,12 +224,13 @@ describe('@angular/core ng_package', () => { describe('typings', () => { const typingsFile = p `testing/index.d.ts`; it('should have a typings file', - () => { expect(shx.cat(typingsFile)).toContain('export * from \'./public_api\';'); }); + () => { expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`); }); obsoleteInIvy( 'now that we don\'t need metadata files, we don\'t need these redirects to help resolve paths to them') - .it('should have an \'redirect\' d.ts file in the parent dir', - () => { expect(shx.cat('testing.d.ts')).toContain(`export *`); }); + .it('should have an \'redirect\' d.ts file in the parent dir', () => { + expect(shx.cat('testing.d.ts')).toContain(`export * from './testing/testing';`); + }); }); obsoleteInIvy('metadata files are no longer needed or produced in Ivy') diff --git a/packages/bazel/test/ng_package/example/BUILD.bazel b/packages/bazel/test/ng_package/example/BUILD.bazel index 11797674c5..6bf8a00242 100644 --- a/packages/bazel/test/ng_package/example/BUILD.bazel +++ b/packages/bazel/test/ng_package/example/BUILD.bazel @@ -5,6 +5,7 @@ load("//tools:defaults.bzl", "ng_module", "ng_package", "npm_package") ng_module( name = "example", srcs = glob(["*.ts"]), + bundle_dts = True, module_name = "example", deps = [ "//packages/bazel/test/ng_package/example/secondary", diff --git a/packages/bazel/test/ng_package/example/secondary/BUILD.bazel b/packages/bazel/test/ng_package/example/secondary/BUILD.bazel index 6fdcbc67b1..e223cd26f2 100644 --- a/packages/bazel/test/ng_package/example/secondary/BUILD.bazel +++ b/packages/bazel/test/ng_package/example/secondary/BUILD.bazel @@ -5,6 +5,7 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "secondary", srcs = glob(["*.ts"]), + bundle_dts = True, module_name = "example/secondary", deps = [ "//packages/core", diff --git a/packages/bazel/test/ng_package/example_package.golden b/packages/bazel/test/ng_package/example_package.golden index cd796eb31e..b84bb36108 100644 --- a/packages/bazel/test/ng_package/example_package.golden +++ b/packages/bazel/test/ng_package/example_package.golden @@ -1,3 +1,4 @@ +README.md arbitrary-npm-package-main.js arbitrary_bin.txt arbitrary_genfiles.txt @@ -12,24 +13,24 @@ bundles bundles/waffels.umd.min.js.map esm2015 esm2015/example.externs.js - esm2015/example_public_index.js + esm2015/example.js esm2015/index.js esm2015/mymodule.js esm2015/secondary esm2015/secondary/index.js esm2015/secondary/secondary.externs.js - esm2015/secondary/secondary_public_index.js + esm2015/secondary/secondary.js esm2015/secondary/secondarymodule.js esm5 - esm5/example_public_index.js + esm5/example.js esm5/index.js esm5/mymodule.js esm5/secondary esm5/secondary/index.js - esm5/secondary/secondary_public_index.js + esm5/secondary/secondary.js esm5/secondary/secondarymodule.js -example_public_index.d.ts -example_public_index.metadata.json +example.d.ts +example.metadata.json extra-styles.css fesm2015 fesm2015/secondary.js @@ -41,18 +42,24 @@ fesm5 fesm5/secondary.js.map fesm5/waffels.js fesm5/waffels.js.map -index.d.ts -mymodule.d.ts package.json secondary - secondary/index.d.ts secondary/package.json - secondary/secondary_public_index.d.ts - secondary/secondary_public_index.metadata.json - secondary/secondarymodule.d.ts + secondary/secondary.d.ts + secondary/secondary.metadata.json secondary.d.ts secondary.metadata.json some-file.txt +--- README.md --- + +Angular +======= + +The sources for this package are in the main [Angular](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. + +License: MIT + + --- arbitrary-npm-package-main.js --- /** @@ -78,150 +85,198 @@ Hello --- bundles/waffels-secondary.umd.js --- +/** + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ + (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) : - typeof define === 'function' && define.amd ? define(['exports', '@angular/core'], factory) : - (factory((global.npm_package = {}),global.ng.core)); -}(this, (function (exports,core) { 'use strict'; + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) : + typeof define === 'function' && define.amd ? define('example/secondary', ['exports', '@angular/core'], factory) : + (global = global || self, factory((global.example = global.example || {}, global.example.secondary = {}), global.ng.core)); +}(this, function (exports, core) { 'use strict'; -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -var SecondaryModule = /** @class */ (function () { - function SecondaryModule() { + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } - SecondaryModule.decorators = [ - { type: core.NgModule, args: [{},] } - ]; - /** @nocollapse */ - SecondaryModule.ctorParameters = function () { return []; }; - return SecondaryModule; -}()); -var a = 1; -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ + /** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + var SecondaryModule = /** @class */ (function () { + function SecondaryModule() { + } + SecondaryModule = __decorate([ + core.NgModule({}) + ], SecondaryModule); + return SecondaryModule; + }()); + var a = 1; -/** - * Generated bundle index. Do not edit. - */ + /** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ -exports.SecondaryModule = SecondaryModule; -exports.a = a; + /** + * Generated bundle index. Do not edit. + */ -Object.defineProperty(exports, '__esModule', { value: true }); + exports.SecondaryModule = SecondaryModule; + exports.a = a; -}))); + Object.defineProperty(exports, '__esModule', { value: true }); + +})); //# sourceMappingURL=waffels-secondary.umd.js.map ---- bundles/waffels-secondary.umd.js.map --- - -{"version":3,"file":"waffels-secondary.umd.js","sources":["../../../../../../../../../../../../execroot/angular/bazel-bin/packages/bazel/test/ng_package/example/npm_package.esm5/packages/bazel/test/ng_package/example/secondary/secondary_public_index.js"],"sourcesContent":["/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport { NgModule } from '@angular/core';\nvar SecondaryModule = /** @class */ (function () {\n function SecondaryModule() {\n }\n SecondaryModule.decorators = [\n { type: NgModule, args: [{},] }\n ];\n /** @nocollapse */\n SecondaryModule.ctorParameters = function () { return []; };\n return SecondaryModule;\n}());\nexport { SecondaryModule };\nexport var a = 1;\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5bW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQzs7Ozs7Z0JBRXRDLFFBQVEsU0FBQyxFQUFFOzs7OzBCQVZaOztTQVdhLGVBQWU7QUFHNUIsTUFBTSxDQUFDLElBQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBTZWNvbmRhcnlNb2R1bGUge1xufVxuXG5leHBvcnQgY29uc3QgYSA9IDE7XG4iXX0=","/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nexport * from './secondarymodule';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9zZWNvbmRhcnkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQVFBLGNBQWMsbUJBQW1CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vc2Vjb25kYXJ5bW9kdWxlJztcbiJdfQ==","/**\n * Generated bundle index. Do not edit.\n */\nexport * from './index';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5X3B1YmxpY19pbmRleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2JhemVsL3Rlc3QvbmdfcGFja2FnZS9leGFtcGxlL3NlY29uZGFyeS9zZWNvbmRhcnlfcHVibGljX2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19"],"names":["NgModule"],"mappings":";;;;;;AAAA;;;;;;;AAOA,AACA,IAAI,eAAe,kBAAkB,YAAY;IAC7C,SAAS,eAAe,GAAG;KAC1B;IACD,eAAe,CAAC,UAAU,GAAG;QACzB,EAAE,IAAI,EAAEA,aAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;KAClC,CAAC;;IAEF,eAAe,CAAC,cAAc,GAAG,YAAY,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAC5D,OAAO,eAAe,CAAC;CAC1B,EAAE,CAAC,CAAC;AACL,AACO,IAAI,CAAC,GAAG,CAAC;;ACnBhB;;;;;;GAMG;;ACNH;;GAEG;;;;;;;;;;;;;"} - --- bundles/waffels-secondary.umd.min.js --- -!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("@angular/core")):"function"==typeof define&&define.amd?define(["exports","@angular/core"],n):n(e.npm_package={},e.ng.core)}(this,function(e,n){"use strict"; /** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */var o=function(){function e(){}return e.decorators=[{type:n.NgModule,args:[{}]}],e.ctorParameters=function(){return[]},e}(); -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@angular/core")):"function"==typeof define&&define.amd?define("example/secondary",["exports","@angular/core"],t):t(((e=e||self).example=e.example||{},e.example.secondary={}),e.ng.core)}(this,function(e,t){"use strict"; +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +var o=function(){return function o(e,t,n,r){var c,f=arguments.length,l=f<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,n,r);else for(var u=e.length-1;u>=0;u--)(c=e[u])&&(l=(f<3?c(l):f>3?c(t,n,l):c(t,n))||l);return f>3&&l&&Object.defineProperty(t,n,l),l}([t.NgModule({})],function e(){})}(); +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ e.SecondaryModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})}); ---- bundles/waffels-secondary.umd.min.js.map --- - -{"version":3,"sources":["packages/bazel/test/ng_package/example/waffels-secondary.umd.js"],"names":["global","factory","exports","module","require","define","amd","npm_package","ng","core","this","SecondaryModule","decorators","type","NgModule","args","ctorParameters","a","Object","defineProperty","value"],"mappings":"CAAC,SAAUA,EAAQC,GACC,iBAAZC,SAA0C,oBAAXC,OAAyBF,EAAQC,QAASE,QAAQ,kBACtE,mBAAXC,QAAyBA,OAAOC,IAAMD,QAAQ,UAAW,iBAAkBJ,GACjFA,EAASD,EAAOO,eAAkBP,EAAOQ,GAAGC,MAH9C,CAIEC,KAAM,SAAWR,EAAQO,GAAQ;;;;;;;GASnC,IAAIE,EAAiC,WACjC,SAASA,KAOT,OALAA,EAAgBC,aACVC,KAAMJ,EAAKK,SAAUC,YAG3BJ,EAAgBK,eAAiB,WAAc,UACxCL,EARyB;;;;;;;;AAwBpCT,EAAQS,gBAAkBA,EAC1BT,EAAQe,EAfA,EAiBRC,OAAOC,eAAejB,EAAS,cAAgBkB,OAAO","sourcesContent":["(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) :\n\ttypeof define === 'function' && define.amd ? define(['exports', '@angular/core'], factory) :\n\t(factory((global.npm_package = {}),global.ng.core));\n}(this, (function (exports,core) { 'use strict';\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nvar SecondaryModule = /** @class */ (function () {\n function SecondaryModule() {\n }\n SecondaryModule.decorators = [\n { type: core.NgModule, args: [{},] }\n ];\n /** @nocollapse */\n SecondaryModule.ctorParameters = function () { return []; };\n return SecondaryModule;\n}());\nvar a = 1;\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\n/**\n * Generated bundle index. Do not edit.\n */\n\nexports.SecondaryModule = SecondaryModule;\nexports.a = a;\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=waffels-secondary.umd.js.map\n"]} - --- bundles/waffels.umd.js --- +/** + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ + (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) : - typeof define === 'function' && define.amd ? define(['exports', '@angular/core'], factory) : - (factory((global.npm_package = {}),global.ng.core)); -}(this, (function (exports,core) { 'use strict'; + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) : + typeof define === 'function' && define.amd ? define('example', ['exports', '@angular/core'], factory) : + (global = global || self, factory(global.example = {}, global.ng.core)); +}(this, function (exports, core) { 'use strict'; -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -var MyModule = /** @class */ (function () { - function MyModule() { + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } - MyModule.decorators = [ - { type: core.NgModule, args: [{},] } - ]; - /** @nocollapse */ - MyModule.ctorParameters = function () { return []; }; - return MyModule; -}()); -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ + /** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + var MyModule = /** @class */ (function () { + function MyModule() { + } + MyModule = __decorate([ + core.NgModule({}) + ], MyModule); + return MyModule; + }()); -/** - * Generated bundle index. Do not edit. - */ + /** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ -exports.MyModule = MyModule; + /** + * Generated bundle index. Do not edit. + */ -Object.defineProperty(exports, '__esModule', { value: true }); + exports.MyModule = MyModule; -}))); + Object.defineProperty(exports, '__esModule', { value: true }); + +})); //# sourceMappingURL=waffels.umd.js.map ---- bundles/waffels.umd.js.map --- - -{"version":3,"file":"waffels.umd.js","sources":["../../../../../../../../../../../../execroot/angular/bazel-bin/packages/bazel/test/ng_package/example/npm_package.esm5/packages/bazel/test/ng_package/example/example_public_index.js"],"sourcesContent":["/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport { NgModule } from '@angular/core';\nvar MyModule = /** @class */ (function () {\n function MyModule() {\n }\n MyModule.decorators = [\n { type: NgModule, args: [{},] }\n ];\n /** @nocollapse */\n MyModule.ctorParameters = function () { return []; };\n return MyModule;\n}());\nexport { MyModule };\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXltb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9teW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQzs7Ozs7Z0JBR3RDLFFBQVEsU0FBQyxFQUFFOzs7O21CQVhaOztTQVlhLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7TmdNb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHthfSBmcm9tICcuL3NlY29uZGFyeS9zZWNvbmRhcnltb2R1bGUnO1xuXG5ATmdNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgTXlNb2R1bGUge1xufSJdfQ==","/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nexport * from './mymodule';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsY0FBYyxZQUFZLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbXltb2R1bGUnOyJdfQ==","/**\n * Generated bundle index. Do not edit.\n */\nexport * from './index';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZV9wdWJsaWNfaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9leGFtcGxlX3B1YmxpY19pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ=="],"names":["NgModule"],"mappings":";;;;;;AAAA;;;;;;;AAOA,AACA,IAAI,QAAQ,kBAAkB,YAAY;IACtC,SAAS,QAAQ,GAAG;KACnB;IACD,QAAQ,CAAC,UAAU,GAAG;QAClB,EAAE,IAAI,EAAEA,aAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;KAClC,CAAC;;IAEF,QAAQ,CAAC,cAAc,GAAG,YAAY,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACrD,OAAO,QAAQ,CAAC;CACnB,EAAE,CAAC;;ACjBJ;;;;;;GAMG;;ACNH;;GAEG;;;;;;;;;;;;"} - --- bundles/waffels.umd.min.js --- -!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("@angular/core")):"function"==typeof define&&define.amd?define(["exports","@angular/core"],n):n(e.npm_package={},e.ng.core)}(this,function(e,n){"use strict"; /** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */var o=function(){function e(){}return e.decorators=[{type:n.NgModule,args:[{}]}],e.ctorParameters=function(){return[]},e}(); + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@angular/core")):"function"==typeof define&&define.amd?define("example",["exports","@angular/core"],t):t((e=e||self).example={},e.ng.core)}(this,function(e,t){"use strict"; /** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */e.MyModule=o,Object.defineProperty(e,"__esModule",{value:!0})}); - ---- bundles/waffels.umd.min.js.map --- - -{"version":3,"sources":["packages/bazel/test/ng_package/example/waffels.umd.js"],"names":["global","factory","exports","module","require","define","amd","npm_package","ng","core","this","MyModule","decorators","type","NgModule","args","ctorParameters","Object","defineProperty","value"],"mappings":"CAAC,SAAUA,EAAQC,GACC,iBAAZC,SAA0C,oBAAXC,OAAyBF,EAAQC,QAASE,QAAQ,kBACtE,mBAAXC,QAAyBA,OAAOC,IAAMD,QAAQ,UAAW,iBAAkBJ,GACjFA,EAASD,EAAOO,eAAkBP,EAAOQ,GAAGC,MAH9C,CAIEC,KAAM,SAAWR,EAAQO,GAAQ;;;;;;;GASnC,IAAIE,EAA0B,WAC1B,SAASA,KAOT,OALAA,EAASC,aACHC,KAAMJ,EAAKK,SAAUC,YAG3BJ,EAASK,eAAiB,WAAc,UACjCL,EARkB;;;;;;;GAuB7BT,EAAQS,SAAWA,EAEnBM,OAAOC,eAAehB,EAAS,cAAgBiB,OAAO","sourcesContent":["(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) :\n\ttypeof define === 'function' && define.amd ? define(['exports', '@angular/core'], factory) :\n\t(factory((global.npm_package = {}),global.ng.core));\n}(this, (function (exports,core) { 'use strict';\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nvar MyModule = /** @class */ (function () {\n function MyModule() {\n }\n MyModule.decorators = [\n { type: core.NgModule, args: [{},] }\n ];\n /** @nocollapse */\n MyModule.ctorParameters = function () { return []; };\n return MyModule;\n}());\n\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\n\n/**\n * Generated bundle index. Do not edit.\n */\n\nexports.MyModule = MyModule;\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\n})));\n//# sourceMappingURL=waffels.umd.js.map\n"]} + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +var o=function(){return function o(e,t,n,r){var f,c=arguments.length,u=c<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)u=Reflect.decorate(e,t,n,r);else for(var i=e.length-1;i>=0;i--)(f=e[i])&&(u=(c<3?f(u):c>3?f(t,n,u):f(t,n))||u);return c>3&&u&&Object.defineProperty(t,n,u),u}([t.NgModule({})],function e(){})}(); +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */e.MyModule=o,Object.defineProperty(e,"__esModule",{value:!0})}); --- esm2015/example.externs.js --- @@ -233,20 +288,19 @@ Object.defineProperty(exports, '__esModule', { value: true }); // NOTE: generated by tsickle, do not edit. ---- esm2015/example_public_index.js --- +--- esm2015/example.js --- /** * Generated bundle index. Do not edit. */ export * from './index'; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZV9wdWJsaWNfaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9leGFtcGxlX3B1YmxpY19pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ== +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2JhemVsL3Rlc3QvbmdfcGFja2FnZS9leGFtcGxlL2V4YW1wbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0= --- esm2015/index.js --- /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @license @@ -256,14 +310,13 @@ export * from './index'; * found in the LICENSE file at https://angular.io/license */ export { MyModule } from './mymodule'; - //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLHlCQUFjLFlBQVksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9teW1vZHVsZSc7Il19 --- esm2015/mymodule.js --- /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @license @@ -278,25 +331,13 @@ export class MyModule { MyModule.decorators = [ { type: NgModule, args: [{},] } ]; -/** @nocollapse */ -MyModule.ctorParameters = () => []; -function MyModule_tsickle_Closure_declarations() { - /** @type {!Array<{type: !Function, args: (undefined|!Array)}>} */ - MyModule.decorators; - /** - * @nocollapse - * @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array)}>)})>} - */ - MyModule.ctorParameters; -} - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXltb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9teW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFJdkMsTUFBTTs7O1lBREwsUUFBUSxTQUFDLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7TmdNb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHthfSBmcm9tICcuL3NlY29uZGFyeS9zZWNvbmRhcnltb2R1bGUnO1xuXG5ATmdNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgTXlNb2R1bGUge1xufSJdfQ== +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXltb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9teW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFJdkMsTUFBTSxPQUFPLFFBQVE7OztZQURwQixRQUFRLFNBQUMsRUFBRSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge2F9IGZyb20gJy4vc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBNeU1vZHVsZSB7XG59Il19 --- esm2015/secondary/index.js --- /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @license @@ -306,7 +347,6 @@ function MyModule_tsickle_Closure_declarations() { * found in the LICENSE file at https://angular.io/license */ export { SecondaryModule, a } from './secondarymodule'; - //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9zZWNvbmRhcnkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFRQSxtQ0FBYyxtQkFBbUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9zZWNvbmRhcnltb2R1bGUnO1xuIl19 --- esm2015/secondary/secondary.externs.js --- @@ -319,20 +359,19 @@ export { SecondaryModule, a } from './secondarymodule'; // NOTE: generated by tsickle, do not edit. ---- esm2015/secondary/secondary_public_index.js --- +--- esm2015/secondary/secondary.js --- /** * Generated bundle index. Do not edit. */ export * from './index'; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5X3B1YmxpY19pbmRleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2JhemVsL3Rlc3QvbmdfcGFja2FnZS9leGFtcGxlL3NlY29uZGFyeS9zZWNvbmRhcnlfcHVibGljX2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19 +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ== --- esm2015/secondary/secondarymodule.js --- /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @license @@ -347,29 +386,17 @@ export class SecondaryModule { SecondaryModule.decorators = [ { type: NgModule, args: [{},] } ]; -/** @nocollapse */ -SecondaryModule.ctorParameters = () => []; -function SecondaryModule_tsickle_Closure_declarations() { - /** @type {!Array<{type: !Function, args: (undefined|!Array)}>} */ - SecondaryModule.decorators; - /** - * @nocollapse - * @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array)}>)})>} - */ - SecondaryModule.ctorParameters; -} -export const /** @type {?} */ a = 1; +/** @type {?} */ +export const a = 1; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5bW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFHdkMsTUFBTSxPQUFPLGVBQWU7OztZQUQzQixRQUFRLFNBQUMsRUFBRTs7O0FBSVosTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge05nTW9kdWxlfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuQE5nTW9kdWxlKHt9KVxuZXhwb3J0IGNsYXNzIFNlY29uZGFyeU1vZHVsZSB7XG59XG5cbmV4cG9ydCBjb25zdCBhID0gMTtcbiJdfQ== -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5bW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFHdkMsTUFBTTs7O1lBREwsUUFBUSxTQUFDLEVBQUU7Ozs7Ozs7Ozs7Ozs7QUFJWixNQUFNLENBQUMsdUJBQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBTZWNvbmRhcnlNb2R1bGUge1xufVxuXG5leHBvcnQgY29uc3QgYSA9IDE7XG4iXX0= - ---- esm5/example_public_index.js --- +--- esm5/example.js --- /** * Generated bundle index. Do not edit. */ export * from './index'; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZV9wdWJsaWNfaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9leGFtcGxlX3B1YmxpY19pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ== +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2JhemVsL3Rlc3QvbmdfcGFja2FnZS9leGFtcGxlL2V4YW1wbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLFNBQVMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9pbmRleCc7XG4iXX0= --- esm5/index.js --- @@ -381,8 +408,7 @@ export * from './index'; * found in the LICENSE file at https://angular.io/license */ export * from './mymodule'; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsY0FBYyxZQUFZLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbXltb2R1bGUnOyJdfQ== +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxjQUFjLFlBQVksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9teW1vZHVsZSc7Il19 --- esm5/mymodule.js --- @@ -393,20 +419,18 @@ export * from './mymodule'; * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import * as tslib_1 from "tslib"; import { NgModule } from '@angular/core'; var MyModule = /** @class */ (function () { function MyModule() { } - MyModule.decorators = [ - { type: NgModule, args: [{},] } - ]; - /** @nocollapse */ - MyModule.ctorParameters = function () { return []; }; + MyModule = tslib_1.__decorate([ + NgModule({}) + ], MyModule); return MyModule; }()); export { MyModule }; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXltb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9teW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQzs7Ozs7Z0JBR3RDLFFBQVEsU0FBQyxFQUFFOzs7O21CQVhaOztTQVlhLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7TmdNb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHthfSBmcm9tICcuL3NlY29uZGFyeS9zZWNvbmRhcnltb2R1bGUnO1xuXG5ATmdNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgTXlNb2R1bGUge1xufSJdfQ== +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXltb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9teW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7O0FBRUgsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUl2QztJQUFBO0lBQ0EsQ0FBQztJQURZLFFBQVE7UUFEcEIsUUFBUSxDQUFDLEVBQUUsQ0FBQztPQUNBLFFBQVEsQ0FDcEI7SUFBRCxlQUFDO0NBQUEsQUFERCxJQUNDO1NBRFksUUFBUSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge2F9IGZyb20gJy4vc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBNeU1vZHVsZSB7XG59Il19 --- esm5/secondary/index.js --- @@ -418,17 +442,15 @@ export { MyModule }; * found in the LICENSE file at https://angular.io/license */ export * from './secondarymodule'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9zZWNvbmRhcnkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsY0FBYyxtQkFBbUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9zZWNvbmRhcnltb2R1bGUnO1xuIl19 -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9zZWNvbmRhcnkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQVFBLGNBQWMsbUJBQW1CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vc2Vjb25kYXJ5bW9kdWxlJztcbiJdfQ== - ---- esm5/secondary/secondary_public_index.js --- +--- esm5/secondary/secondary.js --- /** * Generated bundle index. Do not edit. */ export * from './index'; - -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5X3B1YmxpY19pbmRleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2JhemVsL3Rlc3QvbmdfcGFja2FnZS9leGFtcGxlL3NlY29uZGFyeS9zZWNvbmRhcnlfcHVibGljX2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19 +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ== --- esm5/secondary/secondarymodule.js --- @@ -439,33 +461,39 @@ export * from './index'; * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import * as tslib_1 from "tslib"; import { NgModule } from '@angular/core'; var SecondaryModule = /** @class */ (function () { function SecondaryModule() { } - SecondaryModule.decorators = [ - { type: NgModule, args: [{},] } - ]; - /** @nocollapse */ - SecondaryModule.ctorParameters = function () { return []; }; + SecondaryModule = tslib_1.__decorate([ + NgModule({}) + ], SecondaryModule); return SecondaryModule; }()); export { SecondaryModule }; export var a = 1; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5bW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7O0FBRUgsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUd2QztJQUFBO0lBQ0EsQ0FBQztJQURZLGVBQWU7UUFEM0IsUUFBUSxDQUFDLEVBQUUsQ0FBQztPQUNBLGVBQWUsQ0FDM0I7SUFBRCxzQkFBQztDQUFBLEFBREQsSUFDQztTQURZLGVBQWU7QUFHNUIsTUFBTSxDQUFDLElBQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBTZWNvbmRhcnlNb2R1bGUge1xufVxuXG5leHBvcnQgY29uc3QgYSA9IDE7XG4iXX0= -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5bW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQzs7Ozs7Z0JBRXRDLFFBQVEsU0FBQyxFQUFFOzs7OzBCQVZaOztTQVdhLGVBQWU7QUFHNUIsTUFBTSxDQUFDLElBQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBTZWNvbmRhcnlNb2R1bGUge1xufVxuXG5leHBvcnQgY29uc3QgYSA9IDE7XG4iXX0= - ---- example_public_index.d.ts --- +--- example.d.ts --- /** - * Generated bundle index. Do not edit. + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT */ -export * from './index'; ---- example_public_index.metadata.json --- -{"__symbolic":"module","version":4,"metadata":{"MyModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":11,"character":1},"arguments":[{}]}],"members":{}}},"origins":{"MyModule":"./mymodule"},"importAs":"example"} +export declare class MyModule { +} + +export { } + + +--- example.metadata.json --- + +{"__symbolic":"module","version":4,"metadata":{"MyModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":11,"character":1},"arguments":[{}]}],"members":{}}},"origins":{"MyModule":"./example"},"importAs":"example"} --- extra-styles.css --- @@ -476,38 +504,29 @@ export * from './index'; --- fesm2015/secondary.js --- +/** + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ + import { NgModule } from '@angular/core'; /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc - */ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class SecondaryModule { } SecondaryModule.decorators = [ { type: NgModule, args: [{},] } ]; -/** @nocollapse */ -SecondaryModule.ctorParameters = () => []; +/** @type {?} */ const a = 1; /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc - */ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @@ -518,43 +537,29 @@ export { SecondaryModule, a }; //# sourceMappingURL=secondary.js.map ---- fesm2015/secondary.js.map --- - -{"version":3,"file":"secondary.js","sources":["../../../../../../../../../../../../../execroot/angular/bazel-bin/packages/bazel/test/ng_package/example/npm_package.es6/packages/bazel/test/ng_package/example/secondary/secondary_public_index.js"],"sourcesContent":["/**\n * @fileoverview added by tsickle\n * @suppress {checkTypes} checked by tsc\n */\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport { NgModule } from '@angular/core';\nexport class SecondaryModule {\n}\nSecondaryModule.decorators = [\n { type: NgModule, args: [{},] }\n];\n/** @nocollapse */\nSecondaryModule.ctorParameters = () => [];\nfunction SecondaryModule_tsickle_Closure_declarations() {\n /** @type {!Array<{type: !Function, args: (undefined|!Array)}>} */\n SecondaryModule.decorators;\n /**\n * @nocollapse\n * @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array)}>)})>}\n */\n SecondaryModule.ctorParameters;\n}\nexport const /** @type {?} */ a = 1;\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5bW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFHdkMsTUFBTTs7O1lBREwsUUFBUSxTQUFDLEVBQUU7Ozs7Ozs7Ozs7Ozs7QUFJWixNQUFNLENBQUMsdUJBQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBTZWNvbmRhcnlNb2R1bGUge1xufVxuXG5leHBvcnQgY29uc3QgYSA9IDE7XG4iXX0=","/**\n * @fileoverview added by tsickle\n * @suppress {checkTypes} checked by tsc\n */\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nexport { SecondaryModule, a } from './secondarymodule';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9zZWNvbmRhcnkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFRQSxtQ0FBYyxtQkFBbUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9zZWNvbmRhcnltb2R1bGUnO1xuIl19","/**\n * Generated bundle index. Do not edit.\n */\nexport * from './index';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5X3B1YmxpY19pbmRleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2JhemVsL3Rlc3QvbmdfcGFja2FnZS9leGFtcGxlL3NlY29uZGFyeS9zZWNvbmRhcnlfcHVibGljX2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19"],"names":[],"mappings":";;AAAA;;;;;;;;;;;AAWA,AACO,MAAM,eAAe,CAAC;CAC5B;AACD,eAAe,CAAC,UAAU,GAAG;IACzB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;CAClC,CAAC;;AAEF,eAAe,CAAC,cAAc,GAAG,MAAM,EAAE,CAAC;AAC1C,AASO,MAAuB,CAAC,GAAG,CAAC;;AC5BnC;;;;;;;;;;GAUG;;ACVH;;GAEG;;;;"} - --- fesm2015/waffels.js --- +/** + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ + import { NgModule } from '@angular/core'; /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc - */ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class MyModule { } MyModule.decorators = [ { type: NgModule, args: [{},] } ]; -/** @nocollapse */ -MyModule.ctorParameters = () => []; /** * @fileoverview added by tsickle - * @suppress {checkTypes} checked by tsc - */ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license + * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @@ -565,12 +570,15 @@ export { MyModule }; //# sourceMappingURL=waffels.js.map ---- fesm2015/waffels.js.map --- - -{"version":3,"file":"waffels.js","sources":["../../../../../../../../../../../../../execroot/angular/bazel-bin/packages/bazel/test/ng_package/example/npm_package.es6/packages/bazel/test/ng_package/example/example_public_index.js"],"sourcesContent":["/**\n * @fileoverview added by tsickle\n * @suppress {checkTypes} checked by tsc\n */\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport { NgModule } from '@angular/core';\nexport class MyModule {\n}\nMyModule.decorators = [\n { type: NgModule, args: [{},] }\n];\n/** @nocollapse */\nMyModule.ctorParameters = () => [];\nfunction MyModule_tsickle_Closure_declarations() {\n /** @type {!Array<{type: !Function, args: (undefined|!Array)}>} */\n MyModule.decorators;\n /**\n * @nocollapse\n * @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array)}>)})>}\n */\n MyModule.ctorParameters;\n}\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXltb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9teW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFJdkMsTUFBTTs7O1lBREwsUUFBUSxTQUFDLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7TmdNb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHthfSBmcm9tICcuL3NlY29uZGFyeS9zZWNvbmRhcnltb2R1bGUnO1xuXG5ATmdNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgTXlNb2R1bGUge1xufSJdfQ==","/**\n * @fileoverview added by tsickle\n * @suppress {checkTypes} checked by tsc\n */\n/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nexport { MyModule } from './mymodule';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLHlCQUFjLFlBQVksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9teW1vZHVsZSc7Il19","/**\n * Generated bundle index. Do not edit.\n */\nexport * from './index';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZV9wdWJsaWNfaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9leGFtcGxlX3B1YmxpY19pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ=="],"names":[],"mappings":";;AAAA;;;;;;;;;;;AAWA,AACO,MAAM,QAAQ,CAAC;CACrB;AACD,QAAQ,CAAC,UAAU,GAAG;IAClB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;CAClC,CAAC;;AAEF,QAAQ,CAAC,cAAc,GAAG,MAAM,EAAE,CAAC;;AClBnC;;;;;;;;;;GAUG;;ACVH;;GAEG;;;;"} - --- fesm5/secondary.js --- +/** + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ + +import { __decorate } from 'tslib'; import { NgModule } from '@angular/core'; /** @@ -583,11 +591,9 @@ import { NgModule } from '@angular/core'; var SecondaryModule = /** @class */ (function () { function SecondaryModule() { } - SecondaryModule.decorators = [ - { type: NgModule, args: [{},] } - ]; - /** @nocollapse */ - SecondaryModule.ctorParameters = function () { return []; }; + SecondaryModule = __decorate([ + NgModule({}) + ], SecondaryModule); return SecondaryModule; }()); var a = 1; @@ -608,12 +614,15 @@ export { SecondaryModule, a }; //# sourceMappingURL=secondary.js.map ---- fesm5/secondary.js.map --- - -{"version":3,"file":"secondary.js","sources":["../../../../../../../../../../../../execroot/angular/bazel-bin/packages/bazel/test/ng_package/example/npm_package.esm5/packages/bazel/test/ng_package/example/secondary/secondary_public_index.js"],"sourcesContent":["/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport { NgModule } from '@angular/core';\nvar SecondaryModule = /** @class */ (function () {\n function SecondaryModule() {\n }\n SecondaryModule.decorators = [\n { type: NgModule, args: [{},] }\n ];\n /** @nocollapse */\n SecondaryModule.ctorParameters = function () { return []; };\n return SecondaryModule;\n}());\nexport { SecondaryModule };\nexport var a = 1;\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5bW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYmF6ZWwvdGVzdC9uZ19wYWNrYWdlL2V4YW1wbGUvc2Vjb25kYXJ5L3NlY29uZGFyeW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQzs7Ozs7Z0JBRXRDLFFBQVEsU0FBQyxFQUFFOzs7OzBCQVZaOztTQVdhLGVBQWU7QUFHNUIsTUFBTSxDQUFDLElBQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtOZ01vZHVsZX0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbkBOZ01vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBTZWNvbmRhcnlNb2R1bGUge1xufVxuXG5leHBvcnQgY29uc3QgYSA9IDE7XG4iXX0=","/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nexport * from './secondarymodule';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9zZWNvbmRhcnkvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQVFBLGNBQWMsbUJBQW1CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vc2Vjb25kYXJ5bW9kdWxlJztcbiJdfQ==","/**\n * Generated bundle index. Do not edit.\n */\nexport * from './index';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5X3B1YmxpY19pbmRleC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2JhemVsL3Rlc3QvbmdfcGFja2FnZS9leGFtcGxlL3NlY29uZGFyeS9zZWNvbmRhcnlfcHVibGljX2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19"],"names":[],"mappings":";;AAAA;;;;;;;AAOA,AACA,IAAI,eAAe,kBAAkB,YAAY;IAC7C,SAAS,eAAe,GAAG;KAC1B;IACD,eAAe,CAAC,UAAU,GAAG;QACzB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;KAClC,CAAC;;IAEF,eAAe,CAAC,cAAc,GAAG,YAAY,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAC5D,OAAO,eAAe,CAAC;CAC1B,EAAE,CAAC,CAAC;AACL,AACO,IAAI,CAAC,GAAG,CAAC;;ACnBhB;;;;;;GAMG;;ACNH;;GAEG;;;;"} - --- fesm5/waffels.js --- +/** + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ + +import { __decorate } from 'tslib'; import { NgModule } from '@angular/core'; /** @@ -626,11 +635,9 @@ import { NgModule } from '@angular/core'; var MyModule = /** @class */ (function () { function MyModule() { } - MyModule.decorators = [ - { type: NgModule, args: [{},] } - ]; - /** @nocollapse */ - MyModule.ctorParameters = function () { return []; }; + MyModule = __decorate([ + NgModule({}) + ], MyModule); return MyModule; }()); @@ -650,54 +657,21 @@ export { MyModule }; //# sourceMappingURL=waffels.js.map ---- fesm5/waffels.js.map --- - -{"version":3,"file":"waffels.js","sources":["../../../../../../../../../../../../../execroot/angular/bazel-bin/packages/bazel/test/ng_package/example/npm_package.esm5/packages/bazel/test/ng_package/example/example_public_index.js"],"sourcesContent":["/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nimport { NgModule } from '@angular/core';\nvar MyModule = /** @class */ (function () {\n function MyModule() {\n }\n MyModule.decorators = [\n { type: NgModule, args: [{},] }\n ];\n /** @nocollapse */\n MyModule.ctorParameters = function () { return []; };\n return MyModule;\n}());\nexport { MyModule };\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibXltb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9teW1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQzs7Ozs7Z0JBR3RDLFFBQVEsU0FBQyxFQUFFOzs7O21CQVhaOztTQVlhLFFBQVEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7TmdNb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHthfSBmcm9tICcuL3NlY29uZGFyeS9zZWNvbmRhcnltb2R1bGUnO1xuXG5ATmdNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgTXlNb2R1bGUge1xufSJdfQ==","/**\n * @license\n * Copyright Google Inc. All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.io/license\n */\nexport * from './mymodule';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsY0FBYyxZQUFZLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbXltb2R1bGUnOyJdfQ==","/**\n * Generated bundle index. Do not edit.\n */\nexport * from './index';\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZV9wdWJsaWNfaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9iYXplbC90ZXN0L25nX3BhY2thZ2UvZXhhbXBsZS9leGFtcGxlX3B1YmxpY19pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ=="],"names":[],"mappings":";;AAAA;;;;;;;AAOA,AACA,IAAI,QAAQ,kBAAkB,YAAY;IACtC,SAAS,QAAQ,GAAG;KACnB;IACD,QAAQ,CAAC,UAAU,GAAG;QAClB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;KAClC,CAAC;;IAEF,QAAQ,CAAC,cAAc,GAAG,YAAY,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACrD,OAAO,QAAQ,CAAC;CACnB,EAAE,CAAC;;ACjBJ;;;;;;GAMG;;ACNH;;GAEG;;;;"} - ---- index.d.ts --- - -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -export * from './mymodule'; - - ---- mymodule.d.ts --- - -export declare class MyModule { -} - - --- package.json --- { "name": "example", + "version": "0.0.0", "main": "./bundles/example.umd.js", "fesm5": "./fesm5/example.js", "fesm2015": "./fesm2015/example.js", - "esm5": "./esm5/example_public_index.js", - "esm2015": "./esm2015/example_public_index.js", - "typings": "./example_public_index.d.ts", + "esm5": "./esm5/example.js", + "esm2015": "./esm2015/example.js", + "typings": "./example.d.ts", "module": "./fesm5/example.js", "es2015": "./fesm2015/example.js" } ---- secondary/index.d.ts --- - -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -export * from './secondarymodule'; - - --- secondary/package.json --- { @@ -705,41 +679,49 @@ export * from './secondarymodule'; "main": "../bundles/example-secondary.umd.js", "fesm5": "../fesm5/secondary.js", "fesm2015": "../fesm2015/secondary.js", - "esm5": "../esm5/secondary/secondary_public_index.js", - "esm2015": "../esm2015/secondary/secondary_public_index.js", - "typings": "./secondary_public_index.d.ts", + "esm5": "../esm5/secondary/secondary.js", + "esm2015": "../esm2015/secondary/secondary.js", + "typings": "./secondary.d.ts", "module": "../fesm5/secondary.js", "es2015": "../fesm2015/secondary.js" } ---- secondary/secondary_public_index.d.ts --- +--- secondary/secondary.d.ts --- /** - * Generated bundle index. Do not edit. + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT */ -export * from './index'; ---- secondary/secondary_public_index.metadata.json --- - -{"__symbolic":"module","version":4,"metadata":{"SecondaryModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":10,"character":1},"arguments":[{}]}],"members":{}},"a":1},"origins":{"SecondaryModule":"./secondarymodule","a":"./secondarymodule"},"importAs":"example/secondary"} - ---- secondary/secondarymodule.d.ts --- - -export declare class SecondaryModule { -} export declare const a = 1; +export declare class SecondaryModule { +} + +export { } + + +--- secondary/secondary.metadata.json --- + +{"__symbolic":"module","version":4,"metadata":{"SecondaryModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":10,"character":1},"arguments":[{}]}],"members":{}},"a":1},"origins":{"SecondaryModule":"./secondary","a":"./secondary"},"importAs":"example/secondary"} + --- secondary.d.ts --- +/** + * @license Angular v0.0.0 + * (c) 2010-2019 Google LLC. https://angular.io/ + * License: MIT + */ + +export * from './secondary/secondary'; - export * from './secondary/secondary_public_index'; - --- secondary.metadata.json --- -{"__symbolic":"module","version":3,"metadata":{},"exports":[{"from":"./secondary/secondary_public_index"}],"flatModuleIndexRedirect":true} +{"__symbolic":"module","version":3,"metadata":{},"exports":[{"from":"./secondary/secondary"}],"flatModuleIndexRedirect":true,"importAs":"example/secondary"} --- some-file.txt --- diff --git a/packages/bazel/test/ng_package/example_package.spec.ts b/packages/bazel/test/ng_package/example_package.spec.ts index e8e2339a23..51e39fd816 100644 --- a/packages/bazel/test/ng_package/example_package.spec.ts +++ b/packages/bazel/test/ng_package/example_package.spec.ts @@ -10,14 +10,20 @@ import {createPatch} from 'diff'; import * as fs from 'fs'; import * as path from 'path'; -/** Directory in the Angular repo where package gold tests live. */ -const TEST_DIR = path.resolve(path.join('packages', 'bazel', 'test', 'ng_package')); - type TestPackage = { - dir: string; goldPath: string + displayName: string; packagePath: string; goldenFilePath: string; }; + const packagesToTest: TestPackage[] = [ - {dir: 'example', goldPath: 'example_package.golden'}, + { + displayName: 'Example NPM package', + // Resolve the "npm_package" directory by using the runfile resolution. Note that we need to + // resolve the "package.json" of the package since otherwise NodeJS would resolve the "main" + // file, which is not necessarily at the root of the "npm_package". + packagePath: path.dirname( + require.resolve('angular/packages/bazel/test/ng_package/example/npm_package/package.json')), + goldenFilePath: require.resolve('./example_package.golden') + }, ]; /** @@ -31,10 +37,12 @@ const packagesToTest: TestPackage[] = [ function getIndentedDirectoryStructure(directoryPath: string, depth = 0): string[] { const result: string[] = []; if (fs.statSync(directoryPath).isDirectory()) { - fs.readdirSync(directoryPath).forEach(f => { + // We need to sort the directories because on Windows "readdirsync" is not sorted. Since we + // compare these in a golden file, the order needs to be consistent across different platforms. + fs.readdirSync(directoryPath).sort().forEach(f => { + const filePath = path.posix.join(directoryPath, f); result.push( - ' '.repeat(depth) + path.join(directoryPath, f), - ...getIndentedDirectoryStructure(path.join(directoryPath, f), depth + 1)); + ' '.repeat(depth) + filePath, ...getIndentedDirectoryStructure(filePath, depth + 1)); }); } return result; @@ -50,22 +58,24 @@ function getIndentedDirectoryStructure(directoryPath: string, depth = 0): string function getDescendantFilesContents(directoryPath: string): string[] { const result: string[] = []; if (fs.statSync(directoryPath).isDirectory()) { - fs.readdirSync(directoryPath).forEach(dir => { - result.push(...getDescendantFilesContents(path.join(directoryPath, dir))); + // We need to sort the directories because on Windows "readdirsync" is not sorted. Since we + // compare these in a golden file, the order needs to be consistent across different platforms. + fs.readdirSync(directoryPath).sort().forEach(dir => { + result.push(...getDescendantFilesContents(path.posix.join(directoryPath, dir))); }); - } else { - result.push(`--- ${directoryPath} ---`, '', fs.readFileSync(directoryPath, 'utf-8'), ''); + } + // Note that we don't want to include ".map" files in the golden file since these are not + // consistent across different environments (e.g. path delimiters) + else if (path.extname(directoryPath) !== '.map') { + result.push(`--- ${directoryPath} ---`, '', readFileContents(directoryPath), ''); } return result; } /** Accepts the current package output by overwriting the gold file in source control. */ function acceptNewPackageGold(testPackage: TestPackage) { - const goldenFile = path.join(TEST_DIR, testPackage.goldPath); - process.chdir(path.join(TEST_DIR, `${testPackage.dir}`, 'npm_package')); - - const actual = getCurrentPackageContent(); - fs.writeFileSync(require.resolve(goldenFile), actual, 'utf-8'); + process.chdir(testPackage.packagePath); + fs.writeFileSync(testPackage.goldenFilePath, getCurrentPackageContent(), 'utf-8'); } /** Gets the content of the current package. Depends on the current working directory. */ @@ -77,21 +87,22 @@ function getCurrentPackageContent() { /** Compares the current package output to the gold file in source control in a jasmine test. */ function runPackageGoldTest(testPackage: TestPackage) { - const goldenFile = path.join(TEST_DIR, testPackage.goldPath); - process.chdir(path.join(TEST_DIR, `${testPackage.dir}`, 'npm_package')); + const {displayName, packagePath, goldenFilePath} = testPackage; + + process.chdir(packagePath); // Gold file content from source control. We expect that the output of the package matches this. - const expected = fs.readFileSync(goldenFile, 'utf-8'); + const expected = fs.readFileSync(goldenFilePath, 'utf-8'); // Actual file content generated from the rule. const actual = getCurrentPackageContent(); // Without the `--accept` flag, compare the actual to the expected in a jasmine test. - it(`Package "${testPackage.dir}"`, () => { + it(`Package "${displayName}"`, () => { if (actual !== expected) { // Compute the patch and strip the header - let patch = - createPatch(goldenFile, expected, actual, 'Golden file', 'Generated file', {context: 5}); + let patch = createPatch( + goldenFilePath, expected, actual, 'Golden file', 'Generated file', {context: 5}); const endOfHeader = patch.indexOf('\n', patch.indexOf('\n') + 1) + 1; patch = patch.substring(endOfHeader); @@ -108,55 +119,28 @@ function runPackageGoldTest(testPackage: TestPackage) { }); } -/** Gets all errors for missing golden files or packages. Typically missing from the bazel rule. */ -function getDependencyErrors(testPackage: TestPackage): string[] { - const errors = []; - - const goldenFile = path.join(TEST_DIR, testPackage.goldPath); - if (!fs.existsSync(goldenFile)) { - errors.push( - `The golden file "${testPackage.goldPath}" cannot be found. ` + - `Ensure that the file exists and is added to the 'data' attribute of the test rule`); - } - - if (!fs.existsSync(path.join(TEST_DIR, `${testPackage.dir}`, 'npm_package'))) { - errors.push( - `The package output for "${testPackage.dir}" cannot be found. Ensure that ` + - `the an ng_package named "npm_package" exists in the "${testPackage.dir }" directory ` + - `and that it is added to the "data" attribute of the test rule.`); - } - - return errors; +/** + * Reads the contents of the specified file. Additionally it strips all carriage return (CR) + * characters from the given content. We do this since the content that will be pulled into the + * golden file needs to be consistent across all platforms. + */ +function readFileContents(filePath: string): string { + return fs.readFileSync(filePath, 'utf8').replace(/\r/g, ''); } +if (require.main === module) { + const args = process.argv.slice(2); + const acceptingNewGold = (args[0] === '--accept'); -// If there are any dependency errors, emit the errors and set the exit code. -let hasError = false; -for (let p of packagesToTest) { - const dependencyErrors = getDependencyErrors(p); - if (dependencyErrors.length) { - console.error(dependencyErrors.join('\n\n')); - hasError = true; - } -} - -if (!hasError) { - if (require.main === module) { - const args = process.argv.slice(2); - const acceptingNewGold = (args[0] === '--accept'); - - if (acceptingNewGold) { - for (let p of packagesToTest) { - acceptNewPackageGold(p); - } + if (acceptingNewGold) { + for (let p of packagesToTest) { + acceptNewPackageGold(p); } - } else { - describe('Comparing test packages to golds', () => { - for (let p of packagesToTest) { - runPackageGoldTest(p); - } - }); } +} else { + describe('Comparing test packages to golds', () => { + for (let p of packagesToTest) { + runPackageGoldTest(p); + } + }); } - -process.exitCode = hasError ? 1 : 0; diff --git a/packages/bazel/test/ngc-wrapped/BUILD.bazel b/packages/bazel/test/ngc-wrapped/BUILD.bazel index aaa5aa9cd8..afec3725fe 100644 --- a/packages/bazel/test/ngc-wrapped/BUILD.bazel +++ b/packages/bazel/test/ngc-wrapped/BUILD.bazel @@ -35,3 +35,19 @@ jasmine_node_test( "@build_bazel_rules_typescript//third_party/github.com/bazelbuild/bazel/src/main/protobuf:worker_protocol.proto", ], ) + +ts_library( + name = "flat_module_test_lib", + testonly = True, + srcs = ["flat_module_test.ts"], + tsconfig = ":tsconfig.json", + deps = [ + "//packages/private/testing", + ], +) + +jasmine_node_test( + name = "flat_module_test", + srcs = [":flat_module_test_lib"], + data = ["//packages/bazel/test/ngc-wrapped/flat_module"], +) diff --git a/packages/bazel/test/ngc-wrapped/flat_module/BUILD.bazel b/packages/bazel/test/ngc-wrapped/flat_module/BUILD.bazel new file mode 100644 index 0000000000..9dc3f8f2f6 --- /dev/null +++ b/packages/bazel/test/ngc-wrapped/flat_module/BUILD.bazel @@ -0,0 +1,16 @@ +load("//tools:defaults.bzl", "ng_module") + +package(default_visibility = ["//packages/bazel/test:__subpackages__"]) + +ng_module( + name = "flat_module", + srcs = [ + "export.ts", + "index.ts", + ], + module_name = "flat_module", + tsconfig = ":tsconfig.json", + deps = [ + "//packages/core", + ], +) diff --git a/packages/rollup.config.js b/packages/bazel/test/ngc-wrapped/flat_module/export.ts similarity index 66% rename from packages/rollup.config.js rename to packages/bazel/test/ngc-wrapped/flat_module/export.ts index af011b96c2..22c8f6fd65 100644 --- a/packages/rollup.config.js +++ b/packages/bazel/test/ngc-wrapped/flat_module/export.ts @@ -6,8 +6,4 @@ * found in the LICENSE file at https://angular.io/license */ -const sourcemaps = require('rollup-plugin-sourcemaps'); - -module.exports = { - plugins: [sourcemaps()] -}; +export const Test = 'This is a test export'; diff --git a/packages/compiler-cli/src/ngtsc/host/index.ts b/packages/bazel/test/ngc-wrapped/flat_module/index.ts similarity index 85% rename from packages/compiler-cli/src/ngtsc/host/index.ts rename to packages/bazel/test/ngc-wrapped/flat_module/index.ts index 93a06d7a93..9eec5fecb2 100644 --- a/packages/compiler-cli/src/ngtsc/host/index.ts +++ b/packages/bazel/test/ngc-wrapped/flat_module/index.ts @@ -6,4 +6,4 @@ * found in the LICENSE file at https://angular.io/license */ -export * from './src/reflection'; +export * from './export'; diff --git a/packages/bazel/test/ngc-wrapped/flat_module/tsconfig.json b/packages/bazel/test/ngc-wrapped/flat_module/tsconfig.json new file mode 100644 index 0000000000..dff8f94228 --- /dev/null +++ b/packages/bazel/test/ngc-wrapped/flat_module/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "skipLibCheck": true, + "types": [] + } +} diff --git a/packages/bazel/test/ngc-wrapped/flat_module_test.ts b/packages/bazel/test/ngc-wrapped/flat_module_test.ts new file mode 100644 index 0000000000..b7fdec9b79 --- /dev/null +++ b/packages/bazel/test/ngc-wrapped/flat_module_test.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; +import {existsSync, readFileSync} from 'fs'; +import {dirname, join} from 'path'; + +describe('flat_module ng_module', () => { + + let packageOutput: string; + let flatModuleOutFile: string; + + beforeAll(() => { + packageOutput = + dirname(require.resolve('angular/packages/bazel/test/ngc-wrapped/flat_module/index.js')); + flatModuleOutFile = join(packageOutput, 'flat_module.js'); + }); + + it('should have a flat module out file', + () => { expect(existsSync(flatModuleOutFile)).toBe(true); }); + + describe('flat module out file', () => { + + obsoleteInIvy('Ngtsc computes the AMD module name differently than NGC') + .it('should have a proper AMD module name', () => { + expect(readFileSync(flatModuleOutFile, 'utf8')) + .toContain(`define("flat_module/flat_module"`); + }); + + onlyInIvy('Ngtsc computes the AMD module name differently than NGC') + .it('should have a proper AMD module name', () => { + expect(readFileSync(flatModuleOutFile, 'utf8')).toContain(`define("flat_module"`); + }); + }); +}); diff --git a/packages/bazel/test/protractor-utils/BUILD.bazel b/packages/bazel/test/protractor-utils/BUILD.bazel new file mode 100644 index 0000000000..33c2d77f4f --- /dev/null +++ b/packages/bazel/test/protractor-utils/BUILD.bazel @@ -0,0 +1,29 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "nodejs_binary", "ts_library") + +ts_library( + name = "protractor_utils_tests_lib", + testonly = True, + srcs = ["index_test.ts"], + deps = [ + "//packages/bazel/src/protractor/utils", + ], +) + +nodejs_binary( + name = "fake-devserver", + testonly = True, + data = [ + "fake-devserver.js", + "@ngdeps//minimist", + ], + entry_point = "angular/packages/bazel/test/protractor-utils/fake-devserver.js", +) + +jasmine_node_test( + name = "protractor_utils_tests", + size = "small", + srcs = [":protractor_utils_tests_lib"], + data = [ + ":fake-devserver", + ], +) diff --git a/packages/bazel/test/protractor-utils/fake-devserver.js b/packages/bazel/test/protractor-utils/fake-devserver.js new file mode 100644 index 0000000000..34e84d3a07 --- /dev/null +++ b/packages/bazel/test/protractor-utils/fake-devserver.js @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const http = require('http'); +const minimist = require('minimist'); + +const {port} = minimist(process.argv); +const server = new http.Server(); + +// Basic request handler so that it could respond to fake requests. +server.on('request', (req, res) => { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Running'); +}); + +server.listen(port); + +console.info('Server running on port:', port); diff --git a/packages/bazel/test/protractor-utils/index_test.ts b/packages/bazel/test/protractor-utils/index_test.ts new file mode 100644 index 0000000000..1bc0d97731 --- /dev/null +++ b/packages/bazel/test/protractor-utils/index_test.ts @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {runServer} from '../../src/protractor/utils'; + +describe('Bazel protractor utils', () => { + + it('should be able to start devserver', async() => { + // Test will automatically time out if the server couldn't be launched as expected. + await runServer('angular', 'packages/bazel/test/protractor-utils/fake-devserver', '--port', []); + }); +}); diff --git a/packages/bazel/yarn.lock b/packages/bazel/yarn.lock index 4ebbbbcac7..85efc6631c 100644 --- a/packages/bazel/yarn.lock +++ b/packages/bazel/yarn.lock @@ -32,7 +32,18 @@ rxjs "6.3.3" source-map "0.7.3" -"@angular-devkit/schematics@7.1.2", "@angular-devkit/schematics@^7.0.4": +"@angular-devkit/core@7.3.0-rc.0": + version "7.3.0-rc.0" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.0-rc.0.tgz#e555a08d85259855ff1946f4268936a1aadd38f1" + integrity sha512-0vHuw1gIMh79tI+gRxCMn89U1DnjmBnqybVktaf9YXi9xshxd+nnFb31v7n1tJQVQiQNzGxk3hviFnkzxLZipw== + dependencies: + ajv "6.7.0" + chokidar "2.0.4" + fast-json-stable-stringify "2.0.0" + rxjs "6.3.3" + source-map "0.7.3" + +"@angular-devkit/schematics@7.1.2": version "7.1.2" resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.1.2.tgz#847639044417d044bf1bc87f64508a0c3f99fae2" integrity sha512-NFhHLYWf9gpGQm0s19lq+nAw3CZ0udBpoBLzCm8Crlmu6+7aAXgw7Fv5P4ukWJ/e1m7NDGVids+B6kBGXaY6Ig== @@ -40,15 +51,70 @@ "@angular-devkit/core" "7.1.2" rxjs "6.3.3" -"@bazel/typescript@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.21.0.tgz#41c304f77a42c6a016280d0f4c20e0749c3f4b2a" - integrity sha512-ASXj0RFybmqoa3LwqkTU3gNkX9bY9wL/VDNo5hlp9pynYWl4RMpe9V3m/qDIdtSuLJ+qD+Z3FKT/OcpWQHMlYA== +"@angular-devkit/schematics@^7.3.0-rc.0": + version "7.3.0-rc.0" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-7.3.0-rc.0.tgz#9f1e1f6942da36b12c81241398ed6ca8b2e65875" + integrity sha512-noqcQIOvah2G126DTFKY5Kiga8UwI9cKzyhQdNlf+8hAZpnWwTURItQ5xuMJg/XfRQLUSg9gWS2h1cI9AD7mxQ== dependencies: + "@angular-devkit/core" "7.3.0-rc.0" + rxjs "6.3.3" + +"@bazel/typescript@^0.23.2": + version "0.23.2" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.23.2.tgz#a3ff199880855259d84216cb41644c1d9a0fad14" + integrity sha512-GrTyDW6Fvp/rgnxZGYampB5/QmDWvxtLEtUyMCPa/QXFR1OVxaMWeHxxuFEcES2UKJegqBDKAA8IzX21x4UbEw== + dependencies: + jasmine-core "2.8.0" protobufjs "5.0.3" + semver "5.6.0" source-map-support "0.5.9" tsutils "2.27.2" +"@microsoft/api-extractor@^7.0.17": + version "7.0.17" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.0.17.tgz#fadb376908a57144ba4a8eb18787d6337bfe6b56" + integrity sha512-Mm+6x5/1HRAKno0vow4DyMKcVtB+b6wehMUx21huN+FSpfxID5kAEqKw9OR9XCp7YBXjiISqFBlY4dVYq/bdCw== + dependencies: + "@microsoft/node-core-library" "3.10.0" + "@microsoft/ts-command-line" "4.2.3" + "@microsoft/tsdoc" "0.12.5" + "@types/node" "8.5.8" + "@types/z-schema" "3.16.31" + colors "~1.2.1" + lodash "~4.17.5" + resolve "1.8.1" + typescript "~3.1.6" + z-schema "~3.18.3" + +"@microsoft/node-core-library@3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.10.0.tgz#70e089534d8e20f6a0f9c7a4a12a6aeafd6a1ddb" + integrity sha512-1SbU+XNYAabhV9noGXHtsUVPc5ELV+oEuJQtZQoCncbOd6WAMeTgB1xFwh96hmdEXyKQyML/pnByiKocmh/nbQ== + dependencies: + "@types/fs-extra" "5.0.4" + "@types/jju" "~1.4.0" + "@types/node" "8.5.8" + "@types/z-schema" "3.16.31" + colors "~1.2.1" + fs-extra "~7.0.1" + jju "~1.4.0" + z-schema "~3.18.3" + +"@microsoft/ts-command-line@4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/ts-command-line/-/ts-command-line-4.2.3.tgz#20d6a1684148b9fc0df25ee7335c3bb227d47d4f" + integrity sha512-SIs4q7RcG7efBbh5Ffrf6V4jVLxWihD4NDRY3+gPiOG8CYawBzE22tTEloZ1yj/FBvBZQkQ0GYwXoPhn6ElYXA== + dependencies: + "@types/argparse" "1.0.33" + "@types/node" "8.5.8" + argparse "~1.0.9" + colors "~1.2.1" + +"@microsoft/tsdoc@0.12.5": + version "0.12.5" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.5.tgz#c448a38902ccb5601c1b2ef3b1a105012ef7712c" + integrity sha512-xEAyvLXo4Cter/b0EMCWUZTgXOfLOPJ/Xr52WdjVclPx9eDmNTGFtZl8Pn/nqSnZsQBNcHL0eHk/YyRyyXXpiQ== + "@schematics/angular@^7.0.4": version "7.1.2" resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-7.1.2.tgz#b3eefbc81d12b0b53816896f6172eb613885826c" @@ -58,11 +124,43 @@ "@angular-devkit/schematics" "7.1.2" typescript "3.1.6" +"@types/argparse@1.0.33": + version "1.0.33" + resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.33.tgz#2728669427cdd74a99e53c9f457ca2866a37c52d" + integrity sha512-VQgHxyPMTj3hIlq9SY1mctqx+Jj8kpQfoLvDlVSDNOyuYs8JYfkuY3OW/4+dO657yPmNhHpePRx0/Tje5ImNVQ== + +"@types/fs-extra@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.4.tgz#b971134d162cc0497d221adde3dbb67502225599" + integrity sha512-DsknoBvD8s+RFfSGjmERJ7ZOP1HI0UZRA3FSI+Zakhrc/Gy26YQsLI+m5V5DHxroHRJqCDLKJp7Hixn8zyaF7g== + dependencies: + "@types/node" "*" + +"@types/jju@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@types/jju/-/jju-1.4.0.tgz#ee074af79540c0e187426f46f12acbe8f6c31232" + integrity sha512-s6l49zLzFiXYHaTXbA+FNcDRo8ufZgC2/T5/jH+Wfr+ZV2tYbrBpEpN9oPkXXfug+y7pTZFkdeyQ0L/88Z34JA== + +"@types/node@*": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== + "@types/node@6.0.84": version "6.0.84" resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.84.tgz#193ffe5a9f42864d425ffd9739d95b753c6a1eab" integrity sha512-1SvEazClhUBRNroJM3oB3xf3u2r6xGmHDGbdigqNPHvNKLl8/BtATgO9eC04ZLuovpSh0B20BF1QJxdi+qmTlg== +"@types/node@8.5.8": + version "8.5.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.8.tgz#92509422653f10e9c0ac18d87e0610b39f9821c7" + integrity sha512-8KmlRxwbKZfjUHFIt3q8TF5S2B+/E5BaAoo/3mgc5h6FJzqxXkCK/VMetO+IRDtwtU6HUvovHMBn+XRj7SV9Qg== + +"@types/z-schema@3.16.31": + version "3.16.31" + resolved "https://registry.yarnpkg.com/@types/z-schema/-/z-schema-3.16.31.tgz#2eb1d00a5e4ec3fa58c76afde12e182b66dc5c1c" + integrity sha1-LrHQCl5Ow/pYx2r94S4YK2bcXBw= + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -78,6 +176,16 @@ ajv@6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.7.0.tgz#e3ce7bb372d6577bb1839f1dfdfcbf5ad2948d96" + integrity sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -109,6 +217,13 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" +argparse@~1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -288,11 +403,21 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" +colors@~1.2.1: + version "1.2.5" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc" + integrity sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg== + colour@~0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g= +commander@^2.7.1: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -372,11 +497,6 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -diff@^3.2.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -451,6 +571,15 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +fs-extra@~7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -510,7 +639,7 @@ glob@^7.0.0, glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -graceful-fs@^4.1.11: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.15" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== @@ -730,18 +859,28 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -jasmine-diff@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/jasmine-diff/-/jasmine-diff-0.1.3.tgz#93ccc2dcc41028c5ddd4606558074839f2deeaa8" - integrity sha1-k8zC3MQQKMXd1GBlWAdIOfLe6qg= - dependencies: - diff "^3.2.0" +jasmine-core@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" + integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= + +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha1-o6vicYryQaKykE+EpiWXDzia4yo= json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -778,6 +917,21 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= +lodash.get@^4.0.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.isequal@^4.0.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + +lodash@~4.17.5: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + long@~3: version "3.2.0" resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" @@ -1133,7 +1287,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6: +resolve@1.8.1, resolve@^1.1.6: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== @@ -1181,7 +1335,7 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -semver@^5.3.0, semver@^5.6.0: +semver@5.6.0, semver@^5.3.0, semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -1266,7 +1420,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@0.5.9, source-map-support@^0.5.0: +source-map-support@0.5.9: version "0.5.9" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== @@ -1279,7 +1433,7 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@0.7.3: +source-map@0.7.3, source-map@^0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== @@ -1301,6 +1455,11 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -1390,16 +1549,14 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -tsickle@0.32.1: - version "0.32.1" - resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.32.1.tgz#f16e94ba80b32fc9ebe320dc94fbc2ca7f3521a5" - integrity sha512-JW9j+W0SaMSZGejIFZBk0AiPfnhljK3oLx5SaqxrJhjlvzFyPml5zqG1/PuScUj6yTe1muEqwk5CnDK0cOZmKw== +tsickle@0.34.0: + version "0.34.0" + resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.34.0.tgz#10187fa6401a288a65efb93a60bf28b2ff95f90b" + integrity sha512-O3wCPRtL18Hc/ZBnaiKwmmjVzeCWTOTpsi0btfC7FWL3RnXpxLPxD6hoJ0QEXuSfG/0QJk+MWNjqT9N6fOyyIg== dependencies: - jasmine-diff "^0.1.3" minimist "^1.2.0" mkdirp "^0.5.1" - source-map "^0.6.0" - source-map-support "^0.5.0" + source-map "^0.7.3" tslib@^1.8.1, tslib@^1.9.0: version "1.9.3" @@ -1413,7 +1570,7 @@ tsutils@2.27.2: dependencies: tslib "^1.8.1" -typescript@3.1.6: +typescript@3.1.6, typescript@~3.1.6: version "3.1.6" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68" integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA== @@ -1428,6 +1585,11 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -1463,6 +1625,11 @@ util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +validator@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-8.2.0.tgz#3c1237290e37092355344fef78c231249dab77b9" + integrity sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA== + wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -1510,3 +1677,14 @@ yargs@^3.10.0: string-width "^1.0.1" window-size "^0.1.4" y18n "^3.2.0" + +z-schema@~3.18.3: + version "3.18.4" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-3.18.4.tgz#ea8132b279533ee60be2485a02f7e3e42541a9a2" + integrity sha512-DUOKC/IhbkdLKKiV89gw9DUauTV8U/8yJl1sjf6MtDmzevLKOF2duNJ495S3MFVjqZarr+qNGCPbkg4mu4PpLw== + dependencies: + lodash.get "^4.0.0" + lodash.isequal "^4.0.0" + validator "^8.0.0" + optionalDependencies: + commander "^2.7.1" diff --git a/packages/benchpress/BUILD.bazel b/packages/benchpress/BUILD.bazel index 0ed71573d5..188f8910de 100644 --- a/packages/benchpress/BUILD.bazel +++ b/packages/benchpress/BUILD.bazel @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "npm_package", "ts_library") ts_library( name = "benchpress", @@ -10,7 +10,6 @@ ts_library( "src/**/*.ts", ], ), - module_name = "@angular/benchpress", deps = [ "//packages:types", "//packages/core", @@ -18,3 +17,17 @@ ts_library( "@ngdeps//reflect-metadata", ], ) + +npm_package( + name = "npm_package", + srcs = [ + "README.md", + "package.json", + ], + # Do not add more to this list. + # Dependencies on the full npm_package cause long re-builds. + visibility = ["//visibility:private"], + deps = [ + ":benchpress", + ], +) diff --git a/packages/benchpress/DEVELOPER.md b/packages/benchpress/DEVELOPER.md new file mode 100644 index 0000000000..048484e998 --- /dev/null +++ b/packages/benchpress/DEVELOPER.md @@ -0,0 +1,11 @@ +## Publishing + +The `@angular/benchpress` package is not published together with the framework and therefore +the `npm_package` Bazel target does not have the `release-with-framework` tag. + +In order to publish this package manually, one can run the following command after bumping +the `version` in the `package.json` of this package: + +``` +yarn bazel run //packages/benchpress:npm_package.publish +``` \ No newline at end of file diff --git a/packages/benchpress/docs/marked_timeline.png b/packages/benchpress/docs/marked_timeline.png index 6bec9d083c..376bd394c5 100644 Binary files a/packages/benchpress/docs/marked_timeline.png and b/packages/benchpress/docs/marked_timeline.png differ diff --git a/packages/benchpress/publish.sh b/packages/benchpress/publish.sh deleted file mode 100755 index 2b17befcf5..0000000000 --- a/packages/benchpress/publish.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -cd $(dirname $0)/../../.. -ROOTDIR=$(pwd) -SRCDIR=${ROOTDIR}/packages/benchpress -DESTDIR=${ROOTDIR}/dist/packages-dist/benchpress - -rm -fr ${DESTDIR} - -echo "====== BUILDING... =====" -./build.sh --packages=core,benchpress --bundle=false - -echo "====== PUBLISHING: ${DESTDIR} =====" -npm publish ${DESTDIR} --access public diff --git a/packages/benchpress/src/common_options.ts b/packages/benchpress/src/common_options.ts index 12125c962b..15e63e0314 100644 --- a/packages/benchpress/src/common_options.ts +++ b/packages/benchpress/src/common_options.ts @@ -26,6 +26,7 @@ export class Options { static RECEIVED_DATA = new InjectionToken('Options.receivedData'); static REQUEST_COUNT = new InjectionToken('Options.requestCount'); static CAPTURE_FRAMES = new InjectionToken('Options.frameCapture'); + static RAW_PERFLOG_PATH = new InjectionToken('Options.rawPerflogPath'); static DEFAULT_PROVIDERS = [ {provide: Options.DEFAULT_DESCRIPTION, useValue: {}}, {provide: Options.SAMPLE_DESCRIPTION, useValue: {}}, @@ -36,7 +37,8 @@ export class Options { {provide: Options.RECEIVED_DATA, useValue: false}, {provide: Options.REQUEST_COUNT, useValue: false}, {provide: Options.CAPTURE_FRAMES, useValue: false}, - {provide: Options.WRITE_FILE, useValue: writeFile} + {provide: Options.WRITE_FILE, useValue: writeFile}, + {provide: Options.RAW_PERFLOG_PATH, useValue: null} ]; } diff --git a/packages/benchpress/src/webdriver/chrome_driver_extension.ts b/packages/benchpress/src/webdriver/chrome_driver_extension.ts index 066958afd0..9dba35fb28 100644 --- a/packages/benchpress/src/webdriver/chrome_driver_extension.ts +++ b/packages/benchpress/src/webdriver/chrome_driver_extension.ts @@ -7,6 +7,7 @@ */ import {Inject, Injectable, StaticProvider} from '@angular/core'; +import * as fs from 'fs'; import {Options} from '../common_options'; import {WebDriverAdapter} from '../web_driver_adapter'; @@ -23,15 +24,19 @@ import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_e export class ChromeDriverExtension extends WebDriverExtension { static PROVIDERS = [{ provide: ChromeDriverExtension, - deps: [WebDriverAdapter, Options.USER_AGENT] + deps: [WebDriverAdapter, Options.USER_AGENT, Options.RAW_PERFLOG_PATH] }]; private _majorChromeVersion: number; private _firstRun = true; + private _rawPerflogPath: string|null; - constructor(private _driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string) { + constructor( + private driver: WebDriverAdapter, @Inject(Options.USER_AGENT) userAgent: string, + @Inject(Options.RAW_PERFLOG_PATH) rawPerflogPath: string|null) { super(); this._majorChromeVersion = this._parseChromeVersion(userAgent); + this._rawPerflogPath = rawPerflogPath; } private _parseChromeVersion(userAgent: string): number { @@ -49,16 +54,16 @@ export class ChromeDriverExtension extends WebDriverExtension { return parseInt(v, 10); } - gc() { return this._driver.executeScript('window.gc()'); } + gc() { return this.driver.executeScript('window.gc()'); } async timeBegin(name: string): Promise { if (this._firstRun) { this._firstRun = false; // Before the first run, read out the existing performance logs // so that the chrome buffer does not fill up. - await this._driver.logs('performance'); + await this.driver.logs('performance'); } - return this._driver.executeScript(`performance.mark('${name}-bpstart');`); + return this.driver.executeScript(`performance.mark('${name}-bpstart');`); } timeEnd(name: string, restartName: string|null = null): Promise { @@ -66,7 +71,7 @@ export class ChromeDriverExtension extends WebDriverExtension { if (restartName) { script += `performance.mark('${restartName}-bpstart');`; } - return this._driver.executeScript(script); + return this.driver.executeScript(script); } // See [Chrome Trace Event @@ -74,8 +79,8 @@ export class ChromeDriverExtension extends WebDriverExtension { readPerfLog(): Promise { // TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098 // Need to execute at least one command so that the browser logs can be read out! - return this._driver.executeScript('1+1') - .then((_) => this._driver.logs('performance')) + return this.driver.executeScript('1+1') + .then((_) => this.driver.logs('performance')) .then((entries) => { const events: PerfLogEvent[] = []; entries.forEach((entry: any) => { @@ -87,6 +92,10 @@ export class ChromeDriverExtension extends WebDriverExtension { throw new Error('The DevTools trace buffer filled during the test!'); } }); + + if (this._rawPerflogPath && events.length) { + fs.appendFileSync(this._rawPerflogPath, JSON.stringify(events)); + } return this._convertPerfRecordsToEvents(events); }); } diff --git a/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts b/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts index dbe3f589b9..988352345c 100644 --- a/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts +++ b/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts @@ -47,7 +47,8 @@ import {TraceEventFactory} from '../trace_event_factory'; provide: WebDriverAdapter, useValue: new MockDriverAdapter(log, perfRecords, messageMethod) }, - {provide: Options.USER_AGENT, useValue: userAgent} + {provide: Options.USER_AGENT, useValue: userAgent}, + {provide: Options.RAW_PERFLOG_PATH, useValue: null} ]) .get(ChromeDriverExtension); return extension; diff --git a/packages/common/BUILD.bazel b/packages/common/BUILD.bazel index 2200e2efd3..a1b53fc202 100644 --- a/packages/common/BUILD.bazel +++ b/packages/common/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/common", deps = [ "//packages/core", "@rxjs", @@ -34,6 +33,7 @@ ng_package( # Dependencies on the full npm_package cause long re-builds. visibility = [ "//packages/bazel/test/ng_package:__pkg__", + "//packages/compiler-cli/integrationtest:__pkg__", "//packages/compiler-cli/test:__pkg__", "//packages/compiler-cli/test/diagnostics:__pkg__", "//packages/compiler-cli/test/ngcc:__pkg__", diff --git a/packages/common/http/BUILD.bazel b/packages/common/http/BUILD.bazel index 0e5a0f002d..745c07801d 100644 --- a/packages/common/http/BUILD.bazel +++ b/packages/common/http/BUILD.bazel @@ -12,7 +12,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/common/http", deps = [ "//packages/common", "//packages/core", diff --git a/packages/common/http/rollup.config.js b/packages/common/http/rollup.config.js deleted file mode 100644 index c2a589b01f..0000000000 --- a/packages/common/http/rollup.config.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const globals = { - '@angular/core': 'ng.core', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/common': 'ng.common', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../../dist/packages-dist/common/fesm5/http.js', - dest: '../../../dist/packages-dist/common/bundles/common-http.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/common/http'}, - moduleName: 'ng.common.http', - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/common/http/src/headers.ts b/packages/common/http/src/headers.ts index d11d3658cb..6435757a6b 100755 --- a/packages/common/http/src/headers.ts +++ b/packages/common/http/src/headers.ts @@ -13,7 +13,8 @@ interface Update { } /** - * Immutable set of Http headers, with lazy parsing. + * `HttpHeaders` class represents the header configuration options for an HTTP request. + * Instances should be assumed immutable with lazy parsing. * * Http 头的不可变集合,惰性解析。 * @@ -52,6 +53,8 @@ export class HttpHeaders { */ private lazyUpdate: Update[]|null = null; + /** Constructs a new HTTP header object with the given values.*/ + constructor(headers?: string|{[name: string]: string | string[]}) { if (!headers) { this.headers = new Map(); @@ -92,9 +95,18 @@ export class HttpHeaders { } /** - * Checks for existence of header by given name. + * Checks for existence of a header by a given name. * * 检查是否存在指定名称的头。 + * + * @param name The header name to check for existence. + * + * 要检查是否存在的头名称 + * + * @returns Whether the header exits. + * + * 这个头是否存在。 + * */ has(name: string): boolean { this.init(); @@ -103,9 +115,18 @@ export class HttpHeaders { } /** - * Returns first header that matches given name. + * Returns the first header value that matches a given name. * * 返回匹配指定名称的第一个头的值。 + * + * @param name The header name to retrieve. + * + * 要取的头名称 + * + * @returns A string if the header exists, null otherwise + * + * 如果头存在则返回一个字符串,否则返回 null + * */ get(name: string): string|null { this.init(); @@ -115,9 +136,13 @@ export class HttpHeaders { } /** - * Returns the names of the headers + * Returns the names of the headers. * - * 返回头中所有的名称。 + * 返回所有的头名称。 + * + * @returns A list of header names. + * + * 一个头名称列表。 */ keys(): string[] { this.init(); @@ -126,9 +151,18 @@ export class HttpHeaders { } /** - * Returns list of header values for a given name. + * Returns a list of header values for a given header name. * * 返回头中具有指定名称的值的列表。 + * + * @param name The header name from which to retrieve the values. + * + * 准备获取值的头名称 + * + * @returns A string of values if the header exists, null otherwise. + * + * 如果头存在则返回一个字符串数组,否则返回 null。 + * */ getAll(name: string): string[]|null { this.init(); @@ -136,14 +170,38 @@ export class HttpHeaders { return this.headers.get(name.toLowerCase()) || null; } + /** + * Appends a new header value to the existing set of + * header values. + * + * @param name The header name for which to append the values. + * + * @returns A clone of the HTTP header object with the value appended. + */ + append(name: string, value: string|string[]): HttpHeaders { return this.clone({name, value, op: 'a'}); } - + /** + * Sets a header value for a given name. If the header name already exists, + * its value is replaced with the given value. + * + * @param name The header name. + * @param value Provides the value to set or overide for a given name. + * + * @returns A clone of the HTTP header object with the newly set header value. + */ set(name: string, value: string|string[]): HttpHeaders { return this.clone({name, value, op: 's'}); } - + /** + * Deletes all header values for a given name. + * + * @param name The header name. + * @param value The header values to delete for a given name. + * + * @returns A clone of the HTTP header object. + */ delete (name: string, value?: string|string[]): HttpHeaders { return this.clone({name, value, op: 'd'}); } diff --git a/packages/common/http/src/interceptor.ts b/packages/common/http/src/interceptor.ts index f1f1c51c32..6416fce0e4 100644 --- a/packages/common/http/src/interceptor.ts +++ b/packages/common/http/src/interceptor.ts @@ -14,48 +14,59 @@ import {HttpRequest} from './request'; import {HttpEvent} from './response'; /** - * Intercepts `HttpRequest` and handles them. + * Intercepts `HttpRequest` or `HttpResponse` and handles them. * * 拦截 `HttpRequest` 并处理它们。 * - * Most interceptors will transform the outgoing request before passing it to the + * Most interceptors transform the outgoing request before passing it to the * next interceptor in the chain, by calling `next.handle(transformedReq)`. + * An interceptor may transform the + * response event stream as well, by applying additional RxJS operators on the stream + * returned by `next.handle()`. * * 大多数拦截器都会在外发的请求由 `next.handle(transformedReq)` 发给拦截器链中的下一个拦截器之前,对该请求进行转换。 + * 拦截器还可以通过为 `next.handle()` 返回的流添加额外的 RxJS 操作符,来对响应事件流进行转换。 * - * In rare cases, interceptors may wish to completely handle a request themselves, - * and not delegate to the remainder of the chain. This behavior is allowed. + * More rarely, an interceptor may handle the request entirely, + * and compose a new event stream instead of invoking `next.handle()`. This is an + * acceptable behavior, but keep in mind that further interceptors will be skipped entirely. * - * 极少量情况下,拦截器也可能希望自己完全处理一个请求,而不再委托给拦截器链中的其它部分。这种行为也是允许的。 + * 极少数情况下,拦截器也可以自己完全处理一个请求,并且组合出新的事件流来而不必调用 `next.handle()`。 + * 这也是允许的,不过要时刻记住,这将会完全跳过所有后继拦截器。 + * + * It is also rare but valid for an interceptor to return multiple responses on the + * event stream for a single request. + * + * 另一种同样罕见但是有用的拦截器,会为单个请求在事件流上给出多个响应对象。 * * @publicApi + * + * @see [HTTP Guide](guide/http#intercepting-requests-and-responses) + * + * [HTTP 一章](guide/http#intercepting-requests-and-responses) + * + * @usageNotes + * + * To use the same instance of `HttpInterceptors` for the entire app, import the `HttpClientModule` + * only in your `AppModule`, and add the interceptors to the root application injector . + * If you import `HttpClientModule` multiple times across different modules (for example, in lazy + * loading modules), each import creates a new copy of the `HttpClientModule`, which overwrites the interceptors + * provided in the root module. + * + * 要想在整个应用中使用 `HttpInterceptors` 的同一个实例,就只能在 `AppModule` 模块中导入 `HttpClientModule`,并且把拦截器都添加到应用的根注入器中。 + * 如果你在不同的模块中多次导入 `HttpClientModule`,则每次导入都会创建 `HttpClientModule` 的一个新复本,它将会覆盖根模块上提供的那些拦截器。 + * */ export interface HttpInterceptor { /** - * Intercept an outgoing `HttpRequest` and optionally transform it or the - * response. + * * **req**: The outgoing request to handle * - * 拦截外发的 `HttpRequest`,并(可选的)转换它或转换响应对象。 + * **req**:要处理的外发请求 * - * Typically an interceptor will transform the outgoing request before returning - * `next.handle(transformedReq)`. An interceptor may choose to transform the - * response event stream as well, by applying additional Rx operators on the stream - * returned by `next.handle()`. + * * **next**: The next interceptor in the chain, or the backend if no interceptors in the chain. * - * 通常,拦截器将会在返回 `next.handle(transformedReq)` 之前转换外发请求。 - * 选择器也可以选择通过在 `next.handle()` 返回的流上应用 Rx 操作符(operator)来转换响应事件流。 + * **next**:拦截器链中的下一个拦截器,如果链中没有其它拦截器了,则为后端 HTTP 调用。 * - * More rarely, an interceptor may choose to completely handle the request itself, - * and compose a new event stream instead of invoking `next.handle()`. This is - * acceptable behavior, but keep in mind further interceptors will be skipped entirely. - * - * 更罕见的情况下,拦截器可以选择完全由自己处理该请求,并合成新的事件流而不是调用 `next.handle()`。 - * 这种方式也是可以接受的,不过要记住这样做会完全忽略所有的后续拦截器。 - * - * It is also rare but valid for an interceptor to return multiple responses on the - * event stream for a single request. - * - * 另一种同样罕见但是有用的拦截器,会为单个请求在事件流上给出多个响应对象。 */ intercept(req: HttpRequest, next: HttpHandler): Observable>; } diff --git a/packages/common/http/testing/BUILD.bazel b/packages/common/http/testing/BUILD.bazel index d206a79412..a851ea06f7 100644 --- a/packages/common/http/testing/BUILD.bazel +++ b/packages/common/http/testing/BUILD.bazel @@ -12,7 +12,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/common/http/testing", deps = [ "//packages/common/http", "//packages/core", diff --git a/packages/common/http/testing/rollup.config.js b/packages/common/http/testing/rollup.config.js deleted file mode 100644 index 50ab5a54ee..0000000000 --- a/packages/common/http/testing/rollup.config.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/common': 'ng.common', - '@angular/common/http': 'ng.common.http', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../../../dist/packages-dist/common/fesm5/http/testing.js', - dest: '../../../../dist/packages-dist/common/bundles/common-http-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/common/http/testing'}, - moduleName: 'ng.common.http.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/common/locales/BUILD.bazel b/packages/common/locales/BUILD.bazel index 07be1c9fc1..1ab81ae5b1 100644 --- a/packages/common/locales/BUILD.bazel +++ b/packages/common/locales/BUILD.bazel @@ -8,7 +8,6 @@ ts_library( ["**/*.ts"], exclude = ["closure-locale.ts"], ), - module_name = "@angular/common/locales", ) npm_package( diff --git a/packages/common/rollup.config.js b/packages/common/rollup.config.js deleted file mode 100644 index ff83e4dbdf..0000000000 --- a/packages/common/rollup.config.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../dist/packages-dist/common/fesm5/common.js', - dest: '../../dist/packages-dist/common/bundles/common.umd.js', - format: 'umd', - exports: 'named', - moduleName: 'ng.common', - amd: {id: '@angular/common'}, - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/common/src/directives/ng_for_of.ts b/packages/common/src/directives/ng_for_of.ts index 010f24de61..7915fd1244 100644 --- a/packages/common/src/directives/ng_for_of.ts +++ b/packages/common/src/directives/ng_for_of.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectorRef, Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef, forwardRef, isDevMode} from '@angular/core'; +import {Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef, forwardRef, isDevMode} from '@angular/core'; /** * @publicApi @@ -26,19 +26,65 @@ export class NgForOfContext { } /** - * The `NgForOf` directive instantiates a template once per item from an iterable. The context - * for each instantiated template inherits from the outer context with the given loop variable - * set to the current item from the iterable. + * A [structural directive](guide/structural-directives) that renders + * a template for each item in a collection. + * The directive is placed on an element, which becomes the parent + * of the cloned templates. + * + * The `ngForOf` directive is generally used in the + * [shorthand form](guide/structural-directives#the-asterisk--prefix) `*ngFor`. + * In this form, the template to be rendered for each iteration is the content + * of an anchor element containing the directive. + * + * The following example shows the shorthand syntax with some options, + * contained in an `
  • ` element. + * + * ``` + *
  • ...
  • + * ``` + * + * The shorthand form expands into a long form that uses the `ngForOf` selector + * on an `` element. + * The content of the `` element is the `
  • ` element that held the + * short-form directive. + * + * Here is the expanded version of the short-form example. + * + * ``` + * + *
  • ...
  • + *
    + * ``` + * + * Angular automatically expands the shorthand syntax as it compiles the template. + * The context for each embedded view is logically merged to the current component + * context according to its lexical position. + * + * When using the shorthand syntax, Angular allows only [one structural directive + * on an element](guide/structural-directives#one-structural-directive-per-host-element). + * If you want to iterate conditionally, for example, + * put the `*ngIf` on a container element that wraps the `*ngFor` element. + * For futher discussion, see + * [Structural Directives](guide/structural-directives#one-per-element). * * `NgForOf` 指令会为可迭代对象中的每一个条目实例化一个模板。实例化时的上下文环境来自其外部环境,它以当前正在迭代的条目作为循环变量。 * * @usageNotes * - * ### Local Variables + * ### Local variables * - * ### 局部变量 + * `NgForOf` provides exported values that can be aliased to local variables. + * For example: * - * `NgForOf` provides several exported values that can be aliased to local variables: + * ### 局部变量 + * + * ``` + *
  • + * {{i}}/{{users.length}}. {{user}} default + *
  • + * ``` + * + * The following exported values can be aliased to local variables: * * `NgForOf` 导出了一系列值,可以指定别名后作为局部变量使用: * @@ -73,13 +119,7 @@ export class NgForOfContext { * * `odd: boolean`:如果当前条目在可迭代对象中的索引号为奇数则为 `true`。 * - * ``` - *
  • - * {{i}}/{{users.length}}. {{user}} default - *
  • - * ``` - * - * ### Change Propagation + * ### Change propagation * * ### 变更的传导机制 * @@ -99,74 +139,68 @@ export class NgForOfContext { * * 当条目集被重新排序时,他们对应的模板实例也会在 DOM 中重新排序。 * - * * Otherwise, the DOM element for that item will remain the same. - * - * 否则,条目对应的 DOM 元素就会保持不变。 - * * Angular uses object identity to track insertions and deletions within the iterator and reproduce * those changes in the DOM. This has important implications for animations and any stateful - * controls (such as `` elements which accept user input) that are present. Inserted rows can + * controls that are present, such as `` elements that accept user input. Inserted rows can * be animated in, deleted rows can be animated out, and unchanged rows retain any unsaved state * such as user input. + * For more on animations, see [Transitions and Triggers](guide/transition-and-triggers). * * Angular 使用对象标识符(对象引用)来跟踪迭代器中的添加和删除操作,并把它们同步到 DOM 中。 * 这对于动画和有状态的控件(如用来接收用户输入的 `` 元素)具有重要意义。添加的行可以带着动画效果进来,删除的行也可以带着动画效果离开。 * 而未变化的行则会保留那些尚未保存的状态,比如用户的输入。 * - * It is possible for the identities of elements in the iterator to change while the data does not. - * This can happen, for example, if the iterator produced from an RPC to the server, and that - * RPC is re-run. Even if the data hasn't changed, the second response will produce objects with - * different identities, and Angular will tear down the entire DOM and rebuild it (as if all old - * elements were deleted and all new elements inserted). This is an expensive operation and should - * be avoided if possible. + * The identities of elements in the iterator can change while the data does not. + * This can happen, for example, if the iterator is produced from an RPC to the server, and that + * RPC is re-run. Even if the data hasn't changed, the second response produces objects with + * different identities, and Angular must tear down the entire DOM and rebuild it (as if all old + * elements were deleted and all new elements inserted). * * 即使数据没有变化,迭代器中的元素标识符也可能会发生变化。比如,如果迭代器处理的目标是通过 RPC 从服务器取来的, * 而 RPC 又重新执行了一次。那么即使数据没有变化,第二次的响应体还是会生成一些具有不同标识符的对象。Angular 将会清除整个 DOM, * 并重建它(就仿佛把所有老的元素都删除,并插入所有新元素)。这是很昂贵的操作,应该尽力避免。 * - * To customize the default tracking algorithm, `NgForOf` supports `trackBy` option. - * `trackBy` takes a function which has two arguments: `index` and `item`. + * To avoid this expensive operation, you can customize the default tracking algorithm. + * by supplying the `trackBy` option to `NgForOf`. + * `trackBy` takes a function that has two arguments: `index` and `item`. * If `trackBy` is given, Angular tracks changes by the return value of the function. * * 要想自定义默认的跟踪算法,`NgForOf` 支持 `trackBy` 选项。 * `trackBy` 接受一个带两个参数(`index` 和 `item`)的函数。 * 如果给出了 `trackBy`,Angular 就会使用该函数的返回值来跟踪变化。 * - * ### Syntax - * - * ### 语法 - * - * - `
  • ...
  • ` - * - * With `` element: - * - * 具有一个 `` 元素: - * - * ``` - * - *
  • ...
  • - *
    - * ``` - * - * ### Example - * - * ### 范例 - * - * See a [live demo](http://plnkr.co/edit/KVuXxDp0qinGDyo307QW?p=preview) for a more detailed - * example. - * - * 参见[在线例子](http://plnkr.co/edit/KVuXxDp0qinGDyo307QW?p=preview)了解详情。 - * + * @see [Structural Directives](guide/structural-directives) * @ngModule CommonModule * @publicApi */ @Directive({selector: '[ngFor][ngForOf]'}) export class NgForOf implements DoCheck { + /** + * The value of the iterable expression, which can be used as a + * [template input variable](guide/structural-directives#template-input-variable). + */ @Input() set ngForOf(ngForOf: NgIterable) { this._ngForOf = ngForOf; this._ngForOfDirty = true; } + /** + * A function that defines how to track changes for items in the iterable. + * + * When items are added, moved, or removed in the iterable, + * the directive must re-render the appropriate DOM nodes. + * To minimize churn in the DOM, only nodes that have changed + * are re-rendered. + * + * By default, the change detector assumes that + * the object instance identifies the node in the iterable. + * When this function is supplied, the directive uses + * the result of calling this function to identify the item node, + * rather than the identity of the object itself. + * + * The function receives two inputs, + * the iteration index and the node object ID. + */ @Input() set ngForTrackBy(fn: TrackByFunction) { if (isDevMode() && fn != null && typeof fn !== 'function') { @@ -193,6 +227,10 @@ export class NgForOf implements DoCheck { private _viewContainer: ViewContainerRef, private _template: TemplateRef>, private _differs: IterableDiffers) {} + /** + * A reference to the template that is stamped out for each item in the iterable. + * @see [template reference variable](guide/template-syntax#template-reference-variables--var-) + */ @Input() set ngForTemplate(value: TemplateRef>) { // TODO(TS2.1): make TemplateRef>> once we move to TS v2.1 @@ -203,6 +241,9 @@ export class NgForOf implements DoCheck { } } + /** + * Applies the changes when needed. + */ ngDoCheck(): void { if (this._ngForOfDirty) { this._ngForOfDirty = false; @@ -211,9 +252,9 @@ export class NgForOf implements DoCheck { if (!this._differ && value) { try { this._differ = this._differs.find(value).create(this.ngForTrackBy); - } catch (e) { + } catch { throw new Error( - `Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`); + `Cannot find a differ supporting object '${value}' of type '${getTypeName(value)}'. NgFor only supports binding to Iterables such as Arrays.`); } } } @@ -266,9 +307,9 @@ export class NgForOf implements DoCheck { } /** - * Assert the correct type of the context for the template that `NgForOf` will render. + * Asserts the correct type of the context for the template that `NgForOf` will render. * - * The presence of this method is a signal to the Ivy template type check compiler that the + * The presence of this method is a signal to the Ivy template type-check compiler that the * `NgForOf` structural directive renders its template with a specific context type. */ static ngTemplateContextGuard(dir: NgForOf, ctx: any): ctx is NgForOfContext { @@ -280,6 +321,6 @@ class RecordViewTuple { constructor(public record: any, public view: EmbeddedViewRef>) {} } -export function getTypeNameForDebugging(type: any): string { +function getTypeName(type: any): string { return type['name'] || typeof type; } diff --git a/packages/common/src/directives/ng_if.ts b/packages/common/src/directives/ng_if.ts index bc25cafd1f..4d9f63ddce 100644 --- a/packages/common/src/directives/ng_if.ts +++ b/packages/common/src/directives/ng_if.ts @@ -10,171 +10,140 @@ import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef, ɵstri /** - * Conditionally includes a template based on the value of an `expression`. + * A structural directive that conditionally includes a template based on the value of + * an expression coerced to Boolean. + * When the expression evaluates to true, Angular renders the template + * provided in a `then` clause, and when false or null, + * Angular renders the template provided in an optional `else` clause. The default + * template for the `else` clause is blank. * - * 根据 `expression` 表达式的值,有条件的包含某个模板。 + * A [shorthand form](guide/structural-directives#the-asterisk--prefix) of the directive, + * `*ngIf="condition"`, is generally used, provided + * as an attribute of the anchor element for the inserted template. + * Angular expands this into a more explicit version, in which the anchor element + * is contained in an `` element. * - * `ngIf` evaluates the `expression` and then renders the `then` or `else` template in its place - * when expression is truthy or falsy respectively. Typically the: + * Simple form with shorthand syntax: * - * `ngIf` 会对 `expression` 进行求值,如果为真,则在原地渲染 `then` 模板,否则渲染 `else` 模板。通常: + * ``` + *
    Content to render when condition is true.
    + * ``` * - * - `then` template is the inline template of `ngIf` unless bound to a different value. + * Simple form with expanded syntax: * - * `then` 模板就是 `ngIf` 中内联的模板 —— 除非你指定了另一个值。 + * ``` + *
    Content to render when condition is + * true.
    + * ``` * - * - `else` template is blank unless it is bound. + * Form with an "else" block: * - * `else` 模板是空白的 —— 除非你另行指定了。 + * ``` + *
    Content to render when condition is true.
    + * Content to render when condition is false. + * ``` + * + * Shorthand form with "then" and "else" blocks: + * + * ``` + *
    + * Content to render when condition is true. + * Content to render when condition is false. + * ``` + * + * Form with storing the value locally: + * + * ``` + *
    {{value}}
    + * Content to render when value is null. + * ``` * * @usageNotes * - * ### Most common usage - * - * ### 常见用法 - * - * The most common usage of the `ngIf` directive is to conditionally show the inline template as - * seen in this example: - * - * `ngIf` 指令最常见的用法是根据条件显示其内联模板,比如: + * The `*ngIf` directive is most commonly used to conditionally show an inline template, + * as seen in the following example. + * The default `else` template is blank. * * {@example common/ngIf/ts/module.ts region='NgIfSimple'} * * ### Showing an alternative template using `else` * - * ### 通过 `else` 显示另一个模板 - * - * If it is necessary to display a template when the `expression` is falsy use the `else` template - * binding as shown. Note that the `else` binding points to a `` labeled `#elseBlock`. - * The template can be defined anywhere in the component view but is typically placed right after + * To display a template when `expression` evaluates to false, use an `else` template + * binding as shown in the following example. + * The `else` binding points to an `` element labeled `#elseBlock`. + * The template can be defined anywhere in the component view, but is typically placed right after * `ngIf` for readability. * - * 如果 `expression` 为假时有必要显示一个模板,就可以用上述的 `else` 模板来进行绑定。 - * 注意,`else` 绑定指向的是一个带有 `#elseBlock` 标签的 `` 元素。 - * 该模板可以定义在此组件视图中的任何地方,但为了提高可读性,通常会放在 `ngIf` 的紧下方。 - * * {@example common/ngIf/ts/module.ts region='NgIfElse'} * - * ### Using non-inlined `then` template + * ### Using an external `then` template * - * ### 使用非内联的 `then` 模板 - * - * Usually the `then` template is the inlined template of the `ngIf`, but it can be changed using - * a binding (just like `else`). Because `then` and `else` are bindings, the template references can - * change at runtime as shown in this example. - * - * 通常,`then` 模板就是 `ngIf` 的内联模板,不过你也可以通过绑定机制(就像 `else` 那样)来修改它。 - * 因为 `then` 和 `else` 都是绑定,因此可以在运行期间改变这个模板引用 —— 如下例所示。 + * In the previous example, the then-clause template is specified inline, as the content of the + * tag that contains the `ngIf` directive. You can also specify a template that is defined + * externally, by referencing a labeled `` element. When you do this, you can + * change which template to use at runtime, as shown in the following example. * * {@example common/ngIf/ts/module.ts region='NgIfThenElse'} * - * ### Storing conditional result in a variable + * ### Storing a conditional result in a variable * - * ### 把条件结果保存在变量中 - * - * A common pattern is that we need to show a set of properties from the same object. If the - * object is undefined, then we have to use the safe-traversal-operator `?.` to guard against - * dereferencing a `null` value. This is especially the case when waiting on async data such as - * when using the `async` pipe as shown in following example: - * - * 一种常见的需求模式为:我们要显示来自同一个对象的一组属性。如果该对象是 undefined,那么我们就不得不使用安全遍历操作符 `?.` 来防止引用到空对象。 - * 尤其是在使用 `async` 管道等待异步数据时,例如: - * - * ``` - * Hello {{ (userStream|async)?.last }}, {{ (userStream|async)?.first }}! - * ``` - * - * There are several inefficiencies in the above example: - * - * 上面这个例子中有一系列低效代码: - * - * - We create multiple subscriptions on `userStream`. One for each `async` pipe, or two in the - * example above. - * - * 我们在 `userStream` 上创建了多个订阅。每个 `async` 管道都有一个,比如上面这个例子中就用了两个。 - * - * - We cannot display an alternative screen while waiting for the data to arrive asynchronously. - * - * 在等待异步数据到来的时候,我们没法显示一个备用视图(如 loading)。 - * - * - We have to use the safe-traversal-operator `?.` to access properties, which is cumbersome. - * - * 我们不得不使用安全遍历操作符 `?.` 来访问属性,太繁琐了。 - * - * - We have to place the `async` pipe in parenthesis. - * - * 我们不得不把 `async` 管道放进圆括号里。 - * - * A better way to do this is to use `ngIf` and store the result of the condition in a local - * variable as shown in the the example below: - * - * 更好的方式是使用 `ngIf`,并把该条件的结果存到局部变量里,例如: + * You might want to show a set of properties from the same object. If you are waiting + * for asynchronous data, the object can be undefined. + * In this case, you can use `ngIf` and store the result of the condition in a local + * variable as shown in the the following example. * * {@example common/ngIf/ts/module.ts region='NgIfAs'} * - * Notice that: + * This code uses only one `AsyncPipe`, so only one subscription is created. + * The conditional statement stores the result of `userStream|async` in the local variable `user`. + * You can then bind the local `user` repeatedly. * - * 注意: + * The conditional displays the data only if `userStream` returns a value, + * so you don't need to use the + * [safe-navigation-operator](guide/template-syntax#safe-navigation-operator) (`?.`) + * to guard against null values when accessing properties. + * You can display an alternative template while waiting for the data. * - * - We use only one `async` pipe and hence only one subscription gets created. + * ### Shorthand syntax * - * 我们只用了一个 `async` 管道,因此也只会进行一次订阅。 - * - * - `ngIf` stores the result of the `userStream|async` in the local variable `user`. - * - * `ngIf` 把 `userStream|async` 的结果保存在了局部变量 `user` 中。 - * - * - The local `user` can then be bound repeatedly in a more efficient way. - * - * 局部变量 `user` 可以反复绑定 —— 这很高效。 - * - * - No need to use the safe-traversal-operator `?.` to access properties as `ngIf` will only - * display the data if `userStream` returns a value. - * - * 不需要使用安全遍历操作符 `?.` 来访问属性,因为 `ngIf` 只有在 `userStream` 有数据时才会显示内容。 - * - * - We can display an alternative template while waiting for the data. - * - * 在等待数据到达时,我们可以显示一个代用模板。 - * - * ### Syntax - * - * ### 语法 - * - * Simple form: - * - * 简单形式: - * - * - `
    ...
    ` - * - `
    ...
    ` - * - * Form with an else block: - * - * 带有 `else` 块的形式: + * The shorthand syntax `*ngIf` expands into two separate template specifications + * for the "then" and "else" clauses. For example, consider the following shorthand statement, + * that is meant to show a loading page while waiting for data to be loaded. * * ``` - *
    ...
    - * ... + *
    + * ... + *
    + * + * + *
    Loading...
    + *
    * ``` * - * Form with a `then` and `else` block: + * You can see that the "else" clause references the `` + * with the `#loading` label, and the template for the "then" clause + * is provided as the content of the anchor element. * - * 带有 `then` 和 `else` 块的形式: + * However, when Angular expands the shorthand syntax, it creates + * another `` tag, with `ngIf` and `ngIfElse` directives. + * The anchor element containing the template for the "then" clause becomes + * the content of this unlabeled `` tag. * * ``` - *
    - * ... - * ... + * + *
    + * ... + *
    + *
    + * + * + *
    Loading...
    + *
    * ``` * - * Form with storing the value locally: - * - * 保存到局部变量的形式: - * - * ``` - *
    {{value}}
    - * ... - * ``` + * The presence of the implicit template object has implications for the nesting of + * structural directives. For more on this subject, see + * [Structural Directives](https://angular.io/guide/structural-directives#one-per-element). * * @ngModule CommonModule * @publicApi @@ -191,12 +160,18 @@ export class NgIf { this._thenTemplateRef = templateRef; } + /** + * The Boolean expression to evaluate as the condition for showing a template. + */ @Input() set ngIf(condition: any) { this._context.$implicit = this._context.ngIf = condition; this._updateView(); } + /** + * A template to show if the condition expression evaluates to true. + */ @Input() set ngIfThen(templateRef: TemplateRef|null) { assertTemplate('ngIfThen', templateRef); @@ -205,6 +180,9 @@ export class NgIf { this._updateView(); } + /** + * A template to show if the condition expression evaluates to false. + */ @Input() set ngIfElse(templateRef: TemplateRef|null) { assertTemplate('ngIfElse', templateRef); diff --git a/packages/common/src/directives/ng_style.ts b/packages/common/src/directives/ng_style.ts index 44512597fb..0e8ce03082 100644 --- a/packages/common/src/directives/ng_style.ts +++ b/packages/common/src/directives/ng_style.ts @@ -12,31 +12,37 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChanges, KeyValueDiffer, * @ngModule CommonModule * * @usageNotes + * + * Set the font of the containing element to the result of an expression. + * * ``` * ... + * ``` * + * Set the width of the containing element to a pixel value returned by an expression. + * + * ``` * ... + * ``` * + * Set a collection of style values using an expression that returns key-value pairs. + * + * ``` * ... * ``` * * @description * - * Update an HTML element styles. + * An attribute directive that updates styles for the containing HTML element. + * Sets one or more style properties, specified as colon-separated key-value pairs. + * The key is a style name, with an optional `.` suffix + * (such as 'top.px', 'font-style.em'). + * The value is an expression to be evaluated. + * The resulting non-null value, expressed in the given unit, + * is assigned to the given style property. + * If the result of evaluation is null, the corresponding style is removed. * - * 修改 HTML 元素的样式。 - * - * The styles are updated according to the value of the expression evaluation: - * - * 这些样式会根据表达式的求值结果进行更新: - * - * - keys are style names with an optional `.` suffix (ie 'top.px', 'font-style.em'), - * - * key 是样式名,可以带一个可选的 `.` 后缀(比如 'top.px', 'font-style.em'), - * - * - values are the values assigned to those properties (expressed in the given unit). - * - * value 是一些与这些属性相关的值(以指定的单位表示)。 + * 一个属性指令,用于更新容器元素的样式。可以通过指定用冒号分隔的键值对来设置一个或多个样式属性。其键是样式名称,带有可选的 `` 后缀(比如 'top.px','font-style.em');其值是待求值的表达式。如果求值结果不是 null,则把用指定单位表示的结果赋值给指定的样式属性;如果是 null,则删除相应的样式。 * * @publicApi */ @@ -51,13 +57,24 @@ export class NgStyle implements DoCheck { private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer2) {} @Input() - set ngStyle(values: {[key: string]: string}) { + set ngStyle( + /** + * A map of style properties, specified as colon-separated + * key-value pairs. + * * The key is a style name, with an optional `.` suffix + * (such as 'top.px', 'font-style.em'). + * * The value is an expression to be evaluated. + */ + values: {[key: string]: string}) { this._ngStyle = values; if (!this._differ && values) { this._differ = this._differs.find(values).create(); } } + /** + * Applies the new styles if needed. + */ ngDoCheck() { if (this._differ) { const changes = this._differ.diff(this._ngStyle); diff --git a/packages/common/src/directives/ng_switch.ts b/packages/common/src/directives/ng_switch.ts index 84b4429c4c..83d20067d9 100644 --- a/packages/common/src/directives/ng_switch.ts +++ b/packages/common/src/directives/ng_switch.ts @@ -36,9 +36,53 @@ export class SwitchView { /** * @ngModule CommonModule * + * @description A structural directive that adds or removes templates (displaying or hiding views) + * when the next match expression matches the switch expression. + * + * The `[ngSwitch]` directive on a container specifies an expression to match against. + * The expressions to match are provided by `ngSwitchCase` directives on views within the container. + * - Every view that matches is rendered. + * - If there are no matches, a view with the `ngSwitchDefault` directive is rendered. + * - Elements within the `[NgSwitch]` statement but outside of any `NgSwitchCase` + * or `ngSwitchDefault` directive are preserved at the location. + * * @usageNotes + * Define a container element for the directive, and specify the switch expression + * to match against as an attribute: + * * ``` - * + * + * ``` + * + * Within the container, `*ngSwitchCase` statements specify the match expressions + * as attributes. Include `*ngSwitchDefault` as the final case. + * + * ``` + * + * ... + * ... + * ... + * + * ``` + * + * ### Usage Examples + * + * The following example shows how to use more than one case to display the same view: + * + * ``` + * + * + * ... + * ... + * ... + * + * ... + * + * ``` + * + * The following example shows how cases can be nested: + * ``` + * * ... * ... * ... @@ -50,46 +94,12 @@ export class SwitchView { * ... * * ``` - * @description - * - * Adds / removes DOM sub-trees when the nest match expressions matches the switch expression. - * - * 根据内嵌的匹配表达式和 switch 表达式的匹配结果,添加或删除子树。 - * - * `NgSwitch` stamps out nested views when their match expression value matches the value of the - * switch expression. - * - * 当 `match` 表达式的值与 `switch` 表达式的值匹配时 `NgSwitch` 就会将其内嵌的视图 "印" 出来。 - * - * In other words: - * - * 换句话说: - * - * - you define a container element (where you place the directive with a switch expression on the - * `[ngSwitch]="..."` attribute) - * - * 你定义了一个容器元素(也就是你通过 `[ngSwitch]="..."` 属性来放置 `switch` 表达式的那个元素。 - * - * - you define inner views inside the `NgSwitch` and place a `*ngSwitchCase` attribute on the view - * root elements. - * - * 你在 `NgSwitch` 中定义了内嵌视图,并把 `*ngSwitchCase` 属性放在了视图的根元素上。 - * - * Elements within `NgSwitch` but outside of a `NgSwitchCase` or `NgSwitchDefault` directives will - * be preserved at the location. - * - * `NgSwitch` 中位于 `NgSwitchCase` 或 `NgSwitchDefault` 指令之外的那些元素会保留在原地。 - * - * The `ngSwitchCase` directive informs the parent `NgSwitch` of which view to display when the - * expression is evaluated. - * When no matching expression is found on a `ngSwitchCase` view, the `ngSwitchDefault` view is - * stamped out. - * - * - * 在表达式求值完成之后,`ngSwitchCase` 指令会告诉付指令 `NgSwitch` 要显示哪个视图。 - * 如果 `ngSwitchCase` 中没有找到匹配的表达式,就会显示 `ngSwitchDefault` 视图。 * * @publicApi + * @see `NgSwitchCase` + * @see `NgSwitchDefault` + * @see [Stuctural Directives](guide/structural-directives) + * */ @Directive({selector: '[ngSwitch]'}) export class NgSwitch { @@ -147,38 +157,42 @@ export class NgSwitch { /** * @ngModule CommonModule * + * @description + * Provides a switch case expression to match against an enclosing `ngSwitch` expression. + * When the expressions match, the given `NgSwitchCase` template is rendered. + * If multiple match expressions match the switch expression value, all of them are displayed. + * * @usageNotes + * + * Within a switch container, `*ngSwitchCase` statements specify the match expressions + * as attributes. Include `*ngSwitchDefault` as the final case. + * * ``` * * ... + * ... + * ... * - *``` - * @description + * ``` * - * Creates a view that will be added/removed from the parent {@link NgSwitch} when the - * given expression evaluate to respectively the same/different value as the switch - * expression. + * Each switch-case statement contains an in-line HTML template or template reference + * that defines the subtree to be selected if the value of the match expression + * matches the value of the switch expression. * - * 如果指定的表达式的计算结果和 `switch` 表达式相同,就会在父指令 {@link NgSwitch} 中创建一个视图;如果不同,则移除。 + * Unlike JavaScript, which uses strict equality, Angular uses loose equality. + * This means that the empty string, `""` matches 0. * - * Insert the sub-tree when the expression evaluates to the same value as the enclosing switch - * expression. - * - * 当表达式求值的结果与 `switch` 表达式相同,则插入该子树。 - * - * If multiple match expressions match the switch expression value, all of them are displayed. - * - * 如果多个 `match` 表达式都与 `switch` 表达式的结果相匹配,就全都显示它们。 - * - * See {@link NgSwitch} for more details and example. - * - * 参见 {@link NgSwitch} 了解详情并查看例子。 * @publicApi + * @see `NgSwitch` + * @see `NgSwitchDefault` + * */ @Directive({selector: '[ngSwitchCase]'}) export class NgSwitchCase implements DoCheck { private _view: SwitchView; - + /** + * Stores the HTML template to be selected on match. + */ @Input() ngSwitchCase: any; @@ -189,36 +203,25 @@ export class NgSwitchCase implements DoCheck { this._view = new SwitchView(viewContainer, templateRef); } + /** + * Performs case matching. For internal use only. + */ ngDoCheck() { this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase)); } } /** * @ngModule CommonModule - * @usageNotes - * ``` - * - * ... - * ... - * - * ``` * * @description * - * Creates a view that is added to the parent {@link NgSwitch} when no case expressions - * match the switch expression. - * - * 当没有任何 `case` 表达式匹配 `switch` 表达式的结果时,就会在父指令 {@link NgSwitch} 中创建一个视图。 - * - * Insert the sub-tree when no case expressions evaluate to the same value as the enclosing switch - * expression. - * - * 当没有任何一个 `case` 表达式与 `switch` 表达式的求值结果相同时,则插入该子树。 - * - * See {@link NgSwitch} for more details and example. - * - * 参见 {@link NgSwitch} 了解详情并查看例子。 + * Creates a view that is rendered when no `NgSwitchCase` expressions + * match the `NgSwitch` expression. + * This statement should be the final case in an `NgSwitch`. * * @publicApi + * @see `NgSwitch` + * @see `NgSwitchCase` + * */ @Directive({selector: '[ngSwitchDefault]'}) export class NgSwitchDefault { diff --git a/packages/common/src/directives/ng_template_outlet.ts b/packages/common/src/directives/ng_template_outlet.ts index 0191b8c6b8..a9bee6e968 100644 --- a/packages/common/src/directives/ng_template_outlet.ts +++ b/packages/common/src/directives/ng_template_outlet.ts @@ -44,14 +44,20 @@ import {Directive, EmbeddedViewRef, Input, OnChanges, SimpleChange, SimpleChange */ @Directive({selector: '[ngTemplateOutlet]'}) export class NgTemplateOutlet implements OnChanges { - // TODO(issue/24571): remove '!'. - private _viewRef !: EmbeddedViewRef; + private _viewRef: EmbeddedViewRef|null = null; - // TODO(issue/24571): remove '!'. - @Input() public ngTemplateOutletContext !: Object; + /** + * A context object to attach to the {@link EmbeddedViewRef}. This should be an + * object, the object's keys will be available for binding by the local template `let` + * declarations. + * Using the key `$implicit` in the context object will set its value as default. + */ + @Input() public ngTemplateOutletContext: Object|null = null; - // TODO(issue/24571): remove '!'. - @Input() public ngTemplateOutlet !: TemplateRef; + /** + * A string defining the template reference and optionally the context object for the template. + */ + @Input() public ngTemplateOutlet: TemplateRef|null = null; constructor(private _viewContainerRef: ViewContainerRef) {} @@ -118,7 +124,7 @@ export class NgTemplateOutlet implements OnChanges { private _updateExistingContext(ctx: Object): void { for (let propName of Object.keys(ctx)) { - (this._viewRef.context)[propName] = (this.ngTemplateOutletContext)[propName]; + (this._viewRef !.context)[propName] = (this.ngTemplateOutletContext)[propName]; } } } diff --git a/packages/common/src/location/location_strategy.ts b/packages/common/src/location/location_strategy.ts index f608180acd..2cbf0de24e 100644 --- a/packages/common/src/location/location_strategy.ts +++ b/packages/common/src/location/location_strategy.ts @@ -40,16 +40,15 @@ export abstract class LocationStrategy { /** - * The `APP_BASE_HREF` token represents the base href to be used with the - * {@link PathLocationStrategy}. - * - * If you're using {@link PathLocationStrategy}, you must provide a provider to a string - * representing the URL prefix that should be preserved when generating and recognizing - * URLs. + * A predefined [DI token](guide/glossary#di-token) for the base href + * to be used with the `PathLocationStrategy`. + * The base href is the URL prefix that should be preserved when generating + * and recognizing URLs. * * @usageNotes * - * ### Example + * The following example shows how to use this token to configure the root app injector + * with a base href value, so that the DI framework can supply the dependency anywhere in the app. * * ```typescript * import {Component, NgModule} from '@angular/core'; diff --git a/packages/common/src/viewport_scroller.ts b/packages/common/src/viewport_scroller.ts index 88a5114d94..8c332872a5 100644 --- a/packages/common/src/viewport_scroller.ts +++ b/packages/common/src/viewport_scroller.ts @@ -11,7 +11,7 @@ import {defineInjectable, inject} from '@angular/core'; import {DOCUMENT} from './dom_tokens'; /** - * Manages the scroll position. + * Defines a scroll position manager. Implemented by `BrowserViewportScroller`. * * @publicApi */ @@ -24,40 +24,40 @@ export abstract class ViewportScroller { /** * Configures the top offset used when scrolling to an anchor. + * @param offset A position in screen coordinates (a tuple with x and y values) + * or a function that returns the top offset position. * - * When given a tuple with two number, the service will always use the numbers. - * When given a function, the service will invoke the function every time it restores scroll - * position. */ abstract setOffset(offset: [number, number]|(() => [number, number])): void; /** - * Returns the current scroll position. + * Retrieves the current scroll position. + * @returns A position in screen coordinates (a tuple with x and y values). */ abstract getScrollPosition(): [number, number]; /** - * Sets the scroll position. + * Scrolls to a specified position. + * @param position A position in screen coordinates (a tuple with x and y values). */ abstract scrollToPosition(position: [number, number]): void; /** - * Scrolls to the provided anchor. + * Scrolls to an anchor element. + * @param anchor The ID of the anchor element. */ abstract scrollToAnchor(anchor: string): void; /** - * * Disables automatic scroll restoration provided by the browser. - * * See also [window.history.scrollRestoration - * info](https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration) + * info](https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration). */ abstract setHistoryScrollRestoration(scrollRestoration: 'auto'|'manual'): void; } /** - * Manages the scroll position. + * Manages the scroll position for a browser window. */ export class BrowserViewportScroller implements ViewportScroller { private offset: () => [number, number] = () => [0, 0]; @@ -66,10 +66,9 @@ export class BrowserViewportScroller implements ViewportScroller { /** * Configures the top offset used when scrolling to an anchor. + * @param offset A position in screen coordinates (a tuple with x and y values) + * or a function that returns the top offset position. * - * * When given a number, the service will always use the number. - * * When given a function, the service will invoke the function every time it restores scroll - * position. */ setOffset(offset: [number, number]|(() => [number, number])): void { if (Array.isArray(offset)) { @@ -80,7 +79,8 @@ export class BrowserViewportScroller implements ViewportScroller { } /** - * Returns the current scroll position. + * Retrieves the current scroll position. + * @returns The position in screen coordinates. */ getScrollPosition(): [number, number] { if (this.supportScrollRestoration()) { @@ -92,6 +92,7 @@ export class BrowserViewportScroller implements ViewportScroller { /** * Sets the scroll position. + * @param position The new position in screen coordinates. */ scrollToPosition(position: [number, number]): void { if (this.supportScrollRestoration()) { @@ -100,7 +101,8 @@ export class BrowserViewportScroller implements ViewportScroller { } /** - * Scrolls to the provided anchor. + * Scrolls to an anchor element. + * @param anchor The ID of the anchor element. */ scrollToAnchor(anchor: string): void { if (this.supportScrollRestoration()) { @@ -148,7 +150,7 @@ export class BrowserViewportScroller implements ViewportScroller { private supportScrollRestoration(): boolean { try { return !!this.window && !!this.window.scrollTo; - } catch (e) { + } catch { return false; } } diff --git a/packages/common/testing/BUILD.bazel b/packages/common/testing/BUILD.bazel index a10c80ec90..0a4c036836 100644 --- a/packages/common/testing/BUILD.bazel +++ b/packages/common/testing/BUILD.bazel @@ -7,7 +7,6 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "testing", srcs = glob(["**/*.ts"]), - module_name = "@angular/common/testing", deps = [ "//packages/common", "//packages/core", diff --git a/packages/common/testing/rollup.config.js b/packages/common/testing/rollup.config.js deleted file mode 100644 index 5022ab760e..0000000000 --- a/packages/common/testing/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../../dist/packages-dist/common/fesm5/testing.js', - dest: '../../../dist/packages-dist/common/bundles/common-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/common/testing'}, - moduleName: 'ng.common.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/compiler-cli/BUILD.bazel b/packages/compiler-cli/BUILD.bazel index 97dfc0ff1f..dcd274b1e1 100644 --- a/packages/compiler-cli/BUILD.bazel +++ b/packages/compiler-cli/BUILD.bazel @@ -20,17 +20,23 @@ ts_library( "src/integrationtest/**/*.ts", ], ), - module_name = "@angular/compiler-cli", tsconfig = ":tsconfig", deps = [ "//packages/compiler", "//packages/compiler-cli/src/ngtsc/annotations", + "//packages/compiler-cli/src/ngtsc/cycles", "//packages/compiler-cli/src/ngtsc/diagnostics", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/entry_point", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/path", + "//packages/compiler-cli/src/ngtsc/reflection", + "//packages/compiler-cli/src/ngtsc/routing", "//packages/compiler-cli/src/ngtsc/shims", "//packages/compiler-cli/src/ngtsc/switch", "//packages/compiler-cli/src/ngtsc/transform", "//packages/compiler-cli/src/ngtsc/typecheck", + "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//@bazel/typescript", "@ngdeps//@types", "@ngdeps//tsickle", @@ -48,7 +54,9 @@ npm_package( ], # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. - visibility = ["//visibility:private"], + visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", + ], deps = [ ":compiler-cli", "//packages/compiler-cli/src/ngcc", diff --git a/packages/compiler-cli/README.md b/packages/compiler-cli/README.md deleted file mode 100644 index 5cb161c59b..0000000000 --- a/packages/compiler-cli/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# Angular Template Compiler - -Angular applications are built with templates, which may be `.html` or `.css` files, -or may be inline `template` attributes on Decorators like `@Component`. - -These templates are compiled into executable JS at application runtime (except in `interpretation` mode). -This compilation can occur on the client, but it results in slower bootstrap time, and also -requires that the compiler be included in the code downloaded to the client. - -You can produce smaller, faster applications by running Angular's compiler as a build step, -and then downloading only the executable JS to the client. - -## Install and use - -``` -# First install angular, see https://github.com/angular/angular/blob/master/CHANGELOG.md#200-rc0-2016-05-02 -$ npm install @angular/compiler-cli typescript@next @angular/platform-server @angular/compiler -# Optional sanity check, make sure TypeScript can compile. -$ ./node_modules/.bin/tsc -p path/to/project -# ngc is a drop-in replacement for tsc. -$ ./node_modules/.bin/ngc -p path/to/project -``` - -In order to write a `bootstrap` that imports the generated code, you should first write your -top-level component, and run `ngc` once to produce a generated `.ngfactory.ts` file. -Then you can add an import statement in the `bootstrap` allowing you to bootstrap off the -generated code: - -```typescript -main.module.ts -------------- -import {BrowserModule} from '@angular/platform-browser'; -import {Component, NgModule, ApplicationRef} from '@angular/core'; - -@Component(...) -export class MyComponent {} - -@NgModule({ - imports: [BrowserModule], - declarations: [MyComponent], - entryComponents: [MyComponent] -}) -export class MainModule { - constructor(appRef: ApplicationRef) { - appRef.bootstrap(MyComponent); - } -} - -bootstrap.ts -------------- - -import {MainModuleNgFactory} from './main.module.ngfactory'; -import {platformBrowser} from '@angular/platform-browser'; - -platformBrowser().bootstrapModuleFactory(MainModuleNgFactory); -``` - -## Configuration - -The `tsconfig.json` file may contain an additional configuration block: -``` - "angularCompilerOptions": { - "genDir": ".", - "debug": true - } -``` - -### `genDir` - -the `genDir` option controls the path (relative to `tsconfig.json`) where the generated file tree -will be written. If `genDir` is not set, then the code will be generated in the source tree, next -to your original sources. More options may be added as we implement more features. - -We recommend you avoid checking generated files into version control. This permits a state where -the generated files in the repository were created from sources that were never checked in, -making it impossible to reproduce the current state. Also, your changes will effectively appear -twice in code reviews, with the generated version inscrutible by the reviewer. - -In TypeScript 1.8, the generated sources will have to be written alongside your originals, -so set `genDir` to the same location as your files (typicially the same as `rootDir`). -Add `**/*.ngfactory.ts` and `**/*.ngsummary.json` to your `.gitignore` or other mechanism for your -version control system. - -In TypeScript 1.9 and above, you can add a generated folder into your application, -such as `codegen`. Using the `rootDirs` option, you can allow relative imports like -`import {} from './foo.ngfactory'` even though the `src` and `codegen` trees are distinct. -Add `**/codegen` to your `.gitignore` or similar. - -Note that in the second option, TypeScript will emit the code into two parallel directories -as well. This is by design, see https://github.com/Microsoft/TypeScript/issues/8245. -This makes the configuration of your runtime module loader more complex, so we don't recommend -this option yet. - -### `debug` - -Set the `debug` option to true to generate debug information in the generate files. -Default to `false`. - -See the example in the `test/` directory for a working example. - -## Compiler CLI - -This program mimics the TypeScript tsc command line. It accepts a `-p` flag which points to a -`tsconfig.json` file, or a directory containing one. - -This CLI is intended for demos, prototyping, or for users with simple build systems -that run bare `tsc`. - -Users with a build system should expect an Angular template plugin. Such a plugin would be -based on the `public_api.ts` in this directory, but should share the TypeScript compiler instance -with the one already used in the plugin for TypeScript typechecking and emit. - -## Design -At a high level, this program -- collects static metadata about the sources -- uses the `OfflineCompiler` from `@angular/compiler` to codegen additional `.ts` files -- these `.ts` files are written to the `genDir` path, then compiled together with the application. - -## For developers -``` -# Build Angular and the compiler -./build.sh - -# Run the test once -# (First edit the LINKABLE_PKGS to use npm link instead of npm install) -$ ./scripts/ci/offline_compiler_test.sh - -# Keep a package fresh in watch mode -./node_modules/.bin/tsc -p packages/compiler/tsconfig-build.json -w - -# Recompile @angular/core module (needs to use tsc-ext to keep the metadata) -$ export NODE_PATH=${NODE_PATH}:$(pwd)/dist/all:$(pwd)/dist/tools -$ node dist/tools/@angular/compiler-cli/src/main -p packages/core/tsconfig-build.json - -# Iterate on the test -$ cd /tmp/wherever/e2e_test.1464388257/ -$ ./node_modules/.bin/ngc -$ ./node_modules/.bin/jasmine test/*_spec.js -``` diff --git a/packages/compiler-cli/browser-rollup.config.js b/packages/compiler-cli/browser-rollup.config.js deleted file mode 100644 index d5c583c04b..0000000000 --- a/packages/compiler-cli/browser-rollup.config.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const commonjs = require('rollup-plugin-commonjs'); -const path = require('path'); - -require('reflect-metadata'); - -var m = /^\@angular\/((\w|\-)+)(\/(\w|\d|\/|\-)+)?$/; -var location = normalize('../../dist/packages-dist') + '/'; -var rxjsLocation = normalize('../../node_modules/rxjs'); -var tslibLocation = normalize('../../node_modules/tslib'); -var esm = 'esm/'; - -var locations = {'compiler-cli': normalize('../../dist/packages') + '/'}; - -var esm_suffixes = {}; - -function normalize(fileName) { - return path.resolve(__dirname, fileName); -} - -function resolve(id, from) { - // console.log('Resolve id:', id, 'from', from) - var match = m.exec(id); - if (match) { - var packageName = match[1]; - var esm_suffix = esm_suffixes[packageName] || ''; - var loc = locations[packageName] || location; - var r = loc !== location && (loc + esm_suffix + packageName + (match[3] || '/index') + '.js') || - loc + packageName + '/@angular/' + packageName + '.es5.js'; - // console.log('** ANGULAR MAPPED **: ', r); - return r; - } - if (id && id.startsWith('rxjs/')) { - const resolved = `${rxjsLocation}${id.replace('rxjs', '')}.js`; - return resolved; - } - if (id == 'tslib') { - return tslibLocation + '/tslib.es6.js'; - } -} - -// hack to get around issues with default exports -var banner = `ts['default'] = ts['default'] || ts; fs['default'] = fs['default'] || fs;`; - -module.exports = { - entry: '../../dist/packages-dist/compiler-cli/src/ngc.js', - dest: './browser-bundle.umd.js', - format: 'umd', - amd: {id: '@angular/compiler-cli-browser'}, - moduleName: 'ng.compiler_cli_browser', - exports: 'named', - external: [ - 'fs', - 'path', - 'typescript', - 'reflect-metadata', - ], - globals: { - 'typescript': 'ts', - 'path': 'path', - 'fs': 'fs', - }, - banner: banner, - plugins: [{resolveId: resolve}, commonjs()] -}; diff --git a/packages/compiler-cli/index.ts b/packages/compiler-cli/index.ts index c7fe86a9f6..444b421eb3 100644 --- a/packages/compiler-cli/index.ts +++ b/packages/compiler-cli/index.ts @@ -24,3 +24,4 @@ export {CompilerOptions as AngularCompilerOptions} from './src/transformers/api' export {NgTools_InternalApi_NG_2 as __NGTOOLS_PRIVATE_API_2} from './src/ngtools_api'; export {ngToTsDiagnostic} from './src/transformers/util'; +export {NgTscPlugin} from './src/ngtsc/tsc_plugin'; diff --git a/packages/compiler-cli/integrationtest/BUILD.bazel b/packages/compiler-cli/integrationtest/BUILD.bazel new file mode 100644 index 0000000000..985fdbe756 --- /dev/null +++ b/packages/compiler-cli/integrationtest/BUILD.bazel @@ -0,0 +1,59 @@ +package(default_visibility = ["//visibility:public"]) + +load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_test") +load("//tools:defaults.bzl", "nodejs_binary") + +nodejs_binary( + name = "ngc_bin", + data = [ + "//packages/compiler-cli", + "@ngdeps//chokidar", + "@ngdeps//reflect-metadata", + ], + entry_point = "angular/packages/compiler-cli/src/main.js", +) + +nodejs_binary( + name = "ng_xi18n", + data = [ + "//packages/compiler-cli", + "@ngdeps//chokidar", + "@ngdeps//reflect-metadata", + ], + entry_point = "angular/packages/compiler-cli/src/extract_i18n.js", +) + +nodejs_test( + name = "integrationtest", + data = [ + ":ngc_bin", + ":ng_xi18n", + "@nodejs//:node", + "@ngdeps//domino", + "@ngdeps//chokidar", + "@ngdeps//source-map-support", + "@ngdeps//shelljs", + "@ngdeps//typescript", + "@ngdeps//reflect-metadata", + "@ngdeps//rxjs", + "@ngdeps//tslib", + "@ngdeps//jasmine/bin:jasmine", + "@ngdeps//zone.js", + "@ngdeps//xhr2", + "@ngdeps//@types/node", + "@ngdeps//@types/jasmine", + "//packages/animations:npm_package", + "//packages/common:npm_package", + "//packages/compiler:npm_package", + "//packages/compiler-cli:npm_package", + "//packages/core:npm_package", + "//packages/forms:npm_package", + "//packages/http:npm_package", + "//packages/platform-browser:npm_package", + "//packages/platform-browser-dynamic:npm_package", + "//packages/platform-server:npm_package", + "//packages/router:npm_package", + ] + glob(["**/*"]), + entry_point = "angular/packages/compiler-cli/integrationtest/test.js", + tags = ["no-ivy-aot"], +) diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts index b7d7bf0fb7..d94ec80347 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts @@ -9,7 +9,6 @@ import {Component, INJECTOR, Injectable, NgModule} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {renderModuleFactory} from '@angular/platform-server'; -import {fixmeIvy} from '@angular/private/testing'; import {BasicAppModuleNgFactory} from 'app_built/src/basic.ngfactory'; import {DepAppModuleNgFactory} from 'app_built/src/dep.ngfactory'; import {HierarchyAppModuleNgFactory} from 'app_built/src/hierarchy.ngfactory'; @@ -168,21 +167,20 @@ describe('ngInjectableDef Bazel Integration', () => { expect(TestBed.get(INJECTOR).get('foo')).toEqual('bar'); }); - fixmeIvy('FW-854: NodeInjector does not know how to get itself (INJECTOR)') - .it('Component injector understands requests for INJECTABLE', () => { - @Component({ - selector: 'test-cmp', - template: 'test', - providers: [{provide: 'foo', useValue: 'bar'}], - }) - class TestCmp { - } + it('Component injector understands requests for INJECTABLE', () => { + @Component({ + selector: 'test-cmp', + template: 'test', + providers: [{provide: 'foo', useValue: 'bar'}], + }) + class TestCmp { + } - TestBed.configureTestingModule({ - declarations: [TestCmp], - }); + TestBed.configureTestingModule({ + declarations: [TestCmp], + }); - const fixture = TestBed.createComponent(TestCmp); - expect(fixture.componentRef.injector.get(INJECTOR).get('foo')).toEqual('bar'); - }); + const fixture = TestBed.createComponent(TestCmp); + expect(fixture.componentRef.injector.get(INJECTOR).get('foo')).toEqual('bar'); + }); }); diff --git a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts index f7654591c3..2ff1d1364d 100644 --- a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts +++ b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injectable, InjectionToken, Injector, NgModule, createInjector, forwardRef} from '@angular/core'; +import {Injectable, InjectionToken, Injector, NgModule, forwardRef, ɵcreateInjector as createInjector} from '@angular/core'; import {AOT_TOKEN, AotModule, AotService} from 'app_built/src/module'; describe('Ivy NgModule', () => { diff --git a/packages/compiler-cli/integrationtest/flat_module/tsconfig-build.json b/packages/compiler-cli/integrationtest/flat_module/tsconfig-build.json index 86f8050944..4be4a4fdfa 100644 --- a/packages/compiler-cli/integrationtest/flat_module/tsconfig-build.json +++ b/packages/compiler-cli/integrationtest/flat_module/tsconfig-build.json @@ -1,26 +1,21 @@ { "angularCompilerOptions": { - // For TypeScript 1.8, we have to lay out generated files - // in the same source directory with your code. - "genDir": "ng", "flatModuleId": "flat_module", "flatModuleOutFile": "index.js", "skipTemplateCodegen": true }, "compilerOptions": { - "target": "es5", - "experimentalDecorators": true, - "noImplicitAny": true, - "moduleResolution": "node", - "rootDir": "", - "declaration": true, - "lib": ["es6", "dom"], "baseUrl": ".", + "declaration": true, + "experimentalDecorators": true, + "lib": ["es6", "dom"], + "moduleResolution": "node", + "noImplicitAny": true, "outDir": "../node_modules/flat_module", - // Prevent scanning up the directory tree for types - "typeRoots": ["node_modules/@types"] + "rootDir": "", + "target": "es5" }, "files": ["public-api.ts"] -} \ No newline at end of file +} diff --git a/packages/compiler-cli/integrationtest/ngtools_src/tsconfig-build.json b/packages/compiler-cli/integrationtest/ngtools_src/tsconfig-build.json index 1abc789b13..2a7c12c8bb 100644 --- a/packages/compiler-cli/integrationtest/ngtools_src/tsconfig-build.json +++ b/packages/compiler-cli/integrationtest/ngtools_src/tsconfig-build.json @@ -1,24 +1,17 @@ { "angularCompilerOptions": { - // For TypeScript 1.8, we have to lay out generated files - // in the same source directory with your code. - "genDir": ".", "debug": true }, "compilerOptions": { - "target": "es5", - "experimentalDecorators": true, - "noImplicitAny": true, - "moduleResolution": "node", - "rootDir": "", - "declaration": true, - "lib": [ - "es6", - "dom" - ], "baseUrl": ".", - // don't auto-discover @types/fs-extra + "declaration": true, + "experimentalDecorators": true, + "lib": ["es6", "dom"], + "moduleResolution": "node", + "noImplicitAny": true, + "rootDir": "", + "target": "es5", "types": [] } -} \ No newline at end of file +} diff --git a/packages/compiler-cli/integrationtest/src/messages.fi.xlf b/packages/compiler-cli/integrationtest/src/messages.fi.xlf index 1bc59fc41f..2b9e6058d0 100644 --- a/packages/compiler-cli/integrationtest/src/messages.fi.xlf +++ b/packages/compiler-cli/integrationtest/src/messages.fi.xlf @@ -13,9 +13,11 @@ tervetuloa - other-3rdP-component - other-3rdP-component + other-3rdP-component +multi-lines + other-3rdP-component +multi-lines - \ No newline at end of file + diff --git a/packages/compiler-cli/integrationtest/src/module.ts b/packages/compiler-cli/integrationtest/src/module.ts index 3398cb2ddc..a3d8711a93 100644 --- a/packages/compiler-cli/integrationtest/src/module.ts +++ b/packages/compiler-cli/integrationtest/src/module.ts @@ -8,7 +8,6 @@ import {ApplicationRef, NgModule, forwardRef} from '@angular/core'; import {FormsModule} from '@angular/forms'; -import {MATERIAL_SANITY_CHECKS, MdButtonModule} from '@angular/material'; import {ServerModule} from '@angular/platform-server'; import {FlatModule} from 'flat_module'; // Note: don't refer to third_party_src as we want to test that @@ -60,7 +59,6 @@ export {SomeModule as JitSummariesSomeModule} from './jit_summaries'; imports: [ ServerModule, FormsModule, - MdButtonModule, ModuleUsingCustomElements, SomeLibModule.withProviders(), ThirdpartyModule, @@ -69,9 +67,6 @@ export {SomeModule as JitSummariesSomeModule} from './jit_summaries'; providers: [ SomeService, {provide: CUSTOM, useValue: forwardRef(() => ({name: 'some name'}))}, - // disable sanity check for material because it throws an error when used server-side - // see https://github.com/angular/material2/issues/6292 - {provide: MATERIAL_SANITY_CHECKS, useValue: false}, ], entryComponents: [ AnimateCmp, diff --git a/packages/compiler-cli/integrationtest/test.js b/packages/compiler-cli/integrationtest/test.js new file mode 100644 index 0000000000..2b62fd7f0c --- /dev/null +++ b/packages/compiler-cli/integrationtest/test.js @@ -0,0 +1,54 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const path = require('path'); +const shx = require('shelljs'); +const os = require('os'); +const {runCommand, setupTestDirectory} = require('./test_helpers'); + +const ngcBin = require.resolve('./ngc_bin'); +const xi18nBin = require.resolve('./ng_xi18n'); +const nodeBin = require.resolve(`nodejs/bin/node${(os.platform() === 'win32' ? '.cmd' : '')}`); +const jasmineBin = require.resolve('ngdeps/node_modules/jasmine/bin/jasmine.js'); + +// Prepare the test directory before building the integration test output. This ensures that +// the test runs in an hermetic way and works on Windows. +const tmpDir = setupTestDirectory(); + +// Compile the "flat_module" Angular project using NGC. +runCommand(ngcBin, ['-p', 'flat_module/tsconfig-build.json']); + +// Copy HTML asset files from the "flat_module" package to the NPM output. The "flat_module" +// has template code generation disabled and therefore needs to have the asset files included +// next to the JavaScript output. +shx.cp( + path.join(tmpDir, 'flat_module/src/*.html'), path.join(tmpDir, 'node_modules/flat_module/src')); + +// Compile the "third_party" Angular project using NGC. +runCommand(ngcBin, ['-p', 'third_party_src/tsconfig-build.json']); + +// Compile the main integration-test Angular project using NGC. Also uses a translated +// i18n file which will be used to verify the translated templates of components. +runCommand(ngcBin, [ + '-p', 'tsconfig-build.json', '--i18nFile=src/messages.fi.xlf', '--locale=fi', '--i18nFormat=xlf' +]); + +// Extract the i18n messages into various formats that will be verified +// later on by the "i18n_spec" within "test/". +runCommand(xi18nBin, ['-p', 'tsconfig-xi18n.json', '--i18nFormat=xlf', '--locale=fr']); +runCommand( + xi18nBin, ['-p', 'tsconfig-xi18n.json', '--i18nFormat=xlf2', '--outFile=messages.xliff2.xlf']); +runCommand( + xi18nBin, ['-p', 'tsconfig-xi18n.json', '--i18nFormat=xmb', '--outFile=custom_file.xmb']); + +// Run the ngtools tests that verify that the public API provided by the "compiler-cli" +// is working as expected in real projects. +runCommand(nodeBin, [path.join(tmpDir, 'test/test_ngtools_api.js')]); + +// Run all specs which verify the output from the previously built modules and i18n files. +runCommand(nodeBin, [jasmineBin, path.join(tmpDir, 'test/all_spec.js')]); diff --git a/packages/compiler-cli/integrationtest/test/basic_spec.ts b/packages/compiler-cli/integrationtest/test/basic_spec.ts index 370585521e..eebf199bb1 100644 --- a/packages/compiler-cli/integrationtest/test/basic_spec.ts +++ b/packages/compiler-cli/integrationtest/test/basic_spec.ts @@ -16,10 +16,12 @@ import {createComponent} from './util'; describe('template codegen output', () => { const outDir = 'src'; - it('should lower Decorators without reflect-metadata', () => { - const jsOutput = path.join(outDir, 'basic.js'); - expect(fs.existsSync(jsOutput)).toBeTruthy(); - expect(fs.readFileSync(jsOutput, {encoding: 'utf-8'})).not.toContain('Reflect.decorate'); + it('should be able to lower annotations as static fields', () => { + const basicFilePath = path.join(outDir, 'basic.js'); + expect(fs.existsSync(basicFilePath)).toBeTruthy(); + const fileContent = fs.readFileSync(basicFilePath, 'utf8'); + expect(fileContent).not.toContain('Reflect.decorate'); + expect(fileContent).toContain('BasicComp.decorators = ['); }); it('should produce metadata.json outputs', () => { diff --git a/packages/compiler-cli/integrationtest/test/i18n_spec.ts b/packages/compiler-cli/integrationtest/test/i18n_spec.ts index 0872e96660..773a7b6e04 100644 --- a/packages/compiler-cli/integrationtest/test/i18n_spec.ts +++ b/packages/compiler-cli/integrationtest/test/i18n_spec.ts @@ -36,8 +36,8 @@ const EXPECTED_XMB = ` node_modules/third_party/other_comp.d.ts:1,2other-3rdP-component multi-lines - src/basic.ts:1translate me - src/basic.ts:5src/entry_components.ts:1Welcome + src/basic.html:1translate me + src/basic.html:5src/entry_components.ts:1Welcome `; @@ -56,7 +56,7 @@ multi-lines translate me - src/basic.ts + src/basic.html 1 desc @@ -65,7 +65,7 @@ multi-lines Welcome - src/basic.ts + src/basic.html 5 @@ -94,7 +94,7 @@ multi-lines desc meaning - src/basic.ts:1 + src/basic.html:1 translate me @@ -102,7 +102,7 @@ multi-lines - src/basic.ts:5 + src/basic.html:5 src/entry_components.ts:1 @@ -114,31 +114,31 @@ multi-lines `; describe('template i18n extraction output', () => { - const outDir = 'out'; + const outputDir = path.join(__dirname, '../xi18n-out'); it('should extract i18n messages as xmb', () => { - const xmbOutput = path.join(outDir, 'custom_file.xmb'); + const xmbOutput = path.join(outputDir, 'custom_file.xmb'); expect(fs.existsSync(xmbOutput)).toBeTruthy(); const xmb = fs.readFileSync(xmbOutput, {encoding: 'utf-8'}); expect(xmb).toEqual(EXPECTED_XMB); }); it('should extract i18n messages as xliff', () => { - const xlfOutput = path.join(outDir, 'messages.xlf'); + const xlfOutput = path.join(outputDir, 'messages.xlf'); expect(fs.existsSync(xlfOutput)).toBeTruthy(); const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'}); expect(xlf).toEqual(EXPECTED_XLIFF); }); it('should extract i18n messages as xliff version 2.0', () => { - const xlfOutput = path.join(outDir, 'messages.xliff2.xlf'); + const xlfOutput = path.join(outputDir, 'messages.xliff2.xlf'); expect(fs.existsSync(xlfOutput)).toBeTruthy(); const xlf = fs.readFileSync(xlfOutput, {encoding: 'utf-8'}); expect(xlf).toEqual(EXPECTED_XLIFF2); }); it('should not emit js', () => { - const files = fs.readdirSync(outDir); + const files = fs.readdirSync(outputDir); files.forEach(f => expect(f).not.toMatch(/\.js$/)); }); }); diff --git a/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts b/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts index 0c7a2f9880..f98bb42051 100644 --- a/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts +++ b/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts @@ -13,7 +13,7 @@ import 'reflect-metadata'; import * as path from 'path'; import * as ts from 'typescript'; import * as assert from 'assert'; -import {__NGTOOLS_PRIVATE_API_2, readConfiguration} from '@angular/compiler-cli'; +import {createProgram, readConfiguration} from '@angular/compiler-cli'; /* tslint:disable:no-console */ /** @@ -22,19 +22,10 @@ import {__NGTOOLS_PRIVATE_API_2, readConfiguration} from '@angular/compiler-cli' * properly read and wrote. */ function main() { - console.log(`testing ngtools API...`); - - Promise.resolve() - .then(() => lazyRoutesTest()) - .then(() => { - console.log('All done!'); - process.exit(0); - }) - .catch((err) => { - console.error(err.stack); - console.error('Test failed'); - process.exit(1); - }); + Promise.resolve().then(() => lazyRoutesTest()).then(() => { process.exit(0); }).catch((err) => { + console.error(err.stack); + process.exit(1); + }); } function lazyRoutesTest() { @@ -43,13 +34,15 @@ function lazyRoutesTest() { const config = readConfiguration(project); const host = ts.createCompilerHost(config.options, true); - const program = ts.createProgram(config.rootNames, config.options, host); + const program = createProgram({ + rootNames: config.rootNames, + options: config.options, host, + }); config.options.basePath = basePath; + config.options.rootDir = basePath; - const lazyRoutes = __NGTOOLS_PRIVATE_API_2.listLazyRoutes( - {program, host, angularCompilerOptions: config.options, entryModule: 'app.module#AppModule'}); - + const lazyRoutes = program.listLazyRoutes('app.module#AppModule'); const expectations: {[route: string]: string} = { './lazy.module#LazyModule': 'lazy.module.ts', './feature/feature.module#FeatureModule': 'feature/feature.module.ts', @@ -61,17 +54,25 @@ function lazyRoutesTest() { 'feature/feature.module#FeatureModule': 'feature/feature.module.ts' }; - Object.keys(lazyRoutes).forEach((route: string) => { - assert(route in expectations, `Found a route that was not expected: "${route}".`); + lazyRoutes.forEach(lazyRoute => { + const routeName = lazyRoute.route; + + // Normalize the module path and the expected module path so that these can be compared + // on Windows where path separators are not consistent with TypeScript internal paths. + const modulePath = path.normalize(lazyRoute.referencedModule.filePath); + const expectedModulePath = path.normalize(path.join(basePath, expectations[routeName])); + + assert(routeName in expectations, `Found a route that was not expected: "${routeName}".`); assert( - lazyRoutes[route] == path.join(basePath, expectations[route]), - `Route "${route}" does not point to the expected absolute path ` + - `"${path.join(basePath, expectations[route])}". It points to "${lazyRoutes[route]}"`); + modulePath === expectedModulePath, + `Route "${routeName}" does not point to the expected absolute path ` + + `"${expectedModulePath}". It points to "${modulePath}"`); }); // Verify that all expectations were met. assert.deepEqual( - Object.keys(lazyRoutes), Object.keys(expectations), `Expected routes listed to be: \n` + + lazyRoutes.map(lazyRoute => lazyRoute.route), Object.keys(expectations), + `Expected routes listed to be: \n` + ` ${JSON.stringify(Object.keys(expectations))}\n` + `Actual:\n` + ` ${JSON.stringify(Object.keys(lazyRoutes))}\n`); diff --git a/packages/compiler-cli/integrationtest/test_helpers.js b/packages/compiler-cli/integrationtest/test_helpers.js new file mode 100644 index 0000000000..c0c87fc3c2 --- /dev/null +++ b/packages/compiler-cli/integrationtest/test_helpers.js @@ -0,0 +1,166 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const child_process = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const shx = require('shelljs'); + +/** Manifest path that refers to the Bazel package that contains all test sources. */ +const baseManifestPath = 'angular/packages/compiler-cli/integrationtest'; + +/** + * Temporary directory which will be used to build and run the integration tests. Note that + * this environment variable is automatically set by Bazel for such test actions. + */ +const tmpDir = process.env.TEST_TMPDIR; + +/** Fine grained node modules which are required in order to run the integration test. */ +const requiredNodeModules = { + '@angular/animations': resolveNpmTreeArtifact('angular/packages/animations/npm_package'), + '@angular/common': resolveNpmTreeArtifact('angular/packages/common/npm_package'), + '@angular/compiler': resolveNpmTreeArtifact('angular/packages/compiler/npm_package'), + '@angular/compiler-cli': resolveNpmTreeArtifact('angular/packages/compiler-cli/npm_package'), + '@angular/core': resolveNpmTreeArtifact('angular/packages/core/npm_package'), + '@angular/forms': resolveNpmTreeArtifact('angular/packages/forms/npm_package'), + '@angular/http': resolveNpmTreeArtifact('angular/packages/http/npm_package'), + '@angular/platform-browser': + resolveNpmTreeArtifact('angular/packages/platform-browser/npm_package'), + '@angular/platform-browser-dynamic': + resolveNpmTreeArtifact('angular/packages/platform-browser-dynamic/npm_package'), + '@angular/platform-server': + resolveNpmTreeArtifact('angular/packages/platform-server/npm_package'), + '@angular/router': resolveNpmTreeArtifact('angular/packages/router/npm_package'), + // Note, @bazel/typescript does not appear here because it's not listed as a dependency of + // @angular/compiler-cli + '@types/jasmine': resolveNpmTreeArtifact('ngdeps/node_modules/@types/jasmine'), + '@types/node': resolveNpmTreeArtifact('ngdeps/node_modules/@types/node'), + + // Transitive dependencies which need to be specified because the Angular NPM packages + // depend on these without the Angular NPM packages being part of the Bazel managed deps. + // This means that transitive dependencies need to be manually declared as required. + 'tslib': resolveNpmTreeArtifact('ngdeps/node_modules/tslib'), + 'domino': resolveNpmTreeArtifact('ngdeps/node_modules/domino'), + 'xhr2': resolveNpmTreeArtifact('ngdeps/node_modules/xhr2'), + + // Fine grained dependencies which are used by the integration test Angular modules, and + // need to be symlinked so that they can be resolved by NodeJS or NGC. + 'reflect-metadata': resolveNpmTreeArtifact('ngdeps/node_modules/reflect-metadata'), + 'rxjs': resolveNpmTreeArtifact('ngdeps/node_modules/rxjs'), + 'source-map-support': resolveNpmTreeArtifact('ngdeps/node_modules/source-map-support'), + 'typescript': resolveNpmTreeArtifact('ngdeps/node_modules/typescript'), + 'zone.js': resolveNpmTreeArtifact('ngdeps/node_modules/zone.js'), +}; + +/** Sets up the temporary test directory and returns the path to the directory. */ +exports.setupTestDirectory = function() { + copySourceFilesToTempDir(); + symlinkNodeModules(); + return tmpDir; +}; + +/** + * Runs a given binary with the specified command line arguments. The working directory for + * the spawned process will be the temporary directory. + */ +exports.runCommand = function runCommand(binary, args = []) { + const ngcProcess = child_process.spawnSync(binary, args, { + stdio: 'inherit', + cwd: tmpDir, + env: { + ...process.env, + // We need to set the "NODE_PATH" here because the built Angular NPM packages are symlinks + // which NodeJS resolves into the output location. This is problematic because the output + // location does not have the required dependencies of these NPM packages installed. This + // could be fixed by setting the NodeJS "--preserve-symlinks" option, but this would mean + // that transitive dependencies of fine-grained dependencies cannot be resolved either. + NODE_PATH: path.join(tmpDir, 'node_modules/') + } + }); + + if (ngcProcess.status !== 0) { + console.error(`Command ${binary} failed with arguments: "${args.join(' ')}". See error above.`); + process.exit(1); + } +}; + +/** + * Symlinks the specified node modules within the temporary directory. This is necessary because + * this test is an integration test and we don't want to rely on any path-mapped module resolution. + * Additionally, NGC expects types and imported packages to be within the project's root dir. + */ +function symlinkNodeModules() { + Object.keys(requiredNodeModules).forEach(importName => { + const outputPath = path.join(tmpDir, 'node_modules', importName); + const moduleDir = requiredNodeModules[importName]; + + findFilesWithinDirectory(moduleDir).forEach(filePath => { + const outputFilePath = path.join(outputPath, path.relative(moduleDir, filePath)); + + shx.mkdir('-p', path.dirname(outputFilePath)); + fs.symlinkSync(filePath, outputFilePath); + }); + }); +} + +/** + * Copies all source files for the integration test to a temporary directory. This + * is necessary because runfiles resolve on Windows to the original source location, + * and we don't want to pollute the workspace sources. This breaks hermeticity. + */ +function copySourceFilesToTempDir() { + getSourceFilesFromRunfiles().forEach(({realPath, relativeFilePath}) => { + const tmpFilePath = path.join(tmpDir, relativeFilePath); + + shx.mkdir('-p', path.dirname(tmpFilePath)); + shx.cp(realPath, tmpFilePath); + }); +} + +/** + * Gets all source files for the integration test by querying the Bazel runfiles. + * In case there is a runfiles manifest (e.g. on Windows), the source files are resolved + * through the manifest because on these platforms the runfiles are not symlinked and + * cannot be searched within the real filesystem. + */ +function getSourceFilesFromRunfiles() { + // Path to the Bazel runfiles manifest if present. This file is present if runfiles are + // not symlinked into the runfiles directory. + const runfilesManifestPath = process.env.RUNFILES_MANIFEST_FILE; + + if (!runfilesManifestPath) { + const packageRunfilesDir = path.join(process.env.RUNFILES, baseManifestPath); + return findFilesWithinDirectory(packageRunfilesDir).map(filePath => ({ + realPath: filePath, + relativeFilePath: path.relative( + packageRunfilesDir, filePath) + })); + } + + return fs.readFileSync(runfilesManifestPath, 'utf8') + .split('\n') + .map(mapping => mapping.split(' ')) + .filter(([runfilePath]) => runfilePath.startsWith(baseManifestPath)) + .map( + ([runfilePath, realPath]) => + ({realPath, relativeFilePath: path.relative(baseManifestPath, runfilePath)})); +} + +/** + * Resolves a NPM package from the Bazel runfiles. We need to resolve the Bazel tree + * artifacts using a "resolve file" because the NodeJS module resolution does not allow + * resolving to directory paths. + */ +function resolveNpmTreeArtifact(manifestPath, resolveFile = 'package.json') { + return path.dirname(require.resolve(path.posix.join(manifestPath, resolveFile))); +} + +/** Finds all files within a specified directory. */ +function findFilesWithinDirectory(directoryPath) { + return shx.find(directoryPath).filter(filePath => !fs.statSync(filePath).isDirectory()); +} diff --git a/packages/compiler-cli/integrationtest/third_party_src/tsconfig-build.json b/packages/compiler-cli/integrationtest/third_party_src/tsconfig-build.json index d9f9f536c3..73801e8354 100644 --- a/packages/compiler-cli/integrationtest/third_party_src/tsconfig-build.json +++ b/packages/compiler-cli/integrationtest/third_party_src/tsconfig-build.json @@ -1,21 +1,17 @@ { "angularCompilerOptions": { - // For TypeScript 1.8, we have to lay out generated files - // in the same source directory with your code. "skipTemplateCodegen": true }, "compilerOptions": { - "target": "es5", - "experimentalDecorators": true, - "noImplicitAny": true, - "moduleResolution": "node", - "rootDir": "", - "declaration": true, - "lib": ["es6", "dom"], "baseUrl": ".", + "declaration": true, + "experimentalDecorators": true, + "lib": ["es6", "dom"], + "moduleResolution": "node", + "noImplicitAny": true, "outDir": "../node_modules/third_party", - // Prevent scanning up the directory tree for types - "typeRoots": ["node_modules/@types"] + "rootDir": "", + "target": "es5" } -} \ No newline at end of file +} diff --git a/packages/compiler-cli/integrationtest/tsconfig-build.json b/packages/compiler-cli/integrationtest/tsconfig-build.json index 511a721e2f..3e9b6559d8 100644 --- a/packages/compiler-cli/integrationtest/tsconfig-build.json +++ b/packages/compiler-cli/integrationtest/tsconfig-build.json @@ -1,40 +1,34 @@ { "angularCompilerOptions": { - // For TypeScript 1.8, we have to lay out generated files - // in the same source directory with your code. - "genDir": ".", + "alwaysCompileGeneratedCode": true, + "annotationsAs": "static fields", "debug": true, "enableSummariesForJit": true, - "alwaysCompileGeneratedCode": true, "i18nFormat": "xlf" }, "compilerOptions": { - "target": "es5", - "experimentalDecorators": true, - "noImplicitAny": true, - "strictNullChecks": true, - "strictPropertyInitialization": true, - "skipLibCheck": true, - "moduleResolution": "node", - "rootDir": "", - "declaration": true, - "lib": ["es6", "dom"], "baseUrl": ".", - // Prevent scanning up the directory tree for types - "typeRoots": ["node_modules/@types"], + "declaration": true, + "experimentalDecorators": true, + "lib": ["es6", "dom"], + "moduleResolution": "node", + "noImplicitAny": true, "noUnusedLocals": true, - "sourceMap": true + "rootDir": "", + "skipLibCheck": true, + "sourceMap": true, + "strictNullChecks": true, + // compatible with the option. Disabled until the integration test support the strict flag. + // TODO(devversion): this has been enabled without the integration test code being + "strictPropertyInitialization": false, + "target": "es5" }, "files": [ "src/module", "src/bootstrap", "test/all_spec", - "test/test_ngtools_api", - "benchmarks/src/tree/ng2/index_aot.ts", - "benchmarks/src/tree/ng2_switch/index_aot.ts", - "benchmarks/src/largetable/ng2/index_aot.ts", - "benchmarks/src/largetable/ng2_switch/index_aot.ts" + "test/test_ngtools_api" ] } diff --git a/packages/compiler-cli/integrationtest/tsconfig-ngc-build.json b/packages/compiler-cli/integrationtest/tsconfig-ngc-build.json deleted file mode 100644 index 5c880dc22d..0000000000 --- a/packages/compiler-cli/integrationtest/tsconfig-ngc-build.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "angularCompilerOptions": { - // For TypeScript 1.8, we have to lay out generated files - // in the same source directory with your code. - "genDir": ".", - "debug": true, - "enableSummariesForJit": true, - "alwaysCompileGeneratedCode": true - }, - - "compilerOptions": { - "target": "es5", - "experimentalDecorators": true, - "noImplicitAny": true, - "strictNullChecks": true, - "strictPropertyInitialization": true, - "skipLibCheck": true, - "moduleResolution": "node", - "rootDir": "", - "declaration": true, - "lib": ["es6", "dom"], - "baseUrl": ".", - // Prevent scanning up the directory tree for types - "typeRoots": ["node_modules/@types"], - "noUnusedLocals": true, - "sourceMap": true - }, - - "files": [ - "src/module", - "src/bootstrap", - "test/all_spec", - "test/test_ngtools_api", - "benchmarks/src/tree/ng2/index_aot.ts", - "benchmarks/src/tree/ng2_switch/index_aot.ts", - "benchmarks/src/largetable/ng2/index_aot.ts", - "benchmarks/src/largetable/ng2_switch/index_aot.ts" - ] -} diff --git a/packages/compiler-cli/integrationtest/tsconfig-xi18n.json b/packages/compiler-cli/integrationtest/tsconfig-xi18n.json index 039931f12c..05a7f38733 100644 --- a/packages/compiler-cli/integrationtest/tsconfig-xi18n.json +++ b/packages/compiler-cli/integrationtest/tsconfig-xi18n.json @@ -1,34 +1,26 @@ { "angularCompilerOptions": { - // For TypeScript 1.8, we have to lay out generated files - // in the same source directory with your code. - "genDir": ".", "debug": true, "enableSummariesForJit": true }, "compilerOptions": { - "target": "es5", - "experimentalDecorators": true, - "noImplicitAny": true, - "moduleResolution": "node", - "outDir": "./out", - "rootDir": "", - "declaration": true, - "lib": ["es6", "dom"], "baseUrl": ".", - // Prevent scanning up the directory tree for types - "typeRoots": ["node_modules/@types"] + "declaration": true, + "experimentalDecorators": true, + "lib": ["es6", "dom"], + "moduleResolution": "node", + "noImplicitAny": true, + "outDir": "./xi18n-out", + "rootDir": "", + "skipLibCheck": true, + "target": "es5" }, "files": [ "src/module", "src/bootstrap", "test/all_spec", - "test/test_ngtools_api", - "benchmarks/src/tree/ng2/index_aot.ts", - "benchmarks/src/tree/ng2_switch/index_aot.ts", - "benchmarks/src/largetable/ng2/index_aot.ts", - "benchmarks/src/largetable/ng2_switch/index_aot.ts" + "test/test_ngtools_api" ] } diff --git a/packages/compiler-cli/integrationtest/webpack.config.js b/packages/compiler-cli/integrationtest/webpack.config.js deleted file mode 100644 index 504f93430c..0000000000 --- a/packages/compiler-cli/integrationtest/webpack.config.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -module.exports = { - target: 'node', - entry: './test/all_spec.js', - output: {filename: './all_spec.js'}, - resolve: {extensions: ['.js']}, - devtool: '#source-map', - module: { - loaders: - [{test: /\.js$/, exclude: /node_modules/, loaders: ['source-map-loader'], enforce: 'pre'}] - }, -}; diff --git a/packages/compiler-cli/src/diagnostics/expression_diagnostics.ts b/packages/compiler-cli/src/diagnostics/expression_diagnostics.ts index 3b858c2468..54b026c7ce 100644 --- a/packages/compiler-cli/src/diagnostics/expression_diagnostics.ts +++ b/packages/compiler-cli/src/diagnostics/expression_diagnostics.ts @@ -272,8 +272,7 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { const path = findNode(this.info.htmlAst, ast.sourceSpan.start.offset); const last = path.tail; if (last instanceof Attribute && last.valueSpan) { - // Add 1 for the quote. - return last.valueSpan.start.offset + 1; + return last.valueSpan.start.offset; } return ast.sourceSpan.start.offset; } diff --git a/packages/compiler-cli/src/main.ts b/packages/compiler-cli/src/main.ts index 0801be6106..8446b19e0f 100644 --- a/packages/compiler-cli/src/main.ts +++ b/packages/compiler-cli/src/main.ts @@ -22,7 +22,7 @@ import {performWatchCompilation, createPerformWatchHost} from './perform_watch' export function main( args: string[], consoleError: (s: string) => void = console.error, - config?: NgcParsedConfiguration): number { + config?: NgcParsedConfiguration, customTransformers?: api.CustomTransformers): number { let {project, rootNames, options, errors: configErrors, watch, emitFlags} = config || readNgcCommandLineAndConfiguration(args); if (configErrors.length) { @@ -32,8 +32,12 @@ export function main( const result = watchMode(project, options, consoleError); return reportErrorsAndExit(result.firstCompileResult, options, consoleError); } - const {diagnostics: compileDiags} = performCompilation( - {rootNames, options, emitFlags, emitCallback: createEmitCallback(options)}); + const {diagnostics: compileDiags} = performCompilation({ + rootNames, + options, + emitFlags, + emitCallback: createEmitCallback(options), customTransformers + }); return reportErrorsAndExit(compileDiags, options, consoleError); } @@ -111,7 +115,7 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un export interface NgcParsedConfiguration extends ParsedConfiguration { watch?: boolean; } -function readNgcCommandLineAndConfiguration(args: string[]): NgcParsedConfiguration { +export function readNgcCommandLineAndConfiguration(args: string[]): NgcParsedConfiguration { const options: api.CompilerOptions = {}; const parsedArgs = require('minimist')(args); if (parsedArgs.i18nFile) options.i18nInFile = parsedArgs.i18nFile; @@ -162,17 +166,32 @@ export function readCommandLineAndConfiguration( }; } +function getFormatDiagnosticsHost(options?: api.CompilerOptions): ts.FormatDiagnosticsHost { + const basePath = options ? options.basePath : undefined; + return { + getCurrentDirectory: () => basePath || ts.sys.getCurrentDirectory(), + // We need to normalize the path separators here because by default, TypeScript + // compiler hosts use posix canonical paths. In order to print consistent diagnostics, + // we also normalize the paths. + getCanonicalFileName: fileName => fileName.replace(/\\/g, '/'), + getNewLine: () => { + // Manually determine the proper new line string based on the passed compiler + // options. There is no public TypeScript function that returns the corresponding + // new line string. see: https://github.com/Microsoft/TypeScript/issues/29581 + if (options && options.newLine !== undefined) { + return options.newLine === ts.NewLineKind.LineFeed ? '\n' : '\r\n'; + } + return ts.sys.newLine; + }, + }; +} + function reportErrorsAndExit( allDiagnostics: Diagnostics, options?: api.CompilerOptions, consoleError: (s: string) => void = console.error): number { const errorsAndWarnings = filterErrorsAndWarnings(allDiagnostics); if (errorsAndWarnings.length) { - let currentDir = options ? options.basePath : undefined; - const formatHost: ts.FormatDiagnosticsHost = { - getCurrentDirectory: () => currentDir || ts.sys.getCurrentDirectory(), - getCanonicalFileName: fileName => fileName, - getNewLine: () => ts.sys.newLine - }; + const formatHost = getFormatDiagnosticsHost(options); if (options && (options.enableIvy === true || options.enableIvy === 'ngtsc')) { const ngDiagnostics = errorsAndWarnings.filter(api.isNgDiagnostic); const tsDiagnostics = errorsAndWarnings.filter(api.isTsDiagnostic); @@ -189,7 +208,7 @@ function reportErrorsAndExit( export function watchMode( project: string, options: api.CompilerOptions, consoleError: (s: string) => void) { return performWatchCompilation(createPerformWatchHost(project, diagnostics => { - consoleError(formatDiagnostics(diagnostics)); + consoleError(formatDiagnostics(diagnostics, getFormatDiagnosticsHost(options))); }, options, options => createEmitCallback(options))); } diff --git a/packages/compiler-cli/src/ngcc/BUILD.bazel b/packages/compiler-cli/src/ngcc/BUILD.bazel index b0f98698e3..1915c0e0fd 100644 --- a/packages/compiler-cli/src/ngcc/BUILD.bazel +++ b/packages/compiler-cli/src/ngcc/BUILD.bazel @@ -8,13 +8,15 @@ ts_library( "*.ts", "**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngcc", deps = [ "//packages:types", "//packages/compiler", "//packages/compiler-cli/src/ngtsc/annotations", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/cycles", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/path", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/transform", "//packages/compiler-cli/src/ngtsc/translator", "@ngdeps//@types/convert-source-map", diff --git a/packages/compiler-cli/src/ngcc/README.md b/packages/compiler-cli/src/ngcc/README.md index a6a08170d3..10bb08fac0 100644 --- a/packages/compiler-cli/src/ngcc/README.md +++ b/packages/compiler-cli/src/ngcc/README.md @@ -23,7 +23,7 @@ yarn bazel test //packages/compiler-cli/src/ngcc/test ## Integration Testing -There are tests that check the behaviour of the overall executable: +There are tests that check the behavior of the overall executable: ```bash yarn bazel test //packages/compiler-cli/test/ngcc diff --git a/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts index d9749b1cb1..a5dc35592b 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/decoration_analyzer.ts @@ -11,7 +11,11 @@ import * as fs from 'fs'; import * as ts from 'typescript'; import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader, SelectorScopeRegistry} from '../../../ngtsc/annotations'; -import {CompileResult, DecoratorHandler} from '../../../ngtsc/transform'; +import {CycleAnalyzer, ImportGraph} from '../../../ngtsc/cycles'; +import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, ReferenceEmitter} from '../../../ngtsc/imports'; +import {PartialEvaluator} from '../../../ngtsc/partial_evaluator'; +import {AbsoluteFsPath, LogicalFileSystem} from '../../../ngtsc/path'; +import {CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../../ngtsc/transform'; import {DecoratedClass} from '../host/decorated_class'; import {NgccReflectionHost} from '../host/ngcc_host'; import {isDefined} from '../utils'; @@ -23,8 +27,7 @@ export interface AnalyzedFile { export interface AnalyzedClass extends DecoratedClass { diagnostics?: ts.Diagnostic[]; - handler: DecoratorHandler; - analysis: any; + matches: {handler: DecoratorHandler; analysis: any;}[]; } export interface CompiledClass extends AnalyzedClass { compilation: CompileResult[]; } @@ -40,16 +43,18 @@ export const DecorationAnalyses = Map; export interface MatchingHandler { handler: DecoratorHandler; - match: M; + detected: M; } /** - * `ResourceLoader` which directly uses the filesystem to resolve resources synchronously. + * Simple class that resolves and loads files directly from the filesystem. */ -export class FileResourceLoader implements ResourceLoader { - load(url: string, containingFile: string): string { - url = path.resolve(path.dirname(containingFile), url); - return fs.readFileSync(url, 'utf8'); +class NgccResourceLoader implements ResourceLoader { + canPreload = false; + preload(): undefined|Promise { throw new Error('Not implemented.'); } + load(url: string): string { return fs.readFileSync(url, 'utf8'); } + resolve(url: string, containingFile: string): string { + return path.resolve(path.dirname(containingFile), url); } } @@ -57,34 +62,51 @@ export class FileResourceLoader implements ResourceLoader { * This Analyzer will analyze the files that have decorated classes that need to be transformed. */ export class DecorationAnalyzer { - resourceLoader = new FileResourceLoader(); - scopeRegistry = new SelectorScopeRegistry(this.typeChecker, this.host); + resourceManager = new NgccResourceLoader(); + refEmitter = new ReferenceEmitter([ + new LocalIdentifierStrategy(), + new AbsoluteModuleStrategy(this.program, this.typeChecker, this.options, this.host), + // TODO(alxhub): there's no reason why ngcc needs the "logical file system" logic here, as ngcc + // projects only ever have one rootDir. Instead, ngcc should just switch its emitted imort based + // on whether a bestGuessOwningModule is present in the Reference. + new LogicalProjectStrategy(this.typeChecker, new LogicalFileSystem(this.rootDirs)), + ]); + scopeRegistry = new SelectorScopeRegistry(this.typeChecker, this.reflectionHost, this.refEmitter); + evaluator = new PartialEvaluator(this.reflectionHost, this.typeChecker); + moduleResolver = new ModuleResolver(this.program, this.options, this.host); + importGraph = new ImportGraph(this.moduleResolver); + cycleAnalyzer = new CycleAnalyzer(this.importGraph); handlers: DecoratorHandler[] = [ - new BaseDefDecoratorHandler(this.typeChecker, this.host), + new BaseDefDecoratorHandler(this.reflectionHost, this.evaluator), new ComponentDecoratorHandler( - this.typeChecker, this.host, this.scopeRegistry, this.isCore, this.resourceLoader, - this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true), - new DirectiveDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), - new InjectableDecoratorHandler(this.host, this.isCore), + this.reflectionHost, this.evaluator, this.scopeRegistry, this.isCore, this.resourceManager, + this.rootDirs, /* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true, + this.moduleResolver, this.cycleAnalyzer), + new DirectiveDecoratorHandler( + this.reflectionHost, this.evaluator, this.scopeRegistry, this.isCore), + new InjectableDecoratorHandler(this.reflectionHost, this.isCore, /* strictCtorDeps */ false), new NgModuleDecoratorHandler( - this.typeChecker, this.host, this.scopeRegistry, this.referencesRegistry, this.isCore), - new PipeDecoratorHandler(this.typeChecker, this.host, this.scopeRegistry, this.isCore), + this.reflectionHost, this.evaluator, this.scopeRegistry, this.referencesRegistry, + this.isCore, /* routeAnalyzer */ null, this.refEmitter), + new PipeDecoratorHandler(this.reflectionHost, this.evaluator, this.scopeRegistry, this.isCore), ]; constructor( - private typeChecker: ts.TypeChecker, private host: NgccReflectionHost, - private referencesRegistry: ReferencesRegistry, private rootDirs: string[], - private isCore: boolean) {} + private program: ts.Program, private options: ts.CompilerOptions, + private host: ts.CompilerHost, private typeChecker: ts.TypeChecker, + private reflectionHost: NgccReflectionHost, private referencesRegistry: ReferencesRegistry, + private rootDirs: AbsoluteFsPath[], private isCore: boolean) {} /** * Analyze a program to find all the decorated files should be transformed. - * @param program The program whose files should be analysed. + * * @returns a map of the source files to the analysis for those files. */ - analyzeProgram(program: ts.Program): DecorationAnalyses { + analyzeProgram(): DecorationAnalyses { const decorationAnalyses = new DecorationAnalyses(); - const analysedFiles = - program.getSourceFiles().map(sourceFile => this.analyzeFile(sourceFile)).filter(isDefined); + const analysedFiles = this.program.getSourceFiles() + .map(sourceFile => this.analyzeFile(sourceFile)) + .filter(isDefined); const compiledFiles = analysedFiles.map(analysedFile => this.compileFile(analysedFile)); compiledFiles.forEach( compiledFile => decorationAnalyses.set(compiledFile.sourceFile, compiledFile)); @@ -92,7 +114,7 @@ export class DecorationAnalyzer { } protected analyzeFile(sourceFile: ts.SourceFile): AnalyzedFile|undefined { - const decoratedClasses = this.host.findDecoratedClasses(sourceFile); + const decoratedClasses = this.reflectionHost.findDecoratedClasses(sourceFile); return decoratedClasses.length ? { sourceFile, analyzedClasses: decoratedClasses.map(clazz => this.analyzeClass(clazz)).filter(isDefined) @@ -103,21 +125,52 @@ export class DecorationAnalyzer { protected analyzeClass(clazz: DecoratedClass): AnalyzedClass|null { const matchingHandlers = this.handlers .map(handler => { - const match = + const detected = handler.detect(clazz.declaration, clazz.decorators); - return {handler, match}; + return {handler, detected}; }) .filter(isMatchingHandler); - if (matchingHandlers.length > 1) { - throw new Error('TODO.Diagnostic: Class has multiple Angular decorators.'); - } if (matchingHandlers.length === 0) { return null; } - const {handler, match} = matchingHandlers[0]; - const {analysis, diagnostics} = handler.analyze(clazz.declaration, match); - return {...clazz, handler, analysis, diagnostics}; + const detections: {handler: DecoratorHandler, detected: DetectResult}[] = []; + let hasWeakHandler: boolean = false; + let hasNonWeakHandler: boolean = false; + let hasPrimaryHandler: boolean = false; + + for (const {handler, detected} of matchingHandlers) { + if (hasNonWeakHandler && handler.precedence === HandlerPrecedence.WEAK) { + continue; + } else if (hasWeakHandler && handler.precedence !== HandlerPrecedence.WEAK) { + // Clear all the WEAK handlers from the list of matches. + detections.length = 0; + } + if (hasPrimaryHandler && handler.precedence === HandlerPrecedence.PRIMARY) { + throw new Error(`TODO.Diagnostic: Class has multiple incompatible Angular decorators.`); + } + + detections.push({handler, detected}); + if (handler.precedence === HandlerPrecedence.WEAK) { + hasWeakHandler = true; + } else if (handler.precedence === HandlerPrecedence.SHARED) { + hasNonWeakHandler = true; + } else if (handler.precedence === HandlerPrecedence.PRIMARY) { + hasNonWeakHandler = true; + hasPrimaryHandler = true; + } + } + + const matches: {handler: DecoratorHandler, analysis: any}[] = []; + const allDiagnostics: ts.Diagnostic[] = []; + for (const {handler, detected} of detections) { + const {analysis, diagnostics} = handler.analyze(clazz.declaration, detected.metadata); + if (diagnostics !== undefined) { + allDiagnostics.push(...diagnostics); + } + matches.push({handler, analysis}); + } + return {...clazz, matches, diagnostics: allDiagnostics.length > 0 ? allDiagnostics : undefined}; } protected compileFile(analyzedFile: AnalyzedFile): CompiledFile { @@ -130,15 +183,20 @@ export class DecorationAnalyzer { } protected compileClass(clazz: AnalyzedClass, constantPool: ConstantPool): CompileResult[] { - let compilation = clazz.handler.compile(clazz.declaration, clazz.analysis, constantPool); - if (!Array.isArray(compilation)) { - compilation = [compilation]; + const compilations: CompileResult[] = []; + for (const {handler, analysis} of clazz.matches) { + const result = handler.compile(clazz.declaration, analysis, constantPool); + if (Array.isArray(result)) { + compilations.push(...result); + } else { + compilations.push(result); + } } - return compilation; + return compilations; } } function isMatchingHandler(handler: Partial>): handler is MatchingHandler { - return !!handler.match; + return !!handler.detected; } diff --git a/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts b/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts index fe774860d9..6155c19890 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/module_with_providers_analyzer.ts @@ -8,8 +8,8 @@ import * as ts from 'typescript'; import {ReferencesRegistry} from '../../../ngtsc/annotations'; -import {Declaration} from '../../../ngtsc/host'; -import {ResolvedReference} from '../../../ngtsc/metadata'; +import {Reference} from '../../../ngtsc/imports'; +import {Declaration} from '../../../ngtsc/reflection'; import {NgccReflectionHost} from '../host/ngcc_host'; import {isDefined} from '../utils'; @@ -62,7 +62,9 @@ export class ModuleWithProvidersAnalyzer { `The referenced NgModule in ${fn.declaration.getText()} is not a class declaration in the typings program; instead we get ${dtsNgModule.getText()}`); } // Record the usage of the internal module as it needs to become an exported symbol - this.referencesRegistry.add(new ResolvedReference(ngModule.node, fn.ngModule)); + const reference = new Reference(ngModule.node); + reference.addIdentifier(fn.ngModule); + this.referencesRegistry.add(ngModule.node, reference); ngModule = {node: dtsNgModule, viaModule: null}; } diff --git a/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts b/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts index f4779456b6..08a7f86e24 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/ngcc_references_registry.ts @@ -8,8 +8,8 @@ import * as ts from 'typescript'; import {ReferencesRegistry} from '../../../ngtsc/annotations'; -import {Declaration, ReflectionHost} from '../../../ngtsc/host'; -import {Reference, ResolvedReference} from '../../../ngtsc/metadata'; +import {Reference} from '../../../ngtsc/imports'; +import {Declaration, ReflectionHost} from '../../../ngtsc/reflection'; import {hasNameIdentifier} from '../utils'; /** @@ -29,10 +29,10 @@ export class NgccReferencesRegistry implements ReferencesRegistry { * Only `ResolveReference` references are stored. Other types are ignored. * @param references A collection of references to register. */ - add(...references: Reference[]): void { + add(source: ts.Declaration, ...references: Reference[]): void { references.forEach(ref => { - // Only store resolved references. We are not interested in literals. - if (ref instanceof ResolvedReference && hasNameIdentifier(ref.node)) { + // Only store relative references. We are not interested in literals. + if (ref.bestGuessOwningModule === null && hasNameIdentifier(ref.node)) { const declaration = this.host.getDeclarationOfIdentifier(ref.node.name); if (declaration && hasNameIdentifier(declaration.node)) { this.map.set(declaration.node.name, declaration); diff --git a/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts b/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts index 3420b669b6..bfa76cf0c6 100644 --- a/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts +++ b/packages/compiler-cli/src/ngcc/src/analysis/private_declarations_analyzer.ts @@ -7,10 +7,10 @@ */ import * as ts from 'typescript'; -import {ReferencesRegistry} from '../../../ngtsc/annotations'; -import {Declaration} from '../../../ngtsc/host'; +import {Declaration} from '../../../ngtsc/reflection'; import {NgccReflectionHost} from '../host/ngcc_host'; import {hasNameIdentifier, isDefined} from '../utils'; +import {NgccReferencesRegistry} from './ngcc_references_registry'; export interface ExportInfo { identifier: string; @@ -24,7 +24,8 @@ export type PrivateDeclarationsAnalyses = ExportInfo[]; * (i.e. on an NgModule) that are not publicly exported via an entry-point. */ export class PrivateDeclarationsAnalyzer { - constructor(private host: NgccReflectionHost, private referencesRegistry: ReferencesRegistry) {} + constructor( + private host: NgccReflectionHost, private referencesRegistry: NgccReferencesRegistry) {} analyzeProgram(program: ts.Program): PrivateDeclarationsAnalyses { const rootFiles = this.getRootFiles(program); diff --git a/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts b/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts index 46cd4c8a19..985ef0a596 100644 --- a/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts +++ b/packages/compiler-cli/src/ngcc/src/host/decorated_class.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {Decorator} from '../../../ngtsc/host'; +import {Decorator} from '../../../ngtsc/reflection'; /** * A simple container that holds the details of a decorated class that has been diff --git a/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts index 34f3345369..c0dfa93d1b 100644 --- a/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/src/ngcc/src/host/esm2015_host.ts @@ -8,8 +8,7 @@ import * as ts from 'typescript'; -import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host'; -import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata'; +import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import, TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/reflection'; import {BundleProgram} from '../packages/bundle_program'; import {findAll, getNameText, isDefined} from '../utils'; @@ -103,10 +102,11 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N // that are initialized in the class. if (symbol.members) { symbol.members.forEach((value, key) => { - const decorators = removeFromMap(decoratorsMap, key); - const member = this.reflectMember(value, decorators); - if (member) { - members.push(member); + const decorators = decoratorsMap.get(key as string); + const reflectedMembers = this.reflectMembers(value, decorators); + if (reflectedMembers) { + decoratorsMap.delete(key as string); + members.push(...reflectedMembers); } }); } @@ -114,10 +114,11 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N // The static property map contains all the static properties if (symbol.exports) { symbol.exports.forEach((value, key) => { - const decorators = removeFromMap(decoratorsMap, key); - const member = this.reflectMember(value, decorators, true); - if (member) { - members.push(member); + const decorators = decoratorsMap.get(key as string); + const reflectedMembers = this.reflectMembers(value, decorators, true); + if (reflectedMembers) { + decoratorsMap.delete(key as string); + members.push(...reflectedMembers); } }); } @@ -135,10 +136,11 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N const variableSymbol = this.checker.getSymbolAtLocation(symbol.valueDeclaration.parent.name); if (variableSymbol && variableSymbol.exports) { variableSymbol.exports.forEach((value, key) => { - const decorators = removeFromMap(decoratorsMap, key); - const member = this.reflectMember(value, decorators, true); - if (member) { - members.push(member); + const decorators = decoratorsMap.get(key as string); + const reflectedMembers = this.reflectMembers(value, decorators, true); + if (reflectedMembers) { + decoratorsMap.delete(key as string); + members.push(...reflectedMembers); } }); } @@ -662,8 +664,10 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N */ protected getHelperCall(statement: ts.Statement, helperName: string): ts.CallExpression|null { if (ts.isExpressionStatement(statement)) { - const expression = - isAssignmentStatement(statement) ? statement.expression.right : statement.expression; + let expression = statement.expression; + while (isAssignment(expression)) { + expression = expression.right; + } if (ts.isCallExpression(expression) && getCalleeName(expression) === helperName) { return expression; } @@ -718,37 +722,93 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N /** * Reflect over a symbol and extract the member information, combining it with the * provided decorator information, and whether it is a static member. + * + * A single symbol may represent multiple class members in the case of accessors; + * an equally named getter/setter accessor pair is combined into a single symbol. + * When the symbol is recognized as representing an accessor, its declarations are + * analyzed such that both the setter and getter accessor are returned as separate + * class members. + * + * One difference wrt the TypeScript host is that in ES2015, we cannot see which + * accessor originally had any decorators applied to them, as decorators are applied + * to the property descriptor in general, not a specific accessor. If an accessor + * has both a setter and getter, any decorators are only attached to the setter member. + * * @param symbol the symbol for the member to reflect over. * @param decorators an array of decorators associated with the member. * @param isStatic true if this member is static, false if it is an instance property. * @returns the reflected member information, or null if the symbol is not a member. */ - protected reflectMember(symbol: ts.Symbol, decorators?: Decorator[], isStatic?: boolean): - ClassMember|null { - let kind: ClassMemberKind|null = null; - let value: ts.Expression|null = null; - let name: string|null = null; - let nameNode: ts.Identifier|null = null; + protected reflectMembers(symbol: ts.Symbol, decorators?: Decorator[], isStatic?: boolean): + ClassMember[]|null { + if (symbol.flags & ts.SymbolFlags.Accessor) { + const members: ClassMember[] = []; + const setter = symbol.declarations && symbol.declarations.find(ts.isSetAccessor); + const getter = symbol.declarations && symbol.declarations.find(ts.isGetAccessor); + const setterMember = + setter && this.reflectMember(setter, ClassMemberKind.Setter, decorators, isStatic); + if (setterMember) { + members.push(setterMember); - const node = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; - if (!node || !isClassMemberType(node)) { - return null; + // Prevent attaching the decorators to a potential getter. In ES2015, we can't tell where + // the decorators were originally attached to, however we only want to attach them to a + // single `ClassMember` as otherwise ngtsc would handle the same decorators twice. + decorators = undefined; + } + + const getterMember = + getter && this.reflectMember(getter, ClassMemberKind.Getter, decorators, isStatic); + if (getterMember) { + members.push(getterMember); + } + + return members; } + let kind: ClassMemberKind|null = null; if (symbol.flags & ts.SymbolFlags.Method) { kind = ClassMemberKind.Method; } else if (symbol.flags & ts.SymbolFlags.Property) { kind = ClassMemberKind.Property; - } else if (symbol.flags & ts.SymbolFlags.GetAccessor) { - kind = ClassMemberKind.Getter; - } else if (symbol.flags & ts.SymbolFlags.SetAccessor) { - kind = ClassMemberKind.Setter; + } + + const node = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; + if (!node) { + return null; + } + + const member = this.reflectMember(node, kind, decorators, isStatic); + if (!member) { + return null; + } + + return [member]; + } + + /** + * Reflect over a symbol and extract the member information, combining it with the + * provided decorator information, and whether it is a static member. + * @param node the declaration node for the member to reflect over. + * @param kind the assumed kind of the member, may become more accurate during reflection. + * @param decorators an array of decorators associated with the member. + * @param isStatic true if this member is static, false if it is an instance property. + * @returns the reflected member information, or null if the symbol is not a member. + */ + protected reflectMember( + node: ts.Declaration, kind: ClassMemberKind|null, decorators?: Decorator[], + isStatic?: boolean): ClassMember|null { + let value: ts.Expression|null = null; + let name: string|null = null; + let nameNode: ts.Identifier|null = null; + + if (!isClassMemberType(node)) { + return null; } if (isStatic && isPropertyAccess(node)) { name = node.name.text; - value = symbol.flags & ts.SymbolFlags.Property ? node.parent.right : null; + value = kind === ClassMemberKind.Property ? node.parent.right : null; } else if (isThisAssignment(node)) { kind = ClassMemberKind.Property; name = node.left.name.text; @@ -801,10 +861,16 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N if (constructorSymbol) { // For some reason the constructor does not have a `valueDeclaration` ?!? const constructor = constructorSymbol.declarations && - constructorSymbol.declarations[0] as ts.ConstructorDeclaration; - if (constructor && constructor.parameters) { + constructorSymbol.declarations[0] as ts.ConstructorDeclaration | undefined; + if (!constructor) { + return []; + } + if (constructor.parameters.length > 0) { return Array.from(constructor.parameters); } + if (isSynthesizedConstructor(constructor)) { + return null; + } return []; } return null; @@ -1162,15 +1228,6 @@ function getDecoratorArgs(node: ts.ObjectLiteralExpression): ts.Expression[] { []; } -function removeFromMap(map: Map, key: ts.__String): T|undefined { - const mapKey = key as string; - const value = map.get(mapKey); - if (value !== undefined) { - map.delete(mapKey); - } - return value; -} - function isPropertyAccess(node: ts.Node): node is ts.PropertyAccessExpression& {parent: ts.BinaryExpression} { return !!node.parent && ts.isBinaryExpression(node.parent) && ts.isPropertyAccessExpression(node); @@ -1229,3 +1286,52 @@ function collectExportedDeclarations( }); } } + + +/** + * A constructor function may have been "synthesized" by TypeScript during JavaScript emit, + * in the case no user-defined constructor exists and e.g. property initializers are used. + * Those initializers need to be emitted into a constructor in JavaScript, so the TypeScript + * compiler generates a synthetic constructor. + * + * We need to identify such constructors as ngcc needs to be able to tell if a class did + * originally have a constructor in the TypeScript source. When a class has a superclass, + * a synthesized constructor must not be considered as a user-defined constructor as that + * prevents a base factory call from being created by ngtsc, resulting in a factory function + * that does not inject the dependencies of the superclass. Hence, we identify a default + * synthesized super call in the constructor body, according to the structure that TypeScript + * emits during JavaScript emit: + * https://github.com/Microsoft/TypeScript/blob/v3.2.2/src/compiler/transformers/ts.ts#L1068-L1082 + * + * @param constructor a constructor function to test + * @returns true if the constructor appears to have been synthesized + */ +function isSynthesizedConstructor(constructor: ts.ConstructorDeclaration): boolean { + if (!constructor.body) return false; + + const firstStatement = constructor.body.statements[0]; + if (!firstStatement || !ts.isExpressionStatement(firstStatement)) return false; + + return isSynthesizedSuperCall(firstStatement.expression); +} + +/** + * Tests whether the expression appears to have been synthesized by TypeScript, i.e. whether + * it is of the following form: + * + * ``` + * super(...arguments); + * ``` + * + * @param expression the expression that is to be tested + * @returns true if the expression appears to be a synthesized super call + */ +function isSynthesizedSuperCall(expression: ts.Expression): boolean { + if (!ts.isCallExpression(expression)) return false; + if (expression.expression.kind !== ts.SyntaxKind.SuperKeyword) return false; + if (expression.arguments.length !== 1) return false; + + const argument = expression.arguments[0]; + return ts.isSpreadElement(argument) && ts.isIdentifier(argument.expression) && + argument.expression.text === 'arguments'; +} diff --git a/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts b/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts index 8eb0837607..77490430aa 100644 --- a/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts +++ b/packages/compiler-cli/src/ngcc/src/host/esm5_host.ts @@ -8,9 +8,8 @@ import * as ts from 'typescript'; -import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter} from '../../../ngtsc/host'; -import {reflectObjectLiteral} from '../../../ngtsc/metadata'; -import {getNameText} from '../utils'; +import {ClassMember, ClassMemberKind, Declaration, Decorator, FunctionDefinition, Parameter, reflectObjectLiteral} from '../../../ngtsc/reflection'; +import {getNameText, hasNameIdentifier} from '../utils'; import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './esm2015_host'; @@ -42,11 +41,29 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { return super.isClass(node) || !!this.getClassSymbol(node); } + /** + * Determines whether the given declaration has a base class. + * + * In ES5, we need to determine if the IIFE wrapper takes a `_super` parameter . + */ + hasBaseClass(node: ts.Declaration): boolean { + const classSymbol = this.getClassSymbol(node); + if (!classSymbol) return false; + + const iifeBody = classSymbol.valueDeclaration.parent; + if (!iifeBody || !ts.isBlock(iifeBody)) return false; + + const iife = iifeBody.parent; + if (!iife || !ts.isFunctionExpression(iife)) return false; + + return iife.parameters.length === 1 && isSuperIdentifier(iife.parameters[0].name); + } + /** * Find a symbol for a node that we think is a class. * * In ES5, the implementation of a class is a function expression that is hidden inside an IIFE. - * So we need to dig around inside to get hold of the "class" symbol. + * So we might need to dig around inside to get hold of the "class" symbol. * * `node` might be one of: * - A class declaration (from a declaration file). @@ -70,33 +87,40 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { if (!innerClassIdentifier) return undefined; return this.checker.getSymbolAtLocation(innerClassIdentifier); - } else if (ts.isFunctionDeclaration(node)) { - // It might be the function expression inside the IIFE. We need to go 5 levels up... - - // 1. IIFE body. - let outerNode = node.parent; - if (!outerNode || !ts.isBlock(outerNode)) return undefined; - - // 2. IIFE function expression. - outerNode = outerNode.parent; - if (!outerNode || !ts.isFunctionExpression(outerNode)) return undefined; - - // 3. IIFE call expression. - outerNode = outerNode.parent; - if (!outerNode || !ts.isCallExpression(outerNode)) return undefined; - - // 4. Parenthesis around IIFE. - outerNode = outerNode.parent; - if (!outerNode || !ts.isParenthesizedExpression(outerNode)) return undefined; - - // 5. Outer variable declaration. - outerNode = outerNode.parent; - if (!outerNode || !ts.isVariableDeclaration(outerNode)) return undefined; - - return this.getClassSymbol(outerNode); } - return undefined; + const outerClassNode = getClassDeclarationFromInnerFunctionDeclaration(node); + + return outerClassNode && this.getClassSymbol(outerClassNode); + } + + /** + * Trace an identifier to its declaration, if possible. + * + * This method attempts to resolve the declaration of the given identifier, tracing back through + * imports and re-exports until the original declaration statement is found. A `Declaration` + * object is returned if the original declaration is found, or `null` is returned otherwise. + * + * In ES5, the implementation of a class is a function expression that is hidden inside an IIFE. + * If we are looking for the declaration of the identifier of the inner function expression, we + * will get hold of the outer "class" variable declaration and return its identifier instead. See + * `getClassDeclarationFromInnerFunctionDeclaration()` for more info. + * + * @param id a TypeScript `ts.Identifier` to trace back to a declaration. + * + * @returns metadata about the `Declaration` if the original declaration is found, or `null` + * otherwise. + */ + getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null { + // Get the identifier for the outer class node (if any). + const outerClassNode = getClassDeclarationFromInnerFunctionDeclaration(id.parent); + + if (outerClassNode && hasNameIdentifier(outerClassNode)) { + id = outerClassNode.name; + } + + // Resolve the identifier to a Symbol, and return the declaration of that. + return super.getDeclarationOfIdentifier(id); } /** @@ -138,11 +162,15 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { * @returns an array of `ts.ParameterDeclaration` objects representing each of the parameters in * the class's constructor or null if there is no constructor. */ - protected getConstructorParameterDeclarations(classSymbol: ts.Symbol): ts.ParameterDeclaration[] { + protected getConstructorParameterDeclarations(classSymbol: ts.Symbol): + ts.ParameterDeclaration[]|null { const constructor = classSymbol.valueDeclaration as ts.FunctionDeclaration; - if (constructor && constructor.parameters) { + if (constructor.parameters.length > 0) { return Array.from(constructor.parameters); } + if (isSynthesizedConstructor(constructor)) { + return null; + } return []; } @@ -187,24 +215,69 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { /** * Reflect over a symbol and extract the member information, combining it with the * provided decorator information, and whether it is a static member. + * + * If a class member uses accessors (e.g getters and/or setters) then it gets downleveled + * in ES5 to a single `Object.defineProperty()` call. In that case we must parse this + * call to extract the one or two ClassMember objects that represent the accessors. + * * @param symbol the symbol for the member to reflect over. * @param decorators an array of decorators associated with the member. * @param isStatic true if this member is static, false if it is an instance property. * @returns the reflected member information, or null if the symbol is not a member. */ - protected reflectMember(symbol: ts.Symbol, decorators?: Decorator[], isStatic?: boolean): - ClassMember|null { - const member = super.reflectMember(symbol, decorators, isStatic); - if (member && member.kind === ClassMemberKind.Method && member.isStatic && member.node && - ts.isPropertyAccessExpression(member.node) && member.node.parent && - ts.isBinaryExpression(member.node.parent) && - ts.isFunctionExpression(member.node.parent.right)) { - // Recompute the implementation for this member: - // ES5 static methods are variable declarations so the declaration is actually the - // initializer of the variable assignment - member.implementation = member.node.parent.right; + protected reflectMembers(symbol: ts.Symbol, decorators?: Decorator[], isStatic?: boolean): + ClassMember[]|null { + const node = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; + const propertyDefinition = getPropertyDefinition(node); + if (propertyDefinition) { + const members: ClassMember[] = []; + if (propertyDefinition.setter) { + members.push({ + node, + implementation: propertyDefinition.setter, + kind: ClassMemberKind.Setter, + type: null, + name: symbol.name, + nameNode: null, + value: null, + isStatic: isStatic || false, + decorators: decorators || [], + }); + + // Prevent attaching the decorators to a potential getter. In ES5, we can't tell where the + // decorators were originally attached to, however we only want to attach them to a single + // `ClassMember` as otherwise ngtsc would handle the same decorators twice. + decorators = undefined; + } + if (propertyDefinition.getter) { + members.push({ + node, + implementation: propertyDefinition.getter, + kind: ClassMemberKind.Getter, + type: null, + name: symbol.name, + nameNode: null, + value: null, + isStatic: isStatic || false, + decorators: decorators || [], + }); + } + return members; } - return member; + + const members = super.reflectMembers(symbol, decorators, isStatic); + members && members.forEach(member => { + if (member && member.kind === ClassMemberKind.Method && member.isStatic && member.node && + ts.isPropertyAccessExpression(member.node) && member.node.parent && + ts.isBinaryExpression(member.node.parent) && + ts.isFunctionExpression(member.node.parent.right)) { + // Recompute the implementation for this member: + // ES5 static methods are variable declarations so the declaration is actually the + // initializer of the variable assignment + member.implementation = member.node.parent.right; + } + }); + return members; } /** @@ -225,6 +298,106 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { ///////////// Internal Helpers ///////////// +/** + * Represents the details about property definitions that were set using `Object.defineProperty`. + */ +interface PropertyDefinition { + setter: ts.FunctionExpression|null; + getter: ts.FunctionExpression|null; +} + +/** + * In ES5, getters and setters have been downleveled into call expressions of + * `Object.defineProperty`, such as + * + * ``` + * Object.defineProperty(Clazz.prototype, "property", { + * get: function () { + * return 'value'; + * }, + * set: function (value) { + * this.value = value; + * }, + * enumerable: true, + * configurable: true + * }); + * ``` + * + * This function inspects the given node to determine if it corresponds with such a call, and if so + * extracts the `set` and `get` function expressions from the descriptor object, if they exist. + * + * @param node The node to obtain the property definition from. + * @returns The property definition if the node corresponds with accessor, null otherwise. + */ +function getPropertyDefinition(node: ts.Node): PropertyDefinition|null { + if (!ts.isCallExpression(node)) return null; + + const fn = node.expression; + if (!ts.isPropertyAccessExpression(fn) || !ts.isIdentifier(fn.expression) || + fn.expression.text !== 'Object' || fn.name.text !== 'defineProperty') + return null; + + const descriptor = node.arguments[2]; + if (!descriptor || !ts.isObjectLiteralExpression(descriptor)) return null; + + return { + setter: readPropertyFunctionExpression(descriptor, 'set'), + getter: readPropertyFunctionExpression(descriptor, 'get'), + }; +} + +function readPropertyFunctionExpression(object: ts.ObjectLiteralExpression, name: string) { + const property = object.properties.find( + (p): p is ts.PropertyAssignment => + ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === name); + + return property && ts.isFunctionExpression(property.initializer) && property.initializer || null; +} + +/** + * Get the actual (outer) declaration of a class. + * + * In ES5, the implementation of a class is a function expression that is hidden inside an IIFE and + * returned to be assigned to a variable outside the IIFE, which is what the rest of the program + * interacts with. + * + * Given the inner function declaration, we want to get to the declaration of the outer variable + * that represents the class. + * + * @param node a node that could be the function expression inside an ES5 class IIFE. + * @returns the outer variable declaration or `undefined` if it is not a "class". + */ +function getClassDeclarationFromInnerFunctionDeclaration(node: ts.Node): ts.VariableDeclaration| + undefined { + if (ts.isFunctionDeclaration(node)) { + // It might be the function expression inside the IIFE. We need to go 5 levels up... + + // 1. IIFE body. + let outerNode = node.parent; + if (!outerNode || !ts.isBlock(outerNode)) return undefined; + + // 2. IIFE function expression. + outerNode = outerNode.parent; + if (!outerNode || !ts.isFunctionExpression(outerNode)) return undefined; + + // 3. IIFE call expression. + outerNode = outerNode.parent; + if (!outerNode || !ts.isCallExpression(outerNode)) return undefined; + + // 4. Parenthesis around IIFE. + outerNode = outerNode.parent; + if (!outerNode || !ts.isParenthesizedExpression(outerNode)) return undefined; + + // 5. Outer variable declaration. + outerNode = outerNode.parent; + if (!outerNode || !ts.isVariableDeclaration(outerNode)) return undefined; + + return outerNode; + } + + return undefined; +} + function getIifeBody(declaration: ts.VariableDeclaration): ts.Block|undefined { if (!declaration.initializer || !ts.isParenthesizedExpression(declaration.initializer)) { return undefined; @@ -254,6 +427,147 @@ function reflectArrayElement(element: ts.Expression) { return ts.isObjectLiteralExpression(element) ? reflectObjectLiteral(element) : null; } +/** + * A constructor function may have been "synthesized" by TypeScript during JavaScript emit, + * in the case no user-defined constructor exists and e.g. property initializers are used. + * Those initializers need to be emitted into a constructor in JavaScript, so the TypeScript + * compiler generates a synthetic constructor. + * + * We need to identify such constructors as ngcc needs to be able to tell if a class did + * originally have a constructor in the TypeScript source. For ES5, we can not tell an + * empty constructor apart from a synthesized constructor, but fortunately that does not + * matter for the code generated by ngtsc. + * + * When a class has a superclass however, a synthesized constructor must not be considered + * as a user-defined constructor as that prevents a base factory call from being created by + * ngtsc, resulting in a factory function that does not inject the dependencies of the + * superclass. Hence, we identify a default synthesized super call in the constructor body, + * according to the structure that TypeScript's ES2015 to ES5 transformer generates in + * https://github.com/Microsoft/TypeScript/blob/v3.2.2/src/compiler/transformers/es2015.ts#L1082-L1098 + * + * @param constructor a constructor function to test + * @returns true if the constructor appears to have been synthesized + */ +function isSynthesizedConstructor(constructor: ts.FunctionDeclaration): boolean { + if (!constructor.body) return false; + + const firstStatement = constructor.body.statements[0]; + if (!firstStatement) return false; + + return isSynthesizedSuperThisAssignment(firstStatement) || + isSynthesizedSuperReturnStatement(firstStatement); +} + +/** + * Identifies a synthesized super call of the form: + * + * ``` + * var _this = _super !== null && _super.apply(this, arguments) || this; + * ``` + * + * @param statement a statement that may be a synthesized super call + * @returns true if the statement looks like a synthesized super call + */ +function isSynthesizedSuperThisAssignment(statement: ts.Statement): boolean { + if (!ts.isVariableStatement(statement)) return false; + + const variableDeclarations = statement.declarationList.declarations; + if (variableDeclarations.length !== 1) return false; + + const variableDeclaration = variableDeclarations[0]; + if (!ts.isIdentifier(variableDeclaration.name) || + !variableDeclaration.name.text.startsWith('_this')) + return false; + + const initializer = variableDeclaration.initializer; + if (!initializer) return false; + + return isSynthesizedDefaultSuperCall(initializer); +} +/** + * Identifies a synthesized super call of the form: + * + * ``` + * return _super !== null && _super.apply(this, arguments) || this; + * ``` + * + * @param statement a statement that may be a synthesized super call + * @returns true if the statement looks like a synthesized super call + */ +function isSynthesizedSuperReturnStatement(statement: ts.Statement): boolean { + if (!ts.isReturnStatement(statement)) return false; + + const expression = statement.expression; + if (!expression) return false; + + return isSynthesizedDefaultSuperCall(expression); +} + +/** + * Tests whether the expression is of the form: + * + * ``` + * _super !== null && _super.apply(this, arguments) || this; + * ``` + * + * This structure is generated by TypeScript when transforming ES2015 to ES5, see + * https://github.com/Microsoft/TypeScript/blob/v3.2.2/src/compiler/transformers/es2015.ts#L1148-L1163 + * + * @param expression an expression that may represent a default super call + * @returns true if the expression corresponds with the above form + */ +function isSynthesizedDefaultSuperCall(expression: ts.Expression): boolean { + if (!isBinaryExpr(expression, ts.SyntaxKind.BarBarToken)) return false; + if (expression.right.kind !== ts.SyntaxKind.ThisKeyword) return false; + + const left = expression.left; + if (!isBinaryExpr(left, ts.SyntaxKind.AmpersandAmpersandToken)) return false; + + return isSuperNotNull(left.left) && isSuperApplyCall(left.right); +} + +function isSuperNotNull(expression: ts.Expression): boolean { + return isBinaryExpr(expression, ts.SyntaxKind.ExclamationEqualsEqualsToken) && + isSuperIdentifier(expression.left); +} + +/** + * Tests whether the expression is of the form + * + * ``` + * _super.apply(this, arguments) + * ``` + * + * @param expression an expression that may represent a default super call + * @returns true if the expression corresponds with the above form + */ +function isSuperApplyCall(expression: ts.Expression): boolean { + if (!ts.isCallExpression(expression) || expression.arguments.length !== 2) return false; + + const targetFn = expression.expression; + if (!ts.isPropertyAccessExpression(targetFn)) return false; + if (!isSuperIdentifier(targetFn.expression)) return false; + if (targetFn.name.text !== 'apply') return false; + + const thisArgument = expression.arguments[0]; + if (thisArgument.kind !== ts.SyntaxKind.ThisKeyword) return false; + + const argumentsArgument = expression.arguments[1]; + return ts.isIdentifier(argumentsArgument) && argumentsArgument.text === 'arguments'; +} + +function isBinaryExpr( + expression: ts.Expression, operator: ts.BinaryOperator): expression is ts.BinaryExpression { + return ts.isBinaryExpression(expression) && expression.operatorToken.kind === operator; +} + +function isSuperIdentifier(node: ts.Node): boolean { + // Verify that the identifier is prefixed with `_super`. We don't test for equivalence + // as TypeScript may have suffixed the name, e.g. `_super_1` to avoid name conflicts. + // Requiring only a prefix should be sufficiently accurate. + return ts.isIdentifier(node) && node.text.startsWith('_super'); +} + /** * Parse the statement to extract the ESM5 parameter initializer if there is one. * If one is found, add it to the appropriate parameter in the `parameters` collection. diff --git a/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts b/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts index 1dc7ae8759..38076c9d5e 100644 --- a/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts +++ b/packages/compiler-cli/src/ngcc/src/host/ngcc_host.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import {ReflectionHost} from '../../../ngtsc/host'; +import {ReflectionHost} from '../../../ngtsc/reflection'; import {DecoratedClass} from './decorated_class'; export const PRE_R3_MARKER = '__PRE_R3__'; diff --git a/packages/compiler-cli/src/ngcc/src/packages/bundle_program.ts b/packages/compiler-cli/src/ngcc/src/packages/bundle_program.ts index 9bbcd8abb8..5c8ba5eeb3 100644 --- a/packages/compiler-cli/src/ngcc/src/packages/bundle_program.ts +++ b/packages/compiler-cli/src/ngcc/src/packages/bundle_program.ts @@ -19,6 +19,8 @@ import * as ts from 'typescript'; */ export interface BundleProgram { program: ts.Program; + options: ts.CompilerOptions; + host: ts.CompilerHost; path: string; file: ts.SourceFile; r3SymbolsPath: string|null; @@ -37,7 +39,7 @@ export function makeBundleProgram( const file = program.getSourceFile(path) !; const r3SymbolsFile = r3SymbolsPath && program.getSourceFile(r3SymbolsPath) || null; - return {program, path, file, r3SymbolsPath, r3SymbolsFile}; + return {program, options, host, path, file, r3SymbolsPath, r3SymbolsFile}; } /** diff --git a/packages/compiler-cli/src/ngcc/src/packages/entry_point_bundle.ts b/packages/compiler-cli/src/ngcc/src/packages/entry_point_bundle.ts index 3dbbaee262..d04da8fe7e 100644 --- a/packages/compiler-cli/src/ngcc/src/packages/entry_point_bundle.ts +++ b/packages/compiler-cli/src/ngcc/src/packages/entry_point_bundle.ts @@ -7,10 +7,13 @@ */ import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../../../ngtsc/path'; + import {BundleProgram, makeBundleProgram} from './bundle_program'; import {EntryPoint, EntryPointFormat} from './entry_point'; + /** * A bundle of files and paths (and TS programs) that correspond to a particular * format of a package entry-point. @@ -18,7 +21,7 @@ import {EntryPoint, EntryPointFormat} from './entry_point'; export interface EntryPointBundle { format: EntryPointFormat; isFlat: boolean; - rootDirs: string[]; + rootDirs: AbsoluteFsPath[]; src: BundleProgram; dts: BundleProgram|null; } @@ -45,7 +48,7 @@ export function makeEntryPointBundle( rootDir: entryPoint.path, }; const host = ts.createCompilerHost(options); - const rootDirs = [entryPoint.path]; + const rootDirs = [AbsoluteFsPath.from(entryPoint.path)]; // Create the bundle programs, as necessary. const src = makeBundleProgram(isCore, path, 'r3_symbols.js', options, host); diff --git a/packages/compiler-cli/src/ngcc/src/packages/transformer.ts b/packages/compiler-cli/src/ngcc/src/packages/transformer.ts index e2bf4a57a8..fb1ff94ebc 100644 --- a/packages/compiler-cli/src/ngcc/src/packages/transformer.ts +++ b/packages/compiler-cli/src/ngcc/src/packages/transformer.ts @@ -110,8 +110,9 @@ export class Transformer { const switchMarkerAnalyses = switchMarkerAnalyzer.analyzeProgram(bundle.src.program); const decorationAnalyzer = new DecorationAnalyzer( - typeChecker, reflectionHost, referencesRegistry, bundle.rootDirs, isCore); - const decorationAnalyses = decorationAnalyzer.analyzeProgram(bundle.src.program); + bundle.src.program, bundle.src.options, bundle.src.host, typeChecker, reflectionHost, + referencesRegistry, bundle.rootDirs, isCore); + const decorationAnalyses = decorationAnalyzer.analyzeProgram(); const moduleWithProvidersAnalyzer = bundle.dts && new ModuleWithProvidersAnalyzer(reflectionHost, referencesRegistry); diff --git a/packages/compiler-cli/src/ngcc/src/rendering/ngcc_import_manager.ts b/packages/compiler-cli/src/ngcc/src/rendering/ngcc_import_manager.ts deleted file mode 100644 index 2dbd05f1d8..0000000000 --- a/packages/compiler-cli/src/ngcc/src/rendering/ngcc_import_manager.ts +++ /dev/null @@ -1,22 +0,0 @@ - -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {ImportManager} from '../../../ngtsc/translator'; - -export class NgccImportManager extends ImportManager { - constructor(private isFlat: boolean, isCore: boolean, prefix?: string) { super(isCore, prefix); } - - generateNamedImport(moduleName: string, symbol: string): - {moduleImport: string | null, symbol: string} { - if (this.isFlat && this.isCore && moduleName === '@angular/core') { - return {moduleImport: null, symbol: this.rewriteSymbol(moduleName, symbol)}; - } - return super.generateNamedImport(moduleName, symbol); - } -} diff --git a/packages/compiler-cli/src/ngcc/src/rendering/ngcc_import_rewriter.ts b/packages/compiler-cli/src/ngcc/src/rendering/ngcc_import_rewriter.ts new file mode 100644 index 0000000000..dc63243859 --- /dev/null +++ b/packages/compiler-cli/src/ngcc/src/rendering/ngcc_import_rewriter.ts @@ -0,0 +1,34 @@ + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ImportRewriter, validateAndRewriteCoreSymbol} from '../../../ngtsc/imports'; + +export class NgccFlatImportRewriter implements ImportRewriter { + shouldImportSymbol(symbol: string, specifier: string): boolean { + if (specifier === '@angular/core') { + // Don't use imports for @angular/core symbols in a flat bundle, as they'll be visible + // directly. + return false; + } else { + return true; + } + } + + rewriteSymbol(symbol: string, specifier: string): string { + if (specifier === '@angular/core') { + return validateAndRewriteCoreSymbol(symbol); + } else { + return symbol; + } + } + + rewriteSpecifier(originalModulePath: string, inContextOfFile: string): string { + return originalModulePath; + } +} diff --git a/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts b/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts index f88c6775bf..e310b6172b 100644 --- a/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts +++ b/packages/compiler-cli/src/ngcc/src/rendering/renderer.ts @@ -13,10 +13,10 @@ import {basename, dirname, relative, resolve} from 'canonical-path'; import {SourceMapConsumer, SourceMapGenerator, RawSourceMap} from 'source-map'; import * as ts from 'typescript'; -import {Decorator} from '../../../ngtsc/host'; +import {NoopImportRewriter, ImportRewriter, R3SymbolsImportRewriter} from '@angular/compiler-cli/src/ngtsc/imports'; import {CompileResult} from '@angular/compiler-cli/src/ngtsc/transform'; import {translateStatement, translateType, ImportManager} from '../../../ngtsc/translator'; -import {NgccImportManager} from './ngcc_import_manager'; +import {NgccFlatImportRewriter} from './ngcc_import_rewriter'; import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/decoration_analyzer'; import {ModuleWithProvidersInfo, ModuleWithProvidersAnalyses} from '../analysis/module_with_providers_analyzer'; import {PrivateDeclarationsAnalyses, ExportInfo} from '../analysis/private_declarations_analyzer'; @@ -136,7 +136,8 @@ export abstract class Renderer { } if (compiledFile) { - const importManager = new NgccImportManager(this.bundle.isFlat, this.isCore, IMPORT_PREFIX); + const importManager = new ImportManager( + this.getImportRewriter(this.bundle.src.r3SymbolsFile, this.bundle.isFlat), IMPORT_PREFIX); // TODO: remove constructor param metadata and property decorators (we need info from the // handlers to do this) @@ -153,9 +154,7 @@ export abstract class Renderer { renderConstantPool(compiledFile.sourceFile, compiledFile.constantPool, importManager), compiledFile.sourceFile); - this.addImports( - outputText, importManager.getAllImports( - compiledFile.sourceFile.fileName, this.bundle.src.r3SymbolsFile)); + this.addImports(outputText, importManager.getAllImports(compiledFile.sourceFile.fileName)); } // Add exports to the entry-point file @@ -170,20 +169,22 @@ export abstract class Renderer { renderDtsFile(dtsFile: ts.SourceFile, renderInfo: DtsRenderInfo): FileInfo[] { const input = this.extractSourceMap(dtsFile); const outputText = new MagicString(input.source); - const importManager = new NgccImportManager(false, this.isCore, IMPORT_PREFIX); + const printer = ts.createPrinter(); + const importManager = new ImportManager( + this.getImportRewriter(this.bundle.dts !.r3SymbolsFile, false), IMPORT_PREFIX); renderInfo.classInfo.forEach(dtsClass => { const endOfClass = dtsClass.dtsDeclaration.getEnd(); dtsClass.compilation.forEach(declaration => { const type = translateType(declaration.type, importManager); - const newStatement = ` static ${declaration.name}: ${type};\n`; + const typeStr = printer.printNode(ts.EmitHint.Unspecified, type, dtsFile); + const newStatement = ` static ${declaration.name}: ${typeStr};\n`; outputText.appendRight(endOfClass - 1, newStatement); }); }); this.addModuleWithProvidersParams(outputText, renderInfo.moduleWithProviders, importManager); - this.addImports( - outputText, importManager.getAllImports(dtsFile.fileName, this.bundle.dts !.r3SymbolsFile)); + this.addImports(outputText, importManager.getAllImports(dtsFile.fileName)); this.addExports(outputText, dtsFile.fileName, renderInfo.privateExports); @@ -200,7 +201,7 @@ export abstract class Renderer { */ protected addModuleWithProvidersParams( outputText: MagicString, moduleWithProviders: ModuleWithProvidersInfo[], - importManager: NgccImportManager): void { + importManager: ImportManager): void { moduleWithProviders.forEach(info => { const ngModuleName = (info.ngModule.node as ts.ClassDeclaration).name !.text; const declarationFile = info.declaration.getSourceFile().fileName; @@ -418,6 +419,16 @@ export abstract class Renderer { return ( id && id.name === 'ModuleWithProviders' && (this.isCore || id.from === '@angular/core')); } + + private getImportRewriter(r3SymbolsFile: ts.SourceFile|null, isFlat: boolean): ImportRewriter { + if (this.isCore && isFlat) { + return new NgccFlatImportRewriter(); + } else if (this.isCore) { + return new R3SymbolsImportRewriter(r3SymbolsFile !.fileName); + } else { + return new NoopImportRewriter(); + } + } } /** @@ -452,7 +463,7 @@ export function mergeSourceMaps( * Render the constant pool as source code for the given class. */ export function renderConstantPool( - sourceFile: ts.SourceFile, constantPool: ConstantPool, imports: NgccImportManager): string { + sourceFile: ts.SourceFile, constantPool: ConstantPool, imports: ImportManager): string { const printer = ts.createPrinter(); return constantPool.statements.map(stmt => translateStatement(stmt, imports)) .map(stmt => printer.printNode(ts.EmitHint.Unspecified, stmt, sourceFile)) @@ -468,7 +479,7 @@ export function renderConstantPool( * @param imports An object that tracks the imports that are needed by the rendered definitions. */ export function renderDefinitions( - sourceFile: ts.SourceFile, compiledClass: CompiledClass, imports: NgccImportManager): string { + sourceFile: ts.SourceFile, compiledClass: CompiledClass, imports: ImportManager): string { const printer = ts.createPrinter(); const name = (compiledClass.declaration as ts.NamedDeclaration).name !; const definitions = diff --git a/packages/compiler-cli/src/ngcc/test/BUILD.bazel b/packages/compiler-cli/src/ngcc/test/BUILD.bazel index 826a437aed..f1b6941b95 100644 --- a/packages/compiler-cli/src/ngcc/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngcc/test/BUILD.bazel @@ -10,8 +10,10 @@ ts_library( ]), deps = [ "//packages/compiler-cli/src/ngcc", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/path", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/testing", "//packages/compiler-cli/src/ngtsc/transform", "@ngdeps//@types/convert-source-map", diff --git a/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts index 1978ba02c8..5798fae8b9 100644 --- a/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -7,13 +7,13 @@ */ import * as ts from 'typescript'; -import {Decorator} from '../../../ngtsc/host'; -import {DecoratorHandler} from '../../../ngtsc/transform'; +import {AbsoluteFsPath} from '../../../ngtsc/path'; +import {Decorator} from '../../../ngtsc/reflection'; +import {DecoratorHandler, DetectResult} from '../../../ngtsc/transform'; import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; - -import {makeTestProgram} from '../helpers/utils'; +import {makeTestBundleProgram} from '../helpers/utils'; const TEST_PROGRAM = { name: 'test.js', @@ -63,15 +63,24 @@ function createTestHandler() { 'compile', ]); // Only detect the Component decorator - handler.detect.and.callFake((node: ts.Declaration, decorators: Decorator[]) => { - if (!decorators) { - return undefined; - } - return decorators.find(d => d.name === 'Component'); - }); + handler.detect.and.callFake( + (node: ts.Declaration, decorators: Decorator[]): DetectResult| undefined => { + if (!decorators) { + return undefined; + } + const metadata = decorators.find(d => d.name === 'Component'); + if (metadata === undefined) { + return undefined; + } else { + return { + metadata, + trigger: metadata.node, + }; + } + }); // The "test" analysis is just the name of the decorator being analyzed handler.analyze.and.callFake( - ((decl: ts.Declaration, dec: Decorator) => ({analysis: dec.name, diagnostics: null}))); + ((decl: ts.Declaration, dec: Decorator) => ({analysis: dec.name, diagnostics: undefined}))); // The "test" compilation result is just the name of the decorator being compiled handler.compile.and.callFake(((decl: ts.Declaration, analysis: any) => ({analysis}))); return handler; @@ -84,14 +93,17 @@ describe('DecorationAnalyzer', () => { let result: DecorationAnalyses; beforeEach(() => { - program = makeTestProgram(TEST_PROGRAM); - const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); - const referencesRegistry = new NgccReferencesRegistry(host); - const analyzer = - new DecorationAnalyzer(program.getTypeChecker(), host, referencesRegistry, [''], false); + const {options, host, ...bundle} = makeTestBundleProgram([TEST_PROGRAM]); + program = bundle.program; + + const reflectionHost = new Esm2015ReflectionHost(false, program.getTypeChecker()); + const referencesRegistry = new NgccReferencesRegistry(reflectionHost); + const analyzer = new DecorationAnalyzer( + program, options, host, program.getTypeChecker(), reflectionHost, referencesRegistry, + [AbsoluteFsPath.fromUnchecked('/')], false); testHandler = createTestHandler(); analyzer.handlers = [testHandler]; - result = analyzer.analyzeProgram(program); + result = analyzer.analyzeProgram(); }); it('should return an object containing a reference to the original source file', () => { @@ -127,14 +139,15 @@ describe('DecorationAnalyzer', () => { // is not yet solved. it('should analyze an internally imported component, which is not publicly exported from the entry-point', () => { - const program = makeTestProgram(...INTERNAL_COMPONENT_PROGRAM); - const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); - const referencesRegistry = new NgccReferencesRegistry(host); + const {program, options, host} = makeTestBundleProgram(INTERNAL_COMPONENT_PROGRAM); + const reflectionHost = new Esm2015ReflectionHost(false, program.getTypeChecker()); + const referencesRegistry = new NgccReferencesRegistry(reflectionHost); const analyzer = new DecorationAnalyzer( - program.getTypeChecker(), host, referencesRegistry, [''], false); + program, options, host, program.getTypeChecker(), reflectionHost, referencesRegistry, + [AbsoluteFsPath.fromUnchecked('/')], false); const testHandler = createTestHandler(); analyzer.handlers = [testHandler]; - const result = analyzer.analyzeProgram(program); + const result = analyzer.analyzeProgram(); const file = program.getSourceFile('component.js') !; const analysis = result.get(file) !; expect(analysis).toBeDefined(); @@ -144,14 +157,15 @@ describe('DecorationAnalyzer', () => { }); it('should analyze an internally defined component, which is not exported at all', () => { - const program = makeTestProgram(...INTERNAL_COMPONENT_PROGRAM); - const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); - const referencesRegistry = new NgccReferencesRegistry(host); - const analyzer = - new DecorationAnalyzer(program.getTypeChecker(), host, referencesRegistry, [''], false); + const {program, options, host} = makeTestBundleProgram(INTERNAL_COMPONENT_PROGRAM); + const reflectionHost = new Esm2015ReflectionHost(false, program.getTypeChecker()); + const referencesRegistry = new NgccReferencesRegistry(reflectionHost); + const analyzer = new DecorationAnalyzer( + program, options, host, program.getTypeChecker(), reflectionHost, referencesRegistry, + [AbsoluteFsPath.fromUnchecked('/')], false); const testHandler = createTestHandler(); analyzer.handlers = [testHandler]; - const result = analyzer.analyzeProgram(program); + const result = analyzer.analyzeProgram(); const file = program.getSourceFile('entrypoint.js') !; const analysis = result.get(file) !; expect(analysis).toBeDefined(); diff --git a/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts b/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts index 9188a5344b..ed74e29212 100644 --- a/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/analysis/private_declarations_analyzer_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {ResolvedReference} from '@angular/compiler-cli/src/ngtsc/metadata'; import * as ts from 'typescript'; +import {Reference} from '../../../ngtsc/imports'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; @@ -136,16 +136,13 @@ describe('PrivateDeclarationsAnalyzer', () => { // decoration handlers in the `DecorationAnalyzer`. const publicComponentDeclaration = getDeclaration(program, '/src/a.js', 'PublicComponent', ts.isClassDeclaration); - referencesRegistry.add( - new ResolvedReference(publicComponentDeclaration, publicComponentDeclaration.name !)); + referencesRegistry.add(null !, new Reference(publicComponentDeclaration)); const privateComponentDeclaration = getDeclaration(program, '/src/b.js', 'PrivateComponent', ts.isClassDeclaration); - referencesRegistry.add(new ResolvedReference( - privateComponentDeclaration, privateComponentDeclaration.name !)); + referencesRegistry.add(null !, new Reference(privateComponentDeclaration)); const internalComponentDeclaration = getDeclaration(program, '/src/c.js', 'InternalComponent', ts.isClassDeclaration); - referencesRegistry.add(new ResolvedReference( - internalComponentDeclaration, internalComponentDeclaration.name !)); + referencesRegistry.add(null !, new Reference(internalComponentDeclaration)); const analyses = analyzer.analyzeProgram(program); expect(analyses.length).toEqual(2); diff --git a/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts b/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts index b2f9ce27aa..5f75dae924 100644 --- a/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/analysis/references_registry_spec.ts @@ -8,13 +8,15 @@ import * as ts from 'typescript'; -import {Reference, TypeScriptReflectionHost, staticallyResolve} from '../../../ngtsc/metadata'; +import {Reference} from '../../../ngtsc/imports'; +import {PartialEvaluator} from '../../../ngtsc/partial_evaluator'; +import {TypeScriptReflectionHost} from '../../../ngtsc/reflection'; import {getDeclaration, makeProgram} from '../../../ngtsc/testing/in_memory_typescript'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; describe('NgccReferencesRegistry', () => { it('should return a mapping from resolved reference identifiers to their declarations', () => { - const {program} = makeProgram([{ + const {program, options, host} = makeProgram([{ name: 'index.ts', contents: ` export class SomeClass {} @@ -36,12 +38,13 @@ describe('NgccReferencesRegistry', () => { getDeclaration(program, 'index.ts', 'someVariable', ts.isVariableDeclaration); const testArrayExpression = testArrayDeclaration.initializer !; - const host = new TypeScriptReflectionHost(checker); - const registry = new NgccReferencesRegistry(host); + const reflectionHost = new TypeScriptReflectionHost(checker); + const evaluator = new PartialEvaluator(reflectionHost, checker); + const registry = new NgccReferencesRegistry(reflectionHost); - const references = - staticallyResolve(testArrayExpression, host, checker) as Reference[]; - registry.add(...references); + const references = (evaluator.evaluate(testArrayExpression) as any[]) + .filter(ref => ref instanceof Reference) as Reference[]; + registry.add(null !, ...references); const map = registry.getDeclarationMap(); expect(map.size).toEqual(2); diff --git a/packages/compiler-cli/src/ngcc/test/helpers/utils.ts b/packages/compiler-cli/src/ngcc/test/helpers/utils.ts index 3b5656ffab..917ac21422 100644 --- a/packages/compiler-cli/src/ngcc/test/helpers/utils.ts +++ b/packages/compiler-cli/src/ngcc/test/helpers/utils.ts @@ -7,6 +7,7 @@ */ import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../../../ngtsc/path'; import {makeProgram} from '../../../ngtsc/testing/in_memory_typescript'; import {BundleProgram} from '../../src/packages/bundle_program'; import {EntryPointFormat} from '../../src/packages/entry_point'; @@ -15,6 +16,7 @@ import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; export {getDeclaration} from '../../../ngtsc/testing/in_memory_typescript'; + /** * * @param format The format of the bundle. @@ -27,7 +29,7 @@ export function makeTestEntryPointBundle( const src = makeTestBundleProgram(files); const dts = dtsFiles ? makeTestBundleProgram(dtsFiles) : null; const isFlat = src.r3SymbolsFile === null; - return {format, rootDirs: ['/'], src, dts, isFlat}; + return {format, rootDirs: [AbsoluteFsPath.fromUnchecked('/')], src, dts, isFlat}; } /** @@ -35,20 +37,27 @@ export function makeTestEntryPointBundle( * @param files The source files of the bundle program. */ export function makeTestBundleProgram(files: {name: string, contents: string}[]): BundleProgram { - const program = makeTestProgram(...files); + const {program, options, host} = makeTestProgramInternal(...files); const path = files[0].name; const file = program.getSourceFile(path) !; const r3SymbolsInfo = files.find(file => file.name.indexOf('r3_symbols') !== -1) || null; const r3SymbolsPath = r3SymbolsInfo && r3SymbolsInfo.name; const r3SymbolsFile = r3SymbolsPath && program.getSourceFile(r3SymbolsPath) || null; - return {program, path, file, r3SymbolsPath, r3SymbolsFile}; + return {program, options, host, path, file, r3SymbolsPath, r3SymbolsFile}; } +function makeTestProgramInternal( + ...files: {name: string, contents: string, isRoot?: boolean | undefined}[]): { + program: ts.Program, + host: ts.CompilerHost, + options: ts.CompilerOptions, +} { + return makeProgram([getFakeCore(), getFakeTslib(), ...files], {allowJs: true, checkJs: false}); +} export function makeTestProgram( ...files: {name: string, contents: string, isRoot?: boolean | undefined}[]): ts.Program { - return makeProgram([getFakeCore(), getFakeTslib(), ...files], {allowJs: true, checkJs: false}) - .program; + return makeTestProgramInternal(...files).program; } // TODO: unify this with the //packages/compiler-cli/test/ngtsc/fake_core package diff --git a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts index 9440289e86..c3d09c225c 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_import_helper_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils'; diff --git a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts index 5c40e9f44c..e46f184450 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm2015_host_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {getDeclaration, makeTestBundleProgram, makeTestProgram} from '../helpers/utils'; @@ -52,6 +52,24 @@ const SOME_DIRECTIVE_FILE = { `, }; +const ACCESSORS_FILE = { + name: '/accessors.js', + contents: ` + import { Directive, Input, Output } from '@angular/core'; + + class SomeDirective { + set setterAndGetter(value) { this.value = value; } + get setterAndGetter() { return null; } + } + SomeDirective.decorators = [ + { type: Directive, args: [{ selector: '[someDirective]' },] } + ]; + SomeDirective.propDecorators = { + "setterAndGetter": [{ type: Input },], + }; + `, +}; + const SIMPLE_CLASS_FILE = { name: '/simple_class.js', contents: ` @@ -705,6 +723,27 @@ describe('Fesm2015ReflectionHost', () => { expect(instanceProperty.value !.getText()).toEqual(`'instance'`); }); + it('should handle equally named getter/setter pairs correctly', () => { + const program = makeTestProgram(ACCESSORS_FILE); + const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); + const classNode = + getDeclaration(program, ACCESSORS_FILE.name, 'SomeDirective', ts.isClassDeclaration); + const members = host.getMembersOfClass(classNode); + + const [combinedSetter, combinedGetter] = + members.filter(member => member.name === 'setterAndGetter'); + expect(combinedSetter.kind).toEqual(ClassMemberKind.Setter); + expect(combinedSetter.isStatic).toEqual(false); + expect(ts.isSetAccessor(combinedSetter.implementation !)).toEqual(true); + expect(combinedSetter.value).toBeNull(); + expect(combinedSetter.decorators !.map(d => d.name)).toEqual(['Input']); + expect(combinedGetter.kind).toEqual(ClassMemberKind.Getter); + expect(combinedGetter.isStatic).toEqual(false); + expect(ts.isGetAccessor(combinedGetter.implementation !)).toEqual(true); + expect(combinedGetter.value).toBeNull(); + expect(combinedGetter.decorators !.map(d => d.name)).toEqual([]); + }); + it('should find static methods on a class', () => { const program = makeTestProgram(SOME_DIRECTIVE_FILE); const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); @@ -980,6 +1019,70 @@ describe('Fesm2015ReflectionHost', () => { })); }); + describe('synthesized constructors', () => { + function getConstructorParameters(constructor: string) { + const file = { + name: '/synthesized_constructors.js', + contents: ` + class BaseClass {} + class TestClass extends BaseClass { + ${constructor} + } + `, + }; + + const program = makeTestProgram(file); + const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); + const classNode = getDeclaration(program, file.name, 'TestClass', ts.isClassDeclaration); + return host.getConstructorParameters(classNode); + } + + it('recognizes super call as first statement', () => { + const parameters = getConstructorParameters(` + constructor() { + super(...arguments); + this.synthesizedProperty = null; + }`); + + expect(parameters).toBeNull(); + }); + + it('does not consider super call without spread element as synthesized', () => { + const parameters = getConstructorParameters(` + constructor() { + super(arguments); + }`); + + expect(parameters !.length).toBe(0); + }); + + it('does not consider constructors with parameters as synthesized', () => { + const parameters = getConstructorParameters(` + constructor(arg) { + super(...arguments); + }`); + + expect(parameters !.length).toBe(1); + }); + + it('does not consider manual super calls as synthesized', () => { + const parameters = getConstructorParameters(` + constructor() { + super(); + }`); + + expect(parameters !.length).toBe(0); + }); + + it('does not consider empty constructors as synthesized', () => { + const parameters = getConstructorParameters(` + constructor() { + }`); + + expect(parameters !.length).toBe(0); + }); + }); + describe('(returned parameters `decorators`)', () => { it('should ignore param decorator elements that are not object literals', () => { const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE); diff --git a/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts index a9d4928ef3..55647fbb4f 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm5_host_import_helper_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils'; @@ -304,6 +304,27 @@ describe('Esm5ReflectionHost [import helper style]', () => { }); }); + describe('findDecoratedClasses', () => { + it('should return an array of all decorated classes in the given source file', () => { + const program = makeTestProgram(...fileSystem.files); + const host = new Esm5ReflectionHost(false, program.getTypeChecker()); + + const ngModuleFile = program.getSourceFile('/ngmodule.js') !; + const ngModuleClasses = host.findDecoratedClasses(ngModuleFile); + expect(ngModuleClasses.length).toEqual(1); + const ngModuleClass = ngModuleClasses.find(c => c.name === 'HttpClientXsrfModule') !; + expect(ngModuleClass.decorators.map(decorator => decorator.name)).toEqual(['NgModule']); + + const someDirectiveFile = program.getSourceFile('/some_directive.js') !; + const someDirectiveClasses = host.findDecoratedClasses(someDirectiveFile); + expect(someDirectiveClasses.length).toEqual(1); + const someDirectiveClass = someDirectiveClasses.find(c => c.name === 'SomeDirective') !; + expect(someDirectiveClass.decorators.map(decorator => decorator.name)).toEqual([ + 'Directive' + ]); + }); + }); + describe('getDeclarationOfIdentifier', () => { it('should return the declaration of a locally defined identifier', () => { const program = makeTestProgram(fileSystem.files[0]); diff --git a/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts b/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts index 4fe4b82447..8efc087d2a 100644 --- a/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/host/esm5_host_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMemberKind, Import} from '../../../ngtsc/host'; +import {ClassMemberKind, Import} from '../../../ngtsc/reflection'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {getDeclaration, makeTestProgram} from '../helpers/utils'; @@ -47,6 +47,52 @@ const SOME_DIRECTIVE_FILE = { }()); `, }; +const ACCESSORS_FILE = { + name: '/accessors.js', + contents: ` + import { Directive, Input, Output } from '@angular/core'; + + var SomeDirective = (function() { + function SomeDirective() { + } + Object.defineProperty(SomeDirective.prototype, "setter", { + set: function (value) { this.value = value; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(SomeDirective.prototype, "getter", { + get: function () { return null; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(SomeDirective.prototype, "setterAndGetter", { + get: function () { return null; }, + set: function (value) { this.value = value; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(SomeDirective, "staticSetter", { + set: function (value) { this.value = value; }, + enumerable: true, + configurable: true + }); + Object.defineProperty(SomeDirective.prototype, "none", { + enumerable: true, + configurable: true + }); + Object.defineProperty(SomeDirective.prototype, "incomplete"); + SomeDirective.decorators = [ + { type: Directive, args: [{ selector: '[someDirective]' },] } + ]; + SomeDirective.propDecorators = { + "setter": [{ type: Input },], + "getter": [{ type: Output },], + "setterAndGetter": [{ type: Input },], + }; + return SomeDirective; + }()); + `, +}; const SIMPLE_CLASS_FILE = { name: '/simple_class.js', @@ -627,7 +673,54 @@ describe('Esm5ReflectionHost', () => { const input2 = members.find(member => member.name === 'input2') !; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input2.decorators !.map(d => d.name)).toEqual(['Input']); + }); + + it('should find Object.defineProperty members on a class', () => { + const program = makeTestProgram(ACCESSORS_FILE); + const host = new Esm5ReflectionHost(false, program.getTypeChecker()); + const classNode = + getDeclaration(program, ACCESSORS_FILE.name, 'SomeDirective', ts.isVariableDeclaration); + const members = host.getMembersOfClass(classNode); + + const setter = members.find(member => member.name === 'setter') !; + expect(setter.kind).toEqual(ClassMemberKind.Setter); + expect(setter.isStatic).toEqual(false); + expect(setter.value).toBeNull(); + expect(setter.decorators !.map(d => d.name)).toEqual(['Input']); + expect(ts.isFunctionExpression(setter.implementation !)).toEqual(true); + expect((setter.implementation as ts.FunctionExpression).body.statements[0].getText()) + .toEqual('this.value = value;'); + + const getter = members.find(member => member.name === 'getter') !; + expect(getter.kind).toEqual(ClassMemberKind.Getter); + expect(getter.isStatic).toEqual(false); + expect(getter.value).toBeNull(); + expect(getter.decorators !.map(d => d.name)).toEqual(['Output']); + expect(ts.isFunctionExpression(getter.implementation !)).toEqual(true); + expect((getter.implementation as ts.FunctionExpression).body.statements[0].getText()) + .toEqual('return null;'); + + const [combinedSetter, combinedGetter] = + members.filter(member => member.name === 'setterAndGetter'); + expect(combinedSetter.kind).toEqual(ClassMemberKind.Setter); + expect(combinedSetter.isStatic).toEqual(false); + expect(combinedSetter.decorators !.map(d => d.name)).toEqual(['Input']); + expect(combinedGetter.kind).toEqual(ClassMemberKind.Getter); + expect(combinedGetter.isStatic).toEqual(false); + expect(combinedGetter.decorators !.map(d => d.name)).toEqual([]); + + const staticSetter = members.find(member => member.name === 'staticSetter') !; + expect(staticSetter.kind).toEqual(ClassMemberKind.Setter); + expect(staticSetter.isStatic).toEqual(true); + expect(staticSetter.value).toBeNull(); + expect(staticSetter.decorators !.map(d => d.name)).toEqual([]); + + const none = members.find(member => member.name === 'none'); + expect(none).toBeUndefined(); + + const incomplete = members.find(member => member.name === 'incomplete'); + expect(incomplete).toBeUndefined(); }); it('should find non decorated properties on a class', () => { @@ -654,6 +747,7 @@ describe('Esm5ReflectionHost', () => { const staticMethod = members.find(member => member.name === 'staticMethod') !; expect(staticMethod.kind).toEqual(ClassMemberKind.Method); expect(staticMethod.isStatic).toEqual(true); + expect(staticMethod.value).toBeNull(); expect(ts.isFunctionExpression(staticMethod.implementation !)).toEqual(true); }); @@ -946,6 +1040,84 @@ describe('Esm5ReflectionHost', () => { }); }); + describe('synthesized constructors', () => { + function getConstructorParameters(constructor: string) { + const file = { + name: '/synthesized_constructors.js', + contents: ` + var TestClass = /** @class */ (function (_super) { + __extends(TestClass, _super); + ${constructor} + return TestClass; + }(null)); + `, + }; + + const program = makeTestProgram(file); + const host = new Esm5ReflectionHost(false, program.getTypeChecker()); + const classNode = getDeclaration(program, file.name, 'TestClass', ts.isVariableDeclaration); + return host.getConstructorParameters(classNode); + } + + it('recognizes _this assignment from super call', () => { + const parameters = getConstructorParameters(` + function TestClass() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.synthesizedProperty = null; + return _this; + }`); + + expect(parameters).toBeNull(); + }); + + it('recognizes super call as return statement', () => { + const parameters = getConstructorParameters(` + function TestClass() { + return _super !== null && _super.apply(this, arguments) || this; + }`); + + expect(parameters).toBeNull(); + }); + + it('handles the case where a unique name was generated for _super or _this', () => { + const parameters = getConstructorParameters(` + function TestClass() { + var _this_1 = _super_1 !== null && _super_1.apply(this, arguments) || this; + _this_1._this = null; + _this_1._super = null; + return _this_1; + }`); + + expect(parameters).toBeNull(); + }); + + it('does not consider constructors with parameters as synthesized', () => { + const parameters = getConstructorParameters(` + function TestClass(arg) { + return _super !== null && _super.apply(this, arguments) || this; + }`); + + expect(parameters !.length).toBe(1); + }); + + it('does not consider manual super calls as synthesized', () => { + const parameters = getConstructorParameters(` + function TestClass() { + return _super.call(this) || this; + }`); + + expect(parameters !.length).toBe(0); + }); + + it('does not consider empty constructors as synthesized', () => { + const parameters = getConstructorParameters(` + function TestClass() { + }`); + + expect(parameters !.length).toBe(0); + }); + }); + describe('(returned parameters `decorators.args`)', () => { it('should be an empty array if param decorator has no `args` property', () => { const program = makeTestProgram(INVALID_CTOR_DECORATOR_ARGS_FILE); @@ -1106,6 +1278,34 @@ describe('Esm5ReflectionHost', () => { expect(actualDeclaration !.node).toBe(expectedDeclarationNode); expect(actualDeclaration !.viaModule).toBe('@angular/core'); }); + + it('should return the correct declaration for an inner function identifier inside an ES5 IIFE', + () => { + const superGetDeclarationOfIdentifierSpy = + spyOn(Esm2015ReflectionHost.prototype, 'getDeclarationOfIdentifier').and.callThrough(); + const program = makeTestProgram(SIMPLE_CLASS_FILE); + const host = new Esm5ReflectionHost(false, program.getTypeChecker()); + + const outerDeclaration = getDeclaration( + program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); + const innerDeclaration = (((outerDeclaration.initializer as ts.ParenthesizedExpression) + .expression as ts.CallExpression) + .expression as ts.FunctionExpression) + .body.statements[0] as ts.FunctionDeclaration; + + const outerIdentifier = outerDeclaration.name as ts.Identifier; + const innerIdentifier = innerDeclaration.name as ts.Identifier; + + expect(host.getDeclarationOfIdentifier(outerIdentifier) !.node).toBe(outerDeclaration); + expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledWith(outerIdentifier); + expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledTimes(1); + + superGetDeclarationOfIdentifierSpy.calls.reset(); + + expect(host.getDeclarationOfIdentifier(innerIdentifier) !.node).toBe(outerDeclaration); + expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledWith(outerIdentifier); + expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledTimes(1); + }); }); describe('getExportsOfModule()', () => { @@ -1252,6 +1452,51 @@ describe('Esm5ReflectionHost', () => { }); }); + describe('hasBaseClass()', () => { + function hasBaseClass(source: string) { + const file = { + name: '/synthesized_constructors.js', + contents: source, + }; + + const program = makeTestProgram(file); + const host = new Esm5ReflectionHost(false, program.getTypeChecker()); + const classNode = getDeclaration(program, file.name, 'TestClass', ts.isVariableDeclaration); + return host.hasBaseClass(classNode); + } + + it('should consider an IIFE with _super parameter as having a base class', () => { + const result = hasBaseClass(` + var TestClass = /** @class */ (function (_super) { + __extends(TestClass, _super); + function TestClass() {} + return TestClass; + }(null));`); + expect(result).toBe(true); + }); + + it('should consider an IIFE with a unique name generated for the _super parameter as having a base class', + () => { + const result = hasBaseClass(` + var TestClass = /** @class */ (function (_super_1) { + __extends(TestClass, _super_1); + function TestClass() {} + return TestClass; + }(null));`); + expect(result).toBe(true); + }); + + it('should not consider an IIFE without parameter as having a base class', () => { + const result = hasBaseClass(` + var TestClass = /** @class */ (function () { + __extends(TestClass, _super); + function TestClass() {} + return TestClass; + }(null));`); + expect(result).toBe(false); + }); + }); + describe('findDecoratedClasses()', () => { it('should return an array of all decorated classes in the given source file', () => { const program = makeTestProgram(...DECORATED_FILES); diff --git a/packages/compiler-cli/src/ngcc/test/rendering/esm2015_renderer_spec.ts b/packages/compiler-cli/src/ngcc/test/rendering/esm2015_renderer_spec.ts index 8e91618073..a45ad7e28f 100644 --- a/packages/compiler-cli/src/ngcc/test/rendering/esm2015_renderer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/rendering/esm2015_renderer_spec.ts @@ -8,6 +8,7 @@ import {dirname} from 'canonical-path'; import MagicString from 'magic-string'; import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../../../ngtsc/path'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; @@ -22,8 +23,10 @@ function setup(file: {name: string, contents: string}) { const host = new Esm2015ReflectionHost(false, typeChecker); const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = - new DecorationAnalyzer(typeChecker, host, referencesRegistry, [''], false) - .analyzeProgram(bundle.src.program); + new DecorationAnalyzer( + bundle.src.program, bundle.src.options, bundle.src.host, typeChecker, host, + referencesRegistry, [AbsoluteFsPath.fromUnchecked('/')], false) + .analyzeProgram(); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); const renderer = new EsmRenderer(host, false, bundle, dir, dir); return { diff --git a/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts b/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts index 2642653f62..fe8bf2aaa3 100644 --- a/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/rendering/esm5_renderer_spec.ts @@ -8,6 +8,7 @@ import {dirname} from 'canonical-path'; import MagicString from 'magic-string'; import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../../../ngtsc/path'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; @@ -22,8 +23,10 @@ function setup(file: {name: string, contents: string}) { const host = new Esm5ReflectionHost(false, typeChecker); const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = - new DecorationAnalyzer(typeChecker, host, referencesRegistry, [''], false) - .analyzeProgram(bundle.src.program); + new DecorationAnalyzer( + bundle.src.program, bundle.src.options, bundle.src.host, typeChecker, host, + referencesRegistry, [AbsoluteFsPath.fromUnchecked('/')], false) + .analyzeProgram(); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); const renderer = new Esm5Renderer(host, false, bundle, dir, dir); return { diff --git a/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts index ca4151e524..0c582c52f1 100644 --- a/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/src/ngcc/test/rendering/renderer_spec.ts @@ -54,9 +54,10 @@ function createTestRenderer( const typeChecker = bundle.src.program.getTypeChecker(); const host = new Esm2015ReflectionHost(isCore, typeChecker, bundle.dts); const referencesRegistry = new NgccReferencesRegistry(host); - const decorationAnalyses = - new DecorationAnalyzer(typeChecker, host, referencesRegistry, bundle.rootDirs, isCore) - .analyzeProgram(bundle.src.program); + const decorationAnalyses = new DecorationAnalyzer( + bundle.src.program, bundle.src.options, bundle.src.host, + typeChecker, host, referencesRegistry, bundle.rootDirs, isCore) + .analyzeProgram(); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program); const moduleWithProvidersAnalyses = new ModuleWithProvidersAnalyzer(host, referencesRegistry).analyzeProgram(bundle.src.program); diff --git a/packages/compiler-cli/src/ngtools_api2.ts b/packages/compiler-cli/src/ngtools_api2.ts index eef681486c..ec3a8dfed9 100644 --- a/packages/compiler-cli/src/ngtools_api2.ts +++ b/packages/compiler-cli/src/ngtools_api2.ts @@ -109,7 +109,8 @@ export interface LazyRoute { export interface Program { getTsProgram(): ts.Program; getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken): ReadonlyArray; - getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken): ReadonlyArray; + getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken): + ReadonlyArray; getTsSyntacticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): ReadonlyArray; getNgStructuralDiagnostics(cancellationToken?: ts.CancellationToken): ReadonlyArray; diff --git a/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel b/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel index e86b8e6181..91c845e134 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/annotations/BUILD.bazel @@ -8,14 +8,17 @@ ts_library( "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/annotations", deps = [ "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/cycles", "//packages/compiler-cli/src/ngtsc/diagnostics", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/reflection", + "//packages/compiler-cli/src/ngtsc/routing", "//packages/compiler-cli/src/ngtsc/transform", "//packages/compiler-cli/src/ngtsc/typecheck", + "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//@types/node", "@ngdeps//typescript", ], diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/api.ts b/packages/compiler-cli/src/ngtsc/annotations/src/api.ts index 10b156d031..364cfdaf0c 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/api.ts @@ -6,7 +6,50 @@ * found in the LICENSE file at https://angular.io/license */ +/** + * Resolves and loads resource files that are referenced in Angular metadata. + * + * Note that `preload()` and `load()` take a `resolvedUrl`, which can be found + * by calling `resolve()`. These two steps are separated because sometimes the + * resolved URL to the resource is needed as well as its contents. + */ export interface ResourceLoader { - preload?(url: string, containingFile: string): Promise|undefined; - load(url: string, containingFile: string): string; + /** + * True if this resource loader can preload resources. + * + * Sometimes a `ResourceLoader` is not able to do asynchronous pre-loading of resources. + */ + canPreload: boolean; + + /** + * Resolve the url of a resource relative to the file that contains the reference to it. + * The return value of this method can be used in the `load()` and `preload()` methods. + * + * @param url The, possibly relative, url of the resource. + * @param fromFile The path to the file that contains the URL of the resource. + * @returns A resolved url of resource. + * @throws An error if the resource cannot be resolved. + */ + resolve(file: string, basePath: string): string; + + /** + * Preload the specified resource, asynchronously. Once the resource is loaded, its value + * should be cached so it can be accessed synchronously via the `load()` method. + * + * @param resolvedUrl The url (resolved by a call to `resolve()`) of the resource to preload. + * @returns A Promise that is resolved once the resource has been loaded or `undefined` + * if the file has already been loaded. + * @throws An Error if pre-loading is not available. + */ + preload(resolvedUrl: string): Promise|undefined; + + /** + * Load the resource at the given url, synchronously. + * + * The contents of the resource may have been cached by a previous call to `preload()`. + * + * @param resolvedUrl The url (resolved by a call to `resolve()`) of the resource to load. + * @returns The contents of the resource. + */ + load(resolvedUrl: string): string; } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts b/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts index 5924bde1e2..68941ae221 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/base_def.ts @@ -9,9 +9,9 @@ import {R3BaseRefMetaData, compileBaseDefFromMetadata} from '@angular/compiler'; import * as ts from 'typescript'; -import {ClassMember, Decorator, ReflectionHost} from '../../host'; -import {staticallyResolve} from '../../metadata'; -import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; +import {PartialEvaluator} from '../../partial_evaluator'; +import {ClassMember, Decorator, ReflectionHost} from '../../reflection'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform'; import {isAngularCore} from './util'; function containsNgTopLevelDecorator(decorators: Decorator[] | null): boolean { @@ -26,10 +26,12 @@ function containsNgTopLevelDecorator(decorators: Decorator[] | null): boolean { export class BaseDefDecoratorHandler implements DecoratorHandler { - constructor(private checker: ts.TypeChecker, private reflector: ReflectionHost, ) {} + constructor(private reflector: ReflectionHost, private evaluator: PartialEvaluator) {} - detect(node: ts.ClassDeclaration, decorators: Decorator[]|null): R3BaseRefDecoratorDetection - |undefined { + readonly precedence = HandlerPrecedence.WEAK; + + detect(node: ts.ClassDeclaration, decorators: Decorator[]|null): + DetectResult|undefined { if (containsNgTopLevelDecorator(decorators)) { // If the class is already decorated by @Component or @Directive let that // DecoratorHandler handle this. BaseDef is unnecessary. @@ -56,7 +58,14 @@ export class BaseDefDecoratorHandler implements } }); - return result; + if (result !== undefined) { + return { + metadata: result, + trigger: null, + }; + } else { + return undefined; + } } analyze(node: ts.ClassDeclaration, metadata: R3BaseRefDecoratorDetection): @@ -69,7 +78,7 @@ export class BaseDefDecoratorHandler implements const args = decorator.args; let value: string|[string, string]; if (args && args.length > 0) { - const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker); + const resolvedValue = this.evaluator.evaluate(args[0]); if (typeof resolvedValue !== 'string') { throw new TypeError('Input alias does not resolve to a string value'); } @@ -88,7 +97,7 @@ export class BaseDefDecoratorHandler implements const args = decorator.args; let value: string; if (args && args.length > 0) { - const resolvedValue = staticallyResolve(args[0], this.reflector, this.checker); + const resolvedValue = this.evaluator.evaluate(args[0]); if (typeof resolvedValue !== 'string') { throw new TypeError('Output alias does not resolve to a string value'); } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 8631e89645..20650763d4 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -6,21 +6,24 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, ElementSchemaRegistry, Expression, InterpolationConfig, R3ComponentMetadata, R3DirectiveMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr, compileComponentFromMetadata, makeBindingParser, parseTemplate} from '@angular/compiler'; +import {ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, Expression, ExternalExpr, InterpolationConfig, LexerRange, R3ComponentMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr, compileComponentFromMetadata, makeBindingParser, parseTemplate} from '@angular/compiler'; import * as path from 'path'; import * as ts from 'typescript'; +import {CycleAnalyzer} from '../../cycles'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {AbsoluteReference, Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata'; -import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; -import {TypeCheckContext, TypeCheckableDirectiveMeta} from '../../typecheck'; +import {ModuleResolver, Reference} from '../../imports'; +import {EnumValue, PartialEvaluator} from '../../partial_evaluator'; +import {Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform'; +import {TypeCheckContext} from '../../typecheck'; +import {tsSourceMapBug29300Fixed} from '../../util/src/ts_source_map_bug_29300'; import {ResourceLoader} from './api'; import {extractDirectiveMetadata, extractQueriesFromDecorator, parseFieldArrayValue, queriesFromFields} from './directive'; import {generateSetClassMetadataCall} from './metadata'; import {ScopeDirective, SelectorScopeRegistry} from './selector_scope'; -import {extractDirectiveGuards, isAngularCore, unwrapExpression} from './util'; +import {extractDirectiveGuards, isAngularCore, isAngularCoreReference, unwrapExpression} from './util'; const EMPTY_MAP = new Map(); const EMPTY_ARRAY: any[] = []; @@ -37,51 +40,68 @@ export interface ComponentHandlerData { export class ComponentDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private isCore: boolean, private resourceLoader: ResourceLoader, private rootDirs: string[], - private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean) {} + private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean, + private moduleResolver: ModuleResolver, private cycleAnalyzer: CycleAnalyzer) {} private literalCache = new Map(); private elementSchemaRegistry = new DomElementSchemaRegistry(); + readonly precedence = HandlerPrecedence.PRIMARY; - detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { + detect(node: ts.Declaration, decorators: Decorator[]|null): DetectResult|undefined { if (!decorators) { return undefined; } - return decorators.find( + const decorator = decorators.find( decorator => decorator.name === 'Component' && (this.isCore || isAngularCore(decorator))); + if (decorator !== undefined) { + return { + trigger: decorator.node, + metadata: decorator, + }; + } else { + return undefined; + } } preanalyze(node: ts.ClassDeclaration, decorator: Decorator): Promise|undefined { + if (!this.resourceLoader.canPreload) { + return undefined; + } + const meta = this._resolveLiteral(decorator); const component = reflectObjectLiteral(meta); const promises: Promise[] = []; const containingFile = node.getSourceFile().fileName; - if (this.resourceLoader.preload !== undefined && component.has('templateUrl')) { + if (component.has('templateUrl')) { const templateUrlExpr = component.get('templateUrl') !; - const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker); + const templateUrl = this.evaluator.evaluate(templateUrlExpr); if (typeof templateUrl !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string'); } - const promise = this.resourceLoader.preload(templateUrl, containingFile); + const resourceUrl = this.resourceLoader.resolve(templateUrl, containingFile); + const promise = this.resourceLoader.preload(resourceUrl); if (promise !== undefined) { promises.push(promise); } } const styleUrls = this._extractStyleUrls(component); - if (this.resourceLoader.preload !== undefined && styleUrls !== null) { + if (styleUrls !== null) { for (const styleUrl of styleUrls) { - const promise = this.resourceLoader.preload(styleUrl, containingFile); + const resourceUrl = this.resourceLoader.resolve(styleUrl, containingFile); + const promise = this.resourceLoader.preload(resourceUrl); if (promise !== undefined) { promises.push(promise); } } } + if (promises.length !== 0) { return Promise.all(promises).then(() => undefined); } else { @@ -97,7 +117,7 @@ export class ComponentDecoratorHandler implements // @Component inherits @Directive, so begin by extracting the @Directive metadata and building // on it. const directiveResult = extractDirectiveMetadata( - node, decorator, this.checker, this.reflector, this.isCore, + node, decorator, this.reflector, this.evaluator, this.isCore, this.elementSchemaRegistry.getDefaultComponentElementName()); if (directiveResult === undefined) { // `extractDirectiveMetadata` returns undefined when the @Directive has `jit: true`. In this @@ -109,43 +129,6 @@ export class ComponentDecoratorHandler implements // Next, read the `@Component`-specific fields. const {decoratedElements, decorator: component, metadata} = directiveResult; - let templateStr: string|null = null; - if (component.has('templateUrl')) { - const templateUrlExpr = component.get('templateUrl') !; - const templateUrl = staticallyResolve(templateUrlExpr, this.reflector, this.checker); - if (typeof templateUrl !== 'string') { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string'); - } - templateStr = this.resourceLoader.load(templateUrl, containingFile); - } else if (component.has('template')) { - const templateExpr = component.get('template') !; - const resolvedTemplate = staticallyResolve(templateExpr, this.reflector, this.checker); - if (typeof resolvedTemplate !== 'string') { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, templateExpr, 'template must be a string'); - } - templateStr = resolvedTemplate; - } else { - throw new FatalDiagnosticError( - ErrorCode.COMPONENT_MISSING_TEMPLATE, decorator.node, 'component is missing a template'); - } - - let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces; - if (component.has('preserveWhitespaces')) { - const expr = component.get('preserveWhitespaces') !; - const value = staticallyResolve(expr, this.reflector, this.checker); - if (typeof value !== 'boolean') { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, expr, 'preserveWhitespaces must be a boolean'); - } - preserveWhitespaces = value; - } - - const viewProviders: Expression|null = component.has('viewProviders') ? - new WrappedNodeExpr(component.get('viewProviders') !) : - null; - // Go through the root directories for this project, and select the one with the smallest // relative path representation. const filePath = node.getSourceFile().fileName; @@ -158,10 +141,68 @@ export class ComponentDecoratorHandler implements } }, undefined) !; + let templateStr: string|null = null; + let templateUrl: string = ''; + let templateRange: LexerRange|undefined; + let escapedString: boolean = false; + + if (component.has('templateUrl')) { + const templateUrlExpr = component.get('templateUrl') !; + const evalTemplateUrl = this.evaluator.evaluate(templateUrlExpr); + if (typeof evalTemplateUrl !== 'string') { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, templateUrlExpr, 'templateUrl must be a string'); + } + templateUrl = this.resourceLoader.resolve(evalTemplateUrl, containingFile); + templateStr = this.resourceLoader.load(templateUrl); + if (!tsSourceMapBug29300Fixed()) { + // By removing the template URL we are telling the translator not to try to + // map the external source file to the generated code, since the version + // of TS that is running does not support it. + templateUrl = ''; + } + } else if (component.has('template')) { + const templateExpr = component.get('template') !; + // We only support SourceMaps for inline templates that are simple string literals. + if (ts.isStringLiteral(templateExpr) || ts.isNoSubstitutionTemplateLiteral(templateExpr)) { + // the start and end of the `templateExpr` node includes the quotation marks, which we must + // strip + templateRange = getTemplateRange(templateExpr); + templateStr = templateExpr.getSourceFile().text; + templateUrl = relativeContextFilePath; + escapedString = true; + } else { + const resolvedTemplate = this.evaluator.evaluate(templateExpr); + if (typeof resolvedTemplate !== 'string') { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, templateExpr, 'template must be a string'); + } + templateStr = resolvedTemplate; + } + } else { + throw new FatalDiagnosticError( + ErrorCode.COMPONENT_MISSING_TEMPLATE, decorator.node, 'component is missing a template'); + } + + let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces; + if (component.has('preserveWhitespaces')) { + const expr = component.get('preserveWhitespaces') !; + const value = this.evaluator.evaluate(expr); + if (typeof value !== 'boolean') { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, expr, 'preserveWhitespaces must be a boolean'); + } + preserveWhitespaces = value; + } + + const viewProviders: Expression|null = component.has('viewProviders') ? + new WrappedNodeExpr(component.get('viewProviders') !) : + null; + let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG; if (component.has('interpolation')) { const expr = component.get('interpolation') !; - const value = staticallyResolve(expr, this.reflector, this.checker); + const value = this.evaluator.evaluate(expr); if (!Array.isArray(value) || value.length !== 2 || !value.every(element => typeof element === 'string')) { throw new FatalDiagnosticError( @@ -171,9 +212,11 @@ export class ComponentDecoratorHandler implements interpolation = InterpolationConfig.fromArray(value as[string, string]); } - const template = parseTemplate( - templateStr, `${node.getSourceFile().fileName}#${node.name!.text}/template.html`, - {preserveWhitespaces, interpolationConfig: interpolation}); + const template = parseTemplate(templateStr, templateUrl, { + preserveWhitespaces, + interpolationConfig: interpolation, + range: templateRange, escapedString + }); if (template.errors !== undefined) { throw new Error( `Errors parsing template: ${template.errors.map(e => e.toString()).join(', ')}`); @@ -182,7 +225,7 @@ export class ComponentDecoratorHandler implements // If the component has a selector, it should be registered with the `SelectorScopeRegistry` so // when this component appears in an `@NgModule` scope, its selector can be determined. if (metadata.selector !== null) { - const ref = new ResolvedReference(node, node.name !); + const ref = new Reference(node); this.scopeRegistry.registerDirective(node, { ref, name: node.name !.text, @@ -200,21 +243,21 @@ export class ComponentDecoratorHandler implements const coreModule = this.isCore ? undefined : '@angular/core'; const viewChildFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ViewChild', coreModule), this.reflector, - this.checker); + this.evaluator); const viewChildrenFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ViewChildren', coreModule), this.reflector, - this.checker); + this.evaluator); const viewQueries = [...viewChildFromFields, ...viewChildrenFromFields]; if (component.has('queries')) { const queriesFromDecorator = extractQueriesFromDecorator( - component.get('queries') !, this.reflector, this.checker, this.isCore); + component.get('queries') !, this.reflector, this.evaluator, this.isCore); viewQueries.push(...queriesFromDecorator.view); } let styles: string[]|null = null; if (component.has('styles')) { - styles = parseFieldArrayValue(component, 'styles', this.reflector, this.checker); + styles = parseFieldArrayValue(component, 'styles', this.evaluator); } let styleUrls = this._extractStyleUrls(component); @@ -222,21 +265,24 @@ export class ComponentDecoratorHandler implements if (styles === null) { styles = []; } - styles.push(...styleUrls.map(styleUrl => this.resourceLoader.load(styleUrl, containingFile))); + styleUrls.forEach(styleUrl => { + const resourceUrl = this.resourceLoader.resolve(styleUrl, containingFile); + styles !.push(this.resourceLoader.load(resourceUrl)); + }); } - let encapsulation: number = 0; - if (component.has('encapsulation')) { - encapsulation = parseInt(staticallyResolve( - component.get('encapsulation') !, this.reflector, this.checker) as string); - } + const encapsulation: number = + this._resolveEnumValue(component, 'encapsulation', 'ViewEncapsulation') || 0; + + const changeDetection: number|null = + this._resolveEnumValue(component, 'changeDetection', 'ChangeDetectionStrategy'); let animations: Expression|null = null; if (component.has('animations')) { animations = new WrappedNodeExpr(component.get('animations') !); } - return { + const output = { analysis: { meta: { ...metadata, @@ -260,6 +306,10 @@ export class ComponentDecoratorHandler implements }, typeCheck: true, }; + if (changeDetection !== null) { + (output.analysis.meta as R3ComponentMetadata).changeDetection = changeDetection; + } + return output; } typeCheck(ctx: TypeCheckContext, node: ts.Declaration, meta: ComponentHandlerData): void { @@ -273,28 +323,39 @@ export class ComponentDecoratorHandler implements } } - compile(node: ts.ClassDeclaration, analysis: ComponentHandlerData, pool: ConstantPool): - CompileResult { + resolve(node: ts.ClassDeclaration, analysis: ComponentHandlerData): void { // Check whether this component was registered with an NgModule. If so, it should be compiled // under that module's compilation scope. const scope = this.scopeRegistry.lookupCompilationScope(node); let metadata = analysis.meta; if (scope !== null) { // Replace the empty components and directives from the analyze() step with a fully expanded - // scope. This is possible now because during compile() the whole compilation unit has been + // scope. This is possible now because during resolve() the whole compilation unit has been // fully analyzed. const {pipes, containsForwardDecls} = scope; - const directives: {selector: string, expression: Expression}[] = []; + const directives = + scope.directives.map(dir => ({selector: dir.selector, expression: dir.directive})); - for (const meta of scope.directives) { - directives.push({selector: meta.selector, expression: meta.directive}); + // Scan through the references of the `scope.directives` array and check whether + // any import which needs to be generated for the directive would create a cycle. + const origin = node.getSourceFile(); + const cycleDetected = + scope.directives.some(meta => this._isCyclicImport(meta.directive, origin)) || + Array.from(scope.pipes.values()).some(pipe => this._isCyclicImport(pipe, origin)); + if (!cycleDetected) { + const wrapDirectivesAndPipesInClosure: boolean = !!containsForwardDecls; + metadata.directives = directives; + metadata.pipes = pipes; + metadata.wrapDirectivesAndPipesInClosure = wrapDirectivesAndPipesInClosure; + } else { + this.scopeRegistry.setComponentAsRequiringRemoteScoping(node); } - const wrapDirectivesAndPipesInClosure: boolean = !!containsForwardDecls; - metadata = {...metadata, directives, pipes, wrapDirectivesAndPipesInClosure}; } + } - const res = - compileComponentFromMetadata(metadata, pool, makeBindingParser(metadata.interpolation)); + compile(node: ts.ClassDeclaration, analysis: ComponentHandlerData, pool: ConstantPool): + CompileResult { + const res = compileComponentFromMetadata(analysis.meta, pool, makeBindingParser()); const statements = res.statements; if (analysis.metadataStmt !== null) { @@ -327,17 +388,61 @@ export class ComponentDecoratorHandler implements return meta; } + private _resolveEnumValue( + component: Map, field: string, enumSymbolName: string): number|null { + let resolved: number|null = null; + if (component.has(field)) { + const expr = component.get(field) !; + const value = this.evaluator.evaluate(expr) as any; + if (value instanceof EnumValue && isAngularCoreReference(value.enumRef, enumSymbolName)) { + resolved = value.resolved as number; + } else { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, expr, + `${field} must be a member of ${enumSymbolName} enum from @angular/core`); + } + } + return resolved; + } + private _extractStyleUrls(component: Map): string[]|null { if (!component.has('styleUrls')) { return null; } const styleUrlsExpr = component.get('styleUrls') !; - const styleUrls = staticallyResolve(styleUrlsExpr, this.reflector, this.checker); + const styleUrls = this.evaluator.evaluate(styleUrlsExpr); if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, styleUrlsExpr, 'styleUrls must be an array of strings'); } return styleUrls as string[]; } + + private _isCyclicImport(expr: Expression, origin: ts.SourceFile): boolean { + if (!(expr instanceof ExternalExpr)) { + return false; + } + + // Figure out what file is being imported. + const imported = this.moduleResolver.resolveModuleName(expr.value.moduleName !, origin); + if (imported === null) { + return false; + } + + // Check whether the import is legal. + return this.cycleAnalyzer.wouldCreateCycle(origin, imported); + } +} + +function getTemplateRange(templateExpr: ts.Expression) { + const startPos = templateExpr.getStart() + 1; + const {line, character} = + ts.getLineAndCharacterOfPosition(templateExpr.getSourceFile(), startPos); + return { + startPos, + startLine: line, + startCol: character, + endPos: templateExpr.getEnd() - 1, + }; } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index 164b729d76..f68244a849 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -6,17 +6,18 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings} from '@angular/compiler'; +import {ConstantPool, Expression, ParseError, R3DirectiveMetadata, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings, verifyHostBindings} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {ClassMember, ClassMemberKind, Decorator, Import, ReflectionHost} from '../../host'; -import {Reference, ResolvedReference, filterToMembersWithDecorator, reflectObjectLiteral, staticallyResolve} from '../../metadata'; -import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; +import {Reference} from '../../imports'; +import {EnumValue, PartialEvaluator} from '../../partial_evaluator'; +import {ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform'; import {generateSetClassMetadataCall} from './metadata'; import {SelectorScopeRegistry} from './selector_scope'; -import {extractDirectiveGuards, getConstructorDependencies, isAngularCore, unwrapExpression, unwrapForwardRef} from './util'; +import {extractDirectiveGuards, getValidConstructorDependencies, isAngularCore, unwrapExpression, unwrapForwardRef} from './util'; const EMPTY_OBJECT: {[key: string]: string} = {}; @@ -27,26 +28,36 @@ export interface DirectiveHandlerData { export class DirectiveDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {} - detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { + readonly precedence = HandlerPrecedence.PRIMARY; + + detect(node: ts.Declaration, decorators: Decorator[]|null): DetectResult|undefined { if (!decorators) { return undefined; } - return decorators.find( + const decorator = decorators.find( decorator => decorator.name === 'Directive' && (this.isCore || isAngularCore(decorator))); + if (decorator !== undefined) { + return { + trigger: decorator.node, + metadata: decorator, + }; + } else { + return undefined; + } } analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput { const directiveResult = - extractDirectiveMetadata(node, decorator, this.checker, this.reflector, this.isCore); + extractDirectiveMetadata(node, decorator, this.reflector, this.evaluator, this.isCore); const analysis = directiveResult && directiveResult.metadata; // If the directive has a selector, it should be registered with the `SelectorScopeRegistry` so // when this directive appears in an `@NgModule` scope, its selector can be determined. if (analysis && analysis.selector !== null) { - let ref = new ResolvedReference(node, node.name !); + const ref = new Reference(node); this.scopeRegistry.registerDirective(node, { ref, directive: ref, @@ -92,8 +103,8 @@ export class DirectiveDecoratorHandler implements * Helper function to extract metadata from a `Directive` or `Component`. */ export function extractDirectiveMetadata( - clazz: ts.ClassDeclaration, decorator: Decorator, checker: ts.TypeChecker, - reflector: ReflectionHost, isCore: boolean, defaultSelector: string | null = null): { + clazz: ts.ClassDeclaration, decorator: Decorator, reflector: ReflectionHost, + evaluator: PartialEvaluator, isCore: boolean, defaultSelector: string | null = null): { decorator: Map, metadata: R3DirectiveMetadata, decoratedElements: ClassMember[], @@ -127,29 +138,29 @@ export function extractDirectiveMetadata( // Construct the map of inputs both from the @Directive/@Component // decorator, and the decorated // fields. - const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', reflector, checker); + const inputsFromMeta = parseFieldToPropertyMapping(directive, 'inputs', evaluator); const inputsFromFields = parseDecoratedFields( - filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), reflector, checker, + filterToMembersWithDecorator(decoratedElements, 'Input', coreModule), evaluator, resolveInput); // And outputs. - const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', reflector, checker); + const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator); const outputsFromFields = parseDecoratedFields( - filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), reflector, checker, + filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator, resolveOutput) as{[field: string]: string}; // Construct the list of queries. const contentChildFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector, - checker); + evaluator); const contentChildrenFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ContentChildren', coreModule), reflector, - checker); + evaluator); const queries = [...contentChildFromFields, ...contentChildrenFromFields]; if (directive.has('queries')) { const queriesFromDecorator = - extractQueriesFromDecorator(directive.get('queries') !, reflector, checker, isCore); + extractQueriesFromDecorator(directive.get('queries') !, reflector, evaluator, isCore); queries.push(...queriesFromDecorator.content); } @@ -157,15 +168,18 @@ export function extractDirectiveMetadata( let selector = defaultSelector; if (directive.has('selector')) { const expr = directive.get('selector') !; - const resolved = staticallyResolve(expr, reflector, checker); + const resolved = evaluator.evaluate(expr); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `selector must be a string`); } selector = resolved; } + if (!selector) { + throw new Error(`Directive ${clazz.name !.text} has no selector, please add it!`); + } - const host = extractHostBindings(directive, decoratedElements, reflector, checker, coreModule); + const host = extractHostBindings(directive, decoratedElements, evaluator, coreModule); const providers: Expression|null = directive.has('providers') ? new WrappedNodeExpr(directive.get('providers') !) : null; @@ -176,15 +190,15 @@ export function extractDirectiveMetadata( member.name === 'ngOnChanges'); // Parse exportAs. - let exportAs: string|null = null; + let exportAs: string[]|null = null; if (directive.has('exportAs')) { const expr = directive.get('exportAs') !; - const resolved = staticallyResolve(expr, reflector, checker); + const resolved = evaluator.evaluate(expr); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `exportAs must be a string`); } - exportAs = resolved; + exportAs = resolved.split(',').map(part => part.trim()); } // Detect if the component inherits from another class @@ -192,7 +206,7 @@ export function extractDirectiveMetadata( clazz.heritageClauses.some(hc => hc.token === ts.SyntaxKind.ExtendsKeyword); const metadata: R3DirectiveMetadata = { name: clazz.name !.text, - deps: getConstructorDependencies(clazz, reflector, isCore), host, + deps: getValidConstructorDependencies(clazz, reflector, isCore), host, lifecycle: { usesOnChanges, }, @@ -207,14 +221,14 @@ export function extractDirectiveMetadata( export function extractQueryMetadata( exprNode: ts.Node, name: string, args: ReadonlyArray, propertyName: string, - reflector: ReflectionHost, checker: ts.TypeChecker): R3QueryMetadata { + reflector: ReflectionHost, evaluator: PartialEvaluator): R3QueryMetadata { if (args.length === 0) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_ARITY_WRONG, exprNode, `@${name} must have arguments`); } const first = name === 'ViewChild' || name === 'ContentChild'; const node = unwrapForwardRef(args[0], reflector); - const arg = staticallyResolve(node, reflector, checker); + const arg = evaluator.evaluate(node); // Extract the predicate let predicate: Expression|string[]|null = null; @@ -244,7 +258,7 @@ export function extractQueryMetadata( } if (options.has('descendants')) { - const descendantsValue = staticallyResolve(options.get('descendants') !, reflector, checker); + const descendantsValue = evaluator.evaluate(options.get('descendants') !); if (typeof descendantsValue !== 'boolean') { throw new Error(`@${name} options.descendants must be a boolean`); } @@ -261,7 +275,7 @@ export function extractQueryMetadata( } export function extractQueriesFromDecorator( - queryData: ts.Expression, reflector: ReflectionHost, checker: ts.TypeChecker, + queryData: ts.Expression, reflector: ReflectionHost, evaluator: PartialEvaluator, isCore: boolean): { content: R3QueryMetadata[], view: R3QueryMetadata[], @@ -283,7 +297,7 @@ export function extractQueriesFromDecorator( } const query = extractQueryMetadata( - queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, checker); + queryExpr, type.name, queryExpr.arguments || [], propertyName, reflector, evaluator); if (type.name.startsWith('Content')) { content.push(query); } else { @@ -307,14 +321,14 @@ function isStringArrayOrDie(value: any, name: string): value is string[] { } export function parseFieldArrayValue( - directive: Map, field: string, reflector: ReflectionHost, - checker: ts.TypeChecker): null|string[] { + directive: Map, field: string, evaluator: PartialEvaluator): null| + string[] { if (!directive.has(field)) { return null; } // Resolve the field of interest from the directive metadata to a string[]. - const value = staticallyResolve(directive.get(field) !, reflector, checker); + const value = evaluator.evaluate(directive.get(field) !); if (!isStringArrayOrDie(value, field)) { throw new Error(`Failed to resolve @Directive.${field}`); } @@ -327,9 +341,9 @@ export function parseFieldArrayValue( * correctly shaped metadata object. */ function parseFieldToPropertyMapping( - directive: Map, field: string, reflector: ReflectionHost, - checker: ts.TypeChecker): {[field: string]: string} { - const metaValues = parseFieldArrayValue(directive, field, reflector, checker); + directive: Map, field: string, + evaluator: PartialEvaluator): {[field: string]: string} { + const metaValues = parseFieldArrayValue(directive, field, evaluator); if (!metaValues) { return EMPTY_OBJECT; } @@ -350,8 +364,7 @@ function parseFieldToPropertyMapping( * object. */ function parseDecoratedFields( - fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost, - checker: ts.TypeChecker, + fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator, mapValueResolver: (publicName: string, internalName: string) => string | [string, string]): {[field: string]: string | [string, string]} { return fields.reduce( @@ -363,7 +376,7 @@ function parseDecoratedFields( if (decorator.args == null || decorator.args.length === 0) { results[fieldName] = fieldName; } else if (decorator.args.length === 1) { - const property = staticallyResolve(decorator.args[0], reflector, checker); + const property = evaluator.evaluate(decorator.args[0]); if (typeof property !== 'string') { throw new Error(`Decorator argument must resolve to a string`); } @@ -389,8 +402,12 @@ function resolveOutput(publicName: string, internalName: string) { export function queriesFromFields( fields: {member: ClassMember, decorators: Decorator[]}[], reflector: ReflectionHost, - checker: ts.TypeChecker): R3QueryMetadata[] { + evaluator: PartialEvaluator): R3QueryMetadata[] { return fields.map(({member, decorators}) => { + // Throw in case of `@Input() @ContentChild('foo') foo: any`, which is not supported in Ivy + if (member.decorators !.some(v => v.name === 'Input')) { + throw new Error(`Cannot combine @Input decorators with query decorators`); + } if (decorators.length !== 1) { throw new Error(`Cannot have multiple query decorators on the same class member`); } else if (!isPropertyTypeMember(member)) { @@ -398,7 +415,7 @@ export function queriesFromFields( } const decorator = decorators[0]; return extractQueryMetadata( - decorator.node, decorator.name, decorator.args || [], member.name, reflector, checker); + decorator.node, decorator.name, decorator.args || [], member.name, reflector, evaluator); }); } @@ -412,8 +429,8 @@ type StringMap = { }; function extractHostBindings( - metadata: Map, members: ClassMember[], reflector: ReflectionHost, - checker: ts.TypeChecker, coreModule: string | undefined): { + metadata: Map, members: ClassMember[], evaluator: PartialEvaluator, + coreModule: string | undefined): { attributes: StringMap, listeners: StringMap, properties: StringMap, @@ -421,12 +438,17 @@ function extractHostBindings( let hostMetadata: StringMap = {}; if (metadata.has('host')) { const expr = metadata.get('host') !; - const hostMetaMap = staticallyResolve(expr, reflector, checker); + const hostMetaMap = evaluator.evaluate(expr); if (!(hostMetaMap instanceof Map)) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_ARG_NOT_LITERAL, expr, `Decorator host metadata must be an object`); } hostMetaMap.forEach((value, key) => { + // Resolve Enum references to their declared value. + if (value instanceof EnumValue) { + value = value.resolved; + } + if (typeof value !== 'string' || typeof key !== 'string') { throw new Error(`Decorator host metadata must be a string -> string object, got ${value}`); } @@ -434,7 +456,17 @@ function extractHostBindings( }); } - const {attributes, listeners, properties, animations} = parseHostBindings(hostMetadata); + const bindings = parseHostBindings(hostMetadata); + + // TODO: create and provide proper sourceSpan to make error message more descriptive (FW-995) + const errors = verifyHostBindings(bindings, /* sourceSpan */ null !); + if (errors.length > 0) { + throw new FatalDiagnosticError( + // TODO: provide more granular diagnostic and output specific host expression that triggered + // an error instead of the whole host object + ErrorCode.HOST_BINDING_PARSE_ERROR, metadata.get('host') !, + errors.map((error: ParseError) => error.msg).join('\n')); + } filterToMembersWithDecorator(members, 'HostBinding', coreModule) .forEach(({member, decorators}) => { @@ -445,7 +477,7 @@ function extractHostBindings( throw new Error(`@HostBinding() can have at most one argument`); } - const resolved = staticallyResolve(decorator.args[0], reflector, checker); + const resolved = evaluator.evaluate(decorator.args[0]); if (typeof resolved !== 'string') { throw new Error(`@HostBinding()'s argument must be a string`); } @@ -453,7 +485,7 @@ function extractHostBindings( hostPropertyName = resolved; } - properties[hostPropertyName] = member.name; + bindings.properties[hostPropertyName] = member.name; }); }); @@ -469,7 +501,7 @@ function extractHostBindings( `@HostListener() can have at most two arguments`); } - const resolved = staticallyResolve(decorator.args[0], reflector, checker); + const resolved = evaluator.evaluate(decorator.args[0]); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[0], @@ -479,7 +511,7 @@ function extractHostBindings( eventName = resolved; if (decorator.args.length === 2) { - const resolvedArgs = staticallyResolve(decorator.args[1], reflector, checker); + const resolvedArgs = evaluator.evaluate(decorator.args[1]); if (!isStringArrayOrDie(resolvedArgs, '@HostListener.args')) { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, decorator.args[1], @@ -489,10 +521,10 @@ function extractHostBindings( } } - listeners[eventName] = `${member.name}(${args.join(',')})`; + bindings.listeners[eventName] = `${member.name}(${args.join(',')})`; }); }); - return {attributes, properties, listeners}; + return bindings; } const QUERY_TYPES = new Set([ diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index d779bd4f41..6bd05da041 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -10,12 +10,11 @@ import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, R3R import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {reflectObjectLiteral} from '../../metadata'; -import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; +import {Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform'; import {generateSetClassMetadataCall} from './metadata'; -import {getConstructorDependencies, isAngularCore} from './util'; +import {getConstructorDependencies, getValidConstructorDependencies, isAngularCore, validateConstructorDependencies} from './util'; export interface InjectableHandlerData { meta: R3InjectableMetadata; @@ -27,20 +26,33 @@ export interface InjectableHandlerData { */ export class InjectableDecoratorHandler implements DecoratorHandler { - constructor(private reflector: ReflectionHost, private isCore: boolean) {} + constructor( + private reflector: ReflectionHost, private isCore: boolean, private strictCtorDeps: boolean) { + } - detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { + readonly precedence = HandlerPrecedence.SHARED; + + detect(node: ts.Declaration, decorators: Decorator[]|null): DetectResult|undefined { if (!decorators) { return undefined; } - return decorators.find( + const decorator = decorators.find( decorator => decorator.name === 'Injectable' && (this.isCore || isAngularCore(decorator))); + if (decorator !== undefined) { + return { + trigger: decorator.node, + metadata: decorator, + }; + } else { + return undefined; + } } analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput { return { analysis: { - meta: extractInjectableMetadata(node, decorator, this.reflector, this.isCore), + meta: extractInjectableMetadata( + node, decorator, this.reflector, this.isCore, this.strictCtorDeps), metadataStmt: generateSetClassMetadataCall(node, this.reflector, this.isCore), }, }; @@ -63,23 +75,49 @@ export class InjectableDecoratorHandler implements /** * Read metadata from the `@Injectable` decorator and produce the `IvyInjectableMetadata`, the input * metadata needed to run `compileIvyInjectable`. + * + * A `null` return value indicates this is @Injectable has invalid data. */ function extractInjectableMetadata( - clazz: ts.ClassDeclaration, decorator: Decorator, reflector: ReflectionHost, - isCore: boolean): R3InjectableMetadata { + clazz: ts.ClassDeclaration, decorator: Decorator, reflector: ReflectionHost, isCore: boolean, + strictCtorDeps: boolean): R3InjectableMetadata { if (clazz.name === undefined) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_ON_ANONYMOUS_CLASS, decorator.node, `@Injectable on anonymous class`); } const name = clazz.name.text; const type = new WrappedNodeExpr(clazz.name); - const ctorDeps = getConstructorDependencies(clazz, reflector, isCore); const typeArgumentCount = reflector.getGenericArityOfClass(clazz) || 0; if (decorator.args === null) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_NOT_CALLED, decorator.node, '@Injectable must be called'); } if (decorator.args.length === 0) { + // Ideally, using @Injectable() would have the same effect as using @Injectable({...}), and be + // subject to the same validation. However, existing Angular code abuses @Injectable, applying + // it to things like abstract classes with constructors that were never meant for use with + // Angular's DI. + // + // To deal with this, @Injectable() without an argument is more lenient, and if the constructor + // signature does not work for DI then an ngInjectableDef that throws. + let ctorDeps: R3DependencyMetadata[]|'invalid'|null = null; + if (strictCtorDeps) { + ctorDeps = getValidConstructorDependencies(clazz, reflector, isCore); + } else { + const possibleCtorDeps = getConstructorDependencies(clazz, reflector, isCore); + if (possibleCtorDeps !== null) { + if (possibleCtorDeps.deps !== null) { + // This use of @Injectable has valid constructor dependencies. + ctorDeps = possibleCtorDeps.deps; + } else { + // This use of @Injectable is technically invalid. Generate a factory function which + // throws + // an error. + // TODO(alxhub): log warnings for the bad use of @Injectable. + ctorDeps = 'invalid'; + } + } + } return { name, type, @@ -87,6 +125,20 @@ function extractInjectableMetadata( providedIn: new LiteralExpr(null), ctorDeps, }; } else if (decorator.args.length === 1) { + const rawCtorDeps = getConstructorDependencies(clazz, reflector, isCore); + let ctorDeps: R3DependencyMetadata[]|'invalid'|null = null; + + // rawCtorDeps will be null if the class has no constructor. + if (rawCtorDeps !== null) { + if (rawCtorDeps.deps !== null) { + // A constructor existed and had valid dependencies. + ctorDeps = rawCtorDeps.deps; + } else { + // A constructor existed but had invalid dependencies. + ctorDeps = 'invalid'; + } + } + const metaNode = decorator.args[0]; // Firstly make sure the decorator argument is an inline literal - if not, it's illegal to // transport references from one location to another. This is the problem that lowering @@ -110,9 +162,6 @@ function extractInjectableMetadata( ErrorCode.VALUE_NOT_LITERAL, depsExpr, `In Ivy, deps metadata must be an inline array.`); } - if (depsExpr.elements.length > 0) { - throw new Error(`deps not yet supported`); - } userDeps = depsExpr.elements.map(dep => getDep(dep, reflector)); } @@ -123,7 +172,7 @@ function extractInjectableMetadata( typeArgumentCount, ctorDeps, providedIn, - useValue: new WrappedNodeExpr(meta.get('useValue') !) + useValue: new WrappedNodeExpr(meta.get('useValue') !), }; } else if (meta.has('useExisting')) { return { @@ -132,7 +181,7 @@ function extractInjectableMetadata( typeArgumentCount, ctorDeps, providedIn, - useExisting: new WrappedNodeExpr(meta.get('useExisting') !) + useExisting: new WrappedNodeExpr(meta.get('useExisting') !), }; } else if (meta.has('useClass')) { return { @@ -141,13 +190,23 @@ function extractInjectableMetadata( typeArgumentCount, ctorDeps, providedIn, - useClass: new WrappedNodeExpr(meta.get('useClass') !), userDeps + useClass: new WrappedNodeExpr(meta.get('useClass') !), userDeps, }; } else if (meta.has('useFactory')) { // useFactory is special - the 'deps' property must be analyzed. const factory = new WrappedNodeExpr(meta.get('useFactory') !); - return {name, type, typeArgumentCount, providedIn, useFactory: factory, ctorDeps, userDeps}; + return { + name, + type, + typeArgumentCount, + providedIn, + useFactory: factory, ctorDeps, userDeps, + }; } else { + if (strictCtorDeps) { + // Since use* was not provided, validate the deps according to strictCtorDeps. + validateConstructorDependencies(clazz, rawCtorDeps); + } return {name, type, typeArgumentCount, providedIn, ctorDeps}; } } else { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts b/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts index 79d18220c4..dc8faa1673 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts @@ -9,7 +9,7 @@ import {ExternalExpr, Identifiers, InvokeFunctionExpr, Statement, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {CtorParameter, Decorator, ReflectionHost} from '../../host'; +import {CtorParameter, Decorator, ReflectionHost} from '../../reflection'; /** * Given a class declaration, generate a call to `setClassMetadata` with the Angular metadata diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts index 54cb3a65cb..b8cb380501 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts @@ -6,23 +6,27 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, LiteralArrayExpr, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, Statement, WrappedNodeExpr, compileInjector, compileNgModule} from '@angular/compiler'; +import {Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, R3Identifiers, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, Statement, WrappedNodeExpr, compileInjector, compileNgModule} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, staticallyResolve, typeNodeToValueExpr} from '../../metadata'; -import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform'; +import {Reference, ReferenceEmitter} from '../../imports'; +import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator'; +import {Decorator, ReflectionHost, reflectObjectLiteral, typeNodeToValueExpr} from '../../reflection'; +import {NgModuleRouteAnalyzer} from '../../routing'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform'; +import {getSourceFile} from '../../util/src/typescript'; import {generateSetClassMetadataCall} from './metadata'; import {ReferencesRegistry} from './references_registry'; import {SelectorScopeRegistry} from './selector_scope'; -import {getConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util'; +import {getValidConstructorDependencies, isAngularCore, toR3Reference, unwrapExpression} from './util'; export interface NgModuleAnalysis { ngModuleDef: R3NgModuleMetadata; ngInjectorDef: R3InjectorMetadata; metadataStmt: Statement|null; + declarations: Reference[]; } /** @@ -32,16 +36,27 @@ export interface NgModuleAnalysis { */ export class NgModuleDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry, - private isCore: boolean) {} + private isCore: boolean, private routeAnalyzer: NgModuleRouteAnalyzer|null, + private refEmitter: ReferenceEmitter) {} - detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { + readonly precedence = HandlerPrecedence.PRIMARY; + + detect(node: ts.Declaration, decorators: Decorator[]|null): DetectResult|undefined { if (!decorators) { return undefined; } - return decorators.find( + const decorator = decorators.find( decorator => decorator.name === 'NgModule' && (this.isCore || isAngularCore(decorator))); + if (decorator !== undefined) { + return { + trigger: decorator.node, + metadata: decorator, + }; + } else { + return undefined; + } } analyze(node: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput { @@ -72,34 +87,31 @@ export class NgModuleDecoratorHandler implements DecoratorHandler[] = []; if (ngModule.has('declarations')) { const expr = ngModule.get('declarations') !; - const declarationMeta = staticallyResolve(expr, this.reflector, this.checker); + const declarationMeta = this.evaluator.evaluate(expr); declarations = this.resolveTypeList(expr, declarationMeta, 'declarations'); - this.referencesRegistry.add(...declarations); } let imports: Reference[] = []; + let rawImports: ts.Expression|null = null; if (ngModule.has('imports')) { - const expr = ngModule.get('imports') !; - const importsMeta = staticallyResolve( - expr, this.reflector, this.checker, - ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); - imports = this.resolveTypeList(expr, importsMeta, 'imports'); - this.referencesRegistry.add(...imports); + rawImports = ngModule.get('imports') !; + const importsMeta = this.evaluator.evaluate( + rawImports, ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); + imports = this.resolveTypeList(rawImports, importsMeta, 'imports'); } let exports: Reference[] = []; + let rawExports: ts.Expression|null = null; if (ngModule.has('exports')) { - const expr = ngModule.get('exports') !; - const exportsMeta = staticallyResolve( - expr, this.reflector, this.checker, - ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); - exports = this.resolveTypeList(expr, exportsMeta, 'exports'); - this.referencesRegistry.add(...exports); + rawExports = ngModule.get('exports') !; + const exportsMeta = this.evaluator.evaluate( + rawExports, ref => this._extractModuleFromModuleWithProvidersFn(ref.node)); + exports = this.resolveTypeList(rawExports, exportsMeta, 'exports'); + this.referencesRegistry.add(node, ...exports); } let bootstrap: Reference[] = []; if (ngModule.has('bootstrap')) { const expr = ngModule.get('bootstrap') !; - const bootstrapMeta = staticallyResolve(expr, this.reflector, this.checker); + const bootstrapMeta = this.evaluator.evaluate(expr); bootstrap = this.resolveTypeList(expr, bootstrapMeta, 'bootstrap'); - this.referencesRegistry.add(...bootstrap); } // Register this module's information with the SelectorScopeRegistry. This ensures that during @@ -122,11 +134,14 @@ export class NgModuleDecoratorHandler implements DecoratorHandler this._toR3Reference(exp, valueContext, typeContext)), imports: imports.map(imp => this._toR3Reference(imp, valueContext, typeContext)), emitInline: false, + // TODO: to be implemented as a part of FW-1004. + schemas: [], }; const providers: Expression = ngModule.has('providers') ? new WrappedNodeExpr(ngModule.get('providers') !) : new LiteralArrayExpr([]); + const rawProviders = ngModule.has('providers') ? ngModule.get('providers') ! : null; const injectorImports: WrappedNodeExpr[] = []; if (ngModule.has('imports')) { @@ -136,10 +151,15 @@ export class NgModuleDecoratorHandler implements DecoratorHandler { directives.push(this.refEmitter.emit(directive.ref, context) !); }); + scope.pipes.forEach(pipe => pipes.push(this.refEmitter.emit(pipe, context) !)); + const directiveArray = new LiteralArrayExpr(directives); + const pipesArray = new LiteralArrayExpr(pipes); + const declExpr = this.refEmitter.emit(decl, context) !; + const setComponentScope = new ExternalExpr(R3Identifiers.setComponentScope); + const callExpr = + new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]); + + ngModuleStatements.push(callExpr.toStmt()); + } + } return [ { name: 'ngModuleDef', @@ -179,24 +222,25 @@ export class NgModuleDecoratorHandler implements DecoratorHandler, valueContext: ts.SourceFile, typeContext: ts.SourceFile): R3Reference { - if (!(valueRef instanceof ResolvedReference)) { - return toR3Reference(valueRef, valueRef, valueContext, valueContext); + if (valueRef.hasOwningModuleGuess) { + return toR3Reference(valueRef, valueRef, valueContext, valueContext, this.refEmitter); } else { let typeRef = valueRef; let typeNode = this.reflector.getDtsDeclaration(typeRef.node); if (typeNode !== null && ts.isClassDeclaration(typeNode)) { - typeRef = new ResolvedReference(typeNode, typeNode.name !); + typeRef = new Reference(typeNode); } - return toR3Reference(valueRef, typeRef, valueContext, typeContext); + return toR3Reference(valueRef, typeRef, valueContext, typeContext, this.refEmitter); } } /** - * Given a `FunctionDeclaration` or `MethodDeclaration`, check if it is typed as a - * `ModuleWithProviders` and return an expression referencing the module if available. + * Given a `FunctionDeclaration`, `MethodDeclaration` or `FunctionExpression`, check if it is + * typed as a `ModuleWithProviders` and return an expression referencing the module if available. */ private _extractModuleFromModuleWithProvidersFn(node: ts.FunctionDeclaration| - ts.MethodDeclaration): ts.Expression|null { + ts.MethodDeclaration| + ts.FunctionExpression): ts.Expression|null { const type = node.type || null; return type && (this._reflectModuleFromTypeParam(type) || this._reflectModuleFromLiteralType(type)); @@ -285,10 +329,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler { constructor( - private checker: ts.TypeChecker, private reflector: ReflectionHost, + private reflector: ReflectionHost, private evaluator: PartialEvaluator, private scopeRegistry: SelectorScopeRegistry, private isCore: boolean) {} - detect(node: ts.Declaration, decorators: Decorator[]|null): Decorator|undefined { + readonly precedence = HandlerPrecedence.PRIMARY; + + detect(node: ts.Declaration, decorators: Decorator[]|null): DetectResult|undefined { if (!decorators) { return undefined; } - return decorators.find( + const decorator = decorators.find( decorator => decorator.name === 'Pipe' && (this.isCore || isAngularCore(decorator))); + if (decorator !== undefined) { + return { + trigger: decorator.node, + metadata: decorator, + }; + } else { + return undefined; + } } analyze(clazz: ts.ClassDeclaration, decorator: Decorator): AnalysisOutput { @@ -63,7 +73,7 @@ export class PipeDecoratorHandler implements DecoratorHandler[]): void; - /** - * Create and return a mapping for the registered resolved references. - * @returns A map of reference identifiers to reference declarations. - */ - getDeclarationMap(): Map; + add(source: ts.Declaration, ...references: Reference[]): void; } /** @@ -34,6 +28,5 @@ export interface ReferencesRegistry { * The ngcc tool implements a working version for its purposes. */ export class NoopReferencesRegistry implements ReferencesRegistry { - add(...references: Reference[]): void {} - getDeclarationMap(): Map { return new Map(); } + add(source: ts.Declaration, ...references: Reference[]): void {} } \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts index 2688d1a82a..4b3a19628f 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts @@ -6,12 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@angular/compiler'; +import {Expression, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {ReflectionHost} from '../../host'; -import {AbsoluteReference, Reference, ResolvedReference, reflectTypeEntityToDeclaration} from '../../metadata'; -import {reflectIdentifierOfDeclaration, reflectNameOfDeclaration} from '../../metadata/src/reflector'; +import {Reference, ReferenceEmitter} from '../../imports'; +import {ReflectionHost, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectTypeEntityToDeclaration} from '../../reflection'; import {TypeCheckableDirectiveMeta} from '../../typecheck'; import {extractDirectiveGuards} from './util'; @@ -85,12 +84,19 @@ export class SelectorScopeRegistry { */ private _pipeToName = new Map(); + /** + * Components that require remote scoping. + */ + private _requiresRemoteScope = new Set(); + /** * Map of components/directives/pipes to their module. */ private _declararedTypeToModule = new Map(); - constructor(private checker: ts.TypeChecker, private reflector: ReflectionHost) {} + constructor( + private checker: ts.TypeChecker, private reflector: ReflectionHost, + private refEmitter: ReferenceEmitter) {} /** * Register a module's metadata with the registry. @@ -131,6 +137,21 @@ export class SelectorScopeRegistry { this._pipeToName.set(node, name); } + /** + * Mark a component (identified by its `ts.Declaration`) as requiring its `directives` scope to be + * set remotely, from the file of the @NgModule which declares the component. + */ + setComponentAsRequiringRemoteScoping(component: ts.Declaration): void { + this._requiresRemoteScope.add(component); + } + + /** + * Check whether the given component requires its `directives` scope to be set remotely. + */ + requiresRemoteScope(component: ts.Declaration): boolean { + return this._requiresRemoteScope.has(ts.getOriginalNode(component) as ts.Declaration); + } + lookupCompilationScopeAsRefs(node: ts.Declaration): CompilationScope|null { node = ts.getOriginalNode(node) as ts.Declaration; @@ -162,7 +183,9 @@ export class SelectorScopeRegistry { // Process the declaration scope of the module, and lookup the selector of every declared type. // The initial value of ngModuleImportedFrom is 'null' which signifies that the NgModule // was not imported from a .d.ts source. - for (const ref of this.lookupScopesOrDie(module !, /* ngModuleImportedFrom */ null) + for (const ref of this + .lookupScopesOrDie( + module !, /* ngModuleImportedFrom */ null, node.getSourceFile().fileName) .compilation) { const node = ts.getOriginalNode(ref.node) as ts.Declaration; @@ -201,12 +224,13 @@ export class SelectorScopeRegistry { */ lookupCompilationScope(node: ts.Declaration): CompilationScope|null { const scope = this.lookupCompilationScopeAsRefs(node); - return scope !== null ? convertScopeToExpressions(scope, node) : null; + return scope !== null ? convertScopeToExpressions(scope, node, this.refEmitter) : null; } - private lookupScopesOrDie(node: ts.Declaration, ngModuleImportedFrom: string|null): - SelectorScopes { - const result = this.lookupScopes(node, ngModuleImportedFrom); + private lookupScopesOrDie( + node: ts.Declaration, ngModuleImportedFrom: string|null, + resolutionContext: string): SelectorScopes { + const result = this.lookupScopes(node, ngModuleImportedFrom, resolutionContext); if (result === null) { throw new Error(`Module not found: ${reflectNameOfDeclaration(node)}`); } @@ -220,8 +244,9 @@ export class SelectorScopeRegistry { * (`ngModuleImportedFrom`) then all of its declarations are exported at that same path, as well * as imports and exports from other modules that are relatively imported. */ - private lookupScopes(node: ts.Declaration, ngModuleImportedFrom: string|null): SelectorScopes - |null { + private lookupScopes( + node: ts.Declaration, ngModuleImportedFrom: string|null, + resolutionContext: string): SelectorScopes|null { let data: ModuleData|null = null; // Either this module was analyzed directly, or has a precompiled ngModuleDef. @@ -231,7 +256,7 @@ export class SelectorScopeRegistry { } else { // The module wasn't analyzed before, and probably has a precompiled ngModuleDef with a type // annotation that specifies the needed metadata. - data = this._readModuleDataFromCompiledClass(node, ngModuleImportedFrom); + data = this._readModuleDataFromCompiledClass(node, ngModuleImportedFrom, resolutionContext); // Note that data here could still be null, if the class didn't have a precompiled // ngModuleDef. } @@ -240,22 +265,28 @@ export class SelectorScopeRegistry { return null; } + const context = node.getSourceFile().fileName; + return { compilation: [ ...data.declarations, // Expand imports to the exported scope of those imports. ...flatten(data.imports.map( - ref => this.lookupScopesOrDie(ref.node as ts.Declaration, absoluteModuleName(ref)) - .exported)), + ref => + this.lookupScopesOrDie(ref.node as ts.Declaration, ref.ownedByModuleGuess, context) + .exported)), // And include the compilation scope of exported modules. ...flatten( data.exports - .map(ref => this.lookupScopes(ref.node as ts.Declaration, absoluteModuleName(ref))) + .map( + ref => this.lookupScopes( + ref.node as ts.Declaration, ref.ownedByModuleGuess, context)) .filter((scope: SelectorScopes | null): scope is SelectorScopes => scope !== null) .map(scope => scope.exported)) ], exported: flatten(data.exports.map(ref => { - const scope = this.lookupScopes(ref.node as ts.Declaration, absoluteModuleName(ref)); + const scope = + this.lookupScopes(ref.node as ts.Declaration, ref.ownedByModuleGuess, context); if (scope !== null) { return scope.exported; } else { @@ -298,7 +329,8 @@ export class SelectorScopeRegistry { * stemming from this module. */ private _readModuleDataFromCompiledClass( - clazz: ts.Declaration, ngModuleImportedFrom: string|null): ModuleData|null { + clazz: ts.Declaration, ngModuleImportedFrom: string|null, + resolutionContext: string): ModuleData|null { // This operation is explicitly not memoized, as it depends on `ngModuleImportedFrom`. // TODO(alxhub): investigate caching of .d.ts module metadata. const ngModuleDef = this.reflector.getMembersOfClass(clazz).find( @@ -316,9 +348,12 @@ export class SelectorScopeRegistry { // Read the ModuleData out of the type arguments. const [_, declarationMetadata, importMetadata, exportMetadata] = ngModuleDef.type.typeArguments; return { - declarations: this._extractReferencesFromType(declarationMetadata, ngModuleImportedFrom), - exports: this._extractReferencesFromType(exportMetadata, ngModuleImportedFrom), - imports: this._extractReferencesFromType(importMetadata, ngModuleImportedFrom), + declarations: this._extractReferencesFromType( + declarationMetadata, ngModuleImportedFrom, resolutionContext), + exports: + this._extractReferencesFromType(exportMetadata, ngModuleImportedFrom, resolutionContext), + imports: + this._extractReferencesFromType(importMetadata, ngModuleImportedFrom, resolutionContext), }; } @@ -351,7 +386,7 @@ export class SelectorScopeRegistry { name: clazz.name !.text, directive: ref, isComponent: def.name === 'ngComponentDef', selector, - exportAs: readStringType(def.type.typeArguments[2]), + exportAs: readStringArrayType(def.type.typeArguments[2]), inputs: readStringMapType(def.type.typeArguments[3]), outputs: readStringMapType(def.type.typeArguments[4]), queries: readStringArrayType(def.type.typeArguments[5]), @@ -390,8 +425,9 @@ export class SelectorScopeRegistry { * This operation assumes that these types should be imported from `ngModuleImportedFrom` unless * they themselves were imported from another absolute path. */ - private _extractReferencesFromType(def: ts.TypeNode, ngModuleImportedFrom: string|null): - Reference[] { + private _extractReferencesFromType( + def: ts.TypeNode, ngModuleImportedFrom: string|null, + resolutionContext: string): Reference[] { if (!ts.isTupleTypeNode(def)) { return []; } @@ -402,13 +438,11 @@ export class SelectorScopeRegistry { const type = element.exprName; if (ngModuleImportedFrom !== null) { const {node, from} = reflectTypeEntityToDeclaration(type, this.checker); - const moduleName = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom); - const id = reflectIdentifierOfDeclaration(node); - return new AbsoluteReference(node, id !, moduleName, id !.text); + const specifier = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom); + return new Reference(node, {specifier, resolutionContext}); } else { const {node} = reflectTypeEntityToDeclaration(type, this.checker); - const id = reflectIdentifierOfDeclaration(node); - return new ResolvedReference(node, id !); + return new Reference(node); } }); } @@ -421,17 +455,11 @@ function flatten(array: T[][]): T[] { }, [] as T[]); } -function absoluteModuleName(ref: Reference): string|null { - if (!(ref instanceof AbsoluteReference)) { - return null; - } - return ref.moduleName; -} - function convertDirectiveReferenceList( - input: ScopeDirective[], context: ts.SourceFile): ScopeDirective[] { + input: ScopeDirective[], context: ts.SourceFile, + refEmitter: ReferenceEmitter): ScopeDirective[] { return input.map(meta => { - const directive = meta.directive.toExpression(context); + const directive = refEmitter.emit(meta.directive, context); if (directive === null) { throw new Error(`Could not write expression to reference ${meta.directive.node}`); } @@ -440,10 +468,11 @@ function convertDirectiveReferenceList( } function convertPipeReferenceMap( - map: Map, context: ts.SourceFile): Map { + map: Map, context: ts.SourceFile, + refEmitter: ReferenceEmitter): Map { const newMap = new Map(); map.forEach((meta, selector) => { - const pipe = meta.toExpression(context); + const pipe = refEmitter.emit(meta, context); if (pipe === null) { throw new Error(`Could not write expression to reference ${meta.node}`); } @@ -453,10 +482,11 @@ function convertPipeReferenceMap( } function convertScopeToExpressions( - scope: CompilationScope, context: ts.Declaration): CompilationScope { + scope: CompilationScope, context: ts.Declaration, + refEmitter: ReferenceEmitter): CompilationScope { const sourceContext = ts.getOriginalNode(context).getSourceFile(); - const directives = convertDirectiveReferenceList(scope.directives, sourceContext); - const pipes = convertPipeReferenceMap(scope.pipes, sourceContext); + const directives = convertDirectiveReferenceList(scope.directives, sourceContext, refEmitter); + const pipes = convertPipeReferenceMap(scope.pipes, sourceContext, refEmitter); const declPointer = maybeUnwrapNameOfDeclaration(context); let containsForwardDecls = false; directives.forEach(meta => { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts index 6b929ef0c4..1bd49291ce 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts @@ -6,17 +6,35 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; +import {R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {ClassMemberKind, Decorator, ReflectionHost} from '../../host'; -import {AbsoluteReference, ImportMode, Reference} from '../../metadata'; +import {ImportMode, Reference, ReferenceEmitter} from '../../imports'; +import {ClassMemberKind, CtorParameter, Decorator, ReflectionHost} from '../../reflection'; + +export enum ConstructorDepErrorKind { + NO_SUITABLE_TOKEN, +} + +export type ConstructorDeps = { + deps: R3DependencyMetadata[]; +} | +{ + deps: null; + errors: ConstructorDepError[]; +}; + +export interface ConstructorDepError { + index: number; + param: CtorParameter; + kind: ConstructorDepErrorKind; +} export function getConstructorDependencies( - clazz: ts.ClassDeclaration, reflector: ReflectionHost, isCore: boolean): R3DependencyMetadata[]| - null { - const useType: R3DependencyMetadata[] = []; + clazz: ts.ClassDeclaration, reflector: ReflectionHost, isCore: boolean): ConstructorDeps|null { + const deps: R3DependencyMetadata[] = []; + const errors: ConstructorDepError[] = []; let ctorParams = reflector.getConstructorParameters(clazz); if (ctorParams === null) { if (reflector.hasBaseClass(clazz)) { @@ -60,21 +78,50 @@ export function getConstructorDependencies( } }); if (tokenExpr === null) { - throw new FatalDiagnosticError( - ErrorCode.PARAM_MISSING_TOKEN, param.nameNode, - `No suitable injection token for parameter '${param.name || idx}' of class '${clazz.name!.text}'. Found: ${param.typeNode!.getText()}`); + errors.push({ + index: idx, + kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN, param, + }); + } else { + const token = new WrappedNodeExpr(tokenExpr); + deps.push({token, optional, self, skipSelf, host, resolved}); } - const token = new WrappedNodeExpr(tokenExpr); - useType.push({token, optional, self, skipSelf, host, resolved}); }); - return useType; + if (errors.length === 0) { + return {deps}; + } else { + return {deps: null, errors}; + } +} + +export function getValidConstructorDependencies( + clazz: ts.ClassDeclaration, reflector: ReflectionHost, isCore: boolean): R3DependencyMetadata[]| + null { + return validateConstructorDependencies( + clazz, getConstructorDependencies(clazz, reflector, isCore)); +} + +export function validateConstructorDependencies( + clazz: ts.ClassDeclaration, deps: ConstructorDeps | null): R3DependencyMetadata[]|null { + if (deps === null) { + return null; + } else if (deps.deps !== null) { + return deps.deps; + } else { + // TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here. + const {param, index} = (deps as{errors: ConstructorDepError[]}).errors[0]; + // There is at least one error. + throw new FatalDiagnosticError( + ErrorCode.PARAM_MISSING_TOKEN, param.nameNode, + `No suitable injection token for parameter '${param.name || index}' of class '${clazz.name!.text}'. Found: ${param.typeNode!.getText()}`); + } } export function toR3Reference( valueRef: Reference, typeRef: Reference, valueContext: ts.SourceFile, - typeContext: ts.SourceFile): R3Reference { - const value = valueRef.toExpression(valueContext, ImportMode.UseExistingImport); - const type = typeRef.toExpression(typeContext, ImportMode.ForceNewImport); + typeContext: ts.SourceFile, refEmitter: ReferenceEmitter): R3Reference { + const value = refEmitter.emit(valueRef, valueContext, ImportMode.UseExistingImport); + const type = refEmitter.emit(typeRef, typeContext, ImportMode.ForceNewImport); if (value === null || type === null) { throw new Error(`Could not refer to ${ts.SyntaxKind[valueRef.node.kind]}`); } @@ -85,6 +132,10 @@ export function isAngularCore(decorator: Decorator): boolean { return decorator.import !== null && decorator.import.from === '@angular/core'; } +export function isAngularCoreReference(reference: Reference, symbolName: string) { + return reference.ownedByModuleGuess === '@angular/core' && reference.debugName === symbolName; +} + /** * Unwrap a `ts.Expression`, removing outer type-casts or parentheses until the expression is in its * lowest level form. @@ -157,8 +208,7 @@ export function unwrapForwardRef(node: ts.Expression, reflector: ReflectionHost) export function forwardRefResolver( ref: Reference, args: ts.Expression[]): ts.Expression|null { - if (!(ref instanceof AbsoluteReference) || ref.moduleName !== '@angular/core' || - ref.symbolName !== 'forwardRef' || args.length !== 1) { + if (!isAngularCoreReference(ref, 'forwardRef') || args.length !== 1) { return null; } return expandForwardRef(args[0]); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/annotations/test/BUILD.bazel index fc283563c0..b179d74b6b 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/annotations/test/BUILD.bazel @@ -12,10 +12,15 @@ ts_library( "//packages:types", "//packages/compiler", "//packages/compiler-cli/src/ngtsc/annotations", + "//packages/compiler-cli/src/ngtsc/cycles", "//packages/compiler-cli/src/ngtsc/diagnostics", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/path", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/testing", "//packages/compiler-cli/src/ngtsc/translator", + "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//typescript", ], ) diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts index 1b3bd568b1..f8a65e2a4b 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts @@ -8,20 +8,26 @@ import * as ts from 'typescript'; +import {CycleAnalyzer, ImportGraph} from '../../cycles'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {TypeScriptReflectionHost} from '../../metadata'; +import {ModuleResolver, ReferenceEmitter} from '../../imports'; +import {PartialEvaluator} from '../../partial_evaluator'; +import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; import {ResourceLoader} from '../src/api'; import {ComponentDecoratorHandler} from '../src/component'; import {SelectorScopeRegistry} from '../src/selector_scope'; export class NoopResourceLoader implements ResourceLoader { - load(url: string): string { throw new Error('Not implemented'); } + resolve(): string { throw new Error('Not implemented.'); } + canPreload = false; + load(): string { throw new Error('Not implemented'); } + preload(): Promise|undefined { throw new Error('Not implemented'); } } describe('ComponentDecoratorHandler', () => { it('should produce a diagnostic when @Component has non-literal argument', () => { - const {program} = makeProgram([ + const {program, options, host} = makeProgram([ { name: 'node_modules/@angular/core/index.d.ts', contents: 'export const Component: any;', @@ -37,17 +43,23 @@ describe('ComponentDecoratorHandler', () => { }, ]); const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); + const reflectionHost = new TypeScriptReflectionHost(checker); + const evaluator = new PartialEvaluator(reflectionHost, checker); + const moduleResolver = new ModuleResolver(program, options, host); + const importGraph = new ImportGraph(moduleResolver); + const cycleAnalyzer = new CycleAnalyzer(importGraph); + const handler = new ComponentDecoratorHandler( - checker, host, new SelectorScopeRegistry(checker, host), false, new NoopResourceLoader(), - [''], false, true); + reflectionHost, evaluator, + new SelectorScopeRegistry(checker, reflectionHost, new ReferenceEmitter([])), false, + new NoopResourceLoader(), [''], false, true, moduleResolver, cycleAnalyzer); const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration); - const detected = handler.detect(TestCmp, host.getDecoratorsOfDeclaration(TestCmp)); + const detected = handler.detect(TestCmp, reflectionHost.getDecoratorsOfDeclaration(TestCmp)); if (detected === undefined) { return fail('Failed to recognize @Component'); } try { - handler.analyze(TestCmp, detected); + handler.analyze(TestCmp, detected.metadata); return fail('Analysis should have failed'); } catch (err) { if (!(err instanceof FatalDiagnosticError)) { @@ -56,7 +68,7 @@ describe('ComponentDecoratorHandler', () => { const diag = err.toDiagnostic(); expect(diag.code).toEqual(ivyCode(ErrorCode.DECORATOR_ARG_NOT_LITERAL)); expect(diag.file.fileName.endsWith('entry.ts')).toBe(true); - expect(diag.start).toBe(detected.args ![0].getStart()); + expect(diag.start).toBe(detected.metadata.args ![0].getStart()); } }); }); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts index 405e6ef6aa..adbbed46e5 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts @@ -6,12 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Statement} from '@angular/compiler'; import * as ts from 'typescript'; -import {TypeScriptReflectionHost} from '../../metadata'; +import {NoopImportRewriter} from '../../imports'; +import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; import {ImportManager, translateStatement} from '../../translator'; + import {generateSetClassMetadataCall} from '../src/metadata'; const CORE = { @@ -87,7 +88,7 @@ function compileAndPrint(contents: string): string { return ''; } const sf = program.getSourceFile('index.ts') !; - const im = new ImportManager(false, 'i'); + const im = new ImportManager(new NoopImportRewriter(), 'i'); const tsStatement = translateStatement(call, im); const res = ts.createPrinter().printNode(ts.EmitHint.Unspecified, tsStatement, sf); return res.replace(/\s+/g, ' '); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts index b926dfba15..92f231950f 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/selector_scope_spec.ts @@ -8,15 +8,16 @@ import * as ts from 'typescript'; -import {TypeScriptReflectionHost} from '../../metadata'; -import {AbsoluteReference, ResolvedReference} from '../../metadata/src/resolver'; +import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, Reference, ReferenceEmitter} from '../../imports'; +import {LogicalFileSystem} from '../../path'; +import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; -import {NgModuleDecoratorHandler} from '../src/ng_module'; +import {getRootDirs} from '../../util/src/typescript'; import {SelectorScopeRegistry} from '../src/selector_scope'; describe('SelectorScopeRegistry', () => { it('absolute imports work', () => { - const {program} = makeProgram([ + const {program, options, host} = makeProgram([ { name: 'node_modules/@angular/core/index.d.ts', contents: ` @@ -29,6 +30,7 @@ describe('SelectorScopeRegistry', () => { contents: ` import {NgModuleDef} from '@angular/core'; import * as i0 from './component'; + export {SomeCmp} from './component'; export declare class SomeModule { static ngModuleDef: NgModuleDef; @@ -54,7 +56,7 @@ describe('SelectorScopeRegistry', () => { }, ]); const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); + const reflectionHost = new TypeScriptReflectionHost(checker); const ProgramModule = getDeclaration(program, 'entry.ts', 'ProgramModule', ts.isClassDeclaration); const ProgramCmp = getDeclaration(program, 'entry.ts', 'ProgramCmp', ts.isClassDeclaration); @@ -63,17 +65,19 @@ describe('SelectorScopeRegistry', () => { expect(ProgramModule).toBeDefined(); expect(SomeModule).toBeDefined(); - const ProgramCmpRef = new ResolvedReference(ProgramCmp, ProgramCmp.name !); - - const registry = new SelectorScopeRegistry(checker, host); + const ProgramCmpRef = new Reference(ProgramCmp); + const refEmitter = makeReferenceEmitter(program, checker, options, host); + const registry = new SelectorScopeRegistry(checker, reflectionHost, refEmitter); registry.registerModule(ProgramModule, { - declarations: [new ResolvedReference(ProgramCmp, ProgramCmp.name !)], + declarations: [new Reference(ProgramCmp)], exports: [], - imports: [new AbsoluteReference(SomeModule, SomeModule.name !, 'some_library', 'SomeModule')], + imports: [new Reference( + SomeModule, + {specifier: 'some_library', resolutionContext: '/node_modules/some_library/index.d.ts'})], }); - const ref = new ResolvedReference(ProgramCmp, ProgramCmp.name !); + const ref = new Reference(ProgramCmp); registry.registerDirective(ProgramCmp, { name: 'ProgramCmp', ref: ProgramCmpRef, @@ -95,7 +99,7 @@ describe('SelectorScopeRegistry', () => { }); it('exports of third-party libs work', () => { - const {program} = makeProgram([ + const {program, options, host} = makeProgram([ { name: 'node_modules/@angular/core/index.d.ts', contents: ` @@ -126,7 +130,7 @@ describe('SelectorScopeRegistry', () => { }, ]); const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); + const reflectionHost = new TypeScriptReflectionHost(checker); const ProgramModule = getDeclaration(program, 'entry.ts', 'ProgramModule', ts.isClassDeclaration); const ProgramCmp = getDeclaration(program, 'entry.ts', 'ProgramCmp', ts.isClassDeclaration); @@ -135,13 +139,15 @@ describe('SelectorScopeRegistry', () => { expect(ProgramModule).toBeDefined(); expect(SomeModule).toBeDefined(); - const ProgramCmpRef = new ResolvedReference(ProgramCmp, ProgramCmp.name !); - - const registry = new SelectorScopeRegistry(checker, host); + const ProgramCmpRef = new Reference(ProgramCmp); + const refEmitter = makeReferenceEmitter(program, checker, options, host); + const registry = new SelectorScopeRegistry(checker, reflectionHost, refEmitter); registry.registerModule(ProgramModule, { - declarations: [new ResolvedReference(ProgramCmp, ProgramCmp.name !)], - exports: [new AbsoluteReference(SomeModule, SomeModule.name !, 'some_library', 'SomeModule')], + declarations: [new Reference(ProgramCmp)], + exports: [new Reference( + SomeModule, + {specifier: 'some_library', resolutionContext: '/node_modules/some_library/index.d.ts'})], imports: [], }); @@ -164,4 +170,15 @@ describe('SelectorScopeRegistry', () => { expect(scope.directives).toBeDefined(); expect(scope.directives.length).toBe(2); }); -}); \ No newline at end of file +}); + +function makeReferenceEmitter( + program: ts.Program, checker: ts.TypeChecker, options: ts.CompilerOptions, + host: ts.CompilerHost): ReferenceEmitter { + const rootDirs = getRootDirs(host, options); + return new ReferenceEmitter([ + new LocalIdentifierStrategy(), + new AbsoluteModuleStrategy(program, checker, options, host), + new LogicalProjectStrategy(checker, new LogicalFileSystem(rootDirs)), + ]); +} diff --git a/packages/compiler-cli/src/ngtsc/cycles/BUILD.bazel b/packages/compiler-cli/src/ngtsc/cycles/BUILD.bazel new file mode 100644 index 0000000000..990d00b790 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/cycles/BUILD.bazel @@ -0,0 +1,16 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "cycles", + srcs = glob([ + "index.ts", + "src/**/*.ts", + ]), + module_name = "@angular/compiler-cli/src/ngtsc/cycles", + deps = [ + "//packages/compiler-cli/src/ngtsc/imports", + "@ngdeps//typescript", + ], +) diff --git a/packages/service-worker/worker/rollup-worker.config.js b/packages/compiler-cli/src/ngtsc/cycles/index.ts similarity index 53% rename from packages/service-worker/worker/rollup-worker.config.js rename to packages/compiler-cli/src/ngtsc/cycles/index.ts index bf8be460f9..273598bee5 100644 --- a/packages/service-worker/worker/rollup-worker.config.js +++ b/packages/compiler-cli/src/ngtsc/cycles/index.ts @@ -6,8 +6,5 @@ * found in the LICENSE file at https://angular.io/license */ -export default { - entry: '../../dist/all/@angular/service-worker/worker-es2017/main.js', - dest: '../../dist/packages-dist/service-worker/ngsw-worker.js', - format: 'iife', -}; +export {CycleAnalyzer} from './src/analyzer'; +export {ImportGraph} from './src/imports'; diff --git a/packages/compiler-cli/src/ngtsc/cycles/src/analyzer.ts b/packages/compiler-cli/src/ngtsc/cycles/src/analyzer.ts new file mode 100644 index 0000000000..5d87b47c08 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/cycles/src/analyzer.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ImportGraph} from './imports'; + +/** + * Analyzes a `ts.Program` for cycles. + */ +export class CycleAnalyzer { + constructor(private importGraph: ImportGraph) {} + + /** + * Check whether adding an import from `from` to `to` would create a cycle in the `ts.Program`. + */ + wouldCreateCycle(from: ts.SourceFile, to: ts.SourceFile): boolean { + // Import of 'from' -> 'to' is illegal if an edge 'to' -> 'from' already exists. + return this.importGraph.transitiveImportsOf(to).has(from); + } + + /** + * Record a synthetic import from `from` to `to`. + * + * This is an import that doesn't exist in the `ts.Program` but will be considered as part of the + * import graph for cycle creation. + */ + recordSyntheticImport(from: ts.SourceFile, to: ts.SourceFile): void { + this.importGraph.addSyntheticImport(from, to); + } +} diff --git a/packages/compiler-cli/src/ngtsc/cycles/src/imports.ts b/packages/compiler-cli/src/ngtsc/cycles/src/imports.ts new file mode 100644 index 0000000000..053c1dd277 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/cycles/src/imports.ts @@ -0,0 +1,84 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ModuleResolver} from '../../imports'; + +/** + * A cached graph of imports in the `ts.Program`. + * + * The `ImportGraph` keeps track of dependencies (imports) of individual `ts.SourceFile`s. Only + * dependencies within the same program are tracked; imports into packages on NPM are not. + */ +export class ImportGraph { + private map = new Map>(); + + constructor(private resolver: ModuleResolver) {} + + /** + * List the direct (not transitive) imports of a given `ts.SourceFile`. + * + * This operation is cached. + */ + importsOf(sf: ts.SourceFile): Set { + if (!this.map.has(sf)) { + this.map.set(sf, this.scanImports(sf)); + } + return this.map.get(sf) !; + } + + /** + * Lists the transitive imports of a given `ts.SourceFile`. + */ + transitiveImportsOf(sf: ts.SourceFile): Set { + const imports = new Set(); + this.transitiveImportsOfHelper(sf, imports); + return imports; + } + + private transitiveImportsOfHelper(sf: ts.SourceFile, results: Set): void { + if (results.has(sf)) { + return; + } + results.add(sf); + this.importsOf(sf).forEach(imported => { this.transitiveImportsOfHelper(imported, results); }); + } + + /** + * Add a record of an import from `sf` to `imported`, that's not present in the original + * `ts.Program` but will be remembered by the `ImportGraph`. + */ + addSyntheticImport(sf: ts.SourceFile, imported: ts.SourceFile): void { + if (isLocalFile(imported)) { + this.importsOf(sf).add(imported); + } + } + + private scanImports(sf: ts.SourceFile): Set { + const imports = new Set(); + // Look through the source file for import statements. + sf.statements.forEach(stmt => { + if ((ts.isImportDeclaration(stmt) || ts.isExportDeclaration(stmt)) && + stmt.moduleSpecifier !== undefined && ts.isStringLiteral(stmt.moduleSpecifier)) { + // Resolve the module to a file, and check whether that file is in the ts.Program. + const moduleName = stmt.moduleSpecifier.text; + const moduleFile = this.resolver.resolveModuleName(moduleName, sf); + if (moduleFile !== null && isLocalFile(moduleFile)) { + // Record this local import. + imports.add(moduleFile); + } + } + }); + return imports; + } +} + +function isLocalFile(sf: ts.SourceFile): boolean { + return !sf.fileName.endsWith('.d.ts'); +} diff --git a/packages/compiler-cli/src/ngtsc/metadata/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/cycles/test/BUILD.bazel similarity index 80% rename from packages/compiler-cli/src/ngtsc/metadata/test/BUILD.bazel rename to packages/compiler-cli/src/ngtsc/cycles/test/BUILD.bazel index 7fd3b12092..0ed3c04e0d 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/cycles/test/BUILD.bazel @@ -10,9 +10,8 @@ ts_library( ]), deps = [ "//packages:types", - "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/cycles", + "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/testing", "@ngdeps//typescript", ], diff --git a/packages/compiler-cli/src/ngtsc/cycles/test/analyzer_spec.ts b/packages/compiler-cli/src/ngtsc/cycles/test/analyzer_spec.ts new file mode 100644 index 0000000000..310deaf23f --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/cycles/test/analyzer_spec.ts @@ -0,0 +1,66 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ModuleResolver} from '../../imports'; +import {CycleAnalyzer} from '../src/analyzer'; +import {ImportGraph} from '../src/imports'; + +import {makeProgramFromGraph} from './util'; + +describe('cycle analyzer', () => { + it('should not detect a cycle when there isn\'t one', () => { + const {program, analyzer} = makeAnalyzer('a:b,c;b;c'); + const b = program.getSourceFile('b.ts') !; + const c = program.getSourceFile('c.ts') !; + expect(analyzer.wouldCreateCycle(b, c)).toBe(false); + expect(analyzer.wouldCreateCycle(c, b)).toBe(false); + }); + + it('should detect a simple cycle between two files', () => { + const {program, analyzer} = makeAnalyzer('a:b;b'); + const a = program.getSourceFile('a.ts') !; + const b = program.getSourceFile('b.ts') !; + expect(analyzer.wouldCreateCycle(a, b)).toBe(false); + expect(analyzer.wouldCreateCycle(b, a)).toBe(true); + }); + + it('should detect a cycle with a re-export in the chain', () => { + const {program, analyzer} = makeAnalyzer('a:*b;b:c;c'); + const a = program.getSourceFile('a.ts') !; + const c = program.getSourceFile('c.ts') !; + expect(analyzer.wouldCreateCycle(a, c)).toBe(false); + expect(analyzer.wouldCreateCycle(c, a)).toBe(true); + }); + + it('should detect a cycle in a more complex program', () => { + const {program, analyzer} = makeAnalyzer('a:*b,*c;b:*e,*f;c:*g,*h;e:f;f:c;g;h:g'); + const b = program.getSourceFile('b.ts') !; + const g = program.getSourceFile('g.ts') !; + expect(analyzer.wouldCreateCycle(b, g)).toBe(false); + expect(analyzer.wouldCreateCycle(g, b)).toBe(true); + }); + + it('should detect a cycle caused by a synthetic edge', () => { + const {program, analyzer} = makeAnalyzer('a:b,c;b;c'); + const b = program.getSourceFile('b.ts') !; + const c = program.getSourceFile('c.ts') !; + expect(analyzer.wouldCreateCycle(b, c)).toBe(false); + analyzer.recordSyntheticImport(c, b); + expect(analyzer.wouldCreateCycle(b, c)).toBe(true); + }); +}); + +function makeAnalyzer(graph: string): {program: ts.Program, analyzer: CycleAnalyzer} { + const {program, options, host} = makeProgramFromGraph(graph); + return { + program, + analyzer: new CycleAnalyzer(new ImportGraph(new ModuleResolver(program, options, host))), + }; +} diff --git a/packages/compiler-cli/src/ngtsc/cycles/test/imports_spec.ts b/packages/compiler-cli/src/ngtsc/cycles/test/imports_spec.ts new file mode 100644 index 0000000000..4dba9dd800 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/cycles/test/imports_spec.ts @@ -0,0 +1,63 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ModuleResolver} from '../../imports'; +import {ImportGraph} from '../src/imports'; + +import {makeProgramFromGraph} from './util'; + +describe('import graph', () => { + it('should record imports of a simple program', () => { + const {program, graph} = makeImportGraph('a:b;b:c;c'); + const a = program.getSourceFile('a.ts') !; + const b = program.getSourceFile('b.ts') !; + const c = program.getSourceFile('c.ts') !; + expect(importsToString(graph.importsOf(a))).toBe('b'); + expect(importsToString(graph.importsOf(b))).toBe('c'); + }); + + it('should calculate transitive imports of a simple program', () => { + const {program, graph} = makeImportGraph('a:b;b:c;c'); + const a = program.getSourceFile('a.ts') !; + const b = program.getSourceFile('b.ts') !; + const c = program.getSourceFile('c.ts') !; + expect(importsToString(graph.transitiveImportsOf(a))).toBe('a,b,c'); + }); + + it('should calculate transitive imports in a more complex program (with a cycle)', () => { + const {program, graph} = makeImportGraph('a:*b,*c;b:*e,*f;c:*g,*h;e:f;f;g:e;h:g'); + const c = program.getSourceFile('c.ts') !; + expect(importsToString(graph.transitiveImportsOf(c))).toBe('c,e,f,g,h'); + }); + + it('should reflect the addition of a synthetic import', () => { + const {program, graph} = makeImportGraph('a:b,c,d;b;c;d:b'); + const b = program.getSourceFile('b.ts') !; + const c = program.getSourceFile('c.ts') !; + const d = program.getSourceFile('d.ts') !; + expect(importsToString(graph.importsOf(b))).toEqual(''); + expect(importsToString(graph.transitiveImportsOf(d))).toEqual('b,d'); + graph.addSyntheticImport(b, c); + expect(importsToString(graph.importsOf(b))).toEqual('c'); + expect(importsToString(graph.transitiveImportsOf(d))).toEqual('b,c,d'); + }); +}); + +function makeImportGraph(graph: string): {program: ts.Program, graph: ImportGraph} { + const {program, options, host} = makeProgramFromGraph(graph); + return { + program, + graph: new ImportGraph(new ModuleResolver(program, options, host)), + }; +} + +function importsToString(imports: Set): string { + return Array.from(imports).map(sf => sf.fileName.substr(1).replace('.ts', '')).sort().join(','); +} diff --git a/packages/compiler-cli/src/ngtsc/cycles/test/util.ts b/packages/compiler-cli/src/ngtsc/cycles/test/util.ts new file mode 100644 index 0000000000..9c0dcc73c4 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/cycles/test/util.ts @@ -0,0 +1,58 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {makeProgram} from '../../testing/in_memory_typescript'; + +/** + * Construct a TS program consisting solely of an import graph, from a string-based representation + * of the graph. + * + * The `graph` string consists of semicolon separated files, where each file is specified + * as a name and (optionally) a list of comma-separated imports or exports. For example: + * + * "a:b,c;b;c" + * + * specifies a program with three files (a.ts, b.ts, c.ts) where a.ts imports from both b.ts and + * c.ts. + * + * A more complicated example has a dependency from b.ts to c.ts: "a:b,c;b:c;c". + * + * A * preceding a file name in the list of imports indicates that the dependency should be an + * "export" and not an "import" dependency. For example: + * + * "a:*b,c;b;c" + * + * represents a program where a.ts exports from b.ts and imports from c.ts. + */ +export function makeProgramFromGraph(graph: string): { + program: ts.Program, + host: ts.CompilerHost, + options: ts.CompilerOptions, +} { + const files = graph.split(';').map(fileSegment => { + const [name, importList] = fileSegment.split(':'); + const contents = (importList ? importList.split(',') : []) + .map(i => { + if (i.startsWith('*')) { + const sym = i.substr(1); + return `export {${sym}} from './${sym}';`; + } else { + return `import {${i}} from './${i}';`; + } + }) + .join('\n') + + `export const ${name} = '${name}';\n`; + return { + name: `${name}.ts`, + contents, + }; + }); + return makeProgram(files); +} diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/BUILD.bazel b/packages/compiler-cli/src/ngtsc/diagnostics/BUILD.bazel index 97838673bc..2b0efabac8 100644 --- a/packages/compiler-cli/src/ngtsc/diagnostics/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/diagnostics/BUILD.bazel @@ -8,7 +8,6 @@ ts_library( "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/diagnostics", deps = [ "//packages/compiler", "@ngdeps//typescript", diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/index.ts b/packages/compiler-cli/src/ngtsc/diagnostics/index.ts index c235c43985..48c91aad50 100644 --- a/packages/compiler-cli/src/ngtsc/diagnostics/index.ts +++ b/packages/compiler-cli/src/ngtsc/diagnostics/index.ts @@ -6,6 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -export {ErrorCode} from './src/code'; +export {ErrorCode, ngErrorCode} from './src/code'; export {FatalDiagnosticError, isFatalDiagnosticError} from './src/error'; export {replaceTsWithNgInErrors} from './src/util'; diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/src/code.ts b/packages/compiler-cli/src/ngtsc/diagnostics/src/code.ts index 679e7f6299..0ae49e9cd6 100644 --- a/packages/compiler-cli/src/ngtsc/diagnostics/src/code.ts +++ b/packages/compiler-cli/src/ngtsc/diagnostics/src/code.ts @@ -13,10 +13,30 @@ export enum ErrorCode { DECORATOR_ON_ANONYMOUS_CLASS = 1004, DECORATOR_UNEXPECTED = 1005, + /** + * This error code indicates that there are incompatible decorators on a type. + */ + DECORATOR_COLLISION = 1006, + VALUE_HAS_WRONG_TYPE = 1010, VALUE_NOT_LITERAL = 1011, COMPONENT_MISSING_TEMPLATE = 2001, PIPE_MISSING_NAME = 2002, PARAM_MISSING_TOKEN = 2003, + + SYMBOL_NOT_EXPORTED = 3001, + SYMBOL_EXPORTED_UNDER_DIFFERENT_NAME = 3002, + + CONFIG_FLAT_MODULE_NO_INDEX = 4001, + + /** + * Raised when a host expression has a parse error, such as a host listener or host binding + * expression containing a pipe. + */ + HOST_BINDING_PARSE_ERROR = 5001, +} + +export function ngErrorCode(code: ErrorCode): number { + return parseInt('-99' + code); } diff --git a/packages/compiler-cli/src/ngtsc/entry_point/BUILD.bazel b/packages/compiler-cli/src/ngtsc/entry_point/BUILD.bazel new file mode 100644 index 0000000000..c0c7c991bf --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/BUILD.bazel @@ -0,0 +1,19 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "entry_point", + srcs = glob([ + "index.ts", + "src/**/*.ts", + ]), + module_name = "@angular/compiler-cli/src/ngtsc/entry_point", + deps = [ + "//packages/compiler-cli/src/ngtsc/diagnostics", + "//packages/compiler-cli/src/ngtsc/shims", + "//packages/compiler-cli/src/ngtsc/util", + "@ngdeps//@types/node", + "@ngdeps//typescript", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/entry_point/index.ts b/packages/compiler-cli/src/ngtsc/entry_point/index.ts new file mode 100644 index 0000000000..fa4acebeac --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export {FlatIndexGenerator} from './src/generator'; +export {findFlatIndexEntryPoint} from './src/logic'; +export {checkForPrivateExports} from './src/private_export_checker'; +export {ReferenceGraph} from './src/reference_graph'; diff --git a/packages/compiler-cli/src/ngtsc/entry_point/src/generator.ts b/packages/compiler-cli/src/ngtsc/entry_point/src/generator.ts new file mode 100644 index 0000000000..ef1eaa614a --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/src/generator.ts @@ -0,0 +1,45 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/// + +import * as path from 'path'; +import * as ts from 'typescript'; + +import {ShimGenerator} from '../../shims'; +import {relativePathBetween} from '../../util/src/path'; + +export class FlatIndexGenerator implements ShimGenerator { + readonly flatIndexPath: string; + + constructor( + readonly entryPoint: string, relativeFlatIndexPath: string, + readonly moduleName: string|null) { + this.flatIndexPath = path.posix.join(path.posix.dirname(entryPoint), relativeFlatIndexPath) + .replace(/\.js$/, '') + + '.ts'; + } + + recognize(fileName: string): boolean { return fileName === this.flatIndexPath; } + + generate(): ts.SourceFile { + const relativeEntryPoint = relativePathBetween(this.flatIndexPath, this.entryPoint); + const contents = `/** + * Generated bundle index. Do not edit. + */ + +export * from '${relativeEntryPoint}'; +`; + const genFile = ts.createSourceFile( + this.flatIndexPath, contents, ts.ScriptTarget.ES2015, true, ts.ScriptKind.TS); + if (this.moduleName !== null) { + genFile.moduleName = this.moduleName; + } + return genFile; + } +} diff --git a/packages/compiler-cli/src/ngtsc/entry_point/src/logic.ts b/packages/compiler-cli/src/ngtsc/entry_point/src/logic.ts new file mode 100644 index 0000000000..5bfa55d56b --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/src/logic.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {normalizeSeparators} from '../../util/src/path'; +import {isNonDeclarationTsPath} from '../../util/src/typescript'; + +export function findFlatIndexEntryPoint(rootFiles: ReadonlyArray): string|null { + // There are two ways for a file to be recognized as the flat module index: + // 1) if it's the only file!!!!!! + // 2) (deprecated) if it's named 'index.ts' and has the shortest path of all such files. + const tsFiles = rootFiles.filter(file => isNonDeclarationTsPath(file)); + let resolvedEntryPoint: string|null = null; + + if (tsFiles.length === 1) { + // There's only one file - this is the flat module index. + resolvedEntryPoint = tsFiles[0]; + } else { + // In the event there's more than one TS file, one of them can still be selected as the + // flat module index if it's named 'index.ts'. If there's more than one 'index.ts', the one + // with the shortest path wins. + // + // This behavior is DEPRECATED and only exists to support existing usages. + for (const tsFile of tsFiles) { + if (tsFile.endsWith('/index.ts') && + (resolvedEntryPoint === null || tsFile.length <= resolvedEntryPoint.length)) { + resolvedEntryPoint = tsFile; + } + } + } + + return resolvedEntryPoint ? normalizeSeparators(resolvedEntryPoint) : null; +} diff --git a/packages/compiler-cli/src/ngtsc/entry_point/src/private_export_checker.ts b/packages/compiler-cli/src/ngtsc/entry_point/src/private_export_checker.ts new file mode 100644 index 0000000000..06e04d4cd5 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/src/private_export_checker.ts @@ -0,0 +1,147 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ErrorCode, ngErrorCode} from '../../diagnostics'; + +import {ReferenceGraph} from './reference_graph'; + +/** + * Produce `ts.Diagnostic`s for classes that are visible from exported types (e.g. directives + * exposed by exported `NgModule`s) that are not themselves exported. + * + * This function reconciles two concepts: + * + * A class is Exported if it's exported from the main library `entryPoint` file. + * A class is Visible if, via Angular semantics, a downstream consumer can import an Exported class + * and be affected by the class in question. For example, an Exported NgModule may expose a + * directive class to its consumers. Consumers that import the NgModule may have the directive + * applied to elements in their templates. In this case, the directive is considered Visible. + * + * `checkForPrivateExports` attempts to verify that all Visible classes are Exported, and report + * `ts.Diagnostic`s for those that aren't. + * + * @param entryPoint `ts.SourceFile` of the library's entrypoint, which should export the library's + * public API. + * @param checker `ts.TypeChecker` for the current program. + * @param refGraph `ReferenceGraph` tracking the visibility of Angular types. + * @returns an array of `ts.Diagnostic`s representing errors when visible classes are not exported + * properly. + */ +export function checkForPrivateExports( + entryPoint: ts.SourceFile, checker: ts.TypeChecker, refGraph: ReferenceGraph): ts.Diagnostic[] { + const diagnostics: ts.Diagnostic[] = []; + + // Firstly, compute the exports of the entry point. These are all the Exported classes. + const topLevelExports = new Set(); + + // Do this via `ts.TypeChecker.getExportsOfModule`. + const moduleSymbol = checker.getSymbolAtLocation(entryPoint); + if (moduleSymbol === undefined) { + throw new Error(`Internal error: failed to get symbol for entrypoint`); + } + const exportedSymbols = checker.getExportsOfModule(moduleSymbol); + + // Loop through the exported symbols, de-alias if needed, and add them to `topLevelExports`. + // TODO(alxhub): use proper iteration when build.sh is removed. (#27762) + exportedSymbols.forEach(symbol => { + if (symbol.flags & ts.SymbolFlags.Alias) { + symbol = checker.getAliasedSymbol(symbol); + } + const decl = symbol.valueDeclaration; + if (decl !== undefined) { + topLevelExports.add(decl); + } + }); + + // Next, go through each exported class and expand it to the set of classes it makes Visible, + // using the `ReferenceGraph`. For each Visible class, verify that it's also Exported, and queue + // an error if it isn't. `checkedSet` ensures only one error is queued per class. + const checkedSet = new Set(); + + // Loop through each Exported class. + // TODO(alxhub): use proper iteration when the legacy build is removed. (#27762) + topLevelExports.forEach(mainExport => { + // Loop through each class made Visible by the Exported class. + refGraph.transitiveReferencesOf(mainExport).forEach(transitiveReference => { + // Skip classes which have already been checked. + if (checkedSet.has(transitiveReference)) { + return; + } + checkedSet.add(transitiveReference); + + // Verify that the Visible class is also Exported. + if (!topLevelExports.has(transitiveReference)) { + // This is an error, `mainExport` makes `transitiveReference` Visible, but + // `transitiveReference` is not Exported from the entrypoint. Construct a diagnostic to + // give to the user explaining the situation. + + const descriptor = getDescriptorOfDeclaration(transitiveReference); + const name = getNameOfDeclaration(transitiveReference); + + // Construct the path of visibility, from `mainExport` to `transitiveReference`. + let visibleVia = 'NgModule exports'; + const transitivePath = refGraph.pathFrom(mainExport, transitiveReference); + if (transitivePath !== null) { + visibleVia = transitivePath.map(seg => getNameOfDeclaration(seg)).join(' -> '); + } + + const diagnostic: ts.Diagnostic = { + category: ts.DiagnosticCategory.Error, + code: ngErrorCode(ErrorCode.SYMBOL_NOT_EXPORTED), + file: transitiveReference.getSourceFile(), ...getPosOfDeclaration(transitiveReference), + messageText: + `Unsupported private ${descriptor} ${name}. This ${descriptor} is visible to consumers via ${visibleVia}, but is not exported from the top-level library entrypoint.`, + }; + + diagnostics.push(diagnostic); + } + }); + }); + + return diagnostics; +} + +function getPosOfDeclaration(decl: ts.Declaration): {start: number, length: number} { + const node: ts.Node = getIdentifierOfDeclaration(decl) || decl; + return { + start: node.getStart(), + length: node.getEnd() + 1 - node.getStart(), + }; +} + +function getIdentifierOfDeclaration(decl: ts.Declaration): ts.Identifier|null { + if ((ts.isClassDeclaration(decl) || ts.isVariableDeclaration(decl) || + ts.isFunctionDeclaration(decl)) && + decl.name !== undefined && ts.isIdentifier(decl.name)) { + return decl.name; + } else { + return null; + } +} + +function getNameOfDeclaration(decl: ts.Declaration): string { + const id = getIdentifierOfDeclaration(decl); + return id !== null ? id.text : '(unnamed)'; +} + +function getDescriptorOfDeclaration(decl: ts.Declaration): string { + switch (decl.kind) { + case ts.SyntaxKind.ClassDeclaration: + return 'class'; + case ts.SyntaxKind.FunctionDeclaration: + return 'function'; + case ts.SyntaxKind.VariableDeclaration: + return 'variable'; + case ts.SyntaxKind.EnumDeclaration: + return 'enum'; + default: + return 'declaration'; + } +} diff --git a/packages/compiler-cli/src/ngtsc/entry_point/src/reference_graph.ts b/packages/compiler-cli/src/ngtsc/entry_point/src/reference_graph.ts new file mode 100644 index 0000000000..396e90c5e9 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/src/reference_graph.ts @@ -0,0 +1,78 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +export class ReferenceGraph { + private references = new Map>(); + + add(from: T, to: T): void { + if (!this.references.has(from)) { + this.references.set(from, new Set()); + } + this.references.get(from) !.add(to); + } + + transitiveReferencesOf(target: T): Set { + const set = new Set(); + this.collectTransitiveReferences(set, target); + return set; + } + + pathFrom(source: T, target: T): T[]|null { + return this.collectPathFrom(source, target, new Set()); + } + + private collectPathFrom(source: T, target: T, seen: Set): T[]|null { + if (source === target) { + // Looking for a path from the target to itself - that path is just the target. This is the + // "base case" of the search. + return [target]; + } else if (seen.has(source)) { + // The search has already looked through this source before. + return null; + } + // Consider outgoing edges from `source`. + seen.add(source); + + if (!this.references.has(source)) { + // There are no outgoing edges from `source`. + return null; + } else { + // Look through the outgoing edges of `source`. + // TODO(alxhub): use proper iteration when the legacy build is removed. (#27762) + let candidatePath: T[]|null = null; + this.references.get(source) !.forEach(edge => { + // Early exit if a path has already been found. + if (candidatePath !== null) { + return; + } + // Look for a path from this outgoing edge to `target`. + const partialPath = this.collectPathFrom(edge, target, seen); + if (partialPath !== null) { + // A path exists from `edge` to `target`. Insert `source` at the beginning. + candidatePath = [source, ...partialPath]; + } + }); + + return candidatePath; + } + } + + private collectTransitiveReferences(set: Set, decl: T): void { + if (this.references.has(decl)) { + // TODO(alxhub): use proper iteration when the legacy build is removed. (#27762) + this.references.get(decl) !.forEach(ref => { + if (!set.has(ref)) { + set.add(ref); + this.collectTransitiveReferences(set, ref); + } + }); + } + } +} diff --git a/packages/compiler-cli/src/ngtsc/entry_point/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/entry_point/test/BUILD.bazel new file mode 100644 index 0000000000..e149fa0f33 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/test/BUILD.bazel @@ -0,0 +1,25 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob([ + "**/*.ts", + ]), + deps = [ + "//packages:types", + "//packages/compiler-cli/src/ngtsc/entry_point", + "@ngdeps//typescript", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + deps = [ + ":test_lib", + "//tools/testing:node_no_angular", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/entry_point/test/entry_point_spec.ts b/packages/compiler-cli/src/ngtsc/entry_point/test/entry_point_spec.ts new file mode 100644 index 0000000000..0c2931fd19 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/test/entry_point_spec.ts @@ -0,0 +1,28 @@ + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {findFlatIndexEntryPoint} from '../src/logic'; + +describe('entry_point logic', () => { + + describe('findFlatIndexEntryPoint', () => { + + it('should use the only source file if only a single one is specified', + () => { expect(findFlatIndexEntryPoint(['/src/index.ts'])).toBe('/src/index.ts'); }); + + it('should use the shortest source file ending with "index.ts" for multiple files', () => { + expect(findFlatIndexEntryPoint([ + '/src/deep/index.ts', '/src/index.ts', '/index.ts' + ])).toBe('/index.ts'); + }); + + it('should normalize the path separators for the found entry point', + () => { expect(findFlatIndexEntryPoint(['\\src\\index.ts'])).toBe('/src/index.ts'); }); + }); +}); diff --git a/packages/compiler-cli/src/ngtsc/entry_point/test/reference_graph_spec.ts b/packages/compiler-cli/src/ngtsc/entry_point/test/reference_graph_spec.ts new file mode 100644 index 0000000000..78be9e7e6b --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/entry_point/test/reference_graph_spec.ts @@ -0,0 +1,50 @@ + +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ReferenceGraph} from '../src/reference_graph'; + +describe('entry_point reference graph', () => { + let graph: ReferenceGraph; + + const refs = + (target: string) => { return Array.from(graph.transitiveReferencesOf(target)).sort(); }; + + beforeEach(() => { + graph = new ReferenceGraph(); + graph.add('origin', 'alpha'); + graph.add('alpha', 'beta'); + graph.add('beta', 'gamma'); + }); + + it('should track a simple chain of references', () => { + // origin -> alpha -> beta -> gamma + expect(refs('origin')).toEqual(['alpha', 'beta', 'gamma']); + expect(refs('beta')).toEqual(['gamma']); + }); + + it('should not crash on a cycle', () => { + // origin -> alpha -> beta -> gamma + // ^---------------/ + graph.add('beta', 'origin'); + expect(refs('origin')).toEqual(['alpha', 'beta', 'gamma', 'origin']); + }); + + it('should report a path between two nodes in the graph', () => { + // ,------------------------\ + // origin -> alpha -> beta -> gamma -> delta + // \----------------^ + graph.add('beta', 'delta'); + graph.add('delta', 'alpha'); + expect(graph.pathFrom('origin', 'gamma')).toEqual(['origin', 'alpha', 'beta', 'gamma']); + expect(graph.pathFrom('beta', 'alpha')).toEqual(['beta', 'delta', 'alpha']); + }); + + it('should not report a path that doesn\'t exist', + () => { expect(graph.pathFrom('gamma', 'beta')).toBeNull(); }); +}); diff --git a/packages/compiler-cli/src/ngtsc/metadata/BUILD.bazel b/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel similarity index 73% rename from packages/compiler-cli/src/ngtsc/metadata/BUILD.bazel rename to packages/compiler-cli/src/ngtsc/imports/BUILD.bazel index 530adc1b09..6f8cb487a9 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel @@ -3,16 +3,15 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "ts_library") ts_library( - name = "metadata", + name = "imports", srcs = glob([ "index.ts", "src/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/metadata", deps = [ "//packages:types", "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", + "//packages/compiler-cli/src/ngtsc/path", "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//@types/node", "@ngdeps//typescript", diff --git a/packages/compiler-cli/src/ngtsc/imports/index.ts b/packages/compiler-cli/src/ngtsc/imports/index.ts new file mode 100644 index 0000000000..50af9d405d --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core'; +export {AbsoluteModuleStrategy, FileToModuleHost, FileToModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter} from './src/emitter'; +export {ImportMode, OwningModule, Reference} from './src/references'; +export {ModuleResolver} from './src/resolver'; diff --git a/packages/compiler-cli/src/ngtsc/imports/src/core.ts b/packages/compiler-cli/src/ngtsc/imports/src/core.ts new file mode 100644 index 0000000000..803fae9121 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/src/core.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {relativePathBetween} from '../../util/src/path'; + +/** + * Rewrites imports of symbols being written into generated code. + */ +export interface ImportRewriter { + /** + * Should the given symbol be imported at all? + * + * If `true`, the symbol should be imported from the given specifier. If `false`, the symbol + * should be referenced directly, without an import. + */ + shouldImportSymbol(symbol: string, specifier: string): boolean; + + /** + * Optionally rewrite a reference to an imported symbol, changing either the binding prefix or the + * symbol name itself. + */ + rewriteSymbol(symbol: string, specifier: string): string; + + /** + * Optionally rewrite the given module specifier in the context of a given file. + */ + rewriteSpecifier(specifier: string, inContextOfFile: string): string; +} + +/** + * `ImportRewriter` that does no rewriting. + */ +export class NoopImportRewriter implements ImportRewriter { + shouldImportSymbol(symbol: string, specifier: string): boolean { return true; } + + rewriteSymbol(symbol: string, specifier: string): string { return symbol; } + + rewriteSpecifier(specifier: string, inContextOfFile: string): string { return specifier; } +} + +/** + * A mapping of supported symbols that can be imported from within @angular/core, and the names by + * which they're exported from r3_symbols. + */ +const CORE_SUPPORTED_SYMBOLS = new Map([ + ['defineInjectable', 'defineInjectable'], + ['defineInjector', 'defineInjector'], + ['ɵdefineNgModule', 'defineNgModule'], + ['inject', 'inject'], + ['ɵsetClassMetadata', 'setClassMetadata'], + ['ɵInjectableDef', 'InjectableDef'], + ['ɵInjectorDef', 'InjectorDef'], + ['ɵNgModuleDefWithMeta', 'NgModuleDefWithMeta'], + ['ɵNgModuleFactory', 'NgModuleFactory'], +]); + +const CORE_MODULE = '@angular/core'; + +/** + * `ImportRewriter` that rewrites imports from '@angular/core' to be imported from the r3_symbols.ts + * file instead. + */ +export class R3SymbolsImportRewriter implements ImportRewriter { + constructor(private r3SymbolsPath: string) {} + + shouldImportSymbol(symbol: string, specifier: string): boolean { return true; } + + rewriteSymbol(symbol: string, specifier: string): string { + if (specifier !== CORE_MODULE) { + // This import isn't from core, so ignore it. + return symbol; + } + + return validateAndRewriteCoreSymbol(symbol); + } + + rewriteSpecifier(specifier: string, inContextOfFile: string): string { + if (specifier !== CORE_MODULE) { + // This module isn't core, so ignore it. + return specifier; + } + + const relativePathToR3Symbols = relativePathBetween(inContextOfFile, this.r3SymbolsPath); + if (relativePathToR3Symbols === null) { + throw new Error( + `Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${this.r3SymbolsPath}`); + } + + return relativePathToR3Symbols; + } +} + +export function validateAndRewriteCoreSymbol(name: string): string { + if (!CORE_SUPPORTED_SYMBOLS.has(name)) { + throw new Error(`Importing unexpected symbol ${name} while compiling ${CORE_MODULE}`); + } + return CORE_SUPPORTED_SYMBOLS.get(name) !; +} diff --git a/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts new file mode 100644 index 0000000000..c52d5a4d39 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts @@ -0,0 +1,271 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Expression, ExternalExpr, WrappedNodeExpr} from '@angular/compiler'; +import {ExternalReference} from '@angular/compiler/src/compiler'; +import * as ts from 'typescript'; + +import {LogicalFileSystem, LogicalProjectPath} from '../../path'; +import {getSourceFile, isDeclaration, nodeNameForError} from '../../util/src/typescript'; + +import {findExportedNameOfNode} from './find_export'; +import {ImportMode, Reference} from './references'; + +/** + * A host which supports an operation to convert a file name into a module name. + * + * This operation is typically implemented as part of the compiler host passed to ngtsc when running + * under a build tool like Bazel or Blaze. + */ +export interface FileToModuleHost { + fileNameToModuleName(importedFilePath: string, containingFilePath: string): string; +} + +/** + * A particular strategy for generating an expression which refers to a `Reference`. + * + * There are many potential ways a given `Reference` could be referred to in the context of a given + * file. A local declaration could be available, the `Reference` could be importable via a relative + * import within the project, or an absolute import into `node_modules` might be necessary. + * + * Different `ReferenceEmitStrategy` implementations implement specific logic for generating such + * references. A single strategy (such as using a local declaration) may not always be able to + * generate an expression for every `Reference` (for example, if no local identifier is available), + * and may return `null` in such a case. + */ +export interface ReferenceEmitStrategy { + /** + * Emit an `Expression` which refers to the given `Reference` in the context of a particular + * source file, if possible. + * + * @param ref the `Reference` for which to generate an expression + * @param context the source file in which the `Expression` must be valid + * @param importMode a flag which controls whether imports should be generated or not + * @returns an `Expression` which refers to the `Reference`, or `null` if none can be generated + */ + emit(ref: Reference, context: ts.SourceFile, importMode: ImportMode): Expression|null; +} + +/** + * Generates `Expression`s which refer to `Reference`s in a given context. + * + * A `ReferenceEmitter` uses one or more `ReferenceEmitStrategy` implementations to produce a + * an `Expression` which refers to a `Reference` in the context of a particular file. + */ +export class ReferenceEmitter { + constructor(private strategies: ReferenceEmitStrategy[]) {} + + emit( + ref: Reference, context: ts.SourceFile, + importMode: ImportMode = ImportMode.UseExistingImport): Expression { + for (const strategy of this.strategies) { + const emitted = strategy.emit(ref, context, importMode); + if (emitted !== null) { + return emitted; + } + } + throw new Error( + `Unable to write a reference to ${nodeNameForError(ref.node)} in ${ref.node.getSourceFile().fileName} from ${context.fileName}`); + } +} + +/** + * A `ReferenceEmitStrategy` which will refer to declarations by any local `ts.Identifier`s, if + * such identifiers are available. + */ +export class LocalIdentifierStrategy implements ReferenceEmitStrategy { + emit(ref: Reference, context: ts.SourceFile, importMode: ImportMode): Expression|null { + // If the emitter has specified ForceNewImport, then LocalIdentifierStrategy should not use a + // local identifier at all, *except* in the source file where the node is actually declared. + if (importMode === ImportMode.ForceNewImport && + getSourceFile(ref.node) !== getSourceFile(context)) { + return null; + } + + // A Reference can have multiple identities in different files, so it may already have an + // Identifier in the requested context file. + const identifier = ref.getIdentityIn(context); + if (identifier !== null) { + return new WrappedNodeExpr(identifier); + } else { + return null; + } + } +} + +/** + * A `ReferenceEmitStrategy` which will refer to declarations that come from `node_modules` using + * an absolute import. + * + * Part of this strategy involves looking at the target entry point and identifying the exported + * name of the targeted declaration, as it might be different from the declared name (e.g. a + * directive might be declared as FooDirImpl, but exported as FooDir). If no export can be found + * which maps back to the original directive, an error is thrown. + */ +export class AbsoluteModuleStrategy implements ReferenceEmitStrategy { + /** + * A cache of the exports of specific modules, because resolving a module to its exports is a + * costly operation. + */ + private moduleExportsCache = new Map|null>(); + + constructor( + private program: ts.Program, private checker: ts.TypeChecker, + private options: ts.CompilerOptions, private host: ts.CompilerHost) {} + + emit(ref: Reference, context: ts.SourceFile, importMode: ImportMode): Expression|null { + if (ref.bestGuessOwningModule === null) { + // There is no module name available for this Reference, meaning it was arrived at via a + // relative path. + return null; + } else if (!isDeclaration(ref.node)) { + // It's not possible to import something which isn't a declaration. + throw new Error('Debug assert: importing a Reference to non-declaration?'); + } + + // Try to find the exported name of the declaration, if one is available. + const {specifier, resolutionContext} = ref.bestGuessOwningModule; + const symbolName = this.resolveImportName(specifier, ref.node, resolutionContext); + if (symbolName === null) { + // TODO(alxhub): make this error a ts.Diagnostic pointing at whatever caused this import to be + // triggered. + throw new Error( + `Symbol ${ref.debugName} declared in ${getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${context.fileName})`); + } + + return new ExternalExpr(new ExternalReference(specifier, symbolName)); + } + + private resolveImportName(moduleName: string, target: ts.Declaration, fromFile: string): string + |null { + const exports = this.getExportsOfModule(moduleName, fromFile); + if (exports !== null && exports.has(target)) { + return exports.get(target) !; + } else { + return null; + } + } + + private getExportsOfModule(moduleName: string, fromFile: string): + Map|null { + if (!this.moduleExportsCache.has(moduleName)) { + this.moduleExportsCache.set(moduleName, this.enumerateExportsOfModule(moduleName, fromFile)); + } + return this.moduleExportsCache.get(moduleName) !; + } + + private enumerateExportsOfModule(specifier: string, fromFile: string): + Map|null { + // First, resolve the module specifier to its entry point, and get the ts.Symbol for it. + const resolved = ts.resolveModuleName(specifier, fromFile, this.options, this.host); + if (resolved.resolvedModule === undefined) { + return null; + } + + const entryPointFile = this.program.getSourceFile(resolved.resolvedModule.resolvedFileName); + if (entryPointFile === undefined) { + return null; + } + + const entryPointSymbol = this.checker.getSymbolAtLocation(entryPointFile); + if (entryPointSymbol === undefined) { + return null; + } + + // Next, build a Map of all the ts.Declarations exported via the specifier and their exported + // names. + const exportMap = new Map(); + + const exports = this.checker.getExportsOfModule(entryPointSymbol); + for (const expSymbol of exports) { + // Resolve export symbols to their actual declarations. + const declSymbol = expSymbol.flags & ts.SymbolFlags.Alias ? + this.checker.getAliasedSymbol(expSymbol) : + expSymbol; + + // At this point the valueDeclaration of the symbol should be defined. + const decl = declSymbol.valueDeclaration; + if (decl === undefined) { + continue; + } + + // Prefer importing the symbol via its declared name, but take any export of it otherwise. + if (declSymbol.name === expSymbol.name || !exportMap.has(decl)) { + exportMap.set(decl, expSymbol.name); + } + } + + return exportMap; + } +} + +/** + * A `ReferenceEmitStrategy` which will refer to declarations via relative paths, provided they're + * both in the logical project "space" of paths. + * + * This is trickier than it sounds, as the two files may be in different root directories in the + * project. Simply calculating a file system relative path between the two is not sufficient. + * Instead, `LogicalProjectPath`s are used. + */ +export class LogicalProjectStrategy implements ReferenceEmitStrategy { + constructor(private checker: ts.TypeChecker, private logicalFs: LogicalFileSystem) {} + + emit(ref: Reference, context: ts.SourceFile): Expression|null { + const destSf = getSourceFile(ref.node); + + // Compute the relative path from the importing file to the file being imported. This is done + // as a logical path computation, because the two files might be in different rootDirs. + const destPath = this.logicalFs.logicalPathOfSf(destSf); + if (destPath === null) { + // The imported file is not within the logical project filesystem. + return null; + } + + const originPath = this.logicalFs.logicalPathOfSf(context); + if (originPath === null) { + throw new Error( + `Debug assert: attempt to import from ${context.fileName} but it's outside the program?`); + } + + // There's no way to emit a relative reference from a file to itself. + if (destPath === originPath) { + return null; + } + + const name = findExportedNameOfNode(ref.node, destSf, this.checker); + if (name === null) { + // The target declaration isn't exported from the file it's declared in. This is an issue! + return null; + } + + // With both files expressed as LogicalProjectPaths, getting the module specifier as a relative + // path is now straightforward. + const moduleName = LogicalProjectPath.relativePathBetween(originPath, destPath); + return new ExternalExpr({moduleName, name}); + } +} + +/** + * A `ReferenceEmitStrategy` which uses a `FileToModuleHost` to generate absolute import references. + */ +export class FileToModuleStrategy implements ReferenceEmitStrategy { + constructor(private checker: ts.TypeChecker, private fileToModuleHost: FileToModuleHost) {} + + emit(ref: Reference, context: ts.SourceFile): Expression|null { + const destSf = getSourceFile(ref.node); + const name = findExportedNameOfNode(ref.node, destSf, this.checker); + if (name === null) { + return null; + } + + const moduleName = + this.fileToModuleHost.fileNameToModuleName(destSf.fileName, context.fileName); + + return new ExternalExpr({moduleName, name}); + } +} diff --git a/packages/compiler-cli/src/ngtsc/imports/src/find_export.ts b/packages/compiler-cli/src/ngtsc/imports/src/find_export.ts new file mode 100644 index 0000000000..71a4d45d35 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/src/find_export.ts @@ -0,0 +1,47 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +/** + * Find the name, if any, by which a node is exported from a given file. + */ +export function findExportedNameOfNode( + target: ts.Node, file: ts.SourceFile, checker: ts.TypeChecker): string|null { + // First, get the exports of the file. + const symbol = checker.getSymbolAtLocation(file); + if (symbol === undefined) { + return null; + } + const exports = checker.getExportsOfModule(symbol); + + // Look for the export which declares the node. + const found = exports.find(sym => symbolDeclaresNode(sym, target, checker)); + if (found === undefined) { + throw new Error(`failed to find target in ${file.fileName}`); + } + return found !== undefined ? found.name : null; +} + +/** + * Check whether a given `ts.Symbol` represents a declaration of a given node. + * + * This is not quite as trivial as just checking the declarations, as some nodes are + * `ts.ExportSpecifier`s and need to be unwrapped. + */ +function symbolDeclaresNode(sym: ts.Symbol, node: ts.Node, checker: ts.TypeChecker): boolean { + return sym.declarations.some(decl => { + if (ts.isExportSpecifier(decl)) { + const exportedSymbol = checker.getExportSpecifierLocalTargetSymbol(decl); + if (exportedSymbol !== undefined) { + return symbolDeclaresNode(exportedSymbol, node, checker); + } + } + return decl === node; + }); +} diff --git a/packages/compiler-cli/src/ngtsc/imports/src/references.ts b/packages/compiler-cli/src/ngtsc/imports/src/references.ts new file mode 100644 index 0000000000..348f77fb32 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/src/references.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {identifierOfNode} from '../../util/src/typescript'; + +export enum ImportMode { + UseExistingImport, + ForceNewImport, +} + +export interface OwningModule { + specifier: string; + resolutionContext: string; +} + +/** + * A `ts.Node` plus the context in which it was discovered. + * + * A `Reference` is a pointer to a `ts.Node` that was extracted from the program somehow. It + * contains not only the node itself, but the information regarding how the node was located. In + * particular, it might track different identifiers by which the node is exposed, as well as + * potentially a module specifier which might expose the node. + * + * The Angular compiler uses `Reference`s instead of `ts.Node`s when tracking classes or generating + * imports. + */ +export class Reference { + /** + * The compiler's best guess at an absolute module specifier which owns this `Reference`. + * + * This is usually determined by tracking the import statements which led the compiler to a given + * node. If any of these imports are absolute, it's an indication that the node being imported + * might come from that module. + * + * It is not _guaranteed_ that the node in question is exported from its `bestGuessOwningModule` - + * that is mostly a convention that applies in certain package formats. + * + * If `bestGuessOwningModule` is `null`, then it's likely the node came from the current program. + */ + readonly bestGuessOwningModule: OwningModule|null; + + private identifiers: ts.Identifier[] = []; + + constructor(readonly node: T, bestGuessOwningModule: OwningModule|null = null) { + this.bestGuessOwningModule = bestGuessOwningModule; + + const id = identifierOfNode(node); + if (id !== null) { + this.identifiers.push(id); + } + } + + /** + * The best guess at which module specifier owns this particular reference, or `null` if there + * isn't one. + */ + get ownedByModuleGuess(): string|null { + if (this.bestGuessOwningModule !== null) { + return this.bestGuessOwningModule.specifier; + } else { + return null; + } + } + + /** + * Whether this reference has a potential owning module or not. + * + * See `bestGuessOwningModule`. + */ + get hasOwningModuleGuess(): boolean { return this.bestGuessOwningModule !== null; } + + /** + * A name for the node, if one is available. + * + * This is only suited for debugging. Any actual references to this node should be made with + * `ts.Identifier`s (see `getIdentityIn`). + */ + get debugName(): string|null { + const id = identifierOfNode(this.node); + return id !== null ? id.text : null; + } + + /** + * Record a `ts.Identifier` by which it's valid to refer to this node, within the context of this + * `Reference`. + */ + addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); } + + /** + * Get a `ts.Identifier` within this `Reference` that can be used to refer within the context of a + * given `ts.SourceFile`, if any. + */ + getIdentityIn(context: ts.SourceFile): ts.Identifier|null { + return this.identifiers.find(id => id.getSourceFile() === context) || null; + } +} diff --git a/packages/compiler-cli/src/ngtsc/imports/src/resolver.ts b/packages/compiler-cli/src/ngtsc/imports/src/resolver.ts new file mode 100644 index 0000000000..6fd244555a --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/imports/src/resolver.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {Reference} from './references'; + +export interface ReferenceResolver { + resolve(decl: ts.Declaration, importFromHint: string|null, fromFile: string): + Reference; +} + +/** + * Used by `RouterEntryPointManager` and `NgModuleRouteAnalyzer` (which is in turn is used by + * `NgModuleDecoratorHandler`) for resolving the module source-files references in lazy-loaded + * routes (relative to the source-file containing the `NgModule` that provides the route + * definitions). + */ +export class ModuleResolver { + constructor( + private program: ts.Program, private compilerOptions: ts.CompilerOptions, + private host: ts.CompilerHost) {} + + resolveModuleName(module: string, containingFile: ts.SourceFile): ts.SourceFile|null { + const resolved = + ts.resolveModuleName(module, containingFile.fileName, this.compilerOptions, this.host) + .resolvedModule; + if (resolved === undefined) { + return null; + } + return this.program.getSourceFile(resolved.resolvedFileName) || null; + } +} diff --git a/packages/compiler-cli/src/ngtsc/metadata/index.ts b/packages/compiler-cli/src/ngtsc/metadata/index.ts deleted file mode 100644 index 8e8e7c852c..0000000000 --- a/packages/compiler-cli/src/ngtsc/metadata/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/// - -export {TypeScriptReflectionHost, filterToMembersWithDecorator, findMember, reflectObjectLiteral, reflectTypeEntityToDeclaration, typeNodeToValueExpr} from './src/reflector'; -export {AbsoluteReference, EnumValue, ImportMode, Reference, ResolvedReference, ResolvedValue, isDynamicValue, staticallyResolve} from './src/resolver'; diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/BUILD.bazel b/packages/compiler-cli/src/ngtsc/partial_evaluator/BUILD.bazel new file mode 100644 index 0000000000..95c2478682 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/BUILD.bazel @@ -0,0 +1,21 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "partial_evaluator", + srcs = glob([ + "index.ts", + "src/*.ts", + ]), + module_name = "@angular/compiler-cli/src/ngtsc/partial_evaluator", + deps = [ + "//packages:types", + "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/reflection", + "//packages/compiler-cli/src/ngtsc/util", + "@ngdeps//@types/node", + "@ngdeps//typescript", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/index.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/index.ts new file mode 100644 index 0000000000..f8465eba4e --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/index.ts @@ -0,0 +1,11 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export {DynamicValue} from './src/dynamic'; +export {ForeignFunctionResolver, PartialEvaluator} from './src/interface'; +export {BuiltinFn, EnumValue, ResolvedValue, ResolvedValueArray, ResolvedValueMap} from './src/result'; diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts new file mode 100644 index 0000000000..51373de9ba --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {DynamicValue} from './dynamic'; +import {BuiltinFn, ResolvedValue, ResolvedValueArray} from './result'; + +export class ArraySliceBuiltinFn extends BuiltinFn { + constructor(private node: ts.Node, private lhs: ResolvedValueArray) { super(); } + + evaluate(args: ResolvedValueArray): ResolvedValue { + if (args.length === 0) { + return this.lhs; + } else { + return DynamicValue.fromUnknown(this.node); + } + } +} diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts new file mode 100644 index 0000000000..ddcaf246b2 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts @@ -0,0 +1,110 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {Reference} from '../../imports'; + +/** + * The reason why a value cannot be determined statically. + */ +export const enum DynamicValueReason { + /** + * A value could not be determined statically, because it contains a term that could not be + * determined statically. + * (E.g. a property assignment or call expression where the lhs is a `DynamicValue`, a template + * literal with a dynamic expression, an object literal with a spread assignment which could not + * be determined statically, etc.) + */ + DYNAMIC_INPUT, + + /** + * A string could not be statically evaluated. + * (E.g. a dynamically constructed object property name or a template literal expression that + * could not be statically resolved to a primitive value.) + */ + DYNAMIC_STRING, + + /** + * An external reference could not be resolved to a value which can be evaluated. + * (E.g. a call expression for a function declared in `.d.ts`.) + */ + EXTERNAL_REFERENCE, + + /** + * A type of `ts.Expression` that `StaticInterpreter` doesn't know how to evaluate. + */ + UNKNOWN_EXPRESSION_TYPE, + + /** + * A declaration of a `ts.Identifier` could not be found. + */ + UNKNOWN_IDENTIFIER, + + /** + * A value could not be determined statically for any reason other the above. + */ + UNKNOWN, +} + +/** + * Represents a value which cannot be determined statically. + */ +export class DynamicValue { + private constructor( + readonly node: ts.Node, readonly reason: R, private code: DynamicValueReason) {} + + static fromDynamicInput(node: ts.Node, input: DynamicValue): DynamicValue { + return new DynamicValue(node, input, DynamicValueReason.DYNAMIC_INPUT); + } + + static fromDynamicString(node: ts.Node): DynamicValue { + return new DynamicValue(node, {}, DynamicValueReason.DYNAMIC_STRING); + } + + static fromExternalReference(node: ts.Node, ref: Reference): + DynamicValue> { + return new DynamicValue(node, ref, DynamicValueReason.EXTERNAL_REFERENCE); + } + + static fromUnknownExpressionType(node: ts.Node): DynamicValue { + return new DynamicValue(node, {}, DynamicValueReason.UNKNOWN_EXPRESSION_TYPE); + } + + static fromUnknownIdentifier(node: ts.Identifier): DynamicValue { + return new DynamicValue(node, {}, DynamicValueReason.UNKNOWN_IDENTIFIER); + } + + static fromUnknown(node: ts.Node): DynamicValue { + return new DynamicValue(node, {}, DynamicValueReason.UNKNOWN); + } + + isFromDynamicInput(this: DynamicValue): this is DynamicValue { + return this.code === DynamicValueReason.DYNAMIC_INPUT; + } + + isFromDynamicString(this: DynamicValue): this is DynamicValue { + return this.code === DynamicValueReason.DYNAMIC_STRING; + } + + isFromExternalReference(this: DynamicValue): this is DynamicValue> { + return this.code === DynamicValueReason.EXTERNAL_REFERENCE; + } + + isFromUnknownExpressionType(this: DynamicValue): this is DynamicValue { + return this.code === DynamicValueReason.UNKNOWN_EXPRESSION_TYPE; + } + + isFromUnknownIdentifier(this: DynamicValue): this is DynamicValue { + return this.code === DynamicValueReason.UNKNOWN_IDENTIFIER; + } + + isFromUnknown(this: DynamicValue): this is DynamicValue { + return this.code === DynamicValueReason.UNKNOWN; + } +} diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts new file mode 100644 index 0000000000..28617d1ca1 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {Reference} from '../../imports'; +import {ReflectionHost} from '../../reflection'; + +import {StaticInterpreter} from './interpreter'; +import {ResolvedValue} from './result'; + +export type ForeignFunctionResolver = + (node: Reference, + args: ReadonlyArray) => ts.Expression | null; + +export class PartialEvaluator { + constructor(private host: ReflectionHost, private checker: ts.TypeChecker) {} + + evaluate(expr: ts.Expression, foreignFunctionResolver?: ForeignFunctionResolver): ResolvedValue { + const interpreter = new StaticInterpreter(this.host, this.checker); + return interpreter.visit(expr, { + absoluteModuleName: null, + resolutionContext: expr.getSourceFile().fileName, + scope: new Map(), foreignFunctionResolver, + }); + } +} diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/resolver.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts similarity index 55% rename from packages/compiler-cli/src/ngtsc/metadata/src/resolver.ts rename to packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts index c323160fd9..8a3f662780 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/resolver.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts @@ -6,97 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ -/** - * resolver.ts implements partial computation of expressions, resolving expressions to static - * values where possible and returning a `DynamicValue` signal when not. - */ - -import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@angular/compiler'; -import * as path from 'path'; import * as ts from 'typescript'; -import {ClassMemberKind, ReflectionHost} from '../../host'; +import {Reference} from '../../imports'; +import {OwningModule} from '../../imports/src/references'; +import {Declaration, ReflectionHost} from '../../reflection'; -const TS_DTS_JS_EXTENSION = /(?:\.d)?\.ts$|\.js$/; +import {ArraySliceBuiltinFn} from './builtin'; +import {DynamicValue} from './dynamic'; +import {ForeignFunctionResolver} from './interface'; +import {BuiltinFn, EnumValue, ResolvedValue, ResolvedValueArray, ResolvedValueMap} from './result'; -/** - * Represents a value which cannot be determined statically. - * - * Use `isDynamicValue` to determine whether a `ResolvedValue` is a `DynamicValue`. - */ -export class DynamicValue { - /** - * This is needed so the "is DynamicValue" assertion of `isDynamicValue` actually has meaning. - * - * Otherwise, "is DynamicValue" is akin to "is {}" which doesn't trigger narrowing. - */ - private _isDynamic = true; -} - -/** - * An internal flyweight for `DynamicValue`. Eventually the dynamic value will carry information - * on the location of the node that could not be statically computed. - */ -const DYNAMIC_VALUE: DynamicValue = new DynamicValue(); - -/** - * Used to test whether a `ResolvedValue` is a `DynamicValue`. - */ -export function isDynamicValue(value: any): value is DynamicValue { - return value === DYNAMIC_VALUE; -} - -/** - * A value resulting from static resolution. - * - * This could be a primitive, collection type, reference to a `ts.Node` that declares a - * non-primitive value, or a special `DynamicValue` type which indicates the value was not - * available statically. - */ -export type ResolvedValue = number | boolean | string | null | undefined | Reference | EnumValue | - ResolvedValueArray | ResolvedValueMap | BuiltinFn | DynamicValue; - -/** - * An array of `ResolvedValue`s. - * - * This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueArray` - * -> - * `ResolvedValue`. - */ -export interface ResolvedValueArray extends Array {} - -/** - * A map of strings to `ResolvedValue`s. - * - * This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueMap` -> - * `ResolvedValue`. - */ export interface ResolvedValueMap extends Map {} - -/** - * A value member of an enumeration. - * - * Contains a `Reference` to the enumeration itself, and the name of the referenced member. - */ -export class EnumValue { - constructor(readonly enumRef: Reference, readonly name: string) {} -} - -/** - * An implementation of a builtin function, such as `Array.prototype.slice`. - */ -export abstract class BuiltinFn { abstract evaluate(args: ResolvedValueArray): ResolvedValue; } - -class ArraySliceBuiltinFn extends BuiltinFn { - constructor(private lhs: ResolvedValueArray) { super(); } - - evaluate(args: ResolvedValueArray): ResolvedValue { - if (args.length === 0) { - return this.lhs; - } else { - return DYNAMIC_VALUE; - } - } -} /** * Tracks the scope of a function body, which includes `ResolvedValue`s for the parameters of that @@ -104,164 +24,6 @@ class ArraySliceBuiltinFn extends BuiltinFn { */ type Scope = Map; -export enum ImportMode { - UseExistingImport, - ForceNewImport, -} - -/** - * A reference to a `ts.Node`. - * - * For example, if an expression evaluates to a function or class definition, it will be returned - * as a `Reference` (assuming references are allowed in evaluation). - */ -export abstract class Reference { - constructor(readonly node: T) {} - - /** - * Whether an `Expression` can be generated which references the node. - */ - // TODO(issue/24571): remove '!'. - readonly expressable !: boolean; - - /** - * Generate an `Expression` representing this type, in the context of the given SourceFile. - * - * This could be a local variable reference, if the symbol is imported, or it could be a new - * import if needed. - */ - abstract toExpression(context: ts.SourceFile, importMode?: ImportMode): Expression|null; - - abstract addIdentifier(identifier: ts.Identifier): void; -} - -/** - * A reference to a node only, without any ability to get an `Expression` representing that node. - * - * This is used for returning references to things like method declarations, which are not directly - * referenceable. - */ -export class NodeReference extends Reference { - constructor(node: T, readonly moduleName: string|null) { super(node); } - - toExpression(context: ts.SourceFile): null { return null; } - - addIdentifier(identifier: ts.Identifier): void {} -} - -/** - * A reference to a node which has a `ts.Identifier` and can be resolved to an `Expression`. - * - * Imports generated by `ResolvedReference`s are always relative. - */ -export class ResolvedReference extends Reference { - protected identifiers: ts.Identifier[] = []; - - constructor(node: T, protected primaryIdentifier: ts.Identifier) { super(node); } - - readonly expressable = true; - - toExpression(context: ts.SourceFile, importMode: ImportMode = ImportMode.UseExistingImport): - Expression { - const localIdentifier = - pickIdentifier(context, this.primaryIdentifier, this.identifiers, importMode); - if (localIdentifier !== null) { - return new WrappedNodeExpr(localIdentifier); - } else { - // Relative import from context -> this.node.getSourceFile(). - // TODO(alxhub): investigate the impact of multiple source roots here. - // TODO(alxhub): investigate the need to map such paths via the Host for proper g3 support. - let relative = - path.posix.relative(path.dirname(context.fileName), this.node.getSourceFile().fileName) - .replace(TS_DTS_JS_EXTENSION, ''); - - // path.relative() does not include the leading './'. - if (!relative.startsWith('.')) { - relative = `./${relative}`; - } - - // path.relative() returns the empty string (converted to './' above) if the two paths are the - // same. - if (relative === './') { - // Same file after all. - return new WrappedNodeExpr(this.primaryIdentifier); - } else { - return new ExternalExpr(new ExternalReference(relative, this.primaryIdentifier.text)); - } - } - } - - addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); } -} - -/** - * A reference to a node which has a `ts.Identifer` and an expected absolute module name. - * - * An `AbsoluteReference` can be resolved to an `Expression`, and if that expression is an import - * the module specifier will be an absolute module name, not a relative path. - */ -export class AbsoluteReference extends Reference { - private identifiers: ts.Identifier[] = []; - constructor( - node: T, private primaryIdentifier: ts.Identifier, readonly moduleName: string, - readonly symbolName: string) { - super(node); - } - - readonly expressable = true; - - toExpression(context: ts.SourceFile, importMode: ImportMode = ImportMode.UseExistingImport): - Expression { - const localIdentifier = - pickIdentifier(context, this.primaryIdentifier, this.identifiers, importMode); - if (localIdentifier !== null) { - return new WrappedNodeExpr(localIdentifier); - } else { - return new ExternalExpr(new ExternalReference(this.moduleName, this.symbolName)); - } - } - - addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); } -} - -function pickIdentifier( - context: ts.SourceFile, primary: ts.Identifier, secondaries: ts.Identifier[], - mode: ImportMode): ts.Identifier|null { - context = ts.getOriginalNode(context) as ts.SourceFile; - - if (ts.getOriginalNode(primary).getSourceFile() === context) { - return primary; - } else if (mode === ImportMode.UseExistingImport) { - return secondaries.find(id => ts.getOriginalNode(id).getSourceFile() === context) || null; - } else { - return null; - } -} - -/** - * Statically resolve the given `ts.Expression` into a `ResolvedValue`. - * - * @param node the expression to statically resolve if possible - * @param checker a `ts.TypeChecker` used to understand the expression - * @param foreignFunctionResolver a function which will be used whenever a "foreign function" is - * encountered. A foreign function is a function which has no body - usually the result of calling - * a function declared in another library's .d.ts file. In these cases, the foreignFunctionResolver - * will be called with the function's declaration, and can optionally return a `ts.Expression` - * (possibly extracted from the foreign function's type signature) which will be used as the result - * of the call. - * @returns a `ResolvedValue` representing the resolved value - */ -export function staticallyResolve( - node: ts.Expression, host: ReflectionHost, checker: ts.TypeChecker, - foreignFunctionResolver?: - (node: Reference, args: ts.Expression[]) => - ts.Expression | null): ResolvedValue { - return new StaticInterpreter(host, checker).visit(node, { - absoluteModuleName: null, - scope: new Map(), foreignFunctionResolver, - }); -} - interface BinaryOperatorDef { literal: boolean; op: (a: any, b: any) => ResolvedValue; @@ -302,14 +64,21 @@ const UNARY_OPERATORS = new Map any>([ ]); interface Context { + /** + * The module name (if any) which was used to reach the currently resolving symbols. + */ absoluteModuleName: string|null; + + /** + * A file name representing the context in which the current `absoluteModuleName`, if any, was + * resolved. + */ + resolutionContext: string; scope: Scope; - foreignFunctionResolver? - (ref: Reference, - args: ReadonlyArray): ts.Expression|null; + foreignFunctionResolver?: ForeignFunctionResolver; } -class StaticInterpreter { +export class StaticInterpreter { constructor(private host: ReflectionHost, private checker: ts.TypeChecker) {} visit(node: ts.Expression, context: Context): ResolvedValue { @@ -356,7 +125,7 @@ class StaticInterpreter { } else if (this.host.isClass(node)) { return this.visitDeclaration(node, context); } else { - return DYNAMIC_VALUE; + return DynamicValue.fromUnknownExpressionType(node); } } @@ -367,21 +136,15 @@ class StaticInterpreter { const element = node.elements[i]; if (ts.isSpreadElement(element)) { const spread = this.visitExpression(element.expression, context); - if (isDynamicValue(spread)) { - return DYNAMIC_VALUE; - } - if (!Array.isArray(spread)) { + if (spread instanceof DynamicValue) { + array.push(DynamicValue.fromDynamicInput(element.expression, spread)); + } else if (!Array.isArray(spread)) { throw new Error(`Unexpected value in spread expression: ${spread}`); + } else { + array.push(...spread); } - - array.push(...spread); } else { - const result = this.visitExpression(element, context); - if (isDynamicValue(result)) { - return DYNAMIC_VALUE; - } - - array.push(result); + array.push(this.visitExpression(element, context)); } } return array; @@ -394,30 +157,28 @@ class StaticInterpreter { const property = node.properties[i]; if (ts.isPropertyAssignment(property)) { const name = this.stringNameFromPropertyName(property.name, context); - // Check whether the name can be determined statically. if (name === undefined) { - return DYNAMIC_VALUE; + return DynamicValue.fromDynamicInput(node, DynamicValue.fromDynamicString(property.name)); } - map.set(name, this.visitExpression(property.initializer, context)); } else if (ts.isShorthandPropertyAssignment(property)) { const symbol = this.checker.getShorthandAssignmentValueSymbol(property); if (symbol === undefined || symbol.valueDeclaration === undefined) { - return DYNAMIC_VALUE; + map.set(property.name.text, DynamicValue.fromUnknown(property)); + } else { + map.set(property.name.text, this.visitDeclaration(symbol.valueDeclaration, context)); } - map.set(property.name.text, this.visitDeclaration(symbol.valueDeclaration, context)); } else if (ts.isSpreadAssignment(property)) { const spread = this.visitExpression(property.expression, context); - if (isDynamicValue(spread)) { - return DYNAMIC_VALUE; - } - if (!(spread instanceof Map)) { + if (spread instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, spread); + } else if (!(spread instanceof Map)) { throw new Error(`Unexpected value in spread assignment: ${spread}`); } spread.forEach((value, key) => map.set(key, value)); } else { - return DYNAMIC_VALUE; + return DynamicValue.fromUnknown(node); } } return map; @@ -431,8 +192,10 @@ class StaticInterpreter { if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value == null) { pieces.push(`${value}`); + } else if (value instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, value); } else { - return DYNAMIC_VALUE; + return DynamicValue.fromDynamicInput(node, DynamicValue.fromDynamicString(span.expression)); } pieces.push(span.literal.text); } @@ -442,10 +205,10 @@ class StaticInterpreter { private visitIdentifier(node: ts.Identifier, context: Context): ResolvedValue { const decl = this.host.getDeclarationOfIdentifier(node); if (decl === null) { - return DYNAMIC_VALUE; + return DynamicValue.fromUnknownIdentifier(node); } - const result = this.visitDeclaration( - decl.node, {...context, absoluteModuleName: decl.viaModule || context.absoluteModuleName}); + const result = + this.visitDeclaration(decl.node, {...context, ...joinModuleContext(context, node, decl)}); if (result instanceof Reference) { result.addIdentifier(node); } @@ -487,7 +250,8 @@ class StaticInterpreter { node.members.forEach(member => { const name = this.stringNameFromPropertyName(member.name, context); if (name !== undefined) { - map.set(name, new EnumValue(enumRef, name)); + const resolved = member.initializer && this.visit(member.initializer, context); + map.set(name, new EnumValue(enumRef, name, resolved)); } }); return map; @@ -499,19 +263,19 @@ class StaticInterpreter { if (node.argumentExpression === undefined) { throw new Error(`Expected argument in ElementAccessExpression`); } - if (isDynamicValue(lhs)) { - return DYNAMIC_VALUE; + if (lhs instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, lhs); } const rhs = this.visitExpression(node.argumentExpression, context); - if (isDynamicValue(rhs)) { - return DYNAMIC_VALUE; + if (rhs instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, rhs); } if (typeof rhs !== 'string' && typeof rhs !== 'number') { throw new Error( `ElementAccessExpression index should be string or number, got ${typeof rhs}: ${rhs}`); } - return this.accessHelper(lhs, rhs, context); + return this.accessHelper(node, lhs, rhs, context); } private visitPropertyAccessExpression(node: ts.PropertyAccessExpression, context: Context): @@ -519,30 +283,31 @@ class StaticInterpreter { const lhs = this.visitExpression(node.expression, context); const rhs = node.name.text; // TODO: handle reference to class declaration. - if (isDynamicValue(lhs)) { - return DYNAMIC_VALUE; + if (lhs instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, lhs); } - - return this.accessHelper(lhs, rhs, context); + return this.accessHelper(node, lhs, rhs, context); } private visitSourceFile(node: ts.SourceFile, context: Context): ResolvedValue { const declarations = this.host.getExportsOfModule(node); if (declarations === null) { - return DYNAMIC_VALUE; + return DynamicValue.fromUnknown(node); } const map = new Map(); declarations.forEach((decl, name) => { - const value = this.visitDeclaration(decl.node, { - ...context, - absoluteModuleName: decl.viaModule || context.absoluteModuleName, - }); + const value = this.visitDeclaration( + decl.node, { + ...context, ...joinModuleContext(context, node, decl), + }); map.set(name, value); }); return map; } - private accessHelper(lhs: ResolvedValue, rhs: string|number, context: Context): ResolvedValue { + private accessHelper( + node: ts.Expression, lhs: ResolvedValue, rhs: string|number, + context: Context): ResolvedValue { const strIndex = `${rhs}`; if (lhs instanceof Map) { if (lhs.has(strIndex)) { @@ -554,10 +319,10 @@ class StaticInterpreter { if (rhs === 'length') { return lhs.length; } else if (rhs === 'slice') { - return new ArraySliceBuiltinFn(lhs); + return new ArraySliceBuiltinFn(node, lhs); } if (typeof rhs !== 'number' || !Number.isInteger(rhs)) { - return DYNAMIC_VALUE; + return DynamicValue.fromUnknown(node); } if (rhs < 0 || rhs >= lhs.length) { throw new Error(`Index out of bounds: ${rhs} vs ${lhs.length}`); @@ -566,10 +331,7 @@ class StaticInterpreter { } else if (lhs instanceof Reference) { const ref = lhs.node; if (this.host.isClass(ref)) { - let absoluteModuleName = context.absoluteModuleName; - if (lhs instanceof NodeReference || lhs instanceof AbsoluteReference) { - absoluteModuleName = lhs.moduleName || absoluteModuleName; - } + const module = owningModule(context, lhs.bestGuessOwningModule); let value: ResolvedValue = undefined; const member = this.host.getMembersOfClass(ref).find( member => member.isStatic && member.name === strIndex); @@ -577,21 +339,24 @@ class StaticInterpreter { if (member.value !== null) { value = this.visitExpression(member.value, context); } else if (member.implementation !== null) { - value = new NodeReference(member.implementation, absoluteModuleName); + value = new Reference(member.implementation, module); } else if (member.node) { - value = new NodeReference(member.node, absoluteModuleName); + value = new Reference(member.node, module); } } return value; } + } else if (lhs instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, lhs); + } else { + throw new Error(`Invalid dot property access: ${lhs} dot ${rhs}`); } - throw new Error(`Invalid dot property access: ${lhs} dot ${rhs}`); } private visitCallExpression(node: ts.CallExpression, context: Context): ResolvedValue { const lhs = this.visitExpression(node.expression, context); - if (isDynamicValue(lhs)) { - return DYNAMIC_VALUE; + if (lhs instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, lhs); } // If the call refers to a builtin function, attempt to evaluate the function. @@ -616,18 +381,21 @@ class StaticInterpreter { expr = context.foreignFunctionResolver(lhs, node.arguments); } if (expr === null) { - throw new Error( - `could not resolve foreign function declaration: ${node.getSourceFile().fileName} ${(lhs.node.name as ts.Identifier).text}`); + return DynamicValue.fromDynamicInput( + node, DynamicValue.fromExternalReference(node.expression, lhs)); } // If the function is declared in a different file, resolve the foreign function expression // using the absolute module name of that file (if any). - let absoluteModuleName: string|null = context.absoluteModuleName; - if (lhs instanceof NodeReference || lhs instanceof AbsoluteReference) { - absoluteModuleName = lhs.moduleName || absoluteModuleName; + if (lhs.bestGuessOwningModule !== null) { + context = { + ...context, + absoluteModuleName: lhs.bestGuessOwningModule.specifier, + resolutionContext: node.getSourceFile().fileName, + }; } - return this.visitExpression(expr, {...context, absoluteModuleName}); + return this.visitExpression(expr, context); } const body = fn.body; @@ -657,8 +425,8 @@ class StaticInterpreter { private visitConditionalExpression(node: ts.ConditionalExpression, context: Context): ResolvedValue { const condition = this.visitExpression(node.condition, context); - if (isDynamicValue(condition)) { - return condition; + if (condition instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, condition); } if (condition) { @@ -677,7 +445,11 @@ class StaticInterpreter { const op = UNARY_OPERATORS.get(operatorKind) !; const value = this.visitExpression(node.operand, context); - return isDynamicValue(value) ? DYNAMIC_VALUE : op(value); + if (value instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, value); + } else { + return op(value); + } } private visitBinaryExpression(node: ts.BinaryExpression, context: Context): ResolvedValue { @@ -695,8 +467,13 @@ class StaticInterpreter { lhs = this.visitExpression(node.left, context); rhs = this.visitExpression(node.right, context); } - - return isDynamicValue(lhs) || isDynamicValue(rhs) ? DYNAMIC_VALUE : opRecord.op(lhs, rhs); + if (lhs instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, lhs); + } else if (rhs instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, rhs); + } else { + return opRecord.op(lhs, rhs); + } } private visitParenthesizedExpression(node: ts.ParenthesizedExpression, context: Context): @@ -714,17 +491,7 @@ class StaticInterpreter { } private getReference(node: ts.Declaration, context: Context): Reference { - const id = identifierOfDeclaration(node); - if (id === undefined) { - throw new Error(`Don't know how to refer to ${ts.SyntaxKind[node.kind]}`); - } - if (context.absoluteModuleName !== null) { - // TODO(alxhub): investigate whether this can get symbol names wrong in the event of - // re-exports under different names. - return new AbsoluteReference(node, id, context.absoluteModuleName, id.text); - } else { - return new ResolvedReference(node, id); - } + return new Reference(node, owningModule(context)); } } @@ -735,32 +502,13 @@ function isFunctionOrMethodReference(ref: Reference): } function literal(value: ResolvedValue): any { - if (value === null || value === undefined || typeof value === 'string' || - typeof value === 'number' || typeof value === 'boolean') { + if (value instanceof DynamicValue || value === null || value === undefined || + typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { return value; } - if (isDynamicValue(value)) { - return DYNAMIC_VALUE; - } throw new Error(`Value ${value} is not literal and cannot be used in this context.`); } -function identifierOfDeclaration(decl: ts.Declaration): ts.Identifier|undefined { - if (ts.isClassDeclaration(decl)) { - return decl.name; - } else if (ts.isEnumDeclaration(decl)) { - return decl.name; - } else if (ts.isFunctionDeclaration(decl)) { - return decl.name; - } else if (ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name)) { - return decl.name; - } else if (ts.isShorthandPropertyAssignment(decl)) { - return decl.name; - } else { - return undefined; - } -} - function isVariableDeclarationDeclared(node: ts.VariableDeclaration): boolean { if (node.parent === undefined || !ts.isVariableDeclarationList(node.parent)) { return false; @@ -773,3 +521,34 @@ function isVariableDeclarationDeclared(node: ts.VariableDeclaration): boolean { return varStmt.modifiers !== undefined && varStmt.modifiers.some(mod => mod.kind === ts.SyntaxKind.DeclareKeyword); } + +const EMPTY = {}; + +function joinModuleContext(existing: Context, node: ts.Node, decl: Declaration): { + absoluteModuleName?: string, + resolutionContext?: string, +} { + if (decl.viaModule !== null && decl.viaModule !== existing.absoluteModuleName) { + return { + absoluteModuleName: decl.viaModule, + resolutionContext: node.getSourceFile().fileName, + }; + } else { + return EMPTY; + } +} + +function owningModule(context: Context, override: OwningModule | null = null): OwningModule|null { + let specifier = context.absoluteModuleName; + if (override !== null) { + specifier = override.specifier; + } + if (specifier !== null) { + return { + specifier, + resolutionContext: context.resolutionContext, + }; + } else { + return null; + } +} diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts new file mode 100644 index 0000000000..8f9dcdf56d --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts @@ -0,0 +1,56 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {Reference} from '../../imports'; + +import {DynamicValue} from './dynamic'; + + +/** + * A value resulting from static resolution. + * + * This could be a primitive, collection type, reference to a `ts.Node` that declares a + * non-primitive value, or a special `DynamicValue` type which indicates the value was not + * available statically. + */ +export type ResolvedValue = number | boolean | string | null | undefined | Reference | EnumValue | + ResolvedValueArray | ResolvedValueMap | BuiltinFn | DynamicValue<{}>; + +/** + * An array of `ResolvedValue`s. + * + * This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueArray` + * -> + * `ResolvedValue`. + */ +export interface ResolvedValueArray extends Array {} + +/** + * A map of strings to `ResolvedValue`s. + * + * This is a reified type to allow the circular reference of `ResolvedValue` -> `ResolvedValueMap` -> + * `ResolvedValue`. + */ export interface ResolvedValueMap extends Map {} + +/** + * A value member of an enumeration. + * + * Contains a `Reference` to the enumeration itself, and the name of the referenced member. + */ +export class EnumValue { + constructor( + readonly enumRef: Reference, readonly name: string, + readonly resolved: ResolvedValue) {} +} + +/** + * An implementation of a builtin function, such as `Array.prototype.slice`. + */ +export abstract class BuiltinFn { abstract evaluate(args: ResolvedValueArray): ResolvedValue; } diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel new file mode 100644 index 0000000000..c79c44c2cb --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel @@ -0,0 +1,29 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob([ + "**/*.ts", + ]), + deps = [ + "//packages:types", + "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/reflection", + "//packages/compiler-cli/src/ngtsc/testing", + "@ngdeps//typescript", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + deps = [ + ":test_lib", + "//tools/testing:node_no_angular", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/metadata/test/resolver_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts similarity index 59% rename from packages/compiler-cli/src/ngtsc/metadata/test/resolver_spec.ts rename to packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index 8a4ed0a3fd..640c332b31 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/test/resolver_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -6,57 +6,63 @@ * found in the LICENSE file at https://angular.io/license */ -import {WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {TypeScriptReflectionHost} from '..'; +import {Reference} from '../../imports'; +import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; -import {AbsoluteReference, EnumValue, Reference, ResolvedValue, staticallyResolve} from '../src/resolver'; +import {PartialEvaluator} from '../src/interface'; +import {EnumValue, ResolvedValue} from '../src/result'; function makeSimpleProgram(contents: string): ts.Program { return makeProgram([{name: 'entry.ts', contents}]).program; } function makeExpression( - code: string, expr: string): {expression: ts.Expression, checker: ts.TypeChecker} { - const {program} = - makeProgram([{name: 'entry.ts', contents: `${code}; const target$ = ${expr};`}]); + code: string, expr: string, supportingFiles: {name: string, contents: string}[] = []): { + expression: ts.Expression, + host: ts.CompilerHost, + checker: ts.TypeChecker, + program: ts.Program, + options: ts.CompilerOptions +} { + const {program, options, host} = makeProgram( + [{name: 'entry.ts', contents: `${code}; const target$ = ${expr};`}, ...supportingFiles]); const checker = program.getTypeChecker(); const decl = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); return { expression: decl.initializer !, + host, + options, checker, + program, }; } -function evaluate(code: string, expr: string): T { - const {expression, checker} = makeExpression(code, expr); - const host = new TypeScriptReflectionHost(checker); - return staticallyResolve(expression, host, checker) as T; +function evaluate( + code: string, expr: string, supportingFiles: {name: string, contents: string}[] = []): T { + const {expression, checker, program, options, host} = makeExpression(code, expr, supportingFiles); + const reflectionHost = new TypeScriptReflectionHost(checker); + const evaluator = new PartialEvaluator(reflectionHost, checker); + return evaluator.evaluate(expression) as T; } describe('ngtsc metadata', () => { it('reads a file correctly', () => { - const {program} = makeProgram([ - { - name: 'entry.ts', - contents: ` - import {Y} from './other'; - const A = Y; - export const X = A; - ` - }, - { - name: 'other.ts', - contents: ` + const value = evaluate( + ` + import {Y} from './other'; + const A = Y; + `, + 'A', [ + { + name: 'other.ts', + contents: ` export const Y = 'test'; ` - } - ]); - const decl = getDeclaration(program, 'entry.ts', 'X', ts.isVariableDeclaration); - const host = new TypeScriptReflectionHost(program.getTypeChecker()); + }, + ]); - const value = staticallyResolve(decl.initializer !, host, program.getTypeChecker()); expect(value).toEqual('test'); }); @@ -128,7 +134,7 @@ describe('ngtsc metadata', () => { }); it('imports work', () => { - const {program} = makeProgram([ + const {program, options, host} = makeProgram([ {name: 'second.ts', contents: 'export function foo(bar) { return bar; }'}, { name: 'entry.ts', @@ -139,27 +145,24 @@ describe('ngtsc metadata', () => { }, ]); const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); + const reflectionHost = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); const expr = result.initializer !; - const resolved = staticallyResolve(expr, host, checker); + const evaluator = new PartialEvaluator(reflectionHost, checker); + const resolved = evaluator.evaluate(expr); if (!(resolved instanceof Reference)) { return fail('Expected expression to resolve to a reference'); } expect(ts.isFunctionDeclaration(resolved.node)).toBe(true); - expect(resolved.expressable).toBe(true); - const reference = resolved.toExpression(program.getSourceFile('entry.ts') !); - if (!(reference instanceof WrappedNodeExpr)) { - return fail('Expected expression reference to be a wrapped node'); + const reference = resolved.getIdentityIn(program.getSourceFile('entry.ts') !); + if (reference === null) { + return fail('Expected to get an identifier'); } - if (!ts.isIdentifier(reference.node)) { - return fail('Expected expression to be an Identifier'); - } - expect(reference.node.getSourceFile()).toEqual(program.getSourceFile('entry.ts') !); + expect(reference.getSourceFile()).toEqual(program.getSourceFile('entry.ts') !); }); it('absolute imports work', () => { - const {program} = makeProgram([ + const {program, options, host} = makeProgram([ {name: 'node_modules/some_library/index.d.ts', contents: 'export declare function foo(bar);'}, { name: 'entry.ts', @@ -170,78 +173,47 @@ describe('ngtsc metadata', () => { }, ]); const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); + const reflectionHost = new TypeScriptReflectionHost(checker); const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); const expr = result.initializer !; - const resolved = staticallyResolve(expr, host, checker); - if (!(resolved instanceof AbsoluteReference)) { + const evaluator = new PartialEvaluator(reflectionHost, checker); + const resolved = evaluator.evaluate(expr); + if (!(resolved instanceof Reference)) { return fail('Expected expression to resolve to an absolute reference'); } - expect(resolved.moduleName).toBe('some_library'); + expect(owningModuleOf(resolved)).toBe('some_library'); expect(ts.isFunctionDeclaration(resolved.node)).toBe(true); - expect(resolved.expressable).toBe(true); - const reference = resolved.toExpression(program.getSourceFile('entry.ts') !); - if (!(reference instanceof WrappedNodeExpr)) { - return fail('Expected expression reference to be a wrapped node'); - } - if (!ts.isIdentifier(reference.node)) { - return fail('Expected expression to be an Identifier'); - } - expect(reference.node.getSourceFile()).toEqual(program.getSourceFile('entry.ts') !); + const reference = resolved.getIdentityIn(program.getSourceFile('entry.ts') !); + expect(reference).not.toBeNull(); + expect(reference !.getSourceFile()).toEqual(program.getSourceFile('entry.ts') !); }); it('reads values from default exports', () => { - const {program} = makeProgram([ - {name: 'second.ts', contents: 'export default {property: "test"}'}, - { - name: 'entry.ts', - contents: ` - import mod from './second'; - const target$ = mod.property; - ` - }, - ]); - const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); - const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); - const expr = result.initializer !; - expect(staticallyResolve(expr, host, checker)).toEqual('test'); + const value = evaluate( + ` + import mod from './second'; + `, + 'mod.property', [ + {name: 'second.ts', contents: 'export default {property: "test"}'}, + ]); + expect(value).toEqual('test'); }); it('reads values from named exports', () => { - const {program} = makeProgram([ + const value = evaluate(`import * as mod from './second';`, 'mod.a.property', [ {name: 'second.ts', contents: 'export const a = {property: "test"};'}, - { - name: 'entry.ts', - contents: ` - import * as mod from './second'; - const target$ = mod.a.property; - ` - }, ]); - const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); - const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); - const expr = result.initializer !; - expect(staticallyResolve(expr, host, checker)).toEqual('test'); + expect(value).toEqual('test'); }); it('chain of re-exports works', () => { - const {program} = makeProgram([ + const value = evaluate(`import * as mod from './direct-reexport';`, 'mod.value.property', [ {name: 'const.ts', contents: 'export const value = {property: "test"};'}, {name: 'def.ts', contents: `import {value} from './const'; export default value;`}, {name: 'indirect-reexport.ts', contents: `import value from './def'; export {value};`}, {name: 'direct-reexport.ts', contents: `export {value} from './indirect-reexport';`}, - { - name: 'entry.ts', - contents: `import * as mod from './direct-reexport'; const target$ = mod.value.property;` - }, ]); - const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); - const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); - const expr = result.initializer !; - expect(staticallyResolve(expr, host, checker)).toEqual('test'); + expect(value).toEqual('test'); }); it('map spread works', () => { @@ -290,14 +262,13 @@ describe('ngtsc metadata', () => { }); it('variable declaration resolution works', () => { - const {program} = makeProgram([ + const value = evaluate(`import {value} from './decl';`, 'value', [ {name: 'decl.d.ts', contents: 'export declare let value: number;'}, - {name: 'entry.ts', contents: `import {value} from './decl'; const target$ = value;`}, ]); - const checker = program.getTypeChecker(); - const host = new TypeScriptReflectionHost(checker); - const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration); - const res = staticallyResolve(result.initializer !, host, checker); - expect(res instanceof Reference).toBe(true); + expect(value instanceof Reference).toBe(true); }); }); + +function owningModuleOf(ref: Reference): string|null { + return ref.bestGuessOwningModule !== null ? ref.bestGuessOwningModule.specifier : null; +} diff --git a/packages/compiler-cli/src/ngtsc/path/BUILD.bazel b/packages/compiler-cli/src/ngtsc/path/BUILD.bazel new file mode 100644 index 0000000000..f041fba829 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/BUILD.bazel @@ -0,0 +1,16 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "path", + srcs = glob([ + "index.ts", + "src/*.ts", + ]), + deps = [ + "//packages:types", + "@ngdeps//@types/node", + "@ngdeps//typescript", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/path/README.md b/packages/compiler-cli/src/ngtsc/path/README.md new file mode 100644 index 0000000000..546ae01539 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/README.md @@ -0,0 +1,45 @@ +# About paths in ngtsc + +Within the compiler, there are a number of different types of file system or URL "paths" which are manipulated as strings. While it's possible to declare the variables and fields which store these different kinds of paths using the 'string' type, this has significant drawbacks: + +* When calling a function which accepts a path as an argument, it's not clear what kind of path should be passed. +* It can be expensive to check whether a path is properly formatted, and without types it's easy to fall into the habit of normalizing different kinds of paths repeatedly. +* There is no static check to detect if paths are improperly used in the wrong context (e.g. a relative path passed where an absolute path was required). This can cause subtle bugs. +* When running on Windows, some paths can use different conventions (e.g. forward vs back slashes). It's not always clear when a path needs to be checked for the correct convention. + +To address these issues, ngtsc has specific static types for each kind of path in the system. These types are not mutually assignable, nor can they be directly assigned from `string`s (though they can be assigned _to_ `string`s). Conversion between `string`s and these specific path types happens through a narrow API which validates that all typed paths are valid. + +# The different path kinds + +All paths in the type system use POSIX format (`/` separators). + +## `AbsoluteFsPath` + +This path type represents an absolute path to a physical directory or file. For example, `/foo/bar.txt`. + +## `PathSegment` + +This path type represents a relative path to a directory or file. It only makes sense in the context of some directory (e.g. the working directory) or set of directories to search, and does not need to necessarily represent a relative path between two physical files. + +## `LogicalProjectPath` + +This path type represents a path to a file in TypeScript's logical file system. + +TypeScript supports multiple root directories for a given project, which are effectively overlayed to obtain a file layout. For example, if a project has two root directories `foo` and `bar` with the layout: + +```text +/foo +/foo/foo.ts +/bar +/bar/bar.ts +``` + +Then `foo.ts` could theoretically contain: + +```typescript +import {Bar} from './bar'; +``` + +This import of `./bar` is not a valid relative path from `foo.ts` to `bar.ts` on the physical filesystem, but is valid in the context of the project because the contents of the `foo` and `bar` directories are overlayed as far as TypeScript is concerned. + +In this example, `/foo/foo.ts` has a `LogicalProjectPath` of `/foo.ts` and `/bar/bar.ts` has a `LogicalProjectPath` of `/bar.ts`, allowing the module specifier in the import (`./bar`) to be resolved via standard path operations. \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/path/index.ts b/packages/compiler-cli/src/ngtsc/path/index.ts new file mode 100644 index 0000000000..ad4189411e --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export {LogicalFileSystem, LogicalProjectPath} from './src/logical'; +export {AbsoluteFsPath, PathSegment} from './src/types'; diff --git a/packages/compiler-cli/src/ngtsc/path/src/logical.ts b/packages/compiler-cli/src/ngtsc/path/src/logical.ts new file mode 100644 index 0000000000..217cbb9ab5 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/src/logical.ts @@ -0,0 +1,95 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/// +import * as path from 'path'; + +import * as ts from 'typescript'; + +import {AbsoluteFsPath, BrandedPath, PathSegment} from './types'; +import {stripExtension} from './util'; + +/** + * A path that's relative to the logical root of a TypeScript project (one of the project's + * rootDirs). + */ +export type LogicalProjectPath = BrandedPath<'LogicalProjectPath'>; + +export const LogicalProjectPath = { + /** + * Get the relative path between two `LogicalProjectPath`s. + * + * This will return a `PathSegment` which would be a valid module specifier to use in `from` when + * importing from `to`. + */ + relativePathBetween: function(from: LogicalProjectPath, to: LogicalProjectPath): PathSegment { + let relativePath = path.posix.relative(path.posix.dirname(from), to); + if (!relativePath.startsWith('../')) { + relativePath = ('./' + relativePath); + } + return relativePath as PathSegment; + }, +}; + +/** + * A utility class which can translate absolute paths to source files into logical paths in + * TypeScript's logical file system, based on the root directories of the project. + */ +export class LogicalFileSystem { + /** + * The root directories of the project, sorted with the longest path first. + */ + private rootDirs: AbsoluteFsPath[]; + + /** + * A cache of file paths to project paths, because computation of these paths is slightly + * expensive. + */ + private cache: Map = new Map(); + + constructor(rootDirs: AbsoluteFsPath[]) { + // Make a copy and sort it by length in reverse order (longest first). This speeds up lookups, + // since there's no need to keep going through the array once a match is found. + this.rootDirs = rootDirs.concat([]).sort((a, b) => b.length - a.length); + } + + /** + * Get the logical path in the project of a `ts.SourceFile`. + * + * This method is provided as a convenient alternative to calling + * `logicalPathOfFile(AbsoluteFsPath.fromSourceFile(sf))`. + */ + logicalPathOfSf(sf: ts.SourceFile): LogicalProjectPath|null { + return this.logicalPathOfFile(sf.fileName as AbsoluteFsPath); + } + + /** + * Get the logical path in the project of a source file. + * + * @returns A `LogicalProjectPath` to the source file, or `null` if the source file is not in any + * of the TS project's root directories. + */ + logicalPathOfFile(physicalFile: AbsoluteFsPath): LogicalProjectPath|null { + if (!this.cache.has(physicalFile)) { + let logicalFile: LogicalProjectPath|null = null; + for (const rootDir of this.rootDirs) { + if (physicalFile.startsWith(rootDir)) { + logicalFile = stripExtension(physicalFile.substr(rootDir.length)) as LogicalProjectPath; + // The logical project does not include any special "node_modules" nested directories. + if (logicalFile.indexOf('/node_modules/') !== -1) { + logicalFile = null; + } else { + break; + } + } + } + this.cache.set(physicalFile, logicalFile); + } + return this.cache.get(physicalFile) !; + } +} diff --git a/packages/compiler-cli/src/ngtsc/path/src/types.ts b/packages/compiler-cli/src/ngtsc/path/src/types.ts new file mode 100644 index 0000000000..6c81d54034 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/src/types.ts @@ -0,0 +1,86 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {normalizeSeparators} from './util'; + +/** + * A `string` representing a specific type of path, with a particular brand `B`. + * + * A `string` is not assignable to a `BrandedPath`, but a `BrandedPath` is assignable to a `string`. + * Two `BrandedPath`s with different brands are not mutually assignable. + */ +export type BrandedPath = string & { + _brand: B; +}; + +/** + * A fully qualified path in the file system, in POSIX form. + */ +export type AbsoluteFsPath = BrandedPath<'AbsoluteFsPath'>; + +/** + * A path that's relative to another (unspecified) root. + * + * This does not necessarily have to refer to a physical file. + */ +export type PathSegment = BrandedPath<'PathSegment'>; + +/** + * Contains utility functions for creating and manipulating `AbsoluteFsPath`s. + */ +export const AbsoluteFsPath = { + /** + * Convert the path `str` to an `AbsoluteFsPath`, throwing an error if it's not an absolute path. + */ + from: function(str: string): AbsoluteFsPath { + const normalized = normalizeSeparators(str); + if (!normalized.startsWith('/')) { + throw new Error(`Internal Error: AbsoluteFsPath.from(${str}): path is not absolute`); + } + return normalized as AbsoluteFsPath; + }, + + /** + * Assume that the path `str` is an `AbsoluteFsPath` in the correct format already. + */ + fromUnchecked: function(str: string): AbsoluteFsPath { return str as AbsoluteFsPath;}, + + /** + * Extract an `AbsoluteFsPath` from a `ts.SourceFile`. + * + * This is cheaper than calling `AbsoluteFsPath.from(sf.fileName)`, as source files already have + * their file path in absolute POSIX format. + */ + fromSourceFile: function(sf: ts.SourceFile): AbsoluteFsPath { + // ts.SourceFile paths are always absolute. + return sf.fileName as AbsoluteFsPath; + }, +}; + +/** + * Contains utility functions for creating and manipulating `PathSegment`s. + */ +export const PathSegment = { + /** + * Convert the path `str` to a `PathSegment`, throwing an error if it's not a relative path. + */ + fromFsPath: function(str: string): PathSegment { + const normalized = normalizeSeparators(str); + if (normalized.startsWith('/')) { + throw new Error(`Internal Error: PathSegment.from(${str}): path is not relative`); + } + return normalized as PathSegment; + }, + + /** + * Convert the path `str` to a `PathSegment`, while assuming that `str` is already normalized. + */ + fromUnchecked: function(str: string): PathSegment { return str as PathSegment;}, +}; diff --git a/packages/compiler-cli/src/ngtsc/path/src/util.ts b/packages/compiler-cli/src/ngtsc/path/src/util.ts new file mode 100644 index 0000000000..7ff6c21041 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/src/util.ts @@ -0,0 +1,26 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// TODO(alxhub): Unify this file with `util/src/path`. + +const TS_DTS_JS_EXTENSION = /(?:\.d)?\.ts$|\.js$/; + +/** + * Convert Windows-style paths to POSIX paths. + */ +export function normalizeSeparators(path: string): string { + // TODO: normalize path only for OS that need it. + return path.replace(/\\/g, '/'); +} + +/** + * Remove a .ts, .d.ts, or .js extension from a file name. + */ +export function stripExtension(path: string): string { + return path.replace(TS_DTS_JS_EXTENSION, ''); +} diff --git a/packages/compiler-cli/src/ngtsc/path/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/path/test/BUILD.bazel new file mode 100644 index 0000000000..8b1e2b62c2 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/test/BUILD.bazel @@ -0,0 +1,24 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob([ + "**/*.ts", + ]), + deps = [ + "//packages:types", + "//packages/compiler-cli/src/ngtsc/path", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + deps = [ + ":test_lib", + "//tools/testing:node_no_angular", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/path/test/logical_spec.ts b/packages/compiler-cli/src/ngtsc/path/test/logical_spec.ts new file mode 100644 index 0000000000..f48713e39d --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/test/logical_spec.ts @@ -0,0 +1,53 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {LogicalFileSystem, LogicalProjectPath} from '../src/logical'; +import {AbsoluteFsPath} from '../src/types'; + +describe('logical paths', () => { + describe('LogicalFileSystem', () => { + it('should determine logical paths in a single root file system', () => { + const fs = new LogicalFileSystem([abs('/test')]); + expect(fs.logicalPathOfFile(abs('/test/foo/foo.ts'))) + .toEqual('/foo/foo' as LogicalProjectPath); + expect(fs.logicalPathOfFile(abs('/test/bar/bar.ts'))) + .toEqual('/bar/bar' as LogicalProjectPath); + expect(fs.logicalPathOfFile(abs('/not-test/bar.ts'))).toBeNull(); + }); + + it('should determine logical paths in a multi-root file system', () => { + const fs = new LogicalFileSystem([abs('/test/foo'), abs('/test/bar')]); + expect(fs.logicalPathOfFile(abs('/test/foo/foo.ts'))).toEqual('/foo' as LogicalProjectPath); + expect(fs.logicalPathOfFile(abs('/test/bar/bar.ts'))).toEqual('/bar' as LogicalProjectPath); + }); + + it('should continue to work when one root is a child of another', () => { + const fs = new LogicalFileSystem([abs('/test'), abs('/test/dist')]); + expect(fs.logicalPathOfFile(abs('/test/foo.ts'))).toEqual('/foo' as LogicalProjectPath); + expect(fs.logicalPathOfFile(abs('/test/dist/foo.ts'))).toEqual('/foo' as LogicalProjectPath); + }); + }); + + describe('utilities', () => { + it('should give a relative path between two adjacent logical files', () => { + const res = LogicalProjectPath.relativePathBetween( + '/foo' as LogicalProjectPath, '/bar' as LogicalProjectPath); + expect(res).toEqual('./bar'); + }); + + it('should give a relative path between two non-adjacent logical files', () => { + const res = LogicalProjectPath.relativePathBetween( + '/foo/index' as LogicalProjectPath, '/bar/index' as LogicalProjectPath); + expect(res).toEqual('../bar/index'); + }); + }); +}); + +function abs(file: string): AbsoluteFsPath { + return AbsoluteFsPath.from(file); +} diff --git a/packages/compiler-cli/src/ngtsc/path/test/types_spec.ts b/packages/compiler-cli/src/ngtsc/path/test/types_spec.ts new file mode 100644 index 0000000000..76793b67c3 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/path/test/types_spec.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {AbsoluteFsPath} from '../src/types'; + +describe('path types', () => { + describe('AbsoluteFsPath', () => { + it('should not throw when creating one from a non-absolute path', + () => { expect(AbsoluteFsPath.from('/test.txt')).toEqual('/test.txt'); }); + it('should throw when creating one from a non-absolute path', + () => { expect(() => AbsoluteFsPath.from('test.txt')).toThrow(); }); + it('should convert Windows path separators to POSIX separators', + () => { expect(AbsoluteFsPath.from('\\foo\\test.txt')).toEqual('/foo/test.txt'); }); + }); +}); diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index fe17878985..aa39cfc5b7 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -7,54 +7,66 @@ */ import {GeneratedFile} from '@angular/compiler'; -import * as path from 'path'; import * as ts from 'typescript'; import * as api from '../transformers/api'; import {nocollapseHack} from '../transformers/nocollapse_hack'; -import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from './annotations'; +import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry, SelectorScopeRegistry} from './annotations'; import {BaseDefDecoratorHandler} from './annotations/src/base_def'; -import {TypeScriptReflectionHost} from './metadata'; -import {FileResourceLoader, HostResourceLoader} from './resource_loader'; -import {FactoryGenerator, FactoryInfo, FlatIndexGenerator, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, generatedFactoryTransform} from './shims'; +import {CycleAnalyzer, ImportGraph} from './cycles'; +import {ErrorCode, ngErrorCode} from './diagnostics'; +import {FlatIndexGenerator, ReferenceGraph, checkForPrivateExports, findFlatIndexEntryPoint} from './entry_point'; +import {AbsoluteModuleStrategy, FileToModuleHost, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, R3SymbolsImportRewriter, Reference, ReferenceEmitter} from './imports'; +import {FileToModuleStrategy} from './imports/src/emitter'; +import {PartialEvaluator} from './partial_evaluator'; +import {AbsoluteFsPath, LogicalFileSystem} from './path'; +import {TypeScriptReflectionHost} from './reflection'; +import {HostResourceLoader} from './resource_loader'; +import {NgModuleRouteAnalyzer, entryPointKeyFor} from './routing'; +import {FactoryGenerator, FactoryInfo, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, generatedFactoryTransform} from './shims'; import {ivySwitchTransform} from './switch'; -import {IvyCompilation, ivyTransformFactory} from './transform'; +import {IvyCompilation, declarationTransformFactory, ivyTransformFactory} from './transform'; import {TypeCheckContext, TypeCheckProgramHost} from './typecheck'; +import {normalizeSeparators} from './util/src/path'; +import {getRootDirs, isDtsPath} from './util/src/typescript'; export class NgtscProgram implements api.Program { private tsProgram: ts.Program; - private resourceLoader: ResourceLoader; + private resourceManager: HostResourceLoader; private compilation: IvyCompilation|undefined = undefined; private factoryToSourceInfo: Map|null = null; private sourceToFactorySymbols: Map>|null = null; private host: ts.CompilerHost; private _coreImportsFrom: ts.SourceFile|null|undefined = undefined; + private _importRewriter: ImportRewriter|undefined = undefined; private _reflector: TypeScriptReflectionHost|undefined = undefined; private _isCore: boolean|undefined = undefined; - private rootDirs: string[]; + private rootDirs: AbsoluteFsPath[]; private closureCompilerEnabled: boolean; + private entryPoint: ts.SourceFile|null; + private exportReferenceGraph: ReferenceGraph|null = null; + private flatIndexGenerator: FlatIndexGenerator|null = null; + private routeAnalyzer: NgModuleRouteAnalyzer|null = null; + private constructionDiagnostics: ts.Diagnostic[] = []; + private moduleResolver: ModuleResolver; + private cycleAnalyzer: CycleAnalyzer; + + private refEmitter: ReferenceEmitter|null = null; + private fileToModuleHost: FileToModuleHost|null = null; constructor( rootNames: ReadonlyArray, private options: api.CompilerOptions, host: api.CompilerHost, oldProgram?: api.Program) { - this.rootDirs = []; - if (options.rootDirs !== undefined) { - this.rootDirs.push(...options.rootDirs); - } else if (options.rootDir !== undefined) { - this.rootDirs.push(options.rootDir); - } else { - this.rootDirs.push(host.getCurrentDirectory()); - } + this.rootDirs = getRootDirs(host, options); this.closureCompilerEnabled = !!options.annotateForClosureCompiler; - this.resourceLoader = - host.readResource !== undefined && host.resourceNameToFileName !== undefined ? - new HostResourceLoader( - host.resourceNameToFileName.bind(host), host.readResource.bind(host)) : - new FileResourceLoader(host, this.options); + this.resourceManager = new HostResourceLoader(host, options); const shouldGenerateShims = options.allowEmptyCodegenFiles || false; this.host = host; + if (host.fileNameToModuleName !== undefined) { + this.fileToModuleHost = host as FileToModuleHost; + } let rootFiles = [...rootNames]; const generators: ShimGenerator[] = []; @@ -78,14 +90,10 @@ export class NgtscProgram implements api.Program { generators.push(summaryGenerator, factoryGenerator); } + let entryPoint: string|null = null; if (options.flatModuleOutFile !== undefined) { - const flatModuleId = options.flatModuleId || null; - const flatIndexGenerator = - FlatIndexGenerator.forRootFiles(options.flatModuleOutFile, rootNames, flatModuleId); - if (flatIndexGenerator !== null) { - generators.push(flatIndexGenerator); - rootFiles.push(flatIndexGenerator.flatIndexPath); - } else { + entryPoint = findFlatIndexEntryPoint(rootNames); + if (entryPoint === null) { // This error message talks specifically about having a single .ts file in "files". However // the actual logic is a bit more permissive. If a single file exists, that will be taken, // otherwise the highest level (shortest path) "index.ts" file will be used as the flat @@ -94,8 +102,22 @@ export class NgtscProgram implements api.Program { // // The user is not informed about the "index.ts" option as this behavior is deprecated - // an explicit entrypoint should always be specified. - throw new Error( - 'Angular compiler option "flatModuleIndex" requires one and only one .ts file in the "files" field.'); + this.constructionDiagnostics.push({ + category: ts.DiagnosticCategory.Error, + code: ngErrorCode(ErrorCode.CONFIG_FLAT_MODULE_NO_INDEX), + file: undefined, + start: undefined, + length: undefined, + messageText: + 'Angular compiler option "flatModuleOutFile" requires one and only one .ts file in the "files" field.', + }); + } else { + const flatModuleId = options.flatModuleId || null; + const flatModuleOutFile = normalizeSeparators(options.flatModuleOutFile); + this.flatIndexGenerator = + new FlatIndexGenerator(entryPoint, flatModuleOutFile, flatModuleId); + generators.push(this.flatIndexGenerator); + rootFiles.push(this.flatIndexGenerator.flatIndexPath); } } @@ -105,6 +127,10 @@ export class NgtscProgram implements api.Program { this.tsProgram = ts.createProgram(rootFiles, options, this.host, oldProgram && oldProgram.getTsProgram()); + + this.entryPoint = entryPoint !== null ? this.tsProgram.getSourceFile(entryPoint) || null : null; + this.moduleResolver = new ModuleResolver(this.tsProgram, options, this.host); + this.cycleAnalyzer = new CycleAnalyzer(new ImportGraph(this.moduleResolver)); } getTsProgram(): ts.Program { return this.tsProgram; } @@ -115,8 +141,8 @@ export class NgtscProgram implements api.Program { } getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken| - undefined): ReadonlyArray { - return []; + undefined): ReadonlyArray { + return this.constructionDiagnostics; } getTsSyntacticDiagnostics( @@ -142,10 +168,14 @@ export class NgtscProgram implements api.Program { const compilation = this.ensureAnalyzed(); const diagnostics = [...compilation.diagnostics]; if (!!this.options.fullTemplateTypeCheck) { - const ctx = new TypeCheckContext(); + const ctx = new TypeCheckContext(this.refEmitter !); compilation.typeCheck(ctx); diagnostics.push(...this.compileTypeCheckProgram(ctx)); } + if (this.entryPoint !== null && this.exportReferenceGraph !== null) { + diagnostics.push(...checkForPrivateExports( + this.entryPoint, this.tsProgram.getTypeChecker(), this.exportReferenceGraph)); + } return diagnostics; } @@ -157,9 +187,45 @@ export class NgtscProgram implements api.Program { .filter(file => !file.fileName.endsWith('.d.ts')) .map(file => this.compilation !.analyzeAsync(file)) .filter((result): result is Promise => result !== undefined)); + this.compilation.resolve(); } - listLazyRoutes(entryRoute?: string|undefined): api.LazyRoute[] { return []; } + listLazyRoutes(entryRoute?: string|undefined): api.LazyRoute[] { + if (entryRoute) { + // Note: + // This resolution step is here to match the implementation of the old `AotCompilerHost` (see + // https://github.com/angular/angular/blob/50732e156/packages/compiler-cli/src/transformers/compiler_host.ts#L175-L188). + // + // `@angular/cli` will always call this API with an absolute path, so the resolution step is + // not necessary, but keeping it backwards compatible in case someone else is using the API. + + // Relative entry paths are disallowed. + if (entryRoute.startsWith('.')) { + throw new Error( + `Falied to list lazy routes: Resolution of relative paths (${entryRoute}) is not supported.`); + } + + // Non-relative entry paths fall into one of the following categories: + // - Absolute system paths (e.g. `/foo/bar/my-project/my-module`), which are unaffected by the + // logic below. + // - Paths to enternal modules (e.g. `some-lib`). + // - Paths mapped to directories in `tsconfig.json` (e.g. `shared/my-module`). + // (See https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping.) + // + // In all cases above, the `containingFile` argument is ignored, so we can just take the first + // of the root files. + const containingFile = this.tsProgram.getRootFileNames()[0]; + const [entryPath, moduleName] = entryRoute.split('#'); + const resolved = ts.resolveModuleName(entryPath, containingFile, this.options, this.host); + + if (resolved.resolvedModule) { + entryRoute = entryPointKeyFor(resolved.resolvedModule.resolvedFileName, moduleName); + } + } + + this.ensureAnalyzed(); + return this.routeAnalyzer !.listLazyRoutes(entryRoute); + } getLibrarySummaries(): Map { throw new Error('Method not implemented.'); @@ -179,6 +245,7 @@ export class NgtscProgram implements api.Program { this.tsProgram.getSourceFiles() .filter(file => !file.fileName.endsWith('.d.ts')) .forEach(file => this.compilation !.analyzeSync(file)); + this.compilation.resolve(); } return this.compilation; } @@ -192,30 +259,34 @@ export class NgtscProgram implements api.Program { }): ts.EmitResult { const emitCallback = opts && opts.emitCallback || defaultEmitCallback; - this.ensureAnalyzed(); + const compilation = this.ensureAnalyzed(); - // Since there is no .d.ts transformation API, .d.ts files are transformed during write. const writeFile: ts.WriteFileCallback = (fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, sourceFiles: ReadonlyArray) => { - if (fileName.endsWith('.d.ts')) { - data = sourceFiles.reduce( - (data, sf) => this.compilation !.transformedDtsFor(sf.fileName, data), data); - } else if (this.closureCompilerEnabled && fileName.endsWith('.ts')) { + if (this.closureCompilerEnabled && fileName.endsWith('.js')) { data = nocollapseHack(data); } this.host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles); }; - const transforms = - [ivyTransformFactory(this.compilation !, this.reflector, this.coreImportsFrom)]; + const customTransforms = opts && opts.customTransformers; + const beforeTransforms = + [ivyTransformFactory(compilation, this.reflector, this.importRewriter, this.isCore)]; + const afterDeclarationsTransforms = [declarationTransformFactory(compilation)]; + if (this.factoryToSourceInfo !== null) { - transforms.push(generatedFactoryTransform(this.factoryToSourceInfo, this.coreImportsFrom)); + beforeTransforms.push( + generatedFactoryTransform(this.factoryToSourceInfo, this.importRewriter)); } if (this.isCore) { - transforms.push(ivySwitchTransform); + beforeTransforms.push(ivySwitchTransform); } + if (customTransforms && customTransforms.beforeTs) { + beforeTransforms.push(...customTransforms.beforeTs); + } + // Run the emit, including a custom transformer that will downlevel the Ivy decorators in code. const emitResult = emitCallback({ program: this.tsProgram, @@ -223,7 +294,9 @@ export class NgtscProgram implements api.Program { options: this.options, emitOnlyDtsFiles: false, writeFile, customTransformers: { - before: transforms, + before: beforeTransforms, + after: customTransforms && customTransforms.afterTs, + afterDeclarations: afterDeclarationsTransforms, }, }); return emitResult; @@ -242,24 +315,64 @@ export class NgtscProgram implements api.Program { private makeCompilation(): IvyCompilation { const checker = this.tsProgram.getTypeChecker(); - const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector); - const referencesRegistry = new NoopReferencesRegistry(); + // Construct the ReferenceEmitter. + if (this.fileToModuleHost === null || !this.options._useHostForImportGeneration) { + // The CompilerHost doesn't have fileNameToModuleName, so build an NPM-centric reference + // resolution strategy. + this.refEmitter = new ReferenceEmitter([ + // First, try to use local identifiers if available. + new LocalIdentifierStrategy(), + // Next, attempt to use an absolute import. + new AbsoluteModuleStrategy(this.tsProgram, checker, this.options, this.host), + // Finally, check if the reference is being written into a file within the project's logical + // file system, and use a relative import if so. If this fails, ReferenceEmitter will throw + // an error. + new LogicalProjectStrategy(checker, new LogicalFileSystem(this.rootDirs)), + ]); + } else { + // The CompilerHost supports fileNameToModuleName, so use that to emit imports. + this.refEmitter = new ReferenceEmitter([ + // First, try to use local identifiers if available. + new LocalIdentifierStrategy(), + // Then use fileNameToModuleName to emit imports. + new FileToModuleStrategy(checker, this.fileToModuleHost), + ]); + } + + const evaluator = new PartialEvaluator(this.reflector, checker); + const scopeRegistry = new SelectorScopeRegistry(checker, this.reflector, this.refEmitter); + + // If a flat module entrypoint was specified, then track references via a `ReferenceGraph` in + // order to produce proper diagnostics for incorrectly exported directives/pipes/etc. If there + // is no flat module entrypoint then don't pay the cost of tracking references. + let referencesRegistry: ReferencesRegistry; + if (this.entryPoint !== null) { + this.exportReferenceGraph = new ReferenceGraph(); + referencesRegistry = new ReferenceGraphAdapter(this.exportReferenceGraph); + } else { + referencesRegistry = new NoopReferencesRegistry(); + } + + this.routeAnalyzer = new NgModuleRouteAnalyzer(this.moduleResolver, evaluator); // Set up the IvyCompilation, which manages state for the Ivy transformer. const handlers = [ - new BaseDefDecoratorHandler(checker, this.reflector), + new BaseDefDecoratorHandler(this.reflector, evaluator), new ComponentDecoratorHandler( - checker, this.reflector, scopeRegistry, this.isCore, this.resourceLoader, this.rootDirs, - this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false), - new DirectiveDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), - new InjectableDecoratorHandler(this.reflector, this.isCore), + this.reflector, evaluator, scopeRegistry, this.isCore, this.resourceManager, + this.rootDirs, this.options.preserveWhitespaces || false, + this.options.i18nUseExternalIds !== false, this.moduleResolver, this.cycleAnalyzer), + new DirectiveDecoratorHandler(this.reflector, evaluator, scopeRegistry, this.isCore), + new InjectableDecoratorHandler( + this.reflector, this.isCore, this.options.strictInjectionParameters || false), new NgModuleDecoratorHandler( - checker, this.reflector, scopeRegistry, referencesRegistry, this.isCore), - new PipeDecoratorHandler(checker, this.reflector, scopeRegistry, this.isCore), + this.reflector, evaluator, scopeRegistry, referencesRegistry, this.isCore, + this.routeAnalyzer, this.refEmitter), + new PipeDecoratorHandler(this.reflector, evaluator, scopeRegistry, this.isCore), ]; return new IvyCompilation( - handlers, checker, this.reflector, this.coreImportsFrom, this.sourceToFactorySymbols); + handlers, checker, this.reflector, this.importRewriter, this.sourceToFactorySymbols); } private get reflector(): TypeScriptReflectionHost { @@ -282,6 +395,16 @@ export class NgtscProgram implements api.Program { } return this._isCore; } + + private get importRewriter(): ImportRewriter { + if (this._importRewriter === undefined) { + const coreImportsFrom = this.coreImportsFrom; + this._importRewriter = coreImportsFrom !== null ? + new R3SymbolsImportRewriter(coreImportsFrom.fileName) : + new NoopImportRewriter(); + } + return this._importRewriter; + } } const defaultEmitCallback: api.TsEmitCallback = @@ -345,3 +468,21 @@ function isAngularCorePackage(program: ts.Program): boolean { }); }); } + +export class ReferenceGraphAdapter implements ReferencesRegistry { + constructor(private graph: ReferenceGraph) {} + + add(source: ts.Declaration, ...references: Reference[]): void { + for (const {node} of references) { + let sourceFile = node.getSourceFile(); + if (sourceFile === undefined) { + sourceFile = ts.getOriginalNode(node).getSourceFile(); + } + + // Only record local references (not references into .d.ts files). + if (sourceFile === undefined || !isDtsPath(sourceFile.fileName)) { + this.graph.add(source, node); + } + } + } +} diff --git a/packages/compiler-cli/src/ngtsc/host/BUILD.bazel b/packages/compiler-cli/src/ngtsc/reflection/BUILD.bazel similarity index 73% rename from packages/compiler-cli/src/ngtsc/host/BUILD.bazel rename to packages/compiler-cli/src/ngtsc/reflection/BUILD.bazel index b0cfa74ad6..6047781396 100644 --- a/packages/compiler-cli/src/ngtsc/host/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/reflection/BUILD.bazel @@ -3,11 +3,10 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "ts_library") ts_library( - name = "host", + name = "reflection", srcs = glob([ "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/host", deps = ["@ngdeps//typescript"], ) diff --git a/packages/compiler-cli/src/ngtsc/reflection/index.ts b/packages/compiler-cli/src/ngtsc/reflection/index.ts new file mode 100644 index 0000000000..d5615ed5ac --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/reflection/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export * from './src/host'; +export {TypeScriptReflectionHost, filterToMembersWithDecorator, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectObjectLiteral, reflectTypeEntityToDeclaration, typeNodeToValueExpr} from './src/typescript'; \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/host/src/reflection.ts b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts similarity index 99% rename from packages/compiler-cli/src/ngtsc/host/src/reflection.ts rename to packages/compiler-cli/src/ngtsc/reflection/src/host.ts index c82cadd190..c8b5512694 100644 --- a/packages/compiler-cli/src/ngtsc/host/src/reflection.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts @@ -425,6 +425,9 @@ export interface ReflectionHost { */ isClass(node: ts.Node): node is ts.NamedDeclaration; + /** + * Determines whether the given declaration has a base class. + */ hasBaseClass(node: ts.Declaration): boolean; /** diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts similarity index 99% rename from packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts rename to packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts index 2211a54a2a..460a1e3eea 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost} from '../../host'; +import {ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost} from './host'; /** * reflector.ts implements static reflection of declarations using the TypeScript `ts.TypeChecker`. diff --git a/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel new file mode 100644 index 0000000000..c9301bc16d --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel @@ -0,0 +1,26 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob([ + "**/*.ts", + ]), + deps = [ + "//packages:types", + "//packages/compiler-cli/src/ngtsc/reflection", + "//packages/compiler-cli/src/ngtsc/testing", + "@ngdeps//typescript", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + deps = [ + ":test_lib", + "//tools/testing:node_no_angular", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/metadata/test/reflector_spec.ts b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts similarity index 98% rename from packages/compiler-cli/src/ngtsc/metadata/test/reflector_spec.ts rename to packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts index d8d2c3c2e9..e9e596b434 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/test/reflector_spec.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts @@ -8,9 +8,9 @@ import * as ts from 'typescript'; -import {CtorParameter} from '../../host'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; -import {TypeScriptReflectionHost} from '../src/reflector'; +import {CtorParameter} from '../src/host'; +import {TypeScriptReflectionHost} from '../src/typescript'; describe('reflector', () => { describe('ctor params', () => { diff --git a/packages/compiler-cli/src/ngtsc/resource_loader.ts b/packages/compiler-cli/src/ngtsc/resource_loader.ts index 5986795d97..f728565ff8 100644 --- a/packages/compiler-cli/src/ngtsc/resource_loader.ts +++ b/packages/compiler-cli/src/ngtsc/resource_loader.ts @@ -8,8 +8,8 @@ import * as fs from 'fs'; import * as ts from 'typescript'; - -import {ResourceLoader} from './annotations'; +import {CompilerHost} from '../transformers/api'; +import {ResourceLoader} from './annotations/src/api'; /** * `ResourceLoader` which delegates to a `CompilerHost` resource loading method. @@ -18,107 +18,141 @@ export class HostResourceLoader implements ResourceLoader { private cache = new Map(); private fetching = new Map>(); - constructor( - private resolver: (file: string, basePath: string) => string | null, - private loader: (url: string) => string | Promise) {} + canPreload = !!this.host.readResource; - preload(file: string, containingFile: string): Promise|undefined { - const resolved = this.resolver(file, containingFile); - if (resolved === null) { + constructor(private host: CompilerHost, private options: ts.CompilerOptions) {} + + /** + * Resolve the url of a resource relative to the file that contains the reference to it. + * The return value of this method can be used in the `load()` and `preload()` methods. + * + * Uses the provided CompilerHost if it supports mapping resources to filenames. + * Otherwise, uses a fallback mechanism that searches the module resolution candidates. + * + * @param url The, possibly relative, url of the resource. + * @param fromFile The path to the file that contains the URL of the resource. + * @returns A resolved url of resource. + * @throws An error if the resource cannot be resolved. + */ + resolve(url: string, fromFile: string): string { + let resolvedUrl: string|null = null; + if (this.host.resourceNameToFileName) { + resolvedUrl = this.host.resourceNameToFileName(url, fromFile); + } else { + resolvedUrl = this.fallbackResolve(url, fromFile); + } + if (resolvedUrl === null) { + throw new Error(`HostResourceResolver: could not resolve ${url} in context of ${fromFile})`); + } + return resolvedUrl; + } + + /** + * Preload the specified resource, asynchronously. + * + * Once the resource is loaded, its value is cached so it can be accessed synchronously via the + * `load()` method. + * + * @param resolvedUrl The url (resolved by a call to `resolve()`) of the resource to preload. + * @returns A Promise that is resolved once the resource has been loaded or `undefined` if the + * file has already been loaded. + * @throws An Error if pre-loading is not available. + */ + preload(resolvedUrl: string): Promise|undefined { + if (!this.host.readResource) { + throw new Error( + 'HostResourceLoader: the CompilerHost provided does not support pre-loading resources.'); + } + if (this.cache.has(resolvedUrl)) { return undefined; + } else if (this.fetching.has(resolvedUrl)) { + return this.fetching.get(resolvedUrl); } - if (this.cache.has(resolved)) { - return undefined; - } else if (this.fetching.has(resolved)) { - return this.fetching.get(resolved); - } - - const result = this.loader(resolved); + const result = this.host.readResource(resolvedUrl); if (typeof result === 'string') { - this.cache.set(resolved, result); + this.cache.set(resolvedUrl, result); return undefined; } else { const fetchCompletion = result.then(str => { - this.fetching.delete(resolved); - this.cache.set(resolved, str); + this.fetching.delete(resolvedUrl); + this.cache.set(resolvedUrl, str); }); - this.fetching.set(resolved, fetchCompletion); + this.fetching.set(resolvedUrl, fetchCompletion); return fetchCompletion; } } - load(file: string, containingFile: string): string { - const resolved = this.resolver(file, containingFile); - if (resolved === null) { - throw new Error( - `HostResourceLoader: could not resolve ${file} in context of ${containingFile})`); + /** + * Load the resource at the given url, synchronously. + * + * The contents of the resource may have been cached by a previous call to `preload()`. + * + * @param resolvedUrl The url (resolved by a call to `resolve()`) of the resource to load. + * @returns The contents of the resource. + */ + load(resolvedUrl: string): string { + if (this.cache.has(resolvedUrl)) { + return this.cache.get(resolvedUrl) !; } - if (this.cache.has(resolved)) { - return this.cache.get(resolved) !; - } - - const result = this.loader(resolved); + const result = this.host.readResource ? this.host.readResource(resolvedUrl) : + fs.readFileSync(resolvedUrl, 'utf8'); if (typeof result !== 'string') { - throw new Error(`HostResourceLoader: loader(${resolved}) returned a Promise`); + throw new Error(`HostResourceLoader: loader(${resolvedUrl}) returned a Promise`); } - this.cache.set(resolved, result); + this.cache.set(resolvedUrl, result); return result; } -} - - - -// `failedLookupLocations` is in the name of the type ts.ResolvedModuleWithFailedLookupLocations -// but is marked @internal in TypeScript. See https://github.com/Microsoft/TypeScript/issues/28770. -type ResolvedModuleWithFailedLookupLocations = - ts.ResolvedModuleWithFailedLookupLocations & {failedLookupLocations: ReadonlyArray}; - -/** - * `ResourceLoader` which directly uses the filesystem to resolve resources synchronously. - */ -export class FileResourceLoader implements ResourceLoader { - constructor(private host: ts.CompilerHost, private options: ts.CompilerOptions) {} - - load(file: string, containingFile: string): string { - // Attempt to resolve `file` in the context of `containingFile`, while respecting the rootDirs - // option from the tsconfig. First, normalize the file name. + /** + * Attempt to resolve `url` in the context of `fromFile`, while respecting the rootDirs + * option from the tsconfig. First, normalize the file name. + */ + private fallbackResolve(url: string, fromFile: string): string|null { // Strip a leading '/' if one is present. - if (file.startsWith('/')) { - file = file.substr(1); + if (url.startsWith('/')) { + url = url.substr(1); } // Turn absolute paths into relative paths. - if (!file.startsWith('.')) { - file = `./${file}`; + if (!url.startsWith('.')) { + url = `./${url}`; } - // TypeScript provides utilities to resolve module names, but not resource files (which aren't - // a part of the ts.Program). However, TypeScript's module resolution can be used creatively - // to locate where resource files should be expected to exist. Since module resolution returns - // a list of file names that were considered, the loader can enumerate the possible locations - // for the file by setting up a module resolution for it that will fail. - file += '.$ngresource$'; + const candidateLocations = this.getCandidateLocations(url, fromFile); + for (const candidate of candidateLocations) { + if (fs.existsSync(candidate)) { + return candidate; + } + } + return null; + } + + + /** + * TypeScript provides utilities to resolve module names, but not resource files (which aren't + * a part of the ts.Program). However, TypeScript's module resolution can be used creatively + * to locate where resource files should be expected to exist. Since module resolution returns + * a list of file names that were considered, the loader can enumerate the possible locations + * for the file by setting up a module resolution for it that will fail. + */ + private getCandidateLocations(url: string, fromFile: string): string[] { + // `failedLookupLocations` is in the name of the type ts.ResolvedModuleWithFailedLookupLocations + // but is marked @internal in TypeScript. See + // https://github.com/Microsoft/TypeScript/issues/28770. + type ResolvedModuleWithFailedLookupLocations = + ts.ResolvedModuleWithFailedLookupLocations & {failedLookupLocations: ReadonlyArray}; // clang-format off - const failedLookup = ts.resolveModuleName(file, containingFile, this.options, this.host) as ResolvedModuleWithFailedLookupLocations; + const failedLookup = ts.resolveModuleName(url + '.$ngresource$', fromFile, this.options, this.host) as ResolvedModuleWithFailedLookupLocations; // clang-format on if (failedLookup.failedLookupLocations === undefined) { throw new Error( - `Internal error: expected to find failedLookupLocations during resolution of resource '${file}' in context of ${containingFile}`); + `Internal error: expected to find failedLookupLocations during resolution of resource '${url}' in context of ${fromFile}`); } - const candidateLocations = - failedLookup.failedLookupLocations - .filter(candidate => candidate.endsWith('.$ngresource$.ts')) - .map(candidate => candidate.replace(/\.\$ngresource\$\.ts$/, '')); - - for (const candidate of candidateLocations) { - if (fs.existsSync(candidate)) { - return fs.readFileSync(candidate, 'utf8'); - } - } - throw new Error(`Could not find resource ${file} in context of ${containingFile}`); + return failedLookup.failedLookupLocations + .filter(candidate => candidate.endsWith('.$ngresource$.ts')) + .map(candidate => candidate.replace(/\.\$ngresource\$\.ts$/, '')); } } diff --git a/packages/compiler-cli/src/ngtsc/routing/BUILD.bazel b/packages/compiler-cli/src/ngtsc/routing/BUILD.bazel new file mode 100644 index 0000000000..7d96c18bd7 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/routing/BUILD.bazel @@ -0,0 +1,19 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "routing", + srcs = glob([ + "index.ts", + "src/**/*.ts", + ]), + module_name = "@angular/compiler-cli/src/ngtsc/routing", + deps = [ + "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "@ngdeps//@types/node", + "@ngdeps//typescript", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/routing/index.ts b/packages/compiler-cli/src/ngtsc/routing/index.ts new file mode 100644 index 0000000000..fbab4f94c7 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/routing/index.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/// + +export {LazyRoute, NgModuleRouteAnalyzer} from './src/analyzer'; +export {entryPointKeyFor} from './src/route'; diff --git a/packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts b/packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts new file mode 100644 index 0000000000..d6ef4b4020 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts @@ -0,0 +1,100 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ModuleResolver} from '../../imports'; +import {PartialEvaluator} from '../../partial_evaluator'; + +import {scanForCandidateTransitiveModules, scanForRouteEntryPoints} from './lazy'; +import {RouterEntryPointManager, entryPointKeyFor} from './route'; + +export interface NgModuleRawRouteData { + sourceFile: ts.SourceFile; + moduleName: string; + imports: ts.Expression|null; + exports: ts.Expression|null; + providers: ts.Expression|null; +} + +export interface LazyRoute { + route: string; + module: {name: string, filePath: string}; + referencedModule: {name: string, filePath: string}; +} + +export class NgModuleRouteAnalyzer { + private modules = new Map(); + private entryPointManager: RouterEntryPointManager; + + constructor(moduleResolver: ModuleResolver, private evaluator: PartialEvaluator) { + this.entryPointManager = new RouterEntryPointManager(moduleResolver); + } + + add(sourceFile: ts.SourceFile, moduleName: string, imports: ts.Expression|null, + exports: ts.Expression|null, providers: ts.Expression|null): void { + const key = entryPointKeyFor(sourceFile.fileName, moduleName); + if (this.modules.has(key)) { + throw new Error(`Double route analyzing for '${key}'.`); + } + this.modules.set( + key, { + sourceFile, moduleName, imports, exports, providers, + }); + } + + listLazyRoutes(entryModuleKey?: string|undefined): LazyRoute[] { + if ((entryModuleKey !== undefined) && !this.modules.has(entryModuleKey)) { + throw new Error(`Failed to list lazy routes: Unknown module '${entryModuleKey}'.`); + } + + const routes: LazyRoute[] = []; + const scannedModuleKeys = new Set(); + const pendingModuleKeys = entryModuleKey ? [entryModuleKey] : Array.from(this.modules.keys()); + + // When listing lazy routes for a specific entry module, we need to recursively extract + // "transitive" routes from imported/exported modules. This is not necessary when listing all + // lazy routes, because all analyzed modules will be scanned anyway. + const scanRecursively = entryModuleKey !== undefined; + + while (pendingModuleKeys.length > 0) { + const key = pendingModuleKeys.pop() !; + + if (scannedModuleKeys.has(key)) { + continue; + } else { + scannedModuleKeys.add(key); + } + + const data = this.modules.get(key) !; + const entryPoints = scanForRouteEntryPoints( + data.sourceFile, data.moduleName, data, this.entryPointManager, this.evaluator); + + routes.push(...entryPoints.map(entryPoint => ({ + route: entryPoint.loadChildren, + module: entryPoint.from, + referencedModule: entryPoint.resolvedTo, + }))); + + if (scanRecursively) { + pendingModuleKeys.push( + ...[ + // Scan the retrieved lazy route entry points. + ...entryPoints.map( + ({resolvedTo}) => entryPointKeyFor(resolvedTo.filePath, resolvedTo.moduleName)), + // Scan the current module's imported modules. + ...scanForCandidateTransitiveModules(data.imports, this.evaluator), + // Scan the current module's exported modules. + ...scanForCandidateTransitiveModules(data.exports, this.evaluator), + ].filter(key => this.modules.has(key))); + } + } + + return routes; + } +} diff --git a/packages/compiler-cli/src/ngtsc/routing/src/lazy.ts b/packages/compiler-cli/src/ngtsc/routing/src/lazy.ts new file mode 100644 index 0000000000..3e1eb580c3 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/routing/src/lazy.ts @@ -0,0 +1,200 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {Reference} from '../../imports'; +import {ForeignFunctionResolver, PartialEvaluator, ResolvedValue} from '../../partial_evaluator'; + +import {NgModuleRawRouteData} from './analyzer'; +import {RouterEntryPoint, RouterEntryPointManager, entryPointKeyFor} from './route'; + +const ROUTES_MARKER = '__ngRoutesMarker__'; + +export interface LazyRouteEntry { + loadChildren: string; + from: RouterEntryPoint; + resolvedTo: RouterEntryPoint; +} + +export function scanForCandidateTransitiveModules( + expr: ts.Expression | null, evaluator: PartialEvaluator): string[] { + if (expr === null) { + return []; + } + + const candidateModuleKeys: string[] = []; + const entries = evaluator.evaluate(expr); + + function recursivelyAddModules(entry: ResolvedValue) { + if (Array.isArray(entry)) { + for (const e of entry) { + recursivelyAddModules(e); + } + } else if (entry instanceof Map) { + if (entry.has('ngModule')) { + recursivelyAddModules(entry.get('ngModule') !); + } + } else if ((entry instanceof Reference) && hasIdentifier(entry.node)) { + const filePath = entry.node.getSourceFile().fileName; + const moduleName = entry.node.name.text; + candidateModuleKeys.push(entryPointKeyFor(filePath, moduleName)); + } + } + + recursivelyAddModules(entries); + return candidateModuleKeys; +} + +export function scanForRouteEntryPoints( + ngModule: ts.SourceFile, moduleName: string, data: NgModuleRawRouteData, + entryPointManager: RouterEntryPointManager, evaluator: PartialEvaluator): LazyRouteEntry[] { + const loadChildrenIdentifiers: string[] = []; + const from = entryPointManager.fromNgModule(ngModule, moduleName); + if (data.providers !== null) { + loadChildrenIdentifiers.push(...scanForProviders(data.providers, evaluator)); + } + if (data.imports !== null) { + loadChildrenIdentifiers.push(...scanForRouterModuleUsage(data.imports, evaluator)); + } + if (data.exports !== null) { + loadChildrenIdentifiers.push(...scanForRouterModuleUsage(data.exports, evaluator)); + } + const routes: LazyRouteEntry[] = []; + for (const loadChildren of loadChildrenIdentifiers) { + const resolvedTo = entryPointManager.resolveLoadChildrenIdentifier(loadChildren, ngModule); + if (resolvedTo !== null) { + routes.push({ + loadChildren, from, resolvedTo, + }); + } + } + return routes; +} + +function scanForProviders(expr: ts.Expression, evaluator: PartialEvaluator): string[] { + const loadChildrenIdentifiers: string[] = []; + const providers = evaluator.evaluate(expr); + + function recursivelyAddProviders(provider: ResolvedValue): void { + if (Array.isArray(provider)) { + for (const entry of provider) { + recursivelyAddProviders(entry); + } + } else if (provider instanceof Map) { + if (provider.has('provide') && provider.has('useValue')) { + const provide = provider.get('provide'); + const useValue = provider.get('useValue'); + if (isRouteToken(provide) && Array.isArray(useValue)) { + loadChildrenIdentifiers.push(...scanForLazyRoutes(useValue)); + } + } + } + } + + recursivelyAddProviders(providers); + return loadChildrenIdentifiers; +} + +function scanForRouterModuleUsage(expr: ts.Expression, evaluator: PartialEvaluator): string[] { + const loadChildrenIdentifiers: string[] = []; + const imports = evaluator.evaluate(expr, routerModuleFFR); + + function recursivelyAddRoutes(imp: ResolvedValue) { + if (Array.isArray(imp)) { + for (const entry of imp) { + recursivelyAddRoutes(entry); + } + } else if (imp instanceof Map) { + if (imp.has(ROUTES_MARKER) && imp.has('routes')) { + const routes = imp.get('routes'); + if (Array.isArray(routes)) { + loadChildrenIdentifiers.push(...scanForLazyRoutes(routes)); + } + } + } + } + + recursivelyAddRoutes(imports); + return loadChildrenIdentifiers; +} + +function scanForLazyRoutes(routes: ResolvedValue[]): string[] { + const loadChildrenIdentifiers: string[] = []; + + function recursivelyScanRoutes(routes: ResolvedValue[]): void { + for (let route of routes) { + if (!(route instanceof Map)) { + continue; + } + if (route.has('loadChildren')) { + const loadChildren = route.get('loadChildren'); + if (typeof loadChildren === 'string') { + loadChildrenIdentifiers.push(loadChildren); + } + } else if (route.has('children')) { + const children = route.get('children'); + if (Array.isArray(children)) { + recursivelyScanRoutes(children); + } + } + } + } + + recursivelyScanRoutes(routes); + return loadChildrenIdentifiers; +} + +/** + * A foreign function resolver that converts `RouterModule.forRoot/forChild(X)` to a special object + * of the form `{__ngRoutesMarker__: true, routes: X}`. + * + * These objects are then recognizable inside the larger set of imports/exports. + */ +const routerModuleFFR: ForeignFunctionResolver = + function routerModuleFFR( + ref: Reference, + args: ReadonlyArray): ts.Expression | + null { + if (!isMethodNodeReference(ref) || !ts.isClassDeclaration(ref.node.parent)) { + return null; + } else if ( + ref.bestGuessOwningModule === null || + ref.bestGuessOwningModule.specifier !== '@angular/router') { + return null; + } else if ( + ref.node.parent.name === undefined || ref.node.parent.name.text !== 'RouterModule') { + return null; + } else if ( + !ts.isIdentifier(ref.node.name) || + (ref.node.name.text !== 'forRoot' && ref.node.name.text !== 'forChild')) { + return null; + } + + const routes = args[0]; + return ts.createObjectLiteral([ + ts.createPropertyAssignment(ROUTES_MARKER, ts.createTrue()), + ts.createPropertyAssignment('routes', routes), + ]); + }; + +function hasIdentifier(node: ts.Node): node is ts.Node&{name: ts.Identifier} { + const node_ = node as ts.NamedDeclaration; + return (node_.name !== undefined) && ts.isIdentifier(node_.name); +} + +function isMethodNodeReference( + ref: Reference): + ref is Reference { + return ts.isMethodDeclaration(ref.node); +} + +function isRouteToken(ref: ResolvedValue): boolean { + return ref instanceof Reference && ref.bestGuessOwningModule !== null && + ref.bestGuessOwningModule.specifier === '@angular/router' && ref.debugName === 'ROUTES'; +} diff --git a/packages/compiler-cli/src/ngtsc/routing/src/route.ts b/packages/compiler-cli/src/ngtsc/routing/src/route.ts new file mode 100644 index 0000000000..8c8a5bb7af --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/routing/src/route.ts @@ -0,0 +1,61 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ModuleResolver} from '../../imports'; + +export abstract class RouterEntryPoint { + abstract readonly filePath: string; + + abstract readonly moduleName: string; + + // Alias of moduleName for compatibility with what `ngtools_api` returned. + abstract readonly name: string; +} + +class RouterEntryPointImpl implements RouterEntryPoint { + constructor(readonly filePath: string, readonly moduleName: string) {} + + get name(): string { return this.moduleName; } + + // For debugging purposes. + toString(): string { return `RouterEntryPoint(name: ${this.name}, filePath: ${this.filePath})`; } +} + +export class RouterEntryPointManager { + private map = new Map(); + + constructor(private moduleResolver: ModuleResolver) {} + + resolveLoadChildrenIdentifier(loadChildrenIdentifier: string, context: ts.SourceFile): + RouterEntryPoint|null { + const [relativeFile, moduleName] = loadChildrenIdentifier.split('#'); + if (moduleName === undefined) { + return null; + } + const resolvedSf = this.moduleResolver.resolveModuleName(relativeFile, context); + if (resolvedSf === null) { + return null; + } + return this.fromNgModule(resolvedSf, moduleName); + } + + fromNgModule(sf: ts.SourceFile, moduleName: string): RouterEntryPoint { + const key = entryPointKeyFor(sf.fileName, moduleName); + if (!this.map.has(key)) { + this.map.set(key, new RouterEntryPointImpl(sf.fileName, moduleName)); + } + return this.map.get(key) !; + } +} + +export function entryPointKeyFor(filePath: string, moduleName: string): string { + // Drop the extension to be compatible with how cli calls `listLazyRoutes(entryRoute)`. + return `${filePath.replace(/\.tsx?$/i, '')}#${moduleName}`; +} diff --git a/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel b/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel index 68e66fb562..7f8e78488e 100644 --- a/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/shims/BUILD.bazel @@ -8,11 +8,9 @@ ts_library( "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/shims", deps = [ "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//@types/node", "@ngdeps//typescript", diff --git a/packages/compiler-cli/src/ngtsc/shims/index.ts b/packages/compiler-cli/src/ngtsc/shims/index.ts index 115b80d8f9..25e731d29e 100644 --- a/packages/compiler-cli/src/ngtsc/shims/index.ts +++ b/packages/compiler-cli/src/ngtsc/shims/index.ts @@ -9,6 +9,5 @@ /// export {FactoryGenerator, FactoryInfo, generatedFactoryTransform} from './src/factory_generator'; -export {FlatIndexGenerator} from './src/flat_index_generator'; export {GeneratedShimsHostWrapper, ShimGenerator} from './src/host'; export {SummaryGenerator} from './src/summary_generator'; diff --git a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts index 90829bbaac..c32a288ca3 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts @@ -9,10 +9,12 @@ import * as path from 'path'; import * as ts from 'typescript'; -import {relativePathBetween} from '../../util/src/path'; +import {ImportRewriter} from '../../imports'; +import {normalizeSeparators} from '../../util/src/path'; +import {isNonDeclarationTsPath} from '../../util/src/typescript'; import {ShimGenerator} from './host'; -import {generatedModuleName, isNonDeclarationTsFile} from './util'; +import {generatedModuleName} from './util'; const TS_DTS_SUFFIX = /(\.d)?\.ts$/; const STRIP_NG_FACTORY = /(.*)NgFactory$/; @@ -87,7 +89,8 @@ export class FactoryGenerator implements ShimGenerator { static forRootFiles(files: ReadonlyArray): FactoryGenerator { const map = new Map(); - files.filter(sourceFile => isNonDeclarationTsFile(sourceFile)) + files.filter(sourceFile => isNonDeclarationTsPath(sourceFile)) + .map(sourceFile => normalizeSeparators(sourceFile)) .forEach(sourceFile => map.set(sourceFile.replace(/\.ts$/, '.ngfactory.ts'), sourceFile)); return new FactoryGenerator(map); } @@ -105,17 +108,17 @@ export interface FactoryInfo { export function generatedFactoryTransform( factoryMap: Map, - coreImportsFrom: ts.SourceFile | null): ts.TransformerFactory { + importRewriter: ImportRewriter): ts.TransformerFactory { return (context: ts.TransformationContext): ts.Transformer => { return (file: ts.SourceFile): ts.SourceFile => { - return transformFactorySourceFile(factoryMap, context, coreImportsFrom, file); + return transformFactorySourceFile(factoryMap, context, importRewriter, file); }; }; } function transformFactorySourceFile( factoryMap: Map, context: ts.TransformationContext, - coreImportsFrom: ts.SourceFile | null, file: ts.SourceFile): ts.SourceFile { + importRewriter: ImportRewriter, file: ts.SourceFile): ts.SourceFile { // If this is not a generated file, it won't have factory info associated with it. if (!factoryMap.has(file.fileName)) { // Don't transform non-generated code. @@ -124,7 +127,7 @@ function transformFactorySourceFile( const {moduleSymbolNames, sourceFilePath} = factoryMap.get(file.fileName) !; - const clone = ts.getMutableClone(file); + file = ts.getMutableClone(file); // Not every exported factory statement is valid. They were generated before the program was // analyzed, and before ngtsc knew which symbols were actually NgModules. factoryMap contains @@ -145,17 +148,30 @@ function transformFactorySourceFile( // The statement identified as the ɵNonEmptyModule export. let nonEmptyExport: ts.Statement|null = null; + // Extracted identifiers which refer to import statements from @angular/core. + const coreImportIdentifiers = new Set(); + // Consider all the statements. for (const stmt of file.statements) { // Look for imports to @angular/core. - if (coreImportsFrom !== null && ts.isImportDeclaration(stmt) && - ts.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text === '@angular/core') { - // Update the import path to point to the correct file (coreImportsFrom). - const path = relativePathBetween(sourceFilePath, coreImportsFrom.fileName); - if (path !== null) { + if (ts.isImportDeclaration(stmt) && ts.isStringLiteral(stmt.moduleSpecifier) && + stmt.moduleSpecifier.text === '@angular/core') { + // Update the import path to point to the correct file using the ImportRewriter. + const rewrittenModuleSpecifier = + importRewriter.rewriteSpecifier('@angular/core', sourceFilePath); + if (rewrittenModuleSpecifier !== stmt.moduleSpecifier.text) { transformedStatements.push(ts.updateImportDeclaration( stmt, stmt.decorators, stmt.modifiers, stmt.importClause, - ts.createStringLiteral(path))); + ts.createStringLiteral(rewrittenModuleSpecifier))); + + // Record the identifier by which this imported module goes, so references to its symbols + // can be discovered later. + if (stmt.importClause !== undefined && stmt.importClause.namedBindings !== undefined && + ts.isNamespaceImport(stmt.importClause.namedBindings)) { + coreImportIdentifiers.add(stmt.importClause.namedBindings.name.text); + } + } else { + transformedStatements.push(stmt); } } else if (ts.isVariableStatement(stmt) && stmt.declarationList.declarations.length === 1) { const decl = stmt.declarationList.declarations[0]; @@ -188,6 +204,31 @@ function transformFactorySourceFile( // satisfy closure compiler. transformedStatements.push(nonEmptyExport); } - clone.statements = ts.createNodeArray(transformedStatements); - return clone; + file.statements = ts.createNodeArray(transformedStatements); + + // If any imports to @angular/core were detected and rewritten (which happens when compiling + // @angular/core), go through the SourceFile and rewrite references to symbols imported from core. + if (coreImportIdentifiers.size > 0) { + const visit = (node: T): T => { + node = ts.visitEachChild(node, child => visit(child), context); + + // Look for expressions of the form "i.s" where 'i' is a detected name for an @angular/core + // import that was changed above. Rewrite 's' using the ImportResolver. + if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression) && + coreImportIdentifiers.has(node.expression.text)) { + // This is an import of a symbol from @angular/core. Transform it with the importRewriter. + const rewrittenSymbol = importRewriter.rewriteSymbol(node.name.text, '@angular/core'); + if (rewrittenSymbol !== node.name.text) { + const updated = + ts.updatePropertyAccess(node, node.expression, ts.createIdentifier(rewrittenSymbol)); + node = updated as T & ts.PropertyAccessExpression; + } + } + return node; + }; + + file = visit(file); + } + + return file; } diff --git a/packages/compiler-cli/src/ngtsc/shims/src/flat_index_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/flat_index_generator.ts deleted file mode 100644 index f44296b836..0000000000 --- a/packages/compiler-cli/src/ngtsc/shims/src/flat_index_generator.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as path from 'path'; -import * as ts from 'typescript'; - -import {ShimGenerator} from './host'; -import {isNonDeclarationTsFile} from './util'; - -export class FlatIndexGenerator implements ShimGenerator { - readonly flatIndexPath: string; - - private constructor( - relativeFlatIndexPath: string, readonly entryPoint: string, - readonly moduleName: string|null) { - this.flatIndexPath = path.posix.join(path.posix.dirname(entryPoint), relativeFlatIndexPath) - .replace(/\.js$/, '') + - '.ts'; - } - - static forRootFiles(flatIndexPath: string, files: ReadonlyArray, moduleName: string|null): - FlatIndexGenerator|null { - // If there's only one .ts file in the program, it's the entry. Otherwise, look for the shortest - // (in terms of characters in the filename) file that ends in /index.ts. The second behavior is - // deprecated; users should always explicitly specify a single .ts entrypoint. - const tsFiles = files.filter(isNonDeclarationTsFile); - if (tsFiles.length === 1) { - return new FlatIndexGenerator(flatIndexPath, tsFiles[0], moduleName); - } else { - let indexFile: string|null = null; - for (const tsFile of tsFiles) { - if (tsFile.endsWith('/index.ts') && - (indexFile === null || tsFile.length <= indexFile.length)) { - indexFile = tsFile; - } - } - if (indexFile !== null) { - return new FlatIndexGenerator(flatIndexPath, indexFile, moduleName); - } else { - return null; - } - } - } - - recognize(fileName: string): boolean { return fileName === this.flatIndexPath; } - - generate(): ts.SourceFile { - const relativeEntryPoint = './' + - path.posix.relative(path.posix.dirname(this.flatIndexPath), this.entryPoint) - .replace(/\.tsx?$/, ''); - - const contents = `/** - * Generated bundle index. Do not edit. - */ - -export * from '${relativeEntryPoint}'; -`; - const genFile = ts.createSourceFile( - this.flatIndexPath, contents, ts.ScriptTarget.ES2015, true, ts.ScriptKind.TS); - if (this.moduleName !== null) { - genFile.moduleName = this.moduleName; - } - return genFile; - } -} diff --git a/packages/compiler-cli/src/ngtsc/shims/src/host.ts b/packages/compiler-cli/src/ngtsc/shims/src/host.ts index 4bcf98e2f8..5dcf0af8dc 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/host.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import * as path from 'path'; import * as ts from 'typescript'; export interface ShimGenerator { diff --git a/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts index 158f0fdba6..ef14fae7b7 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts @@ -8,8 +8,11 @@ import * as ts from 'typescript'; +import {normalizeSeparators} from '../../util/src/path'; +import {isNonDeclarationTsPath} from '../../util/src/typescript'; + import {ShimGenerator} from './host'; -import {generatedModuleName, isNonDeclarationTsFile} from './util'; +import {generatedModuleName} from './util'; export class SummaryGenerator implements ShimGenerator { private constructor(private map: Map) {} @@ -61,7 +64,8 @@ export class SummaryGenerator implements ShimGenerator { static forRootFiles(files: ReadonlyArray): SummaryGenerator { const map = new Map(); - files.filter(sourceFile => isNonDeclarationTsFile(sourceFile)) + files.filter(sourceFile => isNonDeclarationTsPath(sourceFile)) + .map(sourceFile => normalizeSeparators(sourceFile)) .forEach(sourceFile => map.set(sourceFile.replace(/\.ts$/, '.ngsummary.ts'), sourceFile)); return new SummaryGenerator(map); } diff --git a/packages/compiler-cli/src/ngtsc/shims/src/util.ts b/packages/compiler-cli/src/ngtsc/shims/src/util.ts index d791258db6..6d76f20a10 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/util.ts @@ -6,16 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import * as path from 'path'; -import * as ts from 'typescript'; - -const TS_FILE = /\.tsx?$/; -const D_TS_FILE = /\.d\.ts$/; - -export function isNonDeclarationTsFile(file: string): boolean { - return TS_FILE.exec(file) !== null && D_TS_FILE.exec(file) === null; -} - export function generatedModuleName( originalModuleName: string, originalFileName: string, genSuffix: string): string { let moduleName: string; diff --git a/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel b/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel index 59b24432f9..e5f9ad5d80 100644 --- a/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/switch/BUILD.bazel @@ -8,12 +8,8 @@ ts_library( "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/switch", deps = [ "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", - "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//typescript", ], ) diff --git a/packages/compiler-cli/src/ngtsc/synthetic_files_compiler_host.ts b/packages/compiler-cli/src/ngtsc/synthetic_files_compiler_host.ts new file mode 100644 index 0000000000..296927fe14 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/synthetic_files_compiler_host.ts @@ -0,0 +1,96 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {PluginCompilerHost} from '@bazel/typescript/internal/tsc_wrapped/plugin_api'; +import * as ts from 'typescript'; + +/** + * Extension of the TypeScript compiler host that supports files added to the Program which + * were never on disk. + * + * This is used for backwards-compatibility with the ViewEngine compiler, which used ngsummary + * and ngfactory files as inputs to the program. We call these inputs "synthetic". + * + * They need to be program inputs because user code may import from these generated files. + * + * TODO(alxhub): remove this after all ng_module users have migrated to Ivy + */ +export class SyntheticFilesCompilerHost implements PluginCompilerHost { + /** + * SourceFiles which are added to the program but which never existed on disk. + */ + syntheticFiles = new Map(); + + constructor( + private rootFiles: string[], private delegate: ts.CompilerHost, + generatedFiles: (rootFiles: string[]) => { + [fileName: string]: (host: ts.CompilerHost) => ts.SourceFile | undefined + }) { + // Allow ngtsc to contribute in-memory synthetic files, which will be loaded + // as if they existed on disk as action inputs. + const angularGeneratedFiles = generatedFiles !(rootFiles); + for (const f of Object.keys(angularGeneratedFiles)) { + const generator = angularGeneratedFiles[f]; + const generated = generator(delegate); + if (generated) { + this.syntheticFiles.set(generated.fileName, generated); + } + } + } + + fileExists(filePath: string): boolean { + if (this.syntheticFiles.has(filePath)) { + return true; + } + return this.delegate.fileExists(filePath); + } + + /** Loads a source file from in-memory map, or delegates. */ + getSourceFile( + fileName: string, languageVersion: ts.ScriptTarget, + onError?: (message: string) => void): ts.SourceFile|undefined { + const syntheticFile = this.syntheticFiles.get(fileName); + if (syntheticFile) { + return syntheticFile !; + } + return this.delegate.getSourceFile(fileName, languageVersion, onError); + } + + get inputFiles() { return [...this.rootFiles, ...Array.from(this.syntheticFiles.keys())]; } + + fileNameToModuleId(fileName: string) { + return fileName; // TODO: Ivy logic. don't forget that the delegate has the google3 logic + } + + // Delegate everything else to the original compiler host. + + getDefaultLibFileName(options: ts.CompilerOptions): string { + return this.delegate.getDefaultLibFileName(options); + } + + writeFile( + fileName: string, content: string, writeByteOrderMark: boolean, + onError: ((message: string) => void)|undefined, + sourceFiles: ReadonlyArray|undefined): void { + this.delegate.writeFile(fileName, content, writeByteOrderMark, onError, sourceFiles); + } + + getCanonicalFileName(path: string) { return this.delegate.getCanonicalFileName(path); } + + getCurrentDirectory(): string { return this.delegate.getCurrentDirectory(); } + + useCaseSensitiveFileNames(): boolean { return this.delegate.useCaseSensitiveFileNames(); } + + getNewLine(): string { return this.delegate.getNewLine(); } + + getDirectories(path: string) { return this.delegate.getDirectories(path); } + + readFile(fileName: string): string|undefined { return this.delegate.readFile(fileName); } + + trace(s: string): void { console.error(s); } +} diff --git a/packages/compiler-cli/src/ngtsc/testing/in_memory_typescript.ts b/packages/compiler-cli/src/ngtsc/testing/in_memory_typescript.ts index 36a5b90b0d..9bbdf1f2c2 100644 --- a/packages/compiler-cli/src/ngtsc/testing/in_memory_typescript.ts +++ b/packages/compiler-cli/src/ngtsc/testing/in_memory_typescript.ts @@ -13,19 +13,18 @@ import * as ts from 'typescript'; export function makeProgram( files: {name: string, contents: string, isRoot?: boolean}[], options?: ts.CompilerOptions, - host: ts.CompilerHost = new InMemoryHost(), - checkForErrors: boolean = true): {program: ts.Program, host: ts.CompilerHost} { + host: ts.CompilerHost = new InMemoryHost(), checkForErrors: boolean = true): + {program: ts.Program, host: ts.CompilerHost, options: ts.CompilerOptions} { files.forEach(file => host.writeFile(file.name, file.contents, false, undefined, [])); const rootNames = files.filter(file => file.isRoot !== false).map(file => host.getCanonicalFileName(file.name)); - const program = ts.createProgram( - rootNames, { - noLib: true, - experimentalDecorators: true, - moduleResolution: ts.ModuleResolutionKind.NodeJs, ...options - }, - host); + const compilerOptions = { + noLib: true, + experimentalDecorators: true, + moduleResolution: ts.ModuleResolutionKind.NodeJs, ...options + }; + const program = ts.createProgram(rootNames, compilerOptions, host); if (checkForErrors) { const diags = [...program.getSyntacticDiagnostics(), ...program.getSemanticDiagnostics()]; if (diags.length > 0) { @@ -41,7 +40,7 @@ export function makeProgram( throw new Error(`Typescript diagnostics failed! ${errors.join(', ')}`); } } - return {program, host}; + return {program, host, options: compilerOptions}; } export class InMemoryHost implements ts.CompilerHost { diff --git a/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel b/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel index 67a726fdbc..e438e91560 100644 --- a/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel @@ -8,12 +8,11 @@ ts_library( "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/transform", deps = [ "//packages/compiler", "//packages/compiler-cli/src/ngtsc/diagnostics", - "//packages/compiler-cli/src/ngtsc/host", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/translator", "//packages/compiler-cli/src/ngtsc/typecheck", "//packages/compiler-cli/src/ngtsc/util", diff --git a/packages/compiler-cli/src/ngtsc/transform/index.ts b/packages/compiler-cli/src/ngtsc/transform/index.ts index d1cd4ded2a..e7a8a0f74e 100644 --- a/packages/compiler-cli/src/ngtsc/transform/index.ts +++ b/packages/compiler-cli/src/ngtsc/transform/index.ts @@ -8,5 +8,5 @@ export * from './src/api'; export {IvyCompilation} from './src/compilation'; -export {DtsFileTransformer} from './src/declaration'; +export {DtsFileTransformer, declarationTransformFactory} from './src/declaration'; export {ivyTransformFactory} from './src/transform'; diff --git a/packages/compiler-cli/src/ngtsc/transform/src/api.ts b/packages/compiler-cli/src/ngtsc/transform/src/api.ts index 59a3182350..ab86acdb18 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/api.ts @@ -9,9 +9,32 @@ import {ConstantPool, Expression, Statement, Type} from '@angular/compiler'; import * as ts from 'typescript'; -import {Decorator} from '../../host'; +import {Decorator} from '../../reflection'; import {TypeCheckContext} from '../../typecheck'; +export enum HandlerPrecedence { + /** + * Handler with PRIMARY precedence cannot overlap - there can only be one on a given class. + * + * If more than one PRIMARY handler matches a class, an error is produced. + */ + PRIMARY, + + /** + * Handlers with SHARED precedence can match any class, possibly in addition to a single PRIMARY + * handler. + * + * It is not an error for a class to have any number of SHARED handlers. + */ + SHARED, + + /** + * Handlers with WEAK precedence that match a class are ignored if any handlers with stronger + * precedence match a class. + */ + WEAK, +} + /** * Provides the interface between a decorator compiler from @angular/compiler and the Typescript @@ -22,11 +45,19 @@ import {TypeCheckContext} from '../../typecheck'; * and Typescript source, invoking the decorator compiler, and returning the result. */ export interface DecoratorHandler { + /** + * The precedence of a handler controls how it interacts with other handlers that match the same + * class. + * + * See the descriptions on `HandlerPrecedence` for an explanation of the behaviors involved. + */ + readonly precedence: HandlerPrecedence; + /** * Scan a set of reflected decorators and determine if this handler is responsible for compilation * of one of them. */ - detect(node: ts.Declaration, decorators: Decorator[]|null): M|undefined; + detect(node: ts.Declaration, decorators: Decorator[]|null): DetectResult|undefined; /** @@ -44,6 +75,15 @@ export interface DecoratorHandler { */ analyze(node: ts.Declaration, metadata: M): AnalysisOutput; + /** + * Perform resolution on the given decorator along with the result of analysis. + * + * The resolution phase happens after the entire `ts.Program` has been analyzed, and gives the + * `DecoratorHandler` a chance to leverage information from the whole compilation unit to enhance + * the `analysis` before the emit phase. + */ + resolve?(node: ts.Declaration, analysis: A): void; + typeCheck?(ctx: TypeCheckContext, node: ts.Declaration, metadata: A): void; /** @@ -54,6 +94,11 @@ export interface DecoratorHandler { |CompileResult[]; } +export interface DetectResult { + trigger: ts.Node|null; + metadata: M; +} + /** * The output of an analysis operation, consisting of possibly an arbitrary analysis object (used as * the input to code generation) and potentially diagnostics if there were errors uncovered during diff --git a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts index f42e828a43..7ce20e9b12 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts @@ -9,23 +9,32 @@ import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; -import {FatalDiagnosticError} from '../../diagnostics'; -import {Decorator, ReflectionHost} from '../../host'; -import {reflectNameOfDeclaration} from '../../metadata/src/reflector'; +import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; +import {ImportRewriter} from '../../imports'; +import {ReflectionHost, reflectNameOfDeclaration} from '../../reflection'; import {TypeCheckContext} from '../../typecheck'; +import {getSourceFile} from '../../util/src/typescript'; -import {AnalysisOutput, CompileResult, DecoratorHandler} from './api'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from './api'; import {DtsFileTransformer} from './declaration'; +const EMPTY_ARRAY: any = []; /** * Record of an adapter which decided to emit a static field, and the analysis it performed to * prepare for that operation. */ -interface EmitFieldOperation { - adapter: DecoratorHandler; - analysis: AnalysisOutput; - metadata: M; +interface MatchedHandler { + handler: DecoratorHandler; + analyzed: AnalysisOutput|null; + detected: DetectResult; +} + +interface IvyClass { + matchedHandlers: MatchedHandler[]; + + hasWeakHandlers: boolean; + hasPrimaryHandler: boolean; } /** @@ -39,8 +48,7 @@ export class IvyCompilation { * Tracks classes which have been analyzed and found to have an Ivy decorator, and the * information recorded about them for later compilation. */ - private analysis = new Map>(); - private typeCheckMap = new Map>(); + private ivyClasses = new Map(); /** * Tracks factory information which needs to be generated. @@ -64,7 +72,7 @@ export class IvyCompilation { */ constructor( private handlers: DecoratorHandler[], private checker: ts.TypeChecker, - private reflector: ReflectionHost, private coreImportsFrom: ts.SourceFile|null, + private reflector: ReflectionHost, private importRewriter: ImportRewriter, private sourceToFactorySymbols: Map>|null) {} @@ -72,6 +80,83 @@ export class IvyCompilation { analyzeAsync(sf: ts.SourceFile): Promise|undefined { return this.analyze(sf, true); } + private detectHandlersForClass(node: ts.Declaration): IvyClass|null { + // The first step is to reflect the decorators. + const classDecorators = this.reflector.getDecoratorsOfDeclaration(node); + let ivyClass: IvyClass|null = null; + + // Look through the DecoratorHandlers to see if any are relevant. + for (const handler of this.handlers) { + // An adapter is relevant if it matches one of the decorators on the class. + const detected = handler.detect(node, classDecorators); + if (detected === undefined) { + // This handler didn't match. + continue; + } + + const isPrimaryHandler = handler.precedence === HandlerPrecedence.PRIMARY; + const isWeakHandler = handler.precedence === HandlerPrecedence.WEAK; + const match = { + handler, + analyzed: null, detected, + }; + + if (ivyClass === null) { + // This is the first handler to match this class. This path is a fast path through which + // most classes will flow. + ivyClass = { + matchedHandlers: [match], + hasPrimaryHandler: isPrimaryHandler, + hasWeakHandlers: isWeakHandler, + }; + this.ivyClasses.set(node, ivyClass); + } else { + // This is at least the second handler to match this class. This is a slower path that some + // classes will go through, which validates that the set of decorators applied to the class + // is valid. + + // Validate according to rules as follows: + // + // * WEAK handlers are removed if a non-WEAK handler matches. + // * Only one PRIMARY handler can match at a time. Any other PRIMARY handler matching a + // class with an existing PRIMARY handler is an error. + + if (!isWeakHandler && ivyClass.hasWeakHandlers) { + // The current handler is not a WEAK handler, but the class has other WEAK handlers. + // Remove them. + ivyClass.matchedHandlers = ivyClass.matchedHandlers.filter( + field => field.handler.precedence !== HandlerPrecedence.WEAK); + ivyClass.hasWeakHandlers = false; + } else if (isWeakHandler && !ivyClass.hasWeakHandlers) { + // The current handler is a WEAK handler, but the class has non-WEAK handlers already. + // Drop the current one. + continue; + } + + if (isPrimaryHandler && ivyClass.hasPrimaryHandler) { + // The class already has a PRIMARY handler, and another one just matched. + this._diagnostics.push({ + category: ts.DiagnosticCategory.Error, + code: Number('-99' + ErrorCode.DECORATOR_COLLISION), + file: getSourceFile(node), + start: node.getStart(undefined, false), + length: node.getWidth(), + messageText: 'Two incompatible decorators on class', + }); + this.ivyClasses.delete(node); + return null; + } + + // Otherwise, it's safe to accept the multiple decorators here. Update some of the metadata + // regarding this class. + ivyClass.matchedHandlers.push(match); + ivyClass.hasPrimaryHandler = ivyClass.hasPrimaryHandler || isPrimaryHandler; + } + } + + return ivyClass; + } + /** * Analyze a source file and produce diagnostics for it (if any). */ @@ -81,48 +166,31 @@ export class IvyCompilation { const promises: Promise[] = []; const analyzeClass = (node: ts.Declaration): void => { - // The first step is to reflect the decorators. - const classDecorators = this.reflector.getDecoratorsOfDeclaration(node); + const ivyClass = this.detectHandlersForClass(node); - // Look through the DecoratorHandlers to see if any are relevant. - this.handlers.forEach(adapter => { + // If the class has no Ivy behavior (or had errors), skip it. + if (ivyClass === null) { + return; + } - // An adapter is relevant if it matches one of the decorators on the class. - const metadata = adapter.detect(node, classDecorators); - if (metadata === undefined) { - return; - } - - const completeAnalysis = () => { - // Check for multiple decorators on the same node. Technically speaking this - // could be supported, but right now it's an error. - if (this.analysis.has(node)) { - throw new Error('TODO.Diagnostic: Class has multiple Angular decorators.'); - } - - // Run analysis on the metadata. This will produce either diagnostics, an - // analysis result, or both. + // Loop through each matched handler that needs to be analyzed and analyze it, either + // synchronously or asynchronously. + for (const match of ivyClass.matchedHandlers) { + // The analyze() function will run the analysis phase of the handler. + const analyze = () => { try { - const analysis = adapter.analyze(node, metadata); - if (analysis.analysis !== undefined) { - this.analysis.set(node, { - adapter, - analysis: analysis.analysis, - metadata: metadata, - }); - if (!!analysis.typeCheck) { - this.typeCheckMap.set(node, adapter); - } + match.analyzed = match.handler.analyze(node, match.detected.metadata); + + if (match.analyzed.diagnostics !== undefined) { + this._diagnostics.push(...match.analyzed.diagnostics); } - if (analysis.diagnostics !== undefined) { - this._diagnostics.push(...analysis.diagnostics); - } - - if (analysis.factorySymbolName !== undefined && this.sourceToFactorySymbols !== null && + if (match.analyzed.factorySymbolName !== undefined && + this.sourceToFactorySymbols !== null && this.sourceToFactorySymbols.has(sf.fileName)) { - this.sourceToFactorySymbols.get(sf.fileName) !.add(analysis.factorySymbolName); + this.sourceToFactorySymbols.get(sf.fileName) !.add(match.analyzed.factorySymbolName); } + } catch (err) { if (err instanceof FatalDiagnosticError) { this._diagnostics.push(err.toDiagnostic()); @@ -132,17 +200,25 @@ export class IvyCompilation { } }; - if (preanalyze && adapter.preanalyze !== undefined) { - const preanalysis = adapter.preanalyze(node, metadata); + // If preanalysis was requested and a preanalysis step exists, then run preanalysis. + // Otherwise, skip directly to analysis. + if (preanalyze && match.handler.preanalyze !== undefined) { + // Preanalysis might return a Promise, indicating an async operation was necessary. Or it + // might return undefined, indicating no async step was needed and analysis can proceed + // immediately. + const preanalysis = match.handler.preanalyze(node, match.detected.metadata); if (preanalysis !== undefined) { - promises.push(preanalysis.then(() => completeAnalysis())); + // Await the results of preanalysis before running analysis. + promises.push(preanalysis.then(analyze)); } else { - completeAnalysis(); + // No async preanalysis needed, skip directly to analysis. + analyze(); } } else { - completeAnalysis(); + // Not in preanalysis mode or not needed for this handler, skip directly to analysis. + analyze(); } - }); + } }; const visit = (node: ts.Node): void => { @@ -162,10 +238,24 @@ export class IvyCompilation { } } + resolve(): void { + this.ivyClasses.forEach((ivyClass, node) => { + for (const match of ivyClass.matchedHandlers) { + if (match.handler.resolve !== undefined && match.analyzed !== null && + match.analyzed.analysis !== undefined) { + match.handler.resolve(node, match.analyzed.analysis); + } + } + }); + } + typeCheck(context: TypeCheckContext): void { - this.typeCheckMap.forEach((handler, node) => { - if (handler.typeCheck !== undefined) { - handler.typeCheck(context, node, this.analysis.get(node) !.analysis); + this.ivyClasses.forEach((ivyClass, node) => { + for (const match of ivyClass.matchedHandlers) { + if (match.handler.typeCheck !== undefined && match.analyzed !== null && + match.analyzed.analysis !== undefined) { + match.handler.typeCheck(context, node, match.analyzed.analysis); + } } }); } @@ -177,58 +267,84 @@ export class IvyCompilation { compileIvyFieldFor(node: ts.Declaration, constantPool: ConstantPool): CompileResult[]|undefined { // Look to see whether the original node was analyzed. If not, there's nothing to do. const original = ts.getOriginalNode(node) as ts.Declaration; - if (!this.analysis.has(original)) { + if (!this.ivyClasses.has(original)) { return undefined; } - const op = this.analysis.get(original) !; - // Run the actual compilation, which generates an Expression for the Ivy field. - let res: CompileResult|CompileResult[] = op.adapter.compile(node, op.analysis, constantPool); - if (!Array.isArray(res)) { - res = [res]; + const ivyClass = this.ivyClasses.get(original) !; + + let res: CompileResult[] = []; + + for (const match of ivyClass.matchedHandlers) { + if (match.analyzed === null || match.analyzed.analysis === undefined) { + continue; + } + + const compileMatchRes = match.handler.compile(node, match.analyzed.analysis, constantPool); + if (!Array.isArray(compileMatchRes)) { + res.push(compileMatchRes); + } else { + res.push(...compileMatchRes); + } } - // Look up the .d.ts transformer for the input file and record that a field was generated, - // which will allow the .d.ts to be transformed later. + // Look up the .d.ts transformer for the input file and record that at least one field was + // generated, which will allow the .d.ts to be transformed later. const fileName = original.getSourceFile().fileName; const dtsTransformer = this.getDtsTransformer(fileName); dtsTransformer.recordStaticField(reflectNameOfDeclaration(node) !, res); - // Return the instruction to the transformer so the field will be added. - return res; + // Return the instruction to the transformer so the fields will be added. + return res.length > 0 ? res : undefined; } /** * Lookup the `ts.Decorator` which triggered transformation of a particular class declaration. */ - ivyDecoratorFor(node: ts.Declaration): Decorator|undefined { + ivyDecoratorsFor(node: ts.Declaration): ts.Decorator[] { const original = ts.getOriginalNode(node) as ts.Declaration; - if (!this.analysis.has(original)) { - return undefined; + + if (!this.ivyClasses.has(original)) { + return EMPTY_ARRAY; + } + const ivyClass = this.ivyClasses.get(original) !; + const decorators: ts.Decorator[] = []; + + for (const match of ivyClass.matchedHandlers) { + if (match.analyzed === null || match.analyzed.analysis === undefined) { + continue; + } + if (match.detected.trigger !== null && ts.isDecorator(match.detected.trigger)) { + decorators.push(match.detected.trigger); + } } - return this.analysis.get(original) !.metadata; + return decorators; } /** - * Process a .d.ts source string and return a transformed version that incorporates the changes + * Process a declaration file and return a transformed version that incorporates the changes * made to the source file. */ - transformedDtsFor(tsFileName: string, dtsOriginalSource: string): string { - // No need to transform if no changes have been requested to the input file. - if (!this.dtsMap.has(tsFileName)) { - return dtsOriginalSource; + transformedDtsFor(file: ts.SourceFile, context: ts.TransformationContext): ts.SourceFile { + // No need to transform if it's not a declarations file, or if no changes have been requested + // to the input file. + // Due to the way TypeScript afterDeclarations transformers work, the SourceFile path is the + // same as the original .ts. + // The only way we know it's actually a declaration file is via the isDeclarationFile property. + if (!file.isDeclarationFile || !this.dtsMap.has(file.fileName)) { + return file; } - // Return the transformed .d.ts source. - return this.dtsMap.get(tsFileName) !.transform(dtsOriginalSource, tsFileName); + // Return the transformed source. + return this.dtsMap.get(file.fileName) !.transform(file, context); } get diagnostics(): ReadonlyArray { return this._diagnostics; } private getDtsTransformer(tsFileName: string): DtsFileTransformer { if (!this.dtsMap.has(tsFileName)) { - this.dtsMap.set(tsFileName, new DtsFileTransformer(this.coreImportsFrom)); + this.dtsMap.set(tsFileName, new DtsFileTransformer(this.importRewriter)); } return this.dtsMap.get(tsFileName) !; } diff --git a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts index 4e009b9969..0873dea3e2 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts @@ -8,12 +8,28 @@ import * as ts from 'typescript'; +import {ImportRewriter} from '../../imports'; import {ImportManager, translateType} from '../../translator'; import {CompileResult} from './api'; +import {IvyCompilation} from './compilation'; +import {addImports} from './utils'; +export function declarationTransformFactory(compilation: IvyCompilation): + ts.TransformerFactory { + return (context: ts.TransformationContext) => { + return (fileOrBundle) => { + if (ts.isBundle(fileOrBundle)) { + // Only attempt to transform source files. + return fileOrBundle; + } + return compilation.transformedDtsFor(fileOrBundle, context); + }; + }; +} + /** * Processes .d.ts file text and adds static field declarations, with types. */ @@ -21,8 +37,8 @@ export class DtsFileTransformer { private ivyFields = new Map(); private imports: ImportManager; - constructor(private coreImportsFrom: ts.SourceFile|null, importPrefix?: string) { - this.imports = new ImportManager(coreImportsFrom !== null, importPrefix); + constructor(private importRewriter: ImportRewriter, importPrefix?: string) { + this.imports = new ImportManager(importRewriter, importPrefix); } /** @@ -31,36 +47,33 @@ export class DtsFileTransformer { recordStaticField(name: string, decls: CompileResult[]): void { this.ivyFields.set(name, decls); } /** - * Process the .d.ts text for a file and add any declarations which were recorded. + * Transform the declaration file and add any declarations which were recorded. */ - transform(dts: string, tsPath: string): string { - const dtsFile = - ts.createSourceFile('out.d.ts', dts, ts.ScriptTarget.Latest, false, ts.ScriptKind.TS); + transform(file: ts.SourceFile, context: ts.TransformationContext): ts.SourceFile { + const visitor: ts.Visitor = (node: ts.Node): ts.VisitResult => { + // This class declaration needs to have fields added to it. + if (ts.isClassDeclaration(node) && node.name !== undefined && + this.ivyFields.has(node.name.text)) { + const decls = this.ivyFields.get(node.name.text) !; + const newMembers = decls.map(decl => { + const modifiers = [ts.createModifier(ts.SyntaxKind.StaticKeyword)]; + const typeRef = translateType(decl.type, this.imports); + return ts.createProperty(undefined, modifiers, decl.name, undefined, typeRef, undefined); + }); - for (let i = dtsFile.statements.length - 1; i >= 0; i--) { - const stmt = dtsFile.statements[i]; - if (ts.isClassDeclaration(stmt) && stmt.name !== undefined && - this.ivyFields.has(stmt.name.text)) { - const decls = this.ivyFields.get(stmt.name.text) !; - const before = dts.substring(0, stmt.end - 1); - const after = dts.substring(stmt.end - 1); - - dts = before + - decls - .map(decl => { - const type = translateType(decl.type, this.imports); - return ` static ${decl.name}: ${type};\n`; - }) - .join('') + - after; + return ts.updateClassDeclaration( + node, node.decorators, node.modifiers, node.name, node.typeParameters, + node.heritageClauses, [...node.members, ...newMembers]); } - } - const imports = this.imports.getAllImports(tsPath, this.coreImportsFrom); - if (imports.length !== 0) { - dts = imports.map(i => `import * as ${i.as} from '${i.name}';\n`).join('') + dts; - } + // Otherwise return node as is. + return ts.visitEachChild(node, visitor, context); + }; - return dts; + // Recursively scan through the AST and add all class members needed. + const sf = ts.visitNode(file, visitor); + + // Add new imports for this file. + return addImports(this.imports, sf); } } diff --git a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts index 267eeff035..5223ee376a 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts @@ -9,22 +9,23 @@ import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; -import {Decorator, ReflectionHost} from '../../host'; +import {ImportRewriter} from '../../imports'; +import {Decorator, ReflectionHost} from '../../reflection'; import {ImportManager, translateExpression, translateStatement} from '../../translator'; -import {relativePathBetween} from '../../util/src/path'; import {VisitListEntryResult, Visitor, visit} from '../../util/src/visitor'; import {CompileResult} from './api'; import {IvyCompilation} from './compilation'; +import {addImports} from './utils'; const NO_DECORATORS = new Set(); export function ivyTransformFactory( - compilation: IvyCompilation, reflector: ReflectionHost, - coreImportsFrom: ts.SourceFile | null): ts.TransformerFactory { + compilation: IvyCompilation, reflector: ReflectionHost, importRewriter: ImportRewriter, + isCore: boolean): ts.TransformerFactory { return (context: ts.TransformationContext): ts.Transformer => { return (file: ts.SourceFile): ts.SourceFile => { - return transformIvySourceFile(compilation, context, reflector, coreImportsFrom, file); + return transformIvySourceFile(compilation, context, reflector, importRewriter, isCore, file); }; }; } @@ -67,8 +68,7 @@ class IvyVisitor extends Visitor { node = ts.updateClassDeclaration( node, // Remove the decorator which triggered this compilation, leaving the others alone. - maybeFilterDecorator( - node.decorators, this.compilation.ivyDecoratorFor(node) !.node as ts.Decorator), + maybeFilterDecorator(node.decorators, this.compilation.ivyDecoratorsFor(node)), node.modifiers, node.name, node.typeParameters, node.heritageClauses || [], // Map over the class members and remove any Angular decorators from them. members.map(member => this._stripAngularDecorators(member))); @@ -189,47 +189,30 @@ class IvyVisitor extends Visitor { */ function transformIvySourceFile( compilation: IvyCompilation, context: ts.TransformationContext, reflector: ReflectionHost, - coreImportsFrom: ts.SourceFile | null, file: ts.SourceFile): ts.SourceFile { + importRewriter: ImportRewriter, isCore: boolean, file: ts.SourceFile): ts.SourceFile { const constantPool = new ConstantPool(); - const importManager = new ImportManager(coreImportsFrom !== null); + const importManager = new ImportManager(importRewriter); // Recursively scan through the AST and perform any updates requested by the IvyCompilation. - const visitor = - new IvyVisitor(compilation, reflector, importManager, coreImportsFrom !== null, constantPool); + const visitor = new IvyVisitor(compilation, reflector, importManager, isCore, constantPool); const sf = visit(file, visitor, context); // Generate the constant statements first, as they may involve adding additional imports // to the ImportManager. const constants = constantPool.statements.map(stmt => translateStatement(stmt, importManager)); - // Generate the import statements to prepend. - const addedImports = importManager.getAllImports(file.fileName, coreImportsFrom).map(i => { - return ts.createImportDeclaration( - undefined, undefined, - ts.createImportClause(undefined, ts.createNamespaceImport(ts.createIdentifier(i.as))), - ts.createLiteral(i.name)); - }); - - // Filter out the existing imports and the source file body. All new statements - // will be inserted between them. - const existingImports = sf.statements.filter(stmt => isImportStatement(stmt)); - const body = sf.statements.filter(stmt => !isImportStatement(stmt)); - - // Prepend imports if needed. - if (addedImports.length > 0) { - sf.statements = - ts.createNodeArray([...existingImports, ...addedImports, ...constants, ...body]); - } - return sf; + // Add new imports for this file. + return addImports(importManager, sf, constants); } function maybeFilterDecorator( decorators: ts.NodeArray| undefined, - toRemove: ts.Decorator): ts.NodeArray|undefined { + toRemove: ts.Decorator[]): ts.NodeArray|undefined { if (decorators === undefined) { return undefined; } - const filtered = decorators.filter(dec => ts.getOriginalNode(dec) !== toRemove); + const filtered = decorators.filter( + dec => toRemove.find(decToRemove => ts.getOriginalNode(dec) === decToRemove) === undefined); if (filtered.length === 0) { return undefined; } @@ -239,8 +222,3 @@ function maybeFilterDecorator( function isFromAngularCore(decorator: Decorator): boolean { return decorator.import !== null && decorator.import.from === '@angular/core'; } - -function isImportStatement(stmt: ts.Statement): boolean { - return ts.isImportDeclaration(stmt) || ts.isImportEqualsDeclaration(stmt) || - ts.isNamespaceImport(stmt); -} diff --git a/packages/compiler-cli/src/ngtsc/transform/src/utils.ts b/packages/compiler-cli/src/ngtsc/transform/src/utils.ts new file mode 100644 index 0000000000..03158c34ea --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/transform/src/utils.ts @@ -0,0 +1,44 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import * as ts from 'typescript'; + +import {ImportManager} from '../../translator'; + +/** + * Adds extra imports in the import manage for this source file, after the existing imports + * and before the module body. + * Can optionally add extra statements (e.g. new constants) before the body as well. + */ +export function addImports( + importManager: ImportManager, sf: ts.SourceFile, + extraStatements: ts.Statement[] = []): ts.SourceFile { + // Generate the import statements to prepend. + const addedImports = importManager.getAllImports(sf.fileName).map(i => { + return ts.createImportDeclaration( + undefined, undefined, + ts.createImportClause(undefined, ts.createNamespaceImport(ts.createIdentifier(i.as))), + ts.createLiteral(i.name)); + }); + + // Filter out the existing imports and the source file body. All new statements + // will be inserted between them. + const existingImports = sf.statements.filter(stmt => isImportStatement(stmt)); + const body = sf.statements.filter(stmt => !isImportStatement(stmt)); + // Prepend imports if needed. + if (addedImports.length > 0) { + sf.statements = + ts.createNodeArray([...existingImports, ...addedImports, ...extraStatements, ...body]); + } + + return sf; +} + +function isImportStatement(stmt: ts.Statement): boolean { + return ts.isImportDeclaration(stmt) || ts.isImportEqualsDeclaration(stmt) || + ts.isNamespaceImport(stmt); +} diff --git a/packages/compiler-cli/src/ngtsc/translator/BUILD.bazel b/packages/compiler-cli/src/ngtsc/translator/BUILD.bazel index d4a22e7c34..df6dd0884f 100644 --- a/packages/compiler-cli/src/ngtsc/translator/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/translator/BUILD.bazel @@ -5,10 +5,10 @@ load("//tools:defaults.bzl", "ts_library") ts_library( name = "translator", srcs = glob(["**/*.ts"]), - module_name = "@angular/compiler-cli/src/ngtsc/translator", deps = [ "//packages:types", "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//typescript", ], diff --git a/packages/compiler-cli/src/ngtsc/translator/src/translator.ts b/packages/compiler-cli/src/ngtsc/translator/src/translator.ts index 814a56e47a..5fd405ab35 100644 --- a/packages/compiler-cli/src/ngtsc/translator/src/translator.ts +++ b/packages/compiler-cli/src/ngtsc/translator/src/translator.ts @@ -9,7 +9,7 @@ import {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinType, BuiltinTypeName, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, Type, TypeVisitor, TypeofExpr, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {relativePathBetween} from '../../util/src/path'; +import {ImportRewriter, NoopImportRewriter} from '../../imports'; export class Context { constructor(readonly isStatement: boolean) {} @@ -38,60 +38,41 @@ const BINARY_OPERATORS = new Map([ [BinaryOperator.Plus, ts.SyntaxKind.PlusToken], ]); -const CORE_SUPPORTED_SYMBOLS = new Map([ - ['defineInjectable', 'defineInjectable'], - ['defineInjector', 'defineInjector'], - ['ɵdefineNgModule', 'defineNgModule'], - ['inject', 'inject'], - ['ɵsetClassMetadata', 'setClassMetadata'], - ['ɵInjectableDef', 'InjectableDef'], - ['ɵInjectorDef', 'InjectorDef'], - ['ɵNgModuleDefWithMeta', 'NgModuleDefWithMeta'], - ['ɵNgModuleFactory', 'NgModuleFactory'], -]); + export class ImportManager { private moduleToIndex = new Map(); + private importedModules = new Set(); private nextIndex = 0; - constructor(protected isCore: boolean, private prefix = 'i') {} + constructor(protected rewriter: ImportRewriter = new NoopImportRewriter(), private prefix = 'i') { + } - generateNamedImport(moduleName: string, symbol: string): + generateNamedImport(moduleName: string, originalSymbol: string): {moduleImport: string | null, symbol: string} { + // First, rewrite the symbol name. + const symbol = this.rewriter.rewriteSymbol(originalSymbol, moduleName); + + // Ask the rewriter if this symbol should be imported at all. If not, it can be referenced + // directly (moduleImport: null). + if (!this.rewriter.shouldImportSymbol(symbol, moduleName)) { + // The symbol should be referenced directly. + return {moduleImport: null, symbol}; + } + + // If not, this symbol will be imported. Allocate a prefix for the imported module if needed. if (!this.moduleToIndex.has(moduleName)) { this.moduleToIndex.set(moduleName, `${this.prefix}${this.nextIndex++}`); } + const moduleImport = this.moduleToIndex.get(moduleName) !; - return { - moduleImport: this.moduleToIndex.get(moduleName) !, - symbol: this.rewriteSymbol(moduleName, symbol) - }; + return {moduleImport, symbol}; } - protected rewriteSymbol(moduleName: string, symbol: string): string { - if (this.isCore && moduleName === '@angular/core') { - if (!CORE_SUPPORTED_SYMBOLS.has(symbol)) { - throw new Error(`Importing unexpected symbol ${symbol} while compiling core`); - } - - symbol = CORE_SUPPORTED_SYMBOLS.get(symbol) !; - } - - return symbol; - } - - getAllImports(contextPath: string, rewriteCoreImportsTo: ts.SourceFile|null): - {name: string, as: string}[] { + getAllImports(contextPath: string): {name: string, as: string}[] { return Array.from(this.moduleToIndex.keys()).map(name => { - const as: string|null = this.moduleToIndex.get(name) !; - if (rewriteCoreImportsTo !== null && name === '@angular/core') { - const relative = relativePathBetween(contextPath, rewriteCoreImportsTo.fileName); - if (relative === null) { - throw new Error( - `Failed to rewrite import inside core: ${contextPath} -> ${rewriteCoreImportsTo.fileName}`); - } - name = relative; - } + const as = this.moduleToIndex.get(name) !; + name = this.rewriter.rewriteSpecifier(name, contextPath); return {name, as}; }); } @@ -105,11 +86,12 @@ export function translateStatement(statement: Statement, imports: ImportManager) return statement.visitStatement(new ExpressionTranslatorVisitor(imports), new Context(true)); } -export function translateType(type: Type, imports: ImportManager): string { +export function translateType(type: Type, imports: ImportManager): ts.TypeNode { return type.visitType(new TypeTranslatorVisitor(imports), new Context(false)); } class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor { + private externalSourceFiles = new Map(); constructor(private imports: ImportManager) {} visitDeclareVarStmt(stmt: DeclareVarStmt, context: Context): ts.VariableStatement { @@ -157,7 +139,9 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor throw new Error('Method not implemented.'); } - visitThrowStmt(stmt: ThrowStmt, context: Context) { throw new Error('Method not implemented.'); } + visitThrowStmt(stmt: ThrowStmt, context: Context): ts.ThrowStatement { + return ts.createThrow(stmt.error.visitExpression(this, context.withExpressionMode)); + } visitCommentStmt(stmt: CommentStmt, context: Context): never { throw new Error('Method not implemented.'); @@ -172,7 +156,9 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor } visitReadVarExpr(ast: ReadVarExpr, context: Context): ts.Identifier { - return ts.createIdentifier(ast.name !); + const identifier = ts.createIdentifier(ast.name !); + this.setSourceMapRange(identifier, ast); + return identifier; } visitWriteVarExpr(expr: WriteVarExpr, context: Context): ts.Expression { @@ -182,8 +168,14 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor return context.isStatement ? result : ts.createParen(result); } - visitWriteKeyExpr(expr: WriteKeyExpr, context: Context): never { - throw new Error('Method not implemented.'); + visitWriteKeyExpr(expr: WriteKeyExpr, context: Context): ts.Expression { + const exprContext = context.withExpressionMode; + const lhs = ts.createElementAccess( + expr.receiver.visitExpression(this, exprContext), + expr.index.visitExpression(this, exprContext), ); + const rhs = expr.value.visitExpression(this, exprContext); + const result: ts.Expression = ts.createBinary(lhs, ts.SyntaxKind.EqualsToken, rhs); + return context.isStatement ? result : ts.createParen(result); } visitWritePropExpr(expr: WritePropExpr, context: Context): ts.BinaryExpression { @@ -194,9 +186,11 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor visitInvokeMethodExpr(ast: InvokeMethodExpr, context: Context): ts.CallExpression { const target = ast.receiver.visitExpression(this, context); - return ts.createCall( + const call = ts.createCall( ast.name !== null ? ts.createPropertyAccess(target, ast.name) : target, undefined, ast.args.map(arg => arg.visitExpression(this, context))); + this.setSourceMapRange(call, ast); + return call; } visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: Context): ts.CallExpression { @@ -206,6 +200,7 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor if (ast.pure) { ts.addSyntheticLeadingComment(expr, ts.SyntaxKind.MultiLineCommentTrivia, '@__PURE__', false); } + this.setSourceMapRange(expr, ast); return expr; } @@ -216,13 +211,16 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor } visitLiteralExpr(ast: LiteralExpr, context: Context): ts.Expression { + let expr: ts.Expression; if (ast.value === undefined) { - return ts.createIdentifier('undefined'); + expr = ts.createIdentifier('undefined'); } else if (ast.value === null) { - return ts.createNull(); + expr = ts.createNull(); } else { - return ts.createLiteral(ast.value); + expr = ts.createLiteral(ast.value); } + this.setSourceMapRange(expr, ast); + return expr; } visitExternalExpr(ast: ExternalExpr, context: Context): ts.PropertyAccessExpression @@ -288,7 +286,10 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor } visitLiteralArrayExpr(ast: LiteralArrayExpr, context: Context): ts.ArrayLiteralExpression { - return ts.createArrayLiteral(ast.entries.map(expr => expr.visitExpression(this, context))); + const expr = + ts.createArrayLiteral(ast.entries.map(expr => expr.visitExpression(this, context))); + this.setSourceMapRange(expr, ast); + return expr; } visitLiteralMapExpr(ast: LiteralMapExpr, context: Context): ts.ObjectLiteralExpression { @@ -296,7 +297,9 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor entry => ts.createPropertyAssignment( entry.quoted ? ts.createLiteral(entry.key) : ts.createIdentifier(entry.key), entry.value.visitExpression(this, context))); - return ts.createObjectLiteral(entries); + const expr = ts.createObjectLiteral(entries); + this.setSourceMapRange(expr, ast); + return expr; } visitCommaExpr(ast: CommaExpr, context: Context): never { @@ -308,49 +311,63 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor visitTypeofExpr(ast: TypeofExpr, context: Context): ts.TypeOfExpression { return ts.createTypeOf(ast.expr.visitExpression(this, context)); } + + private setSourceMapRange(expr: ts.Expression, ast: Expression) { + if (ast.sourceSpan) { + const {start, end} = ast.sourceSpan; + const {url, content} = start.file; + if (url) { + if (!this.externalSourceFiles.has(url)) { + this.externalSourceFiles.set(url, ts.createSourceMapSource(url, content, pos => pos)); + } + const source = this.externalSourceFiles.get(url); + ts.setSourceMapRange(expr, {pos: start.offset, end: end.offset, source}); + } + } + } } export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { constructor(private imports: ImportManager) {} - visitBuiltinType(type: BuiltinType, context: Context): string { + visitBuiltinType(type: BuiltinType, context: Context): ts.KeywordTypeNode { switch (type.name) { case BuiltinTypeName.Bool: - return 'boolean'; + return ts.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword); case BuiltinTypeName.Dynamic: - return 'any'; + return ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword); case BuiltinTypeName.Int: case BuiltinTypeName.Number: - return 'number'; + return ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); case BuiltinTypeName.String: - return 'string'; + return ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword); case BuiltinTypeName.None: - return 'never'; + return ts.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword); default: throw new Error(`Unsupported builtin type: ${BuiltinTypeName[type.name]}`); } } - visitExpressionType(type: ExpressionType, context: Context): string { - const exprStr = type.value.visitExpression(this, context); - if (type.typeParams !== null) { - const typeSegments = type.typeParams.map(param => param.visitType(this, context)); - return `${exprStr}<${typeSegments.join(', ')}>`; - } else { - return exprStr; - } + visitExpressionType(type: ExpressionType, context: Context): ts.TypeReferenceType { + const expr: ts.Identifier|ts.QualifiedName = type.value.visitExpression(this, context); + const typeArgs = type.typeParams !== null ? + type.typeParams.map(param => param.visitType(this, context)) : + undefined; + + return ts.createTypeReferenceNode(expr, typeArgs); } - visitArrayType(type: ArrayType, context: Context): string { - return `Array<${type.visitType(this, context)}>`; + visitArrayType(type: ArrayType, context: Context): ts.ArrayTypeNode { + return ts.createArrayTypeNode(type.visitType(this, context)); } - visitMapType(type: MapType, context: Context): string { - if (type.valueType !== null) { - return `{[key: string]: ${type.valueType.visitType(this, context)}}`; - } else { - return '{[key: string]: any}'; - } + visitMapType(type: MapType, context: Context): ts.TypeLiteralNode { + const parameter = ts.createParameter( + undefined, undefined, undefined, 'key', undefined, + ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)); + const typeArgs = type.valueType !== null ? type.valueType.visitType(this, context) : undefined; + const indexSignature = ts.createIndexSignature(undefined, undefined, [parameter], typeArgs); + return ts.createTypeLiteralNode([indexSignature]); } visitReadVarExpr(ast: ReadVarExpr, context: Context): string { @@ -384,28 +401,26 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { throw new Error('Method not implemented.'); } - visitLiteralExpr(ast: LiteralExpr, context: Context): string { - if (typeof ast.value === 'string') { - const escaped = ast.value.replace(/\'/g, '\\\''); - return `'${escaped}'`; - } else { - return `${ast.value}`; - } + visitLiteralExpr(ast: LiteralExpr, context: Context): ts.LiteralExpression { + return ts.createLiteral(ast.value as string); } - visitExternalExpr(ast: ExternalExpr, context: Context): string { + visitExternalExpr(ast: ExternalExpr, context: Context): ts.TypeNode { if (ast.value.moduleName === null || ast.value.name === null) { throw new Error(`Import unknown module or symbol`); } const {moduleImport, symbol} = this.imports.generateNamedImport(ast.value.moduleName, ast.value.name); - const base = moduleImport ? `${moduleImport}.${symbol}` : symbol; - if (ast.typeParams !== null) { - const generics = ast.typeParams.map(type => type.visitType(this, context)).join(', '); - return `${base}<${generics}>`; - } else { - return base; - } + const symbolIdentifier = ts.createIdentifier(symbol); + + const typeName = moduleImport ? + ts.createPropertyAccess(ts.createIdentifier(moduleImport), symbolIdentifier) : + symbolIdentifier; + + const typeArguments = + ast.typeParams ? ast.typeParams.map(type => type.visitType(this, context)) : undefined; + + return ts.createExpressionWithTypeArguments(typeArguments, typeName); } visitConditionalExpr(ast: ConditionalExpr, context: Context) { @@ -436,37 +451,43 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { throw new Error('Method not implemented.'); } - visitLiteralArrayExpr(ast: LiteralArrayExpr, context: Context): string { + visitLiteralArrayExpr(ast: LiteralArrayExpr, context: Context): ts.TupleTypeNode { const values = ast.entries.map(expr => expr.visitExpression(this, context)); - return `[${values.join(', ')}]`; + return ts.createTupleTypeNode(values); } - visitLiteralMapExpr(ast: LiteralMapExpr, context: Context) { + visitLiteralMapExpr(ast: LiteralMapExpr, context: Context): ts.ObjectLiteralExpression { const entries = ast.entries.map(entry => { const {key, quoted} = entry; const value = entry.value.visitExpression(this, context); - if (quoted) { - return `'${key}': ${value}`; - } else { - return `${key}: ${value}`; - } + return ts.createPropertyAssignment(quoted ? `'${key}'` : key, value); }); - return `{${entries.join(', ')}}`; + return ts.createObjectLiteral(entries); } visitCommaExpr(ast: CommaExpr, context: Context) { throw new Error('Method not implemented.'); } - visitWrappedNodeExpr(ast: WrappedNodeExpr, context: Context) { + visitWrappedNodeExpr(ast: WrappedNodeExpr, context: Context): ts.Identifier { const node: ts.Node = ast.node; if (ts.isIdentifier(node)) { - return node.text; + return node; } else { throw new Error( `Unsupported WrappedNodeExpr in TypeTranslatorVisitor: ${ts.SyntaxKind[node.kind]}`); } } - visitTypeofExpr(ast: TypeofExpr, context: Context): string { - return `typeof ${ast.expr.visitExpression(this, context)}`; + visitTypeofExpr(ast: TypeofExpr, context: Context): ts.TypeQueryNode { + let expr = translateExpression(ast.expr, this.imports); + return ts.createTypeQueryNode(expr as ts.Identifier); } } + +function entityNameToExpr(entity: ts.EntityName): ts.Expression { + if (ts.isIdentifier(entity)) { + return entity; + } + const {left, right} = entity; + const leftExpr = ts.isIdentifier(left) ? left : entityNameToExpr(left); + return ts.createPropertyAccess(leftExpr, right); +} diff --git a/packages/compiler-cli/src/ngtsc/tsc_plugin.ts b/packages/compiler-cli/src/ngtsc/tsc_plugin.ts new file mode 100644 index 0000000000..a06c845957 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/tsc_plugin.ts @@ -0,0 +1,83 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {PluginCompilerHost, TscPlugin} from '@bazel/typescript/internal/tsc_wrapped/plugin_api'; +import * as ts from 'typescript'; + +import {SyntheticFilesCompilerHost} from './synthetic_files_compiler_host'; + +// Copied from tsc_wrapped/plugin_api.ts to avoid a runtime dependency on the +// @bazel/typescript package - it would be strange for non-Bazel users of +// Angular to fetch that package. +function createProxy(delegate: T): T { + const proxy = Object.create(null); + for (const k of Object.keys(delegate)) { + proxy[k] = function() { return (delegate as any)[k].apply(delegate, arguments); }; + } + return proxy; +} + +export class NgTscPlugin implements TscPlugin { + constructor(private angularCompilerOptions: unknown) {} + + wrapHost(inputFiles: string[], compilerHost: ts.CompilerHost) { + return new SyntheticFilesCompilerHost(inputFiles, compilerHost, (rootFiles: string[]) => { + // For demo purposes, assume that the first .ts rootFile is the only + // one that needs ngfactory.js/d.ts back-compat files produced. + const tsInputs = rootFiles.filter(f => f.endsWith('.ts') && !f.endsWith('.d.ts')); + const factoryPath: string = tsInputs[0].replace(/\.ts/, '.ngfactory.ts'); + + return { + factoryPath: (host: ts.CompilerHost) => + ts.createSourceFile(factoryPath, 'contents', ts.ScriptTarget.ES5), + }; + }); + } + + wrap(program: ts.Program, config: {}, host: ts.CompilerHost) { + const proxy = createProxy(program); + proxy.getSemanticDiagnostics = (sourceFile: ts.SourceFile) => { + const result: ts.Diagnostic[] = [...program.getSemanticDiagnostics(sourceFile)]; + + // For demo purposes, trigger a diagnostic when the sourcefile has a magic string + if (sourceFile.text.indexOf('diag') >= 0) { + const fake: ts.Diagnostic = { + file: sourceFile, + start: 0, + length: 3, + messageText: 'Example Angular Compiler Diagnostic', + category: ts.DiagnosticCategory.Error, + code: 12345, + // source is the name of the plugin. + source: 'ngtsc', + }; + result.push(fake); + } + return result; + }; + return proxy; + } + + createTransformers(host: PluginCompilerHost) { + const afterDeclarations: Array> = + [(context: ts.TransformationContext) => (sf: ts.SourceFile | ts.Bundle) => { + const visitor = (node: ts.Node): ts.Node => { + if (node.kind === ts.SyntaxKind.ClassDeclaration) { + const clz = node as ts.ClassDeclaration; + // For demo purposes, transform the class name in the .d.ts output + return ts.updateClassDeclaration( + clz, clz.decorators, node.modifiers, ts.createIdentifier('NEWNAME'), + clz.typeParameters, clz.heritageClauses, clz.members); + } + return ts.visitEachChild(node, visitor, context); + }; + return visitor(sf) as ts.SourceFile; + }]; + return {afterDeclarations}; + } +} diff --git a/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel b/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel index fd79b3cd3c..f76e8d5b0a 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/typecheck/BUILD.bazel @@ -5,11 +5,10 @@ load("//tools:defaults.bzl", "ts_library") ts_library( name = "typecheck", srcs = glob(["**/*.ts"]), - module_name = "@angular/compiler-cli/src/ngtsc/typecheck", deps = [ "//packages:types", "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/metadata", + "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/translator", "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//typescript", diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts index 79ce553b37..b603836a05 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts @@ -9,7 +9,7 @@ import {BoundTarget, DirectiveMeta} from '@angular/compiler'; import * as ts from 'typescript'; -import {Reference} from '../../metadata'; +import {Reference} from '../../imports'; /** * Extension of `DirectiveMeta` that includes additional information required to type-check the diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts index c796c536b7..43500d5955 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts @@ -9,6 +9,7 @@ import {R3TargetBinder, SelectorMatcher, TmplAstNode} from '@angular/compiler'; import * as ts from 'typescript'; +import {NoopImportRewriter, ReferenceEmitter} from '../../imports'; import {ImportManager} from '../../translator'; import {TypeCheckBlockMetadata, TypeCheckableDirectiveMeta, TypeCtorMetadata} from './api'; @@ -16,6 +17,7 @@ import {generateTypeCheckBlock} from './type_check_block'; import {generateTypeCtor} from './type_constructor'; + /** * A template type checking context for a program. * @@ -24,6 +26,8 @@ import {generateTypeCtor} from './type_constructor'; * checking code. */ export class TypeCheckContext { + constructor(private refEmitter: ReferenceEmitter) {} + /** * A `Set` of classes which will be used to generate type constructors. */ @@ -117,7 +121,7 @@ export class TypeCheckContext { // Imports may need to be added to the file to support type-checking of directives used in the // template within it. - const importManager = new ImportManager(false, '_i'); + const importManager = new ImportManager(new NoopImportRewriter(), '_i'); // Each Op has a splitPoint index into the text where it needs to be inserted. Split the // original source text into chunks at these split points, where code will be inserted between @@ -134,12 +138,12 @@ export class TypeCheckContext { // Process each operation and use the printer to generate source code for it, inserting it into // the source code in between the original chunks. ops.forEach((op, idx) => { - const text = op.execute(importManager, sf, printer); + const text = op.execute(importManager, sf, this.refEmitter, printer); code += text + textParts[idx + 1]; }); // Write out the imports that need to be added to the beginning of the file. - let imports = importManager.getAllImports(sf.fileName, null) + let imports = importManager.getAllImports(sf.fileName) .map(i => `import * as ${i.as} from '${i.name}';`) .join('\n'); code = imports + '\n' + code; @@ -180,7 +184,8 @@ interface Op { /** * Execute the operation and return the generated code as text. */ - execute(im: ImportManager, sf: ts.SourceFile, printer: ts.Printer): string; + execute(im: ImportManager, sf: ts.SourceFile, refEmitter: ReferenceEmitter, printer: ts.Printer): + string; } /** @@ -194,8 +199,9 @@ class TcbOp implements Op { */ get splitPoint(): number { return this.node.end + 1; } - execute(im: ImportManager, sf: ts.SourceFile, printer: ts.Printer): string { - const tcb = generateTypeCheckBlock(this.node, this.meta, im); + execute(im: ImportManager, sf: ts.SourceFile, refEmitter: ReferenceEmitter, printer: ts.Printer): + string { + const tcb = generateTypeCheckBlock(this.node, this.meta, im, refEmitter); return printer.printNode(ts.EmitHint.Unspecified, tcb, sf); } } @@ -211,7 +217,8 @@ class TypeCtorOp implements Op { */ get splitPoint(): number { return this.node.end - 1; } - execute(im: ImportManager, sf: ts.SourceFile, printer: ts.Printer): string { + execute(im: ImportManager, sf: ts.SourceFile, refEmitter: ReferenceEmitter, printer: ts.Printer): + string { const tcb = generateTypeCtor(this.node, this.meta); return printer.printNode(ts.EmitHint.Unspecified, tcb, sf); } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts index c37d7a10e5..3dfcc90f13 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts @@ -9,7 +9,7 @@ import {AST, BindingType, BoundTarget, ImplicitReceiver, PropertyRead, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstTemplate, TmplAstVariable} from '@angular/compiler'; import * as ts from 'typescript'; -import {Reference} from '../../metadata'; +import {Reference, ReferenceEmitter} from '../../imports'; import {ImportManager, translateExpression} from '../../translator'; import {TypeCheckBlockMetadata, TypeCheckableDirectiveMeta} from './api'; @@ -28,9 +28,9 @@ import {astToTypescript} from './expression'; * @param importManager an `ImportManager` for the file into which the TCB will be written. */ export function generateTypeCheckBlock( - node: ts.ClassDeclaration, meta: TypeCheckBlockMetadata, - importManager: ImportManager): ts.FunctionDeclaration { - const tcb = new Context(meta.boundTarget, node.getSourceFile(), importManager); + node: ts.ClassDeclaration, meta: TypeCheckBlockMetadata, importManager: ImportManager, + refEmitter: ReferenceEmitter): ts.FunctionDeclaration { + const tcb = new Context(meta.boundTarget, node.getSourceFile(), importManager, refEmitter); const scope = new Scope(tcb); tcbProcessNodes(meta.boundTarget.target.template !, tcb, scope); @@ -59,7 +59,8 @@ class Context { constructor( readonly boundTarget: BoundTarget, - private sourceFile: ts.SourceFile, private importManager: ImportManager) {} + private sourceFile: ts.SourceFile, private importManager: ImportManager, + private refEmitter: ReferenceEmitter) {} /** * Allocate a new variable name for use within the `Context`. @@ -75,7 +76,7 @@ class Context { * This may involve importing the node into the file if it's not declared there already. */ reference(ref: Reference): ts.Expression { - const ngExpr = ref.toExpression(this.sourceFile); + const ngExpr = this.refEmitter.emit(ref, this.sourceFile); if (ngExpr === null) { throw new Error(`Unreachable reference: ${ref.node}`); } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel index 6de544a767..233796c5ff 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel @@ -10,10 +10,11 @@ ts_library( ]), deps = [ "//packages:types", - "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/host", + "//packages/compiler-cli/src/ngtsc/imports", + "//packages/compiler-cli/src/ngtsc/path", "//packages/compiler-cli/src/ngtsc/testing", "//packages/compiler-cli/src/ngtsc/typecheck", + "//packages/compiler-cli/src/ngtsc/util", "@ngdeps//typescript", ], ) diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts index 29779fbb44..e92a7a8840 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts @@ -8,7 +8,10 @@ import * as ts from 'typescript'; +import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitter} from '../../imports'; +import {LogicalFileSystem} from '../../path'; import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript'; +import {getRootDirs} from '../../util/src/typescript'; import {TypeCheckContext} from '../src/context'; import {TypeCheckProgramHost} from '../src/host'; @@ -23,7 +26,6 @@ const LIB_D_TS = { describe('ngtsc typechecking', () => { describe('ctors', () => { it('compiles a basic type constructor', () => { - const ctx = new TypeCheckContext(); const files = [ LIB_D_TS, { name: 'main.ts', @@ -36,7 +38,15 @@ TestClass.ngTypeCtor({value: 'test'}); ` } ]; - const {program, host} = makeProgram(files, undefined, undefined, false); + const {program, host, options} = makeProgram(files, undefined, undefined, false); + const checker = program.getTypeChecker(); + const logicalFs = new LogicalFileSystem(getRootDirs(host, options)); + const emitter = new ReferenceEmitter([ + new LocalIdentifierStrategy(), + new AbsoluteModuleStrategy(program, checker, options, host), + new LogicalProjectStrategy(checker, logicalFs), + ]); + const ctx = new TypeCheckContext(emitter); const TestClass = getDeclaration(program, 'main.ts', 'TestClass', ts.isClassDeclaration); ctx.addTypeCtor(program.getSourceFile('main.ts') !, TestClass, { fnName: 'ngTypeCtor', diff --git a/packages/compiler-cli/src/ngtsc/util/BUILD.bazel b/packages/compiler-cli/src/ngtsc/util/BUILD.bazel index 9deabafc08..4f385af484 100644 --- a/packages/compiler-cli/src/ngtsc/util/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/util/BUILD.bazel @@ -8,9 +8,9 @@ ts_library( "index.ts", "src/**/*.ts", ]), - module_name = "@angular/compiler-cli/src/ngtsc/util", deps = [ "//packages:types", + "//packages/compiler-cli/src/ngtsc/path", "@ngdeps//@types/node", "@ngdeps//typescript", ], diff --git a/packages/compiler-cli/src/ngtsc/util/src/path.ts b/packages/compiler-cli/src/ngtsc/util/src/path.ts index 4c5d11c55f..fc8300f017 100644 --- a/packages/compiler-cli/src/ngtsc/util/src/path.ts +++ b/packages/compiler-cli/src/ngtsc/util/src/path.ts @@ -26,3 +26,8 @@ export function relativePathBetween(from: string, to: string): string|null { return relative; } + +export function normalizeSeparators(path: string): string { + // TODO: normalize path only for OS that need it. + return path.replace(/\\/g, '/'); +} diff --git a/packages/compiler-cli/src/ngtsc/util/src/ts_source_map_bug_29300.ts b/packages/compiler-cli/src/ngtsc/util/src/ts_source_map_bug_29300.ts new file mode 100644 index 0000000000..ede59091e1 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/util/src/ts_source_map_bug_29300.ts @@ -0,0 +1,68 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import * as ts from 'typescript'; + +let _tsSourceMapBug29300Fixed: boolean|undefined; + +/** + * Test the current version of TypeScript to see if it has fixed the external SourceMap + * file bug: https://github.com/Microsoft/TypeScript/issues/29300. + * + * The bug is fixed in TS 3.3+ but this check avoid us having to rely upon the version number, + * and allows us to gracefully fail if the TS version still has the bug. + * + * We check for the bug by compiling a very small program `a;` and transforming it to `b;`, + * where we map the new `b` identifier to an external source file, which has different lines to + * the original source file. If the bug is fixed then the output SourceMap should contain + * mappings that correspond ot the correct line/col pairs for this transformed node. + * + * @returns true if the bug is fixed. + */ +export function tsSourceMapBug29300Fixed() { + if (_tsSourceMapBug29300Fixed === undefined) { + let writtenFiles: {[filename: string]: string} = {}; + const sourceFile = + ts.createSourceFile('test.ts', 'a;', ts.ScriptTarget.ES2015, true, ts.ScriptKind.TS); + const host = { + getSourceFile(): ts.SourceFile | undefined{return sourceFile;}, + fileExists(): boolean{return true;}, + readFile(): string | undefined{return '';}, + writeFile(fileName: string, data: string) { writtenFiles[fileName] = data; }, + getDefaultLibFileName(): string{return '';}, + getCurrentDirectory(): string{return '';}, + getDirectories(): string[]{return [];}, + getCanonicalFileName(): string{return '';}, + useCaseSensitiveFileNames(): boolean{return true;}, + getNewLine(): string{return '\n';}, + }; + + const transform = (context: ts.TransformationContext) => { + return (node: ts.SourceFile) => ts.visitNode(node, visitor); + function visitor(node: ts.Node): ts.Node { + if (ts.isIdentifier(node) && node.text === 'a') { + const newNode = ts.createIdentifier('b'); + ts.setSourceMapRange(newNode, { + pos: 16, + end: 16, + source: ts.createSourceMapSource('test.html', 'abc\ndef\nghi\njkl\nmno\npqr') + }); + return newNode; + } + return ts.visitEachChild(node, visitor, context); + } + }; + + const program = ts.createProgram(['test.ts'], {sourceMap: true}, host); + program.emit(sourceFile, undefined, undefined, undefined, {after: [transform]}); + // The first two mappings in the source map should look like: + // [0,1,4,0] col 0 => source file 1, row 4, column 0) + // [1,0,0,0] col 1 => source file 1, row 4, column 0) + _tsSourceMapBug29300Fixed = /ACIA,CAAA/.test(writtenFiles['test.js.map']); + } + return _tsSourceMapBug29300Fixed; +} \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/util/src/typescript.ts b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts new file mode 100644 index 0000000000..db4860a429 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts @@ -0,0 +1,82 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const TS = /\.tsx?$/i; +const D_TS = /\.d\.ts$/i; + +import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../../path'; + +export function isDtsPath(filePath: string): boolean { + return D_TS.test(filePath); +} + +export function isNonDeclarationTsPath(filePath: string): boolean { + return TS.test(filePath) && !D_TS.test(filePath); +} + +export function isFromDtsFile(node: ts.Node): boolean { + let sf: ts.SourceFile|undefined = node.getSourceFile(); + if (sf === undefined) { + sf = ts.getOriginalNode(node).getSourceFile(); + } + return sf !== undefined && D_TS.test(sf.fileName); +} + +export function nodeNameForError(node: ts.Node & {name?: ts.Node}): string { + if (node.name !== undefined && ts.isIdentifier(node.name)) { + return node.name.text; + } else { + const kind = ts.SyntaxKind[node.kind]; + const {line, character} = + ts.getLineAndCharacterOfPosition(node.getSourceFile(), node.getStart()); + return `${kind}@${line}:${character}`; + } +} + +export function getSourceFile(node: ts.Node): ts.SourceFile { + // In certain transformation contexts, `ts.Node.getSourceFile()` can actually return `undefined`, + // despite the type signature not allowing it. In that event, get the `ts.SourceFile` via the + // original node instead (which works). + const directSf = node.getSourceFile() as ts.SourceFile | undefined; + return directSf !== undefined ? directSf : ts.getOriginalNode(node).getSourceFile(); +} + +export function identifierOfNode(decl: ts.Node & {name?: ts.Node}): ts.Identifier|null { + if (decl.name !== undefined && ts.isIdentifier(decl.name)) { + return decl.name; + } else { + return null; + } +} + +export function isDeclaration(node: ts.Node): node is ts.Declaration { + return false || ts.isEnumDeclaration(node) || ts.isClassDeclaration(node) || + ts.isFunctionDeclaration(node) || ts.isVariableDeclaration(node); +} + +export function isExported(node: ts.Declaration): boolean { + let topLevel: ts.Node = node; + if (ts.isVariableDeclaration(node) && ts.isVariableDeclarationList(node.parent)) { + topLevel = node.parent.parent; + } + return topLevel.modifiers !== undefined && + topLevel.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword); +} + +export function getRootDirs(host: ts.CompilerHost, options: ts.CompilerOptions): AbsoluteFsPath[] { + const rootDirs: string[] = []; + if (options.rootDirs !== undefined) { + rootDirs.push(...options.rootDirs); + } else if (options.rootDir !== undefined) { + rootDirs.push(options.rootDir); + } else { + rootDirs.push(host.getCurrentDirectory()); + } + return rootDirs.map(rootDir => AbsoluteFsPath.fromUnchecked(rootDir)); +} diff --git a/packages/compiler-cli/src/transformers/api.ts b/packages/compiler-cli/src/transformers/api.ts index 419596a0c8..f0c553d229 100644 --- a/packages/compiler-cli/src/transformers/api.ts +++ b/packages/compiler-cli/src/transformers/api.ts @@ -112,6 +112,12 @@ export interface CompilerOptions extends ts.CompilerOptions { // This will be true be default in Angular 6. fullTemplateTypeCheck?: boolean; + // Whether to use the CompilerHost's fileNameToModuleName utility (if available) to generate + // import module specifiers. This is false by default, and exists to support running ngtsc + // within Google. This option is internal and is used by the ng_module.bzl rule to switch + // behavior between Bazel and Blaze. + _useHostForImportGeneration?: boolean; + // Insert JSDoc type annotations needed by Closure Compiler annotateForClosureCompiler?: boolean; @@ -199,6 +205,15 @@ export interface CompilerOptions extends ts.CompilerOptions { /** @internal */ collectAllErrors?: boolean; + + /** + * Whether NGC should generate re-exports for external symbols which are referenced + * in Angular metadata (e.g. @Component, @Inject, @ViewChild). This can be enabled in + * order to avoid dynamically generated module dependencies which can break strict + * dependency enforcements. This is not enabled by default. + * Read more about this here: https://github.com/angular/angular/issues/25644. + */ + createExternalSymbolFactoryReexports?: boolean; } export interface CompilerHost extends ts.CompilerHost { @@ -307,7 +322,8 @@ export interface Program { /** * Retrieve options diagnostics for the Angular options used to create the program. */ - getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken): ReadonlyArray; + getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken): + ReadonlyArray; /** * Retrieve the syntax diagnostics from TypeScript. This is faster than calling diff --git a/packages/compiler-cli/src/transformers/compiler_host.ts b/packages/compiler-cli/src/transformers/compiler_host.ts index 2cd882ca1e..284c96db55 100644 --- a/packages/compiler-cli/src/transformers/compiler_host.ts +++ b/packages/compiler-cli/src/transformers/compiler_host.ts @@ -19,6 +19,7 @@ import {DTS, GENERATED_FILES, isInRootDir, relativeToRootDirs} from './util'; const NODE_MODULES_PACKAGE_NAME = /node_modules\/((\w|-|\.)+|(@(\w|-|\.)+\/(\w|-|\.)+))/; const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/; +const CSS_PREPROCESSOR_EXT = /(\.scss|\.less|\.styl)$/; export function createCompilerHost( {options, tsHost = ts.createCompilerHost(options, true)}: @@ -246,7 +247,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos if (packageTypings === originalImportedFile) { moduleName = importedFilePackageName; } - } catch (e) { + } catch { // the above require() will throw if there is no package.json file // and this is safe to ignore and correct to keep the longer // moduleName in this case @@ -270,8 +271,15 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos } else if (firstChar !== '.') { resourceName = `./${resourceName}`; } - const filePathWithNgResource = + let filePathWithNgResource = this.moduleNameToFileName(addNgResourceSuffix(resourceName), containingFile); + // If the user specified styleUrl pointing to *.scss, but the Sass compiler was run before + // Angular, then the resource may have been generated as *.css. Simply try the resolution again. + if (!filePathWithNgResource && CSS_PREPROCESSOR_EXT.test(resourceName)) { + const fallbackResourceName = resourceName.replace(CSS_PREPROCESSOR_EXT, '.css'); + filePathWithNgResource = + this.moduleNameToFileName(addNgResourceSuffix(fallbackResourceName), containingFile); + } const result = filePathWithNgResource ? stripNgResourceSuffix(filePathWithNgResource) : null; // Used under Bazel to report more specific error with remediation advice if (!result && (this.context as any).reportMissingResource) { @@ -582,7 +590,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos result = false; } } - } catch (e) { + } catch { // If we encounter any errors assume we this isn't a bundle index. result = false; } diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index 85574b48a3..74dec4192a 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -942,6 +942,7 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions { fullTemplateTypeCheck: options.fullTemplateTypeCheck, allowEmptyCodegenFiles: options.allowEmptyCodegenFiles, enableIvy: options.enableIvy, + createExternalSymbolFactoryReexports: options.createExternalSymbolFactoryReexports, }; } diff --git a/packages/compiler-cli/test/BUILD.bazel b/packages/compiler-cli/test/BUILD.bazel index a747f2d8e4..8bb948fec1 100644 --- a/packages/compiler-cli/test/BUILD.bazel +++ b/packages/compiler-cli/test/BUILD.bazel @@ -7,6 +7,7 @@ ts_library( testonly = True, srcs = [ "mocks.ts", + "runfile_helpers.ts", "test_support.ts", ], visibility = [ diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts index 6fd84a85de..497d59d143 100644 --- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts @@ -169,7 +169,7 @@ describe('compiler compliance', () => { }); // TODO(https://github.com/angular/angular/issues/24426): We need to support the parser actually - // building the proper attributes based off of xmlns atttribuates. + // building the proper attributes based off of xmlns attributes. xit('should support namspaced attributes', () => { const files = { app: { @@ -434,14 +434,14 @@ describe('compiler compliance', () => { $r3$.ɵallocHostVars(14); } if (rf & 2) { - $r3$.ɵelementProperty(elIndex, "expansionHeight", + $r3$.ɵcomponentHostSyntheticProperty(elIndex, "@expansionHeight", $r3$.ɵbind( $r3$.ɵpureFunction2(5, $_c1$, ctx.getExpandedState(), $r3$.ɵpureFunction2(2, $_c0$, ctx.collapsedHeight, ctx.expandedHeight) ) ), null, true ); - $r3$.ɵelementProperty(elIndex, "expansionWidth", + $r3$.ɵcomponentHostSyntheticProperty(elIndex, "@expansionWidth", $r3$.ɵbind( $r3$.ɵpureFunction2(11, $_c1$, ctx.getExpandedState(), $r3$.ɵpureFunction2(8, $_c2$, ctx.collapsedWidth, ctx.expandedWidth) @@ -640,9 +640,6 @@ describe('compiler compliance', () => { 'spec.ts': ` import {Component, Directive, NgModule} from '@angular/core'; - @Directive({}) - export class EmptyOutletDirective {} - @Component({template: ''}) export class EmptyOutletComponent {} @@ -652,16 +649,6 @@ describe('compiler compliance', () => { } }; - // EmptyOutletDirective definition should be: - const EmptyOutletDirectiveDefinition = ` - … - EmptyOutletDirective.ngDirectiveDef = $r3$.ɵdefineDirective({ - type: EmptyOutletDirective, - selectors: [], - factory: function EmptyOutletDirective_Factory(t) { return new (t || EmptyOutletDirective)(); } - }); - `; - // EmptyOutletComponent definition should be: const EmptyOutletComponentDefinition = ` … @@ -683,13 +670,48 @@ describe('compiler compliance', () => { const result = compile(files, angularFiles); const source = result.source; - expectEmit( - source, EmptyOutletDirectiveDefinition, - 'Incorrect EmptyOutletDirective.ngDirectiveDefDef'); expectEmit( source, EmptyOutletComponentDefinition, 'Incorrect EmptyOutletComponent.ngComponentDef'); }); + it('should not support directives without selector', () => { + const files = { + app: { + 'spec.ts': ` + import {Component, Directive, NgModule} from '@angular/core'; + + @Directive({}) + export class EmptyOutletDirective {} + + @NgModule({declarations: [EmptyOutletDirective]}) + export class MyModule{} + ` + } + }; + + expect(() => compile(files, angularFiles)) + .toThrowError('Directive EmptyOutletDirective has no selector, please add it!'); + }); + + it('should not support directives with empty selector', () => { + const files = { + app: { + 'spec.ts': ` + import {Component, Directive, NgModule} from '@angular/core'; + + @Directive({selector: ''}) + export class EmptyOutletDirective {} + + @NgModule({declarations: [EmptyOutletDirective]}) + export class MyModule{} + ` + } + }; + + expect(() => compile(files, angularFiles)) + .toThrowError('Directive EmptyOutletDirective has no selector, please add it!'); + }); + it('should not treat ElementRef, ViewContainerRef, or ChangeDetectorRef specially when injecting', () => { const files = { @@ -767,7 +789,7 @@ describe('compiler compliance', () => { const MyComponentDefinition = ` const $c1$ = ["foo", ""]; const $c2$ = ["if", ""]; - function MyComponent_li_Template_2(rf, ctx) { + function MyComponent_li_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "li"); $r3$.ɵtext(1); @@ -789,7 +811,7 @@ describe('compiler compliance', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "ul", null, $c1$); - $r3$.ɵtemplate(2, MyComponent_li_Template_2, 2, 2, "li", $c2$); + $r3$.ɵtemplate(2, MyComponent_li_2_Template, 2, 2, "li", $c2$); $r3$.ɵelementEnd(); } }, @@ -1093,10 +1115,10 @@ describe('compiler compliance', () => { app: { 'spec.ts': ` import {Component, Directive, NgModule, TemplateRef} from '@angular/core'; - + @Component({selector: 'simple', template: '
    '}) export class SimpleComponent {} - + @Component({ selector: 'complex', template: \` @@ -1104,10 +1126,10 @@ describe('compiler compliance', () => {
    \` }) export class ComplexComponent { } - + @NgModule({declarations: [SimpleComponent, ComplexComponent]}) export class MyModule {} - + @Component({ selector: 'my-app', template: 'content ' @@ -1122,6 +1144,7 @@ describe('compiler compliance', () => { type: SimpleComponent, selectors: [["simple"]], factory: function SimpleComponent_Factory(t) { return new (t || SimpleComponent)(); }, + ngContentSelectors: _c0, consts: 2, vars: 0, template: function SimpleComponent_Template(rf, ctx) { @@ -1145,6 +1168,7 @@ describe('compiler compliance', () => { type: ComplexComponent, selectors: [["complex"]], factory: function ComplexComponent_Factory(t) { return new (t || ComplexComponent)(); }, + ngContentSelectors: _c4, consts: 4, vars: 0, template: function ComplexComponent_Template(rf, ctx) { @@ -1176,7 +1200,7 @@ describe('compiler compliance', () => { app: { 'spec.ts': ` import {Component, NgModule} from '@angular/core'; - + @Component({ template: \`
    @@ -1191,7 +1215,7 @@ describe('compiler compliance', () => { \`, }) class Cmp {} - + @NgModule({ declarations: [Cmp] }) class Module {} ` @@ -1200,20 +1224,20 @@ describe('compiler compliance', () => { const output = ` const $_c0$ = [${AttributeMarker.SelectOnly}, "ngIf"]; const $_c1$ = ["id", "second"]; - function Cmp_div_Template_0(rf, ctx) { if (rf & 1) { + function Cmp_div_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $_c1$); $r3$.ɵprojection(1, 1); $r3$.ɵelementEnd(); } } const $_c4$ = ["id", "third"]; - function Cmp_div_Template_1(rf, ctx) { + function Cmp_div_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $_c4$); $r3$.ɵtext(1, " No ng-content, no instructions generated. "); $r3$.ɵelementEnd(); } } - function Cmp_ng_template_Template_2(rf, ctx) { + function Cmp_ng_template_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵtext(0, " '*' selector: "); $r3$.ɵprojection(1); @@ -1225,9 +1249,9 @@ describe('compiler compliance', () => { template: function Cmp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵprojectionDef($_c2$, $_c3$); - $r3$.ɵtemplate(0, Cmp_div_Template_0, 2, 0, "div", $_c0$); - $r3$.ɵtemplate(1, Cmp_div_Template_1, 2, 0, "div", $_c0$); - $r3$.ɵtemplate(2, Cmp_ng_template_Template_2, 2, 0, "ng-template"); + $r3$.ɵtemplate(0, Cmp_div_0_Template, 2, 0, "div", $_c0$); + $r3$.ɵtemplate(1, Cmp_div_1_Template, 2, 0, "div", $_c0$); + $r3$.ɵtemplate(2, Cmp_ng_template_2_Template, 2, 0, "ng-template"); } if (rf & 2) { $r3$.ɵelementProperty(0, "ngIf", $r3$.ɵbind(ctx.visible)); @@ -1245,7 +1269,7 @@ describe('compiler compliance', () => { app: { 'spec.ts': ` import {Component, NgModule} from '@angular/core'; - + @Component({ template: \` @@ -1254,7 +1278,7 @@ describe('compiler compliance', () => { - + '*' selector in a template: @@ -1262,7 +1286,7 @@ describe('compiler compliance', () => { \`, }) class Cmp {} - + @NgModule({ declarations: [Cmp] }) class Module {} ` @@ -1270,18 +1294,18 @@ describe('compiler compliance', () => { }; const output = ` - function Cmp_ng_template_ng_template_Template_1(rf, ctx) { + function Cmp_ng_template_1_ng_template_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵprojection(0, 4); - } + } } - function Cmp_ng_template_Template_1(rf, ctx) { + function Cmp_ng_template_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵprojection(0, 3); - $r3$.ɵtemplate(1, Cmp_ng_template_ng_template_Template_1, 1, 0, "ng-template"); - } + $r3$.ɵtemplate(1, Cmp_ng_template_1_ng_template_1_Template, 1, 0, "ng-template"); + } } - function Cmp_ng_template_Template_2(rf, ctx) { + function Cmp_ng_template_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵtext(0, " '*' selector in a template: "); $r3$.ɵprojection(1); @@ -1294,10 +1318,10 @@ describe('compiler compliance', () => { if (rf & 1) { $r3$.ɵprojectionDef($_c2$, $_c3$); $r3$.ɵprojection(0, 1); - $r3$.ɵtemplate(1, Cmp_ng_template_Template_1, 2, 0, "ng-template"); - $r3$.ɵtemplate(2, Cmp_ng_template_Template_2, 2, 0, "ng-template"); + $r3$.ɵtemplate(1, Cmp_ng_template_1_Template, 2, 0, "ng-template"); + $r3$.ɵtemplate(2, Cmp_ng_template_2_Template, 2, 0, "ng-template"); $r3$.ɵprojection(3, 2); - } + } } `; @@ -1352,20 +1376,20 @@ describe('compiler compliance', () => { factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); }, viewQuery: function ViewQueryComponent_Query(rf, ctx) { if (rf & 1) { - $r3$.ɵquery(0, SomeDirective, true); - $r3$.ɵquery(1, SomeDirective, true); + $r3$.ɵviewQuery(SomeDirective, true); + $r3$.ɵviewQuery(SomeDirective, true); } if (rf & 2) { var $tmp$; - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.someDir = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(1))) && (ctx.someDirs = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.someDir = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.someDirs = $tmp$)); } }, - consts: 3, + consts: 1, vars: 0, template: function ViewQueryComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵelement(2, "div", $e0_attrs$); + $r3$.ɵelement(0, "div", $e0_attrs$); } }, directives: function () { return [SomeDirective]; }, @@ -1410,13 +1434,13 @@ describe('compiler compliance', () => { … viewQuery: function ViewQueryComponent_Query(rf, ctx) { if (rf & 1) { - $r3$.ɵquery(0, $e0_attrs$, true); - $r3$.ɵquery(1, $e1_attrs$, true); + $r3$.ɵviewQuery($e0_attrs$, true); + $r3$.ɵviewQuery($e1_attrs$, true); } if (rf & 2) { var $tmp$; - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.myRef = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(1))) && (ctx.myRefs = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.myRef = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.myRefs = $tmp$)); } }, … @@ -1465,17 +1489,17 @@ describe('compiler compliance', () => { … viewQuery: function ViewQueryComponent_Query(rf, ctx) { if (rf & 1) { - $r3$.ɵquery(0, $e0_attrs$, true, TemplateRef); - $r3$.ɵquery(1, SomeDirective, true, ElementRef); - $r3$.ɵquery(2, $e1_attrs$, true, ElementRef); - $r3$.ɵquery(3, SomeDirective, true, TemplateRef); + $r3$.ɵviewQuery($e0_attrs$, true, TemplateRef); + $r3$.ɵviewQuery(SomeDirective, true, ElementRef); + $r3$.ɵviewQuery($e1_attrs$, true, ElementRef); + $r3$.ɵviewQuery(SomeDirective, true, TemplateRef); } if (rf & 2) { var $tmp$; - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.myRef = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(1))) && (ctx.someDir = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(2))) && (ctx.myRefs = $tmp$)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(3))) && (ctx.someDirs = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.myRef = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.someDir = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.myRefs = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.someDirs = $tmp$)); } }, … @@ -1529,16 +1553,18 @@ describe('compiler compliance', () => { factory: function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); }, - contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) { - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true), dirIndex); - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false), dirIndex); - }, - contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) { - const instance = $r3$.ɵload(dirIndex); + contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) { + if (rf & 1) { + $r3$.ɵcontentQuery(dirIndex, SomeDirective, true); + $r3$.ɵcontentQuery(dirIndex, SomeDirective, false); + } + if (rf & 2) { var $tmp$; - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && ($instance$.someDir = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.someDir = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.someDirList = $tmp$)); + } }, + ngContentSelectors: _c0, consts: 2, vars: 0, template: function ContentQueryComponent_Template(rf, ctx) { @@ -1587,15 +1613,16 @@ describe('compiler compliance', () => { … ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({ … - contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) { - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$, true), dirIndex); - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false), dirIndex); - }, - contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) { - const instance = $r3$.ɵload(dirIndex); + contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) { + if (rf & 1) { + $r3$.ɵcontentQuery(dirIndex, $e0_attrs$, true); + $r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false); + } + if (rf & 2) { var $tmp$; - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.myRef = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.myRefs = $tmp$)); + } }, … });`; @@ -1640,19 +1667,20 @@ describe('compiler compliance', () => { … ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({ … - contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) { - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$ , true, TemplateRef), dirIndex); - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true, ElementRef), dirIndex); - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false, ElementRef), dirIndex); - $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false, TemplateRef), dirIndex); - }, - contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) { - const instance = $r3$.ɵload(dirIndex); + contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) { + if (rf & 1) { + $r3$.ɵcontentQuery(dirIndex, $e0_attrs$, true, TemplateRef); + $r3$.ɵcontentQuery(dirIndex, SomeDirective, true, ElementRef); + $r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false, ElementRef); + $r3$.ɵcontentQuery(dirIndex, SomeDirective, false, TemplateRef); + } + if (rf & 2) { var $tmp$; - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.someDir = $tmp$.first)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 2)))) && (instance.myRefs = $tmp$)); - ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 3)))) && (instance.someDirs = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.myRef = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.someDir = $tmp$.first)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.myRefs = $tmp$)); + ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.someDirs = $tmp$)); + } }, … });`; @@ -1663,6 +1691,43 @@ describe('compiler compliance', () => { expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration'); }); + it('should throw error if content queries share a property with inputs', () => { + const files = { + app: { + ...directive, + 'content_query.ts': ` + import {Component, ContentChild, Input, NgModule} from '@angular/core'; + + @Component({ + selector: 'content-query-component', + template: \` +
    + \` + }) + export class ContentQueryComponent { + @Input() @ContentChild('foo') foo: any; + } + + @Component({ + selector: 'my-app', + template: \` + +
    +
    + \` + }) + export class MyApp { } + + @NgModule({declarations: [ContentQueryComponent, MyApp]}) + export class MyModule { } + ` + } + }; + + expect(() => compile(files, angularFiles)) + .toThrowError(/Cannot combine @Input decorators with query decorators/); + }); + }); describe('pipes', () => { @@ -1694,7 +1759,7 @@ describe('compiler compliance', () => { @Component({ selector: 'my-app', - template: '{{name | myPipe:size | myPurePipe:size }}

    {{ name | myPipe:1:2:3:4:5 }}

    ' + template: '{{name | myPipe:size | myPurePipe:size }}

    {{ name | myPipe:1:2:3:4:5 }} {{ name ? 1 : 2 | myPipe }}

    ' }) export class MyApp { name = 'World'; @@ -1733,8 +1798,8 @@ describe('compiler compliance', () => { type: MyApp, selectors: [["my-app"]], factory: function MyApp_Factory(t) { return new (t || MyApp)(); }, - consts: 6, - vars: 17, + consts: 7, + vars: 20, template: function MyApp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵtext(0); @@ -1743,11 +1808,12 @@ describe('compiler compliance', () => { $r3$.ɵelementStart(3, "p"); $r3$.ɵtext(4); $r3$.ɵpipe(5, "myPipe"); + $r3$.ɵpipe(6, "myPipe"); $r3$.ɵelementEnd(); } if (rf & 2) { - $r3$.ɵtextBinding(0, $r3$.ɵinterpolation1("", $r3$.ɵpipeBind2(1, 2, $r3$.ɵpipeBind2(2, 5, ctx.name, ctx.size), ctx.size), "")); - $r3$.ɵtextBinding(4, $r3$.ɵinterpolation1("", $r3$.ɵpipeBindV(5, 8, $r3$.ɵpureFunction1(15, $c0$, ctx.name)), "")); + $r3$.ɵtextBinding(0, $r3$.ɵinterpolation1("", $r3$.ɵpipeBind2(1, 3, $r3$.ɵpipeBind2(2, 6, ctx.name, ctx.size), ctx.size), "")); + $r3$.ɵtextBinding(4, $r3$.ɵinterpolation2("", $r3$.ɵpipeBindV(5, 9, $r3$.ɵpureFunction1(18, $c0$, ctx.name)), " ", (ctx.name ? 1 : $r3$.ɵpipeBind1(6, 16, 2)), "")); } }, pipes: [MyPurePipe, MyPipe], @@ -1911,7 +1977,7 @@ describe('compiler compliance', () => { const $c2$ = ["if", ""]; const $c3$ = ["baz", ""]; const $c4$ = ["bar", ""]; - function MyComponent_div_span_Template_2(rf, ctx) { + function MyComponent_div_3_span_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "span"); $r3$.ɵtext(1); @@ -1926,11 +1992,11 @@ describe('compiler compliance', () => { $r3$.ɵtextBinding(1, $r3$.ɵinterpolation3("", $foo$, "-", $bar$, "-", $baz$, "")); } } - function MyComponent_div_Template_3(rf, ctx) { + function MyComponent_div_3_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵtext(1); - $r3$.ɵtemplate(2, MyComponent_div_span_Template_2, 2, 3, "span", $c2$); + $r3$.ɵtemplate(2, MyComponent_div_3_span_2_Template, 2, 3, "span", $c2$); $r3$.ɵelement(3, "span", null, $c4$); $r3$.ɵelementEnd(); } @@ -1952,7 +2018,7 @@ describe('compiler compliance', () => { if (rf & 1) { $r3$.ɵelement(0, "div", null, $c1$); $r3$.ɵtext(2); - $r3$.ɵtemplate(3, MyComponent_div_Template_3, 5, 2, "div", $c2$); + $r3$.ɵtemplate(3, MyComponent_div_3_Template, 5, 2, "div", $c2$); $r3$.ɵelement(4, "div", null, $c3$); } if (rf & 2) { @@ -2000,7 +2066,7 @@ describe('compiler compliance', () => { const $c1$ = ["foo", ""]; const $c2$ = [${AttributeMarker.SelectOnly}, "ngIf"]; - function MyComponent_div_span_Template_3(rf, ctx) { + function MyComponent_div_0_span_3_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "span"); $i0$.ɵtext(1); @@ -2013,11 +2079,11 @@ describe('compiler compliance', () => { } } - function MyComponent_div_Template_0(rf, ctx) { + function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); $i0$.ɵelement(1, "div", null, $c1$); - $i0$.ɵtemplate(3, MyComponent_div_span_Template_3, 2, 2, "span", $c2$); + $i0$.ɵtemplate(3, MyComponent_div_0_span_3_Template, 2, 2, "span", $c2$); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -2029,7 +2095,7 @@ describe('compiler compliance', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_div_Template_0, 4, 1, "div", $c0$); + $i0$.ɵtemplate(0, MyComponent_div_0_Template, 4, 1, "div", $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -2092,7 +2158,7 @@ describe('compiler compliance', () => { selectors: [["lifecycle-comp"]], factory: function LifecycleComp_Factory(t) { return new (t || LifecycleComp)(); }, inputs: {nameMin: ["name", "nameMin"]}, - features: [$r3$.ɵNgOnChangesFeature], + features: [$r3$.ɵNgOnChangesFeature()], consts: 0, vars: 0, template: function LifecycleComp_Template(rf, ctx) {}, @@ -2182,9 +2248,6 @@ describe('compiler compliance', () => { } }; - // TODO(akushnir): tag name generated for element inside is incorrect. - // It's generated as ":svg:g", when it should be just "g". Potentially related to - // the issue described in FW-672. it('should support embedded views in the SVG namespace', () => { const files = { app: { @@ -2217,14 +2280,14 @@ describe('compiler compliance', () => { factory: function ForOfDirective_Factory(t) { return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef)); }, - features: [$r3$.ɵNgOnChangesFeature], + features: [$r3$.ɵNgOnChangesFeature()], inputs: {forOf: "forOf"} }); `; const MyComponentDefinition = ` const $t1_attrs$ = ["for", "", ${AttributeMarker.SelectOnly}, "forOf"]; - function MyComponent__svg_g_Template_1(rf, ctx) { + function MyComponent__svg_g_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵnamespaceSVG(); $r3$.ɵelementStart(0,"g"); @@ -2243,7 +2306,7 @@ describe('compiler compliance', () => { if (rf & 1) { $r3$.ɵnamespaceSVG(); $r3$.ɵelementStart(0,"svg"); - $r3$.ɵtemplate(1, MyComponent__svg_g_Template_1, 2, 0, ":svg:g", $t1_attrs$); + $r3$.ɵtemplate(1, MyComponent__svg_g_1_Template, 2, 0, "g", $t1_attrs$); $r3$.ɵelementEnd(); } if (rf & 2) { $r3$.ɵelementProperty(1,"forOf",$r3$.ɵbind(ctx.items)); } @@ -2293,14 +2356,14 @@ describe('compiler compliance', () => { factory: function ForOfDirective_Factory(t) { return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef)); }, - features: [$r3$.ɵNgOnChangesFeature], + features: [$r3$.ɵNgOnChangesFeature()], inputs: {forOf: "forOf"} }); `; const MyComponentDefinition = ` const $t1_attrs$ = ["for", "", ${AttributeMarker.SelectOnly}, "forOf"]; - function MyComponent_li_Template_1(rf, ctx) { + function MyComponent_li_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "li"); $r3$.ɵtext(1); @@ -2321,7 +2384,7 @@ describe('compiler compliance', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "ul"); - $r3$.ɵtemplate(1, MyComponent_li_Template_1, 2, 1, "li", $t1_attrs$); + $r3$.ɵtemplate(1, MyComponent_li_1_Template, 2, 1, "li", $t1_attrs$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -2380,7 +2443,7 @@ describe('compiler compliance', () => { const MyComponentDefinition = ` const $t4_attrs$ = ["for", "", ${AttributeMarker.SelectOnly}, "forOf"]; - function MyComponent_li_li_Template_4(rf, ctx) { + function MyComponent_li_1_li_4_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "li"); $r3$.ɵtext(1); @@ -2393,14 +2456,14 @@ describe('compiler compliance', () => { } } - function MyComponent_li_Template_1(rf, ctx) { + function MyComponent_li_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "li"); $r3$.ɵelementStart(1, "div"); $r3$.ɵtext(2); $r3$.ɵelementEnd(); $r3$.ɵelementStart(3, "ul"); - $r3$.ɵtemplate(4, MyComponent_li_li_Template_4, 2, 2, "li", $t4_attrs$); + $r3$.ɵtemplate(4, MyComponent_li_1_li_4_Template, 2, 2, "li", $t4_attrs$); $r3$.ɵelementEnd(); $r3$.ɵelementEnd(); } @@ -2421,7 +2484,7 @@ describe('compiler compliance', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "ul"); - $r3$.ɵtemplate(1, MyComponent_li_Template_1, 5, 2, "li", $c1$); + $r3$.ɵtemplate(1, MyComponent_li_1_Template, 5, 2, "li", $c1$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -2511,6 +2574,38 @@ describe('compiler compliance', () => { const source = result.source; expectEmit(source, MyAppDefinition, 'Invalid component definition'); }); + + it('should split multiple `exportAs` values into an array', () => { + const files = { + app: { + 'spec.ts': ` + import {Directive, NgModule} from '@angular/core'; + + @Directive({selector: '[some-directive]', exportAs: 'someDir, otherDir'}) + export class SomeDirective {} + + @NgModule({declarations: [SomeDirective]}) + export class MyModule{} + ` + } + }; + + // SomeDirective definition should be: + const SomeDirectiveDefinition = ` + SomeDirective.ngDirectiveDef = $r3$.ɵdefineDirective({ + type: SomeDirective, + selectors: [["", "some-directive", ""]], + factory: function SomeDirective_Factory(t) {return new (t || SomeDirective)(); }, + exportAs: ["someDir", "otherDir"] + }); + `; + + const result = compile(files, angularFiles); + const source = result.source; + + expectEmit(source, SomeDirectiveDefinition, 'Incorrect SomeDirective.ngDirectiveDef'); + }); + }); describe('inherited base classes', () => { diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts index e4d5da4bbb..ef78ee8caa 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts @@ -120,6 +120,23 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); expectEmit(result.source, template, 'Incorrect interpolated property binding'); }); + + it('should ignore empty bindings', () => { + const files: MockDirectory = { + app: { + 'example.ts': ` + import {Component} from '@angular/core'; + @Component({ + selector: 'test', + template: '
    ' + }) + class FooCmp {} + ` + } + }; + const result = compile(files, angularFiles); + expect(result.source).not.toContain('i0.ɵelementProperty'); + }); }); describe('host bindings', () => { @@ -279,11 +296,17 @@ describe('compiler compliance: bindings', () => { }; const HostAttributeDirDeclaration = ` + const $c0$ = ["aria-label", "label"]; + … HostAttributeDir.ngDirectiveDef = $r3$.ɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); }, - attributes: ["aria-label", "label"] + hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + $r3$.ɵelementHostAttrs(ctx, $c0$); + } + } }); `; @@ -293,6 +316,75 @@ describe('compiler compliance: bindings', () => { expectEmit(source, HostAttributeDirDeclaration, 'Invalid host attribute code'); }); + it('should support host attributes together with host classes and styles', () => { + const files = { + app: { + 'spec.ts': ` + import {Component, Directive, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-host-attribute-component', + template: "...", + host: { + 'title': 'hello there from component', + 'style': 'opacity:1' + } + }) + export class HostAttributeComp { + } + + @Directive({ + selector: '[hostAttributeDir]', + host: { + 'style': 'width: 200px; height: 500px', + '[style.opacity]': "true", + 'class': 'one two', + '[class.three]': "true", + 'title': 'hello there from directive', + } + }) + export class HostAttributeDir { + } + + @NgModule({declarations: [HostAttributeComp, HostAttributeDir]}) + export class MyModule {} + ` + } + }; + + const CompAndDirDeclaration = ` + const $c0$ = ["title", "hello there from component", ${AttributeMarker.Styles}, "opacity", "1"]; + const $c1$ = ["title", "hello there from directive", ${AttributeMarker.Classes}, "one", "two", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"]; + … + HostAttributeComp.ngComponentDef = $r3$.ɵdefineComponent({ + type: HostAttributeComp, + selectors: [["my-host-attribute-component"]], + factory: function HostAttributeComp_Factory(t) { return new (t || HostAttributeComp)(); }, + hostBindings: function HostAttributeComp_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + $r3$.ɵelementHostAttrs(ctx, $c0$); + … + } + … + } + … + HostAttributeDir.ngDirectiveDef = $r3$.ɵdefineDirective({ + type: HostAttributeDir, + selectors: [["", "hostAttributeDir", ""]], + factory: function HostAttributeDir_Factory(t) { return new (t || HostAttributeDir)(); }, + hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + $r3$.ɵelementHostAttrs(ctx, $c1$); + … + } + … + } + `; + + const result = compile(files, angularFiles); + const source = result.source; + expectEmit(source, CompAndDirDeclaration, 'Invalid host attribute code'); + }); }); describe('non bindable behavior', () => { diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts index b9f96de301..45bf4feaa0 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts @@ -24,13 +24,13 @@ describe('compiler compliance: directives', () => { app: { 'spec.ts': ` import {Component, Directive, NgModule} from '@angular/core'; - + @Directive({selector: '[i18n]'}) export class I18nDirective {} - + @Component({selector: 'my-component', template: '
    '}) export class MyComponent {} - + @NgModule({declarations: [I18nDirective, MyComponent]}) export class MyModule{}` } @@ -39,11 +39,11 @@ describe('compiler compliance: directives', () => { // MyComponent definition should be: const MyComponentDefinition = ` MyComponent.ngComponentDef = $r3$.ɵdefineComponent({ - type: MyComponent, - selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, - consts: 1, - vars: 0, + type: MyComponent, + selectors: [["my-component"]], + factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, + consts: 1, + vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "div"); @@ -64,7 +64,7 @@ describe('compiler compliance: directives', () => { app: { 'spec.ts': ` import {Component, Directive, NgModule} from '@angular/core'; - + @Directive({selector: '[i18n]'}) export class I18nDirective {} @@ -73,10 +73,10 @@ describe('compiler compliance: directives', () => { @Directive({selector: '[foo]'}) export class FooDirective {} - + @Component({selector: 'my-component', template: '
    '}) export class MyComponent {} - + @NgModule({declarations: [I18nDirective, I18nFooDirective, FooDirective, MyComponent]}) export class MyModule{}` } @@ -85,11 +85,11 @@ describe('compiler compliance: directives', () => { // MyComponent definition should be: const MyComponentDefinition = ` MyComponent.ngComponentDef = $r3$.ɵdefineComponent({ - type: MyComponent, - selectors: [["my-component"]], - factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, - consts: 1, - vars: 0, + type: MyComponent, + selectors: [["my-component"]], + factory: function MyComponent_Factory(t) { return new (t || MyComponent)(); }, + consts: 1, + vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "div"); @@ -111,15 +111,15 @@ describe('compiler compliance: directives', () => { app: { 'spec.ts': ` import {Component, Directive, Input, NgModule} from '@angular/core'; - + @Directive({selector: '[someDirective]'}) export class SomeDirective { @Input() someDirective; } - + @Component({selector: 'my-component', template: '
    '}) export class MyComponent {} - + @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` @@ -129,7 +129,7 @@ describe('compiler compliance: directives', () => { // MyComponent definition should be: const MyComponentDefinition = ` - … + … const _c0 = [${AttributeMarker.SelectOnly}, "someDirective"]; … MyComponent.ngComponentDef = $r3$.ɵdefineComponent({ @@ -184,7 +184,7 @@ describe('compiler compliance: directives', () => { const MyComponentDefinition = ` … const $_c0$ = ["directiveA", ""]; - function MyComponent_ng_template_Template_0(rf, ctx) { + function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵtext(0, "Some content"); } @@ -194,7 +194,7 @@ describe('compiler compliance: directives', () => { … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_ng_template_Template_0, 1, 0, "ng-template", $_c0$); + $r3$.ɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", $_c0$); } }, … @@ -238,7 +238,7 @@ describe('compiler compliance: directives', () => { … const $_c0$ = [${AttributeMarker.SelectOnly}, "ngIf"]; const $_c1$ = ["directiveA", ""]; - function MyComponent_ng_container_Template_0(rf, ctx) { + function MyComponent_ng_container_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementContainerStart(0, $_c1$); $r3$.ɵtext(1, "Some content"); @@ -250,7 +250,7 @@ describe('compiler compliance: directives', () => { … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_ng_container_Template_0, 2, 0, "ng-container", $_c0$); + $r3$.ɵtemplate(0, MyComponent_ng_container_0_Template, 2, 0, "ng-container", $_c0$); } if (rf & 2) { $r3$.ɵelementProperty(0, "ngIf", $r3$.ɵbind(ctx.showing)); @@ -272,15 +272,15 @@ describe('compiler compliance: directives', () => { app: { 'spec.ts': ` import {Component, Directive, Input, NgModule} from '@angular/core'; - + @Directive({selector: '[someDirective]'}) export class SomeDirective { @Input() someDirective; } - + @Component({selector: 'my-component', template: ''}) export class MyComponent {} - + @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` @@ -290,14 +290,14 @@ describe('compiler compliance: directives', () => { // MyComponent definition should be: const MyComponentDefinition = ` - … + … const $c0_a0$ = [${AttributeMarker.SelectOnly}, "someDirective"]; … MyComponent.ngComponentDef = $r3$.ɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_ng_template_Template_0, 0, 0, "ng-template", $c0_a0$); + $r3$.ɵtemplate(0, MyComponent_ng_template_0_Template, 0, 0, "ng-template", $c0_a0$); } if (rf & 2) { $r3$.ɵelementProperty(0, "someDirective", $r3$.ɵbind(true)); @@ -321,15 +321,15 @@ describe('compiler compliance: directives', () => { app: { 'spec.ts': ` import {Component, Directive, Input, NgModule} from '@angular/core'; - + @Directive({selector: '[someDirective]'}) export class SomeDirective { @Input() someDirective; } - + @Component({selector: 'my-component', template: '
    '}) export class MyComponent {} - + @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` @@ -338,14 +338,14 @@ describe('compiler compliance: directives', () => { // MyComponent definition should be: const MyComponentDefinition = ` - … + … const $c0_a0$ = ["someDirective", ""]; … MyComponent.ngComponentDef = $r3$.ɵdefineComponent({ … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_div_Template_0, 1, 0, "div", $c0_a0$); + $r3$.ɵtemplate(0, MyComponent_div_0_Template, 1, 0, "div", $c0_a0$); } }, … @@ -367,17 +367,17 @@ describe('compiler compliance: directives', () => { app: { 'spec.ts': ` import {Component, Directive, Output, EventEmitter, NgModule} from '@angular/core'; - + @Directive({selector: '[someDirective]'}) export class SomeDirective { @Output() someDirective = new EventEmitter(); } - + @Component({selector: 'my-component', template: '
    '}) export class MyComponent { noop() {} } - + @NgModule({declarations: [SomeDirective, MyComponent]}) export class MyModule{} ` @@ -387,7 +387,7 @@ describe('compiler compliance: directives', () => { // MyComponent definition should be: const MyComponentDefinition = ` - … + … const $c0_a0$ = [${AttributeMarker.SelectOnly}, "someDirective"]; … MyComponent.ngComponentDef = $r3$.ɵdefineComponent({ @@ -395,7 +395,7 @@ describe('compiler compliance: directives', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $c0_a0$); - $r3$.ɵlistener("someDirective", function MyComponent_Template_div_someDirective_listener($event) { return ctx.noop(); }); + $r3$.ɵlistener("someDirective", function MyComponent_Template_div_someDirective_0_listener($event) { return ctx.noop(); }); $r3$.ɵelementEnd(); } }, diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts index 32d4232117..99dbc96717 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts @@ -41,7 +41,8 @@ const extract = (from: string, regex: any, transformFn: (match: any[]) => any) = const verifyTranslationIds = (source: string, output: string, exceptions = {}, interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG) => { - const parseResult = htmlParser.parse(source, 'path:://to/template', true); + const parseResult = + htmlParser.parse(source, 'path:://to/template', {tokenizeExpansionForms: true}); const extractedIdToMsg = new Map(); const extractedIds = new Set(); const generatedIds = new Set(); @@ -129,23 +130,25 @@ const verify = (input: string, output: string, extra: any = {}): void => { ({i18nUseExternalIds, ...(extra.compilerOptions || {})}); // invoke with file-based prefix translation names - let result = compile(files, angularFiles, opts(false)); - maybePrint(result.source, extra.verbose); - expect(verifyPlaceholdersIntegrity(result.source)).toBe(true); - expectEmit(result.source, output, 'Incorrect template'); - - if (extra.skipIdBasedCheck) return; + if (!extra.skipPathBasedCheck) { + const result = compile(files, angularFiles, opts(false)); + maybePrint(result.source, extra.verbose); + expect(verifyPlaceholdersIntegrity(result.source)).toBe(true); + expectEmit(result.source, output, 'Incorrect template'); + } // invoke with translation names based on external ids - result = compile(files, angularFiles, opts(true)); - maybePrint(result.source, extra.verbose); - const interpolationConfig = extra.inputArgs && extra.inputArgs.interpolation ? - InterpolationConfig.fromArray(extra.inputArgs.interpolation) : - undefined; - expect(verifyTranslationIds(input, result.source, extra.exceptions, interpolationConfig)) - .toBe(true); - expect(verifyPlaceholdersIntegrity(result.source)).toBe(true); - expectEmit(result.source, output, 'Incorrect template'); + if (!extra.skipIdBasedCheck) { + const result = compile(files, angularFiles, opts(true)); + maybePrint(result.source, extra.verbose); + const interpolationConfig = extra.inputArgs && extra.inputArgs.interpolation ? + InterpolationConfig.fromArray(extra.inputArgs.interpolation) : + undefined; + expect(verifyTranslationIds(input, result.source, extra.exceptions, interpolationConfig)) + .toBe(true); + expect(verifyPlaceholdersIntegrity(result.source)).toBe(true); + expectEmit(result.source, output, 'Incorrect template'); + } }; describe('i18n support in the view compiler', () => { @@ -389,7 +392,7 @@ describe('i18n support in the view compiler', () => { it('should correctly bind to context in nested template', () => { const input = `
    -
    +
    `; @@ -403,7 +406,7 @@ describe('i18n support in the view compiler', () => { "interpolation": "\uFFFD0\uFFFD" }); const $_c1$ = ["title", $MSG_EXTERNAL_8538466649243975456$$APP_SPEC_TS__1$]; - function MyComponent_div_Template_0(rf, ctx) { + function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(1, "div"); @@ -423,7 +426,7 @@ describe('i18n support in the view compiler', () => { vars: 1, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_div_Template_0, 4, 3, "div", $_c0$); + $r3$.ɵtemplate(0, MyComponent_div_0_Template, 4, 3, "div", $_c0$); } if (rf & 2) { $r3$.ɵelementProperty(0, "ngForOf", $r3$.ɵbind(ctx.items)); @@ -518,7 +521,7 @@ describe('i18n support in the view compiler', () => { it('should correctly bind to context in nested template', () => { const input = `
    -
    +
    `; @@ -532,7 +535,7 @@ describe('i18n support in the view compiler', () => { "interpolation": "\uFFFD0\uFFFD" }); const $_c1$ = ["title", $MSG_EXTERNAL_8538466649243975456$$APP_SPEC_TS__1$]; - function MyComponent_div_Template_0(rf, ctx) { + function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(1, "div"); @@ -552,7 +555,7 @@ describe('i18n support in the view compiler', () => { vars: 1, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_div_Template_0, 4, 3, "div", $_c0$); + $r3$.ɵtemplate(0, MyComponent_div_0_Template, 4, 3, "div", $_c0$); } if (rf & 2) { $r3$.ɵelementProperty(0, "ngForOf", $r3$.ɵbind(ctx.items)); @@ -580,8 +583,8 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); - $r3$.ɵi18n(1, $MSG_EXTERNAL_4969674997806975147$$APP_SPEC_TS_0$); - $r3$.ɵi18nAttributes(2, $_c0$); + $r3$.ɵi18nAttributes(1, $_c0$); + $r3$.ɵi18n(2, $MSG_EXTERNAL_4969674997806975147$$APP_SPEC_TS_0$); $r3$.ɵelementEnd(); } } @@ -589,6 +592,27 @@ describe('i18n support in the view compiler', () => { verify(input, output); }); + + it('should sanitize ids and generate proper const names', () => { + const input = ` +
    + Some content +
    + `; + + const output = String.raw ` + const MSG_EXTERNAL_ID_WITH_INVALID_CHARS$$APP_SPEC_TS_0 = goog.getMsg("Element title"); + const $_c1$ = ["title", MSG_EXTERNAL_ID_WITH_INVALID_CHARS$$APP_SPEC_TS_0]; + const MSG_EXTERNAL_ID_WITH_INVALID_CHARS_2$$APP_SPEC_TS_2 = goog.getMsg(" Some content "); + … + `; + + const exceptions = { + 'ID.WITH.INVALID.CHARS': 'Verify const name generation only', + 'ID.WITH.INVALID.CHARS.2': 'Verify const name generation only' + }; + verify(input, output, {exceptions, skipPathBasedCheck: true}); + }); }); describe('nested nodes', () => { @@ -931,7 +955,7 @@ describe('i18n support in the view compiler', () => { "closeTagDiv": "\uFFFD/#3\uFFFD" }); … - function MyComponent_div_Template_2(rf, ctx) { + function MyComponent_div_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(1, "div"); @@ -956,7 +980,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵtext(1, " Some content "); - $r3$.ɵtemplate(2, MyComponent_div_Template_2, 5, 4, "div", $_c0$); + $r3$.ɵtemplate(2, MyComponent_div_2_Template, 5, 4, "div", $_c0$); $r3$.ɵelementEnd(); } if (rf & 2) { @@ -978,7 +1002,7 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = ["src", "logo.png"]; const $_c1$ = [${AttributeMarker.SelectOnly}, "ngIf"]; - function MyComponent_img_Template_1(rf, ctx) { + function MyComponent_img_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "img", $_c0$); } @@ -987,7 +1011,7 @@ describe('i18n support in the view compiler', () => { "interpolation": "\uFFFD0\uFFFD" }); const $_c2$ = ["title", $MSG_EXTERNAL_2367729185105559721$]; - function MyComponent_img_Template_2(rf, ctx) { + function MyComponent_img_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "img", $_c0$); $r3$.ɵi18nAttributes(1, $_c2$); @@ -1005,8 +1029,8 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelement(0, "img", $_c0$); - $r3$.ɵtemplate(1, MyComponent_img_Template_1, 1, 0, "img", $_c1$); - $r3$.ɵtemplate(2, MyComponent_img_Template_2, 2, 1, "img", $_c1$); + $r3$.ɵtemplate(1, MyComponent_img_1_Template, 1, 0, "img", $_c1$); + $r3$.ɵtemplate(2, MyComponent_img_2_Template, 2, 1, "img", $_c1$); } if (rf & 2) { $r3$.ɵelementProperty(1, "ngIf", $r3$.ɵbind(ctx.visible)); @@ -1045,7 +1069,7 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $_c0$ = [${AttributeMarker.SelectOnly}, "ngIf"]; - function MyComponent_div_div_Template_4(rf, ctx) { + function MyComponent_div_2_div_4_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $I18N_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$, 2); $r3$.ɵelementStart(1, "div"); @@ -1060,13 +1084,13 @@ describe('i18n support in the view compiler', () => { $r3$.ɵi18nApply(0); } } - function MyComponent_div_Template_2(rf, ctx) { + function MyComponent_div_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $I18N_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$, 1); $r3$.ɵelementStart(1, "div"); $r3$.ɵelementStart(2, "div"); $r3$.ɵpipe(3, "uppercase"); - $r3$.ɵtemplate(4, MyComponent_div_div_Template_4, 3, 2, "div", $_c1$); + $r3$.ɵtemplate(4, MyComponent_div_2_div_4_Template, 3, 2, "div", $_c1$); $r3$.ɵelementEnd(); $r3$.ɵelementEnd(); $r3$.ɵi18nEnd(); @@ -1093,7 +1117,7 @@ describe('i18n support in the view compiler', () => { "interpolation_5": "\uFFFD1:3\uFFFD" }); const $I18N_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$); - function MyComponent_div_Template_3(rf, ctx) { + function MyComponent_div_3_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $I18N_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$, 3); $r3$.ɵelementStart(1, "div"); @@ -1116,8 +1140,8 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18nStart(1, $I18N_EXTERNAL_1221890473527419724$$APP_SPEC_TS_0$); - $r3$.ɵtemplate(2, MyComponent_div_Template_2, 5, 5, "div", $_c1$); - $r3$.ɵtemplate(3, MyComponent_div_Template_3, 4, 4, "div", $_c1$); + $r3$.ɵtemplate(2, MyComponent_div_2_Template, 5, 5, "div", $_c1$); + $r3$.ɵtemplate(3, MyComponent_div_3_Template, 4, 4, "div", $_c1$); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); } @@ -1144,7 +1168,7 @@ describe('i18n support in the view compiler', () => { "closeTagSpan": "\uFFFD/#2\uFFFD" }); … - function MyComponent_div_Template_0(rf, ctx) { + function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18nStart(1, $MSG_EXTERNAL_119975189388320493$$APP_SPEC_TS__1$); @@ -1163,7 +1187,7 @@ describe('i18n support in the view compiler', () => { vars: 1, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_div_Template_0, 3, 1, "div", $_c0$); + $r3$.ɵtemplate(0, MyComponent_div_0_Template, 3, 1, "div", $_c0$); } if (rf & 2) { $r3$.ɵelementProperty(0, "ngIf", $r3$.ɵbind(ctx.visible)); @@ -1234,7 +1258,7 @@ describe('i18n support in the view compiler', () => { const output = String.raw ` const $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_0$ = goog.getMsg("My i18n block #2"); const $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS__1$ = goog.getMsg("My i18n block #1"); - function MyComponent_ng_template_Template_0(rf, ctx) { + function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18n(0, $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS__1$); } @@ -1242,7 +1266,7 @@ describe('i18n support in the view compiler', () => { … template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_ng_template_Template_0, 1, 0, "ng-template"); + $r3$.ɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template"); $r3$.ɵelementContainerStart(1); $r3$.ɵi18n(2, $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_0$); $r3$.ɵelementContainerEnd(); @@ -1270,12 +1294,10 @@ describe('i18n support in the view compiler', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "span", $_c0$); - $r3$.ɵi18nStart(1, $MSG_EXTERNAL_5295701706185791735$$APP_SPEC_TS_0$); - $r3$.ɵi18nEnd(); + $r3$.ɵi18n(1, $MSG_EXTERNAL_5295701706185791735$$APP_SPEC_TS_0$); $r3$.ɵelementEnd(); $r3$.ɵelementStart(2, "span", $_c1$); - $r3$.ɵi18nStart(3, $MSG_EXTERNAL_4722270221386399294$$APP_SPEC_TS_2$); - $r3$.ɵi18nEnd(); + $r3$.ɵi18n(3, $MSG_EXTERNAL_4722270221386399294$$APP_SPEC_TS_2$); $r3$.ɵelementEnd(); } } @@ -1324,7 +1346,7 @@ describe('i18n support in the view compiler', () => { const $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS__0$ = goog.getMsg("Some content: {$interpolation}", { "interpolation": "\uFFFD0\uFFFD" }); - function MyComponent_ng_template_Template_0(rf, ctx) { + function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18n(0, $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS__0$); $r3$.ɵpipe(1, "uppercase"); @@ -1339,7 +1361,7 @@ describe('i18n support in the view compiler', () => { vars: 0, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_ng_template_Template_0, 2, 3, "ng-template"); + $r3$.ɵtemplate(0, MyComponent_ng_template_0_Template, 2, 3, "ng-template"); } } `; @@ -1347,7 +1369,7 @@ describe('i18n support in the view compiler', () => { verify(input, output); }); - it('should be able to be child elements inside i18n block', () => { + it('should be able to act as child elements inside i18n block', () => { const input = `
    Template content: {{ valueA | uppercase }} @@ -1364,7 +1386,7 @@ describe('i18n support in the view compiler', () => { "closeTagNgContainer": "\uFFFD/#3\uFFFD", "interpolation": "\uFFFD0:1\uFFFD" }); - function MyComponent_ng_template_Template_2(rf, ctx) { + function MyComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18n(0, $MSG_EXTERNAL_702706566400598764$$APP_SPEC_TS_0$, 1); $r3$.ɵpipe(1, "uppercase"); @@ -1382,7 +1404,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18nStart(1, $MSG_EXTERNAL_702706566400598764$$APP_SPEC_TS_0$); - $r3$.ɵtemplate(2, MyComponent_ng_template_Template_2, 2, 3, "ng-template"); + $r3$.ɵtemplate(2, MyComponent_ng_template_2_Template, 2, 3, "ng-template"); $r3$.ɵelementContainerStart(3); $r3$.ɵpipe(4, "uppercase"); $r3$.ɵelementContainerEnd(); @@ -1414,7 +1436,7 @@ describe('i18n support in the view compiler', () => { const $I18N_EXTERNAL_7842238767399919809$$APP_SPEC_TS__1$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS__1$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - function MyComponent_ng_template_Template_0(rf, ctx) { + function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18n(0, $I18N_EXTERNAL_7842238767399919809$$APP_SPEC_TS__1$); } @@ -1429,7 +1451,7 @@ describe('i18n support in the view compiler', () => { vars: 1, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_ng_template_Template_0, 1, 1, "ng-template"); + $r3$.ɵtemplate(0, MyComponent_ng_template_0_Template, 1, 1, "ng-template"); $r3$.ɵelementContainerStart(1); $r3$.ɵi18n(2, $I18N_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$); $r3$.ɵelementContainerEnd(); @@ -1460,7 +1482,7 @@ describe('i18n support in the view compiler', () => { `; const output = String.raw ` - function MyComponent_ng_template_ng_template_ng_template_Template_1(rf, ctx) { + function MyComponent_ng_template_2_ng_template_2_ng_template_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18n(0, $I18N_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$, 3); } @@ -1470,10 +1492,10 @@ describe('i18n support in the view compiler', () => { $r3$.ɵi18nApply(0); } } - function MyComponent_ng_template_ng_template_Template_2(rf, ctx) { + function MyComponent_ng_template_2_ng_template_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $I18N_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$, 2); - $r3$.ɵtemplate(1, MyComponent_ng_template_ng_template_ng_template_Template_1, 1, 1, "ng-template"); + $r3$.ɵtemplate(1, MyComponent_ng_template_2_ng_template_2_ng_template_1_Template, 1, 1, "ng-template"); $r3$.ɵi18nEnd(); } if (rf & 2) { @@ -1490,11 +1512,11 @@ describe('i18n support in the view compiler', () => { "interpolation_2": "\uFFFD0:3\uFFFD" }); const $I18N_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$); - function MyComponent_ng_template_Template_2(rf, ctx) { + function MyComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $I18N_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$, 1); $r3$.ɵpipe(1, "uppercase"); - $r3$.ɵtemplate(2, MyComponent_ng_template_ng_template_Template_2, 2, 1, "ng-template"); + $r3$.ɵtemplate(2, MyComponent_ng_template_2_ng_template_2_Template, 2, 1, "ng-template"); $r3$.ɵi18nEnd(); } if (rf & 2) { @@ -1510,7 +1532,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18nStart(1, $I18N_EXTERNAL_2051477021417799640$$APP_SPEC_TS_0$); - $r3$.ɵtemplate(2, MyComponent_ng_template_Template_2, 3, 3, "ng-template"); + $r3$.ɵtemplate(2, MyComponent_ng_template_2_Template, 3, 3, "ng-template"); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); } @@ -1535,7 +1557,7 @@ describe('i18n support in the view compiler', () => { const $I18N_EXTERNAL_8806993169187953163$$APP_SPEC_TS__1$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__1$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - function MyComponent_ng_template_Template_2(rf, ctx) { + function MyComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18n(0, $I18N_EXTERNAL_8806993169187953163$$APP_SPEC_TS__1$); } @@ -1553,7 +1575,7 @@ describe('i18n support in the view compiler', () => { $r3$.ɵelementContainerStart(0); $r3$.ɵi18n(1, $I18N_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$); $r3$.ɵelementContainerEnd(); - $r3$.ɵtemplate(2, MyComponent_ng_template_Template_2, 1, 1, "ng-template"); + $r3$.ɵtemplate(2, MyComponent_ng_template_2_Template, 1, 1, "ng-template"); } if (rf & 2) { $r3$.ɵi18nExp($r3$.ɵbind(ctx.gender)); @@ -1583,7 +1605,7 @@ describe('i18n support in the view compiler', () => { const $MSG_EXTERNAL_461986953980355147$$APP_SPEC_TS__2$ = goog.getMsg("{$tagImg} is my logo #2 ", { "tagImg": "\uFFFD#1\uFFFD\uFFFD/#1\uFFFD" }); - function MyComponent_ng_template_Template_3(rf, ctx) { + function MyComponent_ng_template_3_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $MSG_EXTERNAL_461986953980355147$$APP_SPEC_TS__2$); $r3$.ɵelement(1, "img", $_c0$); @@ -1598,7 +1620,7 @@ describe('i18n support in the view compiler', () => { $r3$.ɵelement(2, "img", $_c0$); $r3$.ɵi18nEnd(); $r3$.ɵelementContainerEnd(); - $r3$.ɵtemplate(3, MyComponent_ng_template_Template_3, 2, 0, "ng-template"); + $r3$.ɵtemplate(3, MyComponent_ng_template_3_Template, 2, 0, "ng-template"); } } `; @@ -1684,6 +1706,31 @@ describe('i18n support in the view compiler', () => { verify(input, output); }); + it('should support ICU-only templates', () => { + const input = ` + {age, select, 10 {ten} 20 {twenty} other {other}} + `; + + const output = String.raw ` + const $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); + const $I18N_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); + … + consts: 1, + vars: 1, + template: function MyComponent_Template(rf, ctx) { + if (rf & 1) { + $r3$.ɵi18n(0, $I18N_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$); + } + if (rf & 2) { + $r3$.ɵi18nExp($r3$.ɵbind(ctx.age)); + $r3$.ɵi18nApply(0); + } + } + `; + + verify(input, output); + }); + it('should generate i18n instructions for icus generated outside of i18n blocks', () => { const input = `
    {gender, select, male {male} female {female} other {other}}
    @@ -1706,7 +1753,7 @@ describe('i18n support in the view compiler', () => { const $I18N_EXTERNAL_8806993169187953163$$APP_SPEC_TS__3$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS__3$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - function MyComponent_div_Template_2(rf, ctx) { + function MyComponent_div_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $_c1$); $r3$.ɵi18n(1, $I18N_EXTERNAL_8806993169187953163$$APP_SPEC_TS__3$); @@ -1725,7 +1772,7 @@ describe('i18n support in the view compiler', () => { const $I18N_EXTERNAL_1922743304863699161$$APP_SPEC_TS__5$ = $r3$.ɵi18nPostprocess($MSG_EXTERNAL_1922743304863699161$$APP_SPEC_TS__5$, { "VAR_SELECT": "\uFFFD0\uFFFD" }); - function MyComponent_div_Template_3(rf, ctx) { + function MyComponent_div_3_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $_c2$); $r3$.ɵtext(1, " You have "); @@ -1748,8 +1795,8 @@ describe('i18n support in the view compiler', () => { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18n(1, $I18N_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$); $r3$.ɵelementEnd(); - $r3$.ɵtemplate(2, MyComponent_div_Template_2, 2, 1, "div", $_c0$); - $r3$.ɵtemplate(3, MyComponent_div_Template_3, 4, 2, "div", $_c0$); + $r3$.ɵtemplate(2, MyComponent_div_2_Template, 2, 1, "div", $_c0$); + $r3$.ɵtemplate(3, MyComponent_div_3_Template, 4, 2, "div", $_c0$); } if (rf & 2) { $r3$.ɵi18nExp($r3$.ɵbind(ctx.gender)); @@ -1955,7 +2002,7 @@ describe('i18n support in the view compiler', () => { const $I18N_APP_SPEC_TS_0$ = $r3$.ɵi18nPostprocess($MSG_APP_SPEC_TS_0$, { "ICU": [$I18N_APP_SPEC_TS_1$, $I18N_APP_SPEC_TS_2$, $I18N_APP_SPEC_TS__4$] }); - function MyComponent_div_Template_3(rf, ctx) { + function MyComponent_div_3_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $I18N_APP_SPEC_TS_0$, 1); $r3$.ɵelement(1, "div"); @@ -1975,7 +2022,7 @@ describe('i18n support in the view compiler', () => { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18nStart(1, $I18N_APP_SPEC_TS_0$); $r3$.ɵelement(2, "div"); - $r3$.ɵtemplate(3, MyComponent_div_Template_3, 2, 1, "div", $_c3$); + $r3$.ɵtemplate(3, MyComponent_div_3_Template, 2, 1, "div", $_c3$); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); } @@ -2060,7 +2107,7 @@ describe('i18n support in the view compiler', () => { "icu": $I18N_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$, "icu_1": $I18N_EXTERNAL_7068143081688428291$$APP_SPEC_TS__3$ }); - function MyComponent_span_Template_2(rf, ctx) { + function MyComponent_span_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $MSG_EXTERNAL_1194472282609532229$$APP_SPEC_TS_0$, 1); $r3$.ɵelement(1, "span"); @@ -2079,7 +2126,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18nStart(1, $MSG_EXTERNAL_1194472282609532229$$APP_SPEC_TS_0$); - $r3$.ɵtemplate(2, MyComponent_span_Template_2, 2, 1, "span", $_c2$); + $r3$.ɵtemplate(2, MyComponent_span_2_Template, 2, 1, "span", $_c2$); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); } @@ -2125,7 +2172,7 @@ describe('i18n support in the view compiler', () => { "icu": $I18N_EXTERNAL_7825031864601787094$$APP_SPEC_TS_1$, "icu_1": $I18N_EXTERNAL_2310343208266678305$$APP_SPEC_TS__3$ }); - function MyComponent_span_Template_2(rf, ctx) { + function MyComponent_span_2_Template(rf, ctx) { if (rf & 1) { $r3$.ɵi18nStart(0, $MSG_EXTERNAL_7186042105600518133$$APP_SPEC_TS_0$, 1); $r3$.ɵelement(1, "span"); @@ -2145,7 +2192,7 @@ describe('i18n support in the view compiler', () => { if (rf & 1) { $r3$.ɵelementStart(0, "div"); $r3$.ɵi18nStart(1, $MSG_EXTERNAL_7186042105600518133$$APP_SPEC_TS_0$); - $r3$.ɵtemplate(2, MyComponent_span_Template_2, 2, 2, "span", $_c2$); + $r3$.ɵtemplate(2, MyComponent_span_2_Template, 2, 2, "span", $_c2$); $r3$.ɵi18nEnd(); $r3$.ɵelementEnd(); } diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts index e8c993e387..207a0e2cb6 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts @@ -46,7 +46,7 @@ describe('compiler compliance: listen()', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "div", $e0_attrs$); - $r3$.ɵlistener("click", function MyComponent_Template_div_click_listener($event) { + $r3$.ɵlistener("click", function MyComponent_Template_div_click_0_listener($event) { ctx.onClick($event); return (1 == 2); }); @@ -92,7 +92,7 @@ describe('compiler compliance: listen()', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵelementStart(0, "my-app", $e0_attrs$); - $r3$.ɵlistener("click", function MyComponent_Template_my_app_click_listener($event) { + $r3$.ɵlistener("click", function MyComponent_Template_my_app_click_0_listener($event) { return ctx.onClick($event); }); $r3$.ɵelementEnd(); @@ -136,19 +136,19 @@ describe('compiler compliance: listen()', () => { const $t0_attrs$ = [${AttributeMarker.SelectOnly}, "ngIf"]; const $e_attrs$ = [${AttributeMarker.SelectOnly}, "click"]; - function MyComponent_div_Template_0(rf, ctx) { + function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { const $s$ = $r3$.ɵgetCurrentView(); $r3$.ɵelementStart(0, "div"); $r3$.ɵelementStart(1, "div", $e_attrs$); - $r3$.ɵlistener("click", function MyComponent_div_Template_0_div_click_listener($event) { + $r3$.ɵlistener("click", function MyComponent_div_0_Template_div_click_1_listener($event) { $r3$.ɵrestoreView($s$); const $comp$ = $r3$.ɵnextContext(); return $comp$.onClick($comp$.foo); }); $r3$.ɵelementEnd(); $r3$.ɵelementStart(2, "button", $e_attrs$); - $r3$.ɵlistener("click", function MyComponent_div_Template_0_button_click_listener($event) { + $r3$.ɵlistener("click", function MyComponent_div_0_Template_button_click_2_listener($event) { $r3$.ɵrestoreView($s$); const $comp2$ = $r3$.ɵnextContext(); return $comp2$.onClick2($comp2$.bar); @@ -160,7 +160,7 @@ describe('compiler compliance: listen()', () => { // ... template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵtemplate(0, MyComponent_div_Template_0, 3, 0, "div", $c0$); + $r3$.ɵtemplate(0, MyComponent_div_0_Template, 3, 0, "div", $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngIf", $i0$.ɵbind(ctx.showing)); @@ -208,7 +208,7 @@ describe('compiler compliance: listen()', () => { if (rf & 1) { const $s$ = $r3$.ɵgetCurrentView(); $r3$.ɵelementStart(0, "button", $e0_attrs$); - $r3$.ɵlistener("click", function MyComponent_Template_button_click_listener($event) { + $r3$.ɵlistener("click", function MyComponent_Template_button_click_0_listener($event) { $r3$.ɵrestoreView($s$); const $user$ = $r3$.ɵreference(3); return ctx.onClick($user$.value); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts index 013d28e5b9..8f484a3284 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_spec.ts @@ -120,4 +120,68 @@ describe('r3_view_compiler', () => { expectEmit(result.source, bV_call, 'Incorrect bV call'); }); }); + + describe('animations', () => { + it('should not register any @attr attributes as static attributes', () => { + const files: MockDirectory = { + app: { + 'example.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-app', + template: '
    ' + }) + export class MyApp { + } + + @NgModule({declarations: [MyApp]}) + export class MyModule {}` + } + }; + + const template = ` + template: function MyApp_Template(rf, ctx) { + if (rf & 1) { + $i0$.ɵelement(0, "div"); + } + if (rf & 2) { + $i0$.ɵelementProperty(0, "@attr", …); + $i0$.ɵelementProperty(0, "@binding", …); + } + }`; + const result = compile(files, angularFiles); + expectEmit(result.source, template, 'Incorrect initialization attributes'); + }); + + it('should dedup multiple [@event] listeners', () => { + const files: MockDirectory = { + app: { + 'example.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-app', + template: '
    ' + }) + export class MyApp { + } + + @NgModule({declarations: [MyApp]}) + export class MyModule {}` + } + }; + + const template = ` + template: function MyApp_Template(rf, ctx) { + if (rf & 1) { + $i0$.ɵelementStart(0, "div"); + … + $i0$.ɵelementProperty(0, "@mySelector", …); + } + }`; + const result = compile(files, angularFiles); + expectEmit(result.source, template, 'Incorrect initialization attributes'); + }); + }); }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts index 3827ff7294..98bfd8595f 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts @@ -50,11 +50,11 @@ describe('compiler compliance: styling', () => { const files = { app: { 'spec.ts': ` - import {Component, NgModule} from '@angular/core'; + import {Component, NgModule, ViewEncapsulation} from '@angular/core'; @Component({ selector: "my-component", - encapsulation: ${ViewEncapsulation.None}, + encapsulation: ViewEncapsulation.None, styles: ["div.tall { height: 123px; }", ":host.small p { height:5px; }"], template: "..." }) @@ -77,10 +77,10 @@ describe('compiler compliance: styling', () => { const files = { app: { 'spec.ts': ` - import {Component, NgModule} from '@angular/core'; + import {Component, NgModule, ViewEncapsulation} from '@angular/core'; @Component({ - encapsulation: ${ViewEncapsulation.Native}, + encapsulation: ViewEncapsulation.Native, selector: "my-component", styles: ["div.cool { color: blue; }", ":host.nice p { color: gold; }"], template: "..." @@ -214,22 +214,21 @@ describe('compiler compliance: styling', () => { }; const template = ` - const $e0_attrs$ = ["@foo", ""]; - const $e1_attrs$ = ["@bar", ""]; - const $e2_attrs$ = ["@baz", ""]; … MyComponent.ngComponentDef = $r3$.ɵdefineComponent({ … consts: 3, - vars: 1, + vars: 3, template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { - $r3$.ɵelement(0, "div", $e0_attrs$); - $r3$.ɵelement(1, "div", $e1_attrs$); - $r3$.ɵelement(2, "div", $e2_attrs$); + $r3$.ɵelement(0, "div"); + $r3$.ɵelement(1, "div"); + $r3$.ɵelement(2, "div"); } if (rf & 2) { $r3$.ɵelementProperty(0, "@foo", $r3$.ɵbind(ctx.exp)); + $r3$.ɵelementProperty(1, "@bar", $r3$.ɵbind(undefined)); + $r3$.ɵelementProperty(2, "@baz", $r3$.ɵbind(undefined)); } }, encapsulation: 2 @@ -281,9 +280,9 @@ describe('compiler compliance: styling', () => { vars: 1, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵelementStart(0, "div", _c0); - $r3$.ɵlistener("@myAnimation.start", function MyComponent_Template_div__myAnimation_start_listener($event) { return ctx.onStart($event); }); - $r3$.ɵlistener("@myAnimation.done", function MyComponent_Template_div__myAnimation_done_listener($event) { return ctx.onDone($event); }); + $r3$.ɵelementStart(0, "div"); + $r3$.ɵlistener("@myAnimation.start", function MyComponent_Template_div_animation_myAnimation_start_0_listener($event) { return ctx.onStart($event); }); + $r3$.ɵlistener("@myAnimation.done", function MyComponent_Template_div_animation_myAnimation_done_0_listener($event) { return ctx.onDone($event); }); $r3$.ɵelementEnd(); } if (rf & 2) { $r3$.ɵelementProperty(0, "@myAnimation", $r3$.ɵbind(ctx.exp)); @@ -297,6 +296,64 @@ describe('compiler compliance: styling', () => { const result = compile(files, angularFiles); expectEmit(result.source, template, 'Incorrect template'); }); + + it('should generate animation host binding and listener code for directives', () => { + const files = { + app: { + 'spec.ts': ` + import {Directive, Component, NgModule} from '@angular/core'; + + @Directive({ + selector: '[my-anim-dir]', + animations: [ + {name: 'myAnim'} + ], + host: { + '[@myAnim]': 'myAnimState', + '(@myAnim.start)': 'onStart()', + '(@myAnim.done)': 'onDone()' + } + }) + class MyAnimDir { + onStart() {} + onDone() {} + myAnimState = '123'; + } + + @Component({ + selector: 'my-cmp', + template: \` +
    + \` + }) + class MyComponent { + } + + @NgModule({declarations: [MyComponent, MyAnimDir]}) + export class MyModule {} + ` + } + }; + + const template = ` + MyAnimDir.ngDirectiveDef = $r3$.ɵdefineDirective({ + … + hostBindings: function MyAnimDir_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + $r3$.ɵallocHostVars(1); + $r3$.ɵcomponentHostSyntheticListener("@myAnim.start", function MyAnimDir_animation_myAnim_start_HostBindingHandler($event) { return ctx.onStart(); }); + $r3$.ɵcomponentHostSyntheticListener("@myAnim.done", function MyAnimDir_animation_myAnim_done_HostBindingHandler($event) { return ctx.onDone(); }); + } if (rf & 2) { + $r3$.ɵcomponentHostSyntheticProperty(elIndex, "@myAnim", $r3$.ɵbind(ctx.myAnimState), null, true); + } + } + … + }); + `; + + const result = compile(files, angularFiles); + expectEmit(result.source, template, 'Incorrect template'); + }); }); describe('[style] and [style.prop]', () => { @@ -338,6 +395,99 @@ describe('compiler compliance: styling', () => { expectEmit(result.source, template, 'Incorrect template'); }); + it('should correctly count the total slots required when style/class bindings include interpolation', + () => { + const files = { + app: { + 'spec.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-component-with-interpolation', + template: \` +
    + \` + }) + export class MyComponentWithInterpolation { + fooId = '123'; + } + + @Component({ + selector: 'my-component-with-muchos-interpolation', + template: \` +
    + \` + }) + export class MyComponentWithMuchosInterpolation { + fooId = '123'; + fooUsername = 'superfoo'; + } + + @Component({ + selector: 'my-component-without-interpolation', + template: \` +
    + \` + }) + export class MyComponentWithoutInterpolation { + exp = 'bar'; + } + + @NgModule({declarations: [MyComponentWithInterpolation, MyComponentWithMuchosInterpolation, MyComponentWithoutInterpolation]}) + export class MyModule {} + ` + } + }; + + const template = ` + … + consts: 1, + vars: 1, + template: function MyComponentWithInterpolation_Template(rf, $ctx$) { + if (rf & 1) { + $r3$.ɵelementStart(0, "div"); + $r3$.ɵelementStyling(); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + $r3$.ɵelementStylingMap(0, $r3$.ɵinterpolation1("foo foo-", $ctx$.fooId, "")); + $r3$.ɵelementStylingApply(0); + } + } + … + consts: 1, + vars: 2, + template: function MyComponentWithMuchosInterpolation_Template(rf, $ctx$) { + if (rf & 1) { + $r3$.ɵelementStart(0, "div"); + $r3$.ɵelementStyling(); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + $r3$.ɵelementStylingMap(0, $r3$.ɵinterpolation2("foo foo-", $ctx$.fooId, "-", $ctx$.fooUsername, "")); + $r3$.ɵelementStylingApply(0); + } + } + … + consts: 1, + vars: 0, + template: function MyComponentWithoutInterpolation_Template(rf, $ctx$) { + if (rf & 1) { + $r3$.ɵelementStart(0, "div"); + $r3$.ɵelementStyling(); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + $r3$.ɵelementStylingMap(0, $ctx$.exp); + $r3$.ɵelementStylingApply(0); + } + } + `; + + const result = compile(files, angularFiles); + expectEmit(result.source, template, 'Incorrect template'); + }); + it('should place initial, multi, singular and application followed by attribute style instructions in the template code in that order', () => { const files = { @@ -631,8 +781,7 @@ describe('compiler compliance: styling', () => { vars: 2, template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { - $r3$.ɵelementStart(0, "div", $e0_attrs$); - $r3$.ɵelementEnd(); + $r3$.ɵelement(0, "div", $e0_attrs$); } if (rf & 2) { $r3$.ɵelementAttribute(0, "class", $r3$.ɵbind("round")); @@ -913,6 +1062,84 @@ describe('compiler compliance: styling', () => { expectEmit(result.source, template, 'Incorrect template'); }); + it('should generate override instructions for only single-level styling bindings when !important is present', + () => { + const files = { + app: { + 'spec.ts': ` + import {Component, NgModule, HostBinding} from '@angular/core'; + + @Component({ + selector: 'my-component', + template: \` +
    + \`, + host: { + '[style!important]': 'myStyleExp', + '[class!important]': 'myClassExp' + } + }) + export class MyComponent { + @HostBinding('class.foo!important') + myFooClassExp = true; + + @HostBinding('style.width!important') + myWidthExp = '100px'; + + myBarClassExp = true; + myHeightExp = '200px'; + } + + @NgModule({declarations: [MyComponent]}) + export class MyModule {} + ` + } + }; + + const template = ` + const _c2 = ["bar"]; + const _c3 = ["height"]; + … + function MyComponent_Template(rf, ctx) { + if (rf & 1) { + $r3$.ɵelementStart(0, "div"); + $r3$.ɵelementStyling(_c2, _c3, $r3$.ɵdefaultStyleSanitizer); + $r3$.ɵelementEnd(); + } + if (rf & 2) { + $r3$.ɵelementStylingMap(0, ctx.myClassExp, ctx.myStyleExp); + $r3$.ɵelementStyleProp(0, 0, ctx.myHeightExp, null, true); + $r3$.ɵelementClassProp(0, 0, ctx.myBarClassExp, null, true); + $r3$.ɵelementStylingApply(0); + } + }, + `; + + const hostBindings = ` + const _c0 = ["foo"]; + const _c1 = ["width"]; + … + hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + $r3$.ɵelementStyling(_c0, _c1, $r3$.ɵdefaultStyleSanitizer, ctx); + } + if (rf & 2) { + $r3$.ɵelementStylingMap(elIndex, ctx.myClassExp, ctx.myStyleExp, ctx); + $r3$.ɵelementStyleProp(elIndex, 0, ctx.myWidthExp, null, ctx, true); + $r3$.ɵelementClassProp(elIndex, 0, ctx.myFooClassExp, ctx, true); + $r3$.ɵelementStylingApply(elIndex, ctx); + } + }, + `; + + const result = compile(files, angularFiles); + expectEmit(result.source, hostBindings, 'Incorrect template'); + expectEmit(result.source, template, 'Incorrect template'); + }); + it('should generate styling instructions for multiple directives that contain host binding definitions', () => { const files = { @@ -1043,7 +1270,7 @@ describe('compiler compliance: styling', () => { }; const template = ` - const $_c0$ = [${AttributeMarker.Classes}, "foo", "baz", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"]; + const $_c0$ = ["title", "foo title", ${AttributeMarker.Classes}, "foo", "baz", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"]; … hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { if (rf & 1) { @@ -1057,9 +1284,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵelementStylingMap(elIndex, ctx.myClass, ctx.myStyle, ctx); $r3$.ɵelementStylingApply(elIndex, ctx); } - }, - consts: 0, - vars: 0, + } `; const result = compile(files, angularFiles); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts index d7ebaf48a0..5af1113bca 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts @@ -52,12 +52,12 @@ describe('compiler compliance: template', () => { const template = ` const $c0$ = ["ngFor", "", ${AttributeMarker.SelectOnly}, "ngForOf"]; const $e0_attrs$ = [${AttributeMarker.SelectOnly}, "title", "click"]; - function MyComponent_ul_li_div_Template_1(rf, ctx) { + function MyComponent_ul_0_li_1_div_1_Template(rf, ctx) { if (rf & 1) { const $s$ = $i0$.ɵgetCurrentView(); $i0$.ɵelementStart(0, "div", $e0_attrs$); - $i0$.ɵlistener("click", function MyComponent_ul_li_div_Template_1_div_click_listener($event){ + $i0$.ɵlistener("click", function MyComponent_ul_0_li_1_div_1_Template_div_click_0_listener($event){ $i0$.ɵrestoreView($s$); const $inner$ = ctx.$implicit; const $middle$ = $i0$.ɵnextContext().$implicit; @@ -79,10 +79,10 @@ describe('compiler compliance: template', () => { } } - function MyComponent_ul_li_Template_1(rf, ctx) { + function MyComponent_ul_0_li_1_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "li"); - $i0$.ɵtemplate(1, MyComponent_ul_li_div_Template_1, 2, 2, "div", _c0); + $i0$.ɵtemplate(1, MyComponent_ul_0_li_1_div_1_Template, 2, 2, "div", _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -91,10 +91,10 @@ describe('compiler compliance: template', () => { } } - function MyComponent_ul_Template_0(rf, ctx) { + function MyComponent_ul_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "ul"); - $i0$.ɵtemplate(1, MyComponent_ul_li_Template_1, 2, 1, "li", _c0); + $i0$.ɵtemplate(1, MyComponent_ul_0_li_1_Template, 2, 1, "li", _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -105,7 +105,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_ul_Template_0, 2, 1, "ul", _c0); + $i0$.ɵtemplate(0, MyComponent_ul_0_Template, 2, 1, "ul", _c0); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -141,7 +141,7 @@ describe('compiler compliance: template', () => { const template = ` const $c0$ = ["ngFor", "", ${AttributeMarker.SelectOnly}, "ngForOf"]; - function MyComponent_span_Template_0(rf, ctx) { + function MyComponent_span_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "span"); $i0$.ɵtext(1); @@ -156,7 +156,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_span_Template_0, 2, 2, "span", _c0); + $i0$.ɵtemplate(0, MyComponent_span_0_Template, 2, 2, "span", _c0); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -195,7 +195,7 @@ describe('compiler compliance: template', () => { const $c0$ = ["ngFor", "", ${AttributeMarker.SelectOnly}, "ngForOf"]; const $c1$ = [${AttributeMarker.SelectOnly}, "ngIf"]; - function MyComponent_div_span_Template_1(rf, ctx) { + function MyComponent_div_0_span_1_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "span"); $i0$.ɵtext(1); @@ -209,10 +209,10 @@ describe('compiler compliance: template', () => { } } - function MyComponent_div_Template_0(rf, ctx) { + function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); - $i0$.ɵtemplate(1, MyComponent_div_span_Template_1, 2, 2, "span", $c1$); + $i0$.ɵtemplate(1, MyComponent_div_0_span_1_Template, 2, 2, "span", $c1$); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -224,7 +224,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_div_Template_0, 2, 1, "div", $c0$); + $i0$.ɵtemplate(0, MyComponent_div_0_Template, 2, 1, "div", $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -264,7 +264,7 @@ describe('compiler compliance: template', () => { // The template should look like this (where IDENT is a wild card for an identifier): const template = ` const $c0$ = ["ngFor", "", ${AttributeMarker.SelectOnly}, "ngForOf"]; - function MyComponent_div_div_div_Template_1(rf, ctx) { + function MyComponent_div_0_div_1_div_1_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); $i0$.ɵtext(1); @@ -277,10 +277,10 @@ describe('compiler compliance: template', () => { } } - function MyComponent_div_div_Template_1(rf, ctx) { + function MyComponent_div_0_div_1_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); - $i0$.ɵtemplate(1, MyComponent_div_div_div_Template_1, 2, 2, "div", _c0); + $i0$.ɵtemplate(1, MyComponent_div_0_div_1_div_1_Template, 2, 2, "div", _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -289,10 +289,10 @@ describe('compiler compliance: template', () => { } } - function MyComponent_div_Template_0(rf, ctx) { + function MyComponent_div_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵelementStart(0, "div"); - $i0$.ɵtemplate(1, MyComponent_div_div_Template_1, 2, 1, "div", _c0); + $i0$.ɵtemplate(1, MyComponent_div_0_div_1_Template, 2, 1, "div", _c0); $i0$.ɵelementEnd(); } if (rf & 2) { @@ -303,7 +303,7 @@ describe('compiler compliance: template', () => { // ... template:function MyComponent_Template(rf, ctx){ if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_div_Template_0, 2, 1, "div", _c0); + $i0$.ɵtemplate(0, MyComponent_div_0_Template, 2, 1, "div", _c0); } if (rf & 2) { $i0$.ɵelementProperty(0, "ngForOf", $i0$.ɵbind(ctx.items)); @@ -339,7 +339,7 @@ describe('compiler compliance: template', () => { const template = ` const $c0$ = ["attr", "l", ${AttributeMarker.SelectOnly}, "boundAttr"]; - function MyComponent_ng_template_Template_0(rf, ctx) { + function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵtext(0, " some-content "); } @@ -349,7 +349,7 @@ describe('compiler compliance: template', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_ng_template_Template_0, 1, 0, "ng-template", $c0$); + $i0$.ɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", $c0$); } if (rf & 2) { $i0$.ɵelementProperty(0, "boundAttr", $i0$.ɵbind(ctx.b)); @@ -370,7 +370,7 @@ describe('compiler compliance: template', () => { @Component({ selector: 'my-component', - template: 'some-content'; + template: 'some-content', }) export class MyComponent {} @@ -383,7 +383,7 @@ describe('compiler compliance: template', () => { const template = ` const $t0_refs$ = ["foo", ""]; - function MyComponent_ng_template_Template_0(rf, ctx) { + function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { $i0$.ɵtext(0, "some-content"); } @@ -393,7 +393,7 @@ describe('compiler compliance: template', () => { template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_ng_template_Template_0, 1, 0, "ng-template", null, $t0_refs$, $i0$.ɵtemplateRefExtractor); + $i0$.ɵtemplate(0, MyComponent_ng_template_0_Template, 1, 0, "ng-template", null, $t0_refs$, $i0$.ɵtemplateRefExtractor); } }`; @@ -411,7 +411,7 @@ describe('compiler compliance: template', () => { @Component({ selector: 'my-component', - template: ''; + template: '', }) export class MyComponent {} @@ -424,14 +424,14 @@ describe('compiler compliance: template', () => { const template = ` const $t0_attrs$ = [${AttributeMarker.SelectOnly}, "outDirective"]; - function MyComponent_ng_template_Template_0(rf, ctx) { } + function MyComponent_ng_template_0_Template(rf, ctx) { } // ... template: function MyComponent_Template(rf, ctx) { if (rf & 1) { - $i0$.ɵtemplate(0, MyComponent_ng_template_Template_0, 0, 0, "ng-template", $t0_attrs$); - $i0$.ɵlistener("outDirective", function MyComponent_Template_ng_template_outDirective_listener($event) { return $event.doSth(); }); + $i0$.ɵtemplate(0, MyComponent_ng_template_0_Template, 0, 0, "ng-template", $t0_attrs$); + $i0$.ɵlistener("outDirective", function MyComponent_Template_ng_template_outDirective_0_listener($event) { return $event.doSth(); }); } }`; @@ -440,4 +440,166 @@ describe('compiler compliance: template', () => { expectEmit(result.source, template, 'Incorrect template'); }); + + it('should create unique template function names even for similar nested template structures', + () => { + const files = { + app: { + 'spec1.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'a-component', + template: \` +
    +

    less than 10

    +

    less than 10

    +
    +
    +

    more than 10

    +
    + \`, + }) + export class AComponent { + items = [4, 2]; + } + + @NgModule({declarations: [AComponent]}) + export class AModule {} + `, + 'spec2.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'b-component', + template: \` +
    + +

    less than 10

    +

    less than 10

    +
    + +

    less than 10

    +
    +
    +
    + +

    more than 10

    +
    +
    + \`, + }) + export class BComponent { + items = [ + {subitems: [1, 3]}, + {subitems: [3, 7]}, + ]; + } + + @NgModule({declarations: [BComponent]}) + export class BModule {} + `, + }, + }; + + const result = compile(files, angularFiles); + + const allTemplateFunctionsNames = (result.source.match(/function ([^\s(]+)/g) || []) + .map(x => x.slice(9)) + .filter(x => x.includes('Template')) + .sort(); + const uniqueTemplateFunctionNames = Array.from(new Set(allTemplateFunctionsNames)); + + // Expected template function: + // - 5 for AComponent's template. + // - 9 for BComponent's template. + // - 2 for the two components. + expect(allTemplateFunctionsNames.length).toBe(5 + 9 + 2); + expect(allTemplateFunctionsNames).toEqual(uniqueTemplateFunctionNames); + }); + + it('should create unique listener function names even for similar nested template structures', + () => { + const files = { + app: { + 'spec.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-component', + template: \` +
    +

    {{ item }}

    +

    {{ item }}

    +
    +
    +

    {{ item }}

    +
    + \`, + }) + export class MyComponent { + items = [4, 2]; + } + + @NgModule({declarations: [MyComponent]}) + export class MyModule {} + `, + }, + }; + + const result = compile(files, angularFiles); + + const allListenerFunctionsNames = (result.source.match(/function ([^\s(]+)/g) || []) + .map(x => x.slice(9)) + .filter(x => x.includes('listener')) + .sort(); + const uniqueListenerFunctionNames = Array.from(new Set(allListenerFunctionsNames)); + + expect(allListenerFunctionsNames.length).toBe(3); + expect(allListenerFunctionsNames).toEqual(uniqueListenerFunctionNames); + }); + + it('should support pipes in template bindings', () => { + const files = { + app: { + 'spec.ts': ` + import {Component, NgModule} from '@angular/core'; + + @Component({ + selector: 'my-component', + template: \` +
    \` + }) + export class MyComponent {} + + @NgModule({declarations: [MyComponent]}) + export class MyModule {} + ` + } + }; + + const template = ` + const $c0$ = [${AttributeMarker.SelectOnly}, "ngIf"]; + + function MyComponent_div_0_Template(rf, ctx) { + if (rf & 1) { + $i0$.ɵelement(0, "div"); + } + } + + // ... + + template: function MyComponent_Template(rf, ctx) { + if (rf & 1) { + $i0$.ɵtemplate(0, MyComponent_div_0_Template, 1, 0, "div", $c0$); + $i0$.ɵpipe(1, "pipe"); + } if (rf & 2) { + $i0$.ɵelementProperty(0, "ngIf", $i0$.ɵbind($i0$.ɵpipeBind1(1, 1, ctx.val))); + } + }`; + + const result = compile(files, angularFiles); + + expectEmit(result.source, template, 'Incorrect template'); + }); }); diff --git a/packages/compiler-cli/test/diagnostics/mocks.ts b/packages/compiler-cli/test/diagnostics/mocks.ts index aa3fefbcc4..6542b4bd5d 100644 --- a/packages/compiler-cli/test/diagnostics/mocks.ts +++ b/packages/compiler-cli/test/diagnostics/mocks.ts @@ -6,27 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotCompilerHost, AotSummaryResolver, CompileMetadataResolver, CompilerConfig, DEFAULT_INTERPOLATION_CONFIG, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, InterpolationConfig, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, SummaryResolver, TemplateParser, analyzeNgModules, createOfflineCompileUrlResolver} from '@angular/compiler'; +import {AotSummaryResolver, CompileMetadataResolver, CompilerConfig, DEFAULT_INTERPOLATION_CONFIG, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, InterpolationConfig, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, SummaryResolver, TemplateParser, analyzeNgModules, createOfflineCompileUrlResolver} from '@angular/compiler'; import {ViewEncapsulation, ɵConsole as Console} from '@angular/core'; import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; import {DiagnosticTemplateInfo} from '../../src/diagnostics/expression_diagnostics'; -import {getClassFromStaticSymbol, getClassMembers, getPipesTable, getSymbolQuery} from '../../src/diagnostics/typescript_symbols'; +import {getClassMembers, getPipesTable, getSymbolQuery} from '../../src/diagnostics/typescript_symbols'; import {Directory, MockAotContext} from '../mocks'; -import {isInBazel, setup} from '../test_support'; - -function calculateAngularPath() { - if (isInBazel()) { - const support = setup(); - return path.join(support.basePath, 'node_modules/@angular/*'); - } else { - const moduleFilename = module.filename.replace(/\\/g, '/'); - const distIndex = moduleFilename.indexOf('/dist/all'); - return moduleFilename.substr(0, distIndex) + '/packages/*'; - } -} +import {setup} from '../test_support'; const realFiles = new Map(); @@ -36,6 +25,8 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { private assumedExist = new Set(); constructor(private scripts: string[], files: Directory, currentDirectory: string = '/') { + const support = setup(); + this.options = { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, @@ -49,7 +40,7 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { strictNullChecks: true, baseUrl: currentDirectory, lib: ['lib.es2015.d.ts', 'lib.dom.d.ts'], - paths: {'@angular/*': [calculateAngularPath()]} + paths: {'@angular/*': [path.join(support.basePath, 'node_modules/@angular/*')]} }; this.context = new MockAotContext(currentDirectory, files); } @@ -84,11 +75,11 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { private internalReadFile(fileName: string): string|undefined { let basename = path.basename(fileName); if (/^lib.*\.d\.ts$/.test(basename)) { - let libPath = path.dirname(ts.getDefaultLibFilePath(this.getCompilationSettings())); - fileName = path.join(libPath, basename); + let libPath = path.posix.dirname(ts.getDefaultLibFilePath(this.getCompilationSettings())); + fileName = path.posix.join(libPath, basename); } if (fileName.startsWith('app/')) { - fileName = path.join(this.context.currentDirectory, fileName); + fileName = path.posix.join(this.context.currentDirectory, fileName); } if (this.context.fileExists(fileName)) { return this.context.readFile(fileName); @@ -166,12 +157,7 @@ export class DiagnosticContext { }; const urlResolver = createOfflineCompileUrlResolver(); const htmlParser = new class extends HtmlParser { - parse( - source: string, url: string, parseExpansionForms: boolean = false, - interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): - ParseTreeResult { - return new ParseTreeResult([], []); - } + parse(): ParseTreeResult { return new ParseTreeResult([], []); } }; // This tracks the CompileConfig in codegen.ts. Currently these options @@ -218,7 +204,7 @@ function compileTemplate(context: DiagnosticContext, type: StaticSymbol, templat const parser = new TemplateParser( config, context.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser, null !, []); - const htmlResult = htmlParser.parse(template, '', true); + const htmlResult = htmlParser.parse(template, '', {tokenizeExpansionForms: true}); const analyzedModules = context.analyzedModules; // let errors: Diagnostic[]|undefined = undefined; let ngModule = analyzedModules.ngModuleByPipeOrDirective.get(type); diff --git a/packages/compiler-cli/test/extract_i18n_spec.ts b/packages/compiler-cli/test/extract_i18n_spec.ts index 3a03392b11..39d70991a5 100644 --- a/packages/compiler-cli/test/extract_i18n_spec.ts +++ b/packages/compiler-cli/test/extract_i18n_spec.ts @@ -8,17 +8,9 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as ts from 'typescript'; import {mainXi18n} from '../src/extract_i18n'; - -import {isInBazel, makeTempDir, setup} from './test_support'; - -function getNgRootDir() { - const moduleFilename = module.filename.replace(/\\/g, '/'); - const distIndex = moduleFilename.indexOf('/dist/all'); - return moduleFilename.substr(0, distIndex); -} +import {makeTempDir, setup} from './test_support'; const EXPECTED_XMB = ` { beforeEach(() => { errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error); - if (isInBazel()) { - const support = setup(); - write = (fileName: string, content: string) => { support.write(fileName, content); }; - basePath = support.basePath; - outDir = path.join(basePath, 'built'); - } else { - basePath = makeTempDir(); - write = (fileName: string, content: string) => { - const dir = path.dirname(fileName); - if (dir !== '.') { - const newDir = path.join(basePath, dir); - if (!fs.existsSync(newDir)) fs.mkdirSync(newDir); - } - fs.writeFileSync(path.join(basePath, fileName), content, {encoding: 'utf-8'}); - }; - outDir = path.resolve(basePath, 'built'); - const ngRootDir = getNgRootDir(); - const nodeModulesPath = path.resolve(basePath, 'node_modules'); - fs.mkdirSync(nodeModulesPath); - fs.symlinkSync( - path.resolve(ngRootDir, 'dist', 'all', '@angular'), - path.resolve(nodeModulesPath, '@angular')); - fs.symlinkSync( - path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs')); - } + const support = setup(); + write = (fileName: string, content: string) => { support.write(fileName, content); }; + basePath = support.basePath; + outDir = path.join(basePath, 'built'); write('tsconfig-base.json', `{ "compilerOptions": { "experimentalDecorators": true, diff --git a/packages/compiler-cli/test/ngc_spec.ts b/packages/compiler-cli/test/ngc_spec.ts index 55dbc8ca0e..d3de276a32 100644 --- a/packages/compiler-cli/test/ngc_spec.ts +++ b/packages/compiler-cli/test/ngc_spec.ts @@ -11,14 +11,7 @@ import * as path from 'path'; import * as ts from 'typescript'; import {main, readCommandLineAndConfiguration, watchMode} from '../src/main'; - -import {isInBazel, makeTempDir, setup} from './test_support'; - -function getNgRootDir() { - const moduleFilename = module.filename.replace(/\\/g, '/'); - const distIndex = moduleFilename.indexOf('/dist/all'); - return moduleFilename.substr(0, distIndex); -} +import {setup} from './test_support'; describe('ngc transformer command-line', () => { let basePath: string; @@ -44,33 +37,12 @@ describe('ngc transformer command-line', () => { beforeEach(() => { errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error); - if (isInBazel) { - const support = setup(); - basePath = support.basePath; - outDir = path.join(basePath, 'built'); - process.chdir(basePath); - write = (fileName: string, content: string) => { support.write(fileName, content); }; - } else { - basePath = makeTempDir(); - process.chdir(basePath); - write = (fileName: string, content: string) => { - const dir = path.dirname(fileName); - if (dir != '.') { - const newDir = path.join(basePath, dir); - if (!fs.existsSync(newDir)) fs.mkdirSync(newDir); - } - fs.writeFileSync(path.join(basePath, fileName), content, {encoding: 'utf-8'}); - }; - outDir = path.resolve(basePath, 'built'); - const ngRootDir = getNgRootDir(); - const nodeModulesPath = path.resolve(basePath, 'node_modules'); - fs.mkdirSync(nodeModulesPath); - fs.symlinkSync( - path.resolve(ngRootDir, 'dist', 'all', '@angular'), - path.resolve(nodeModulesPath, '@angular')); - fs.symlinkSync( - path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs')); - } + const support = setup(); + basePath = support.basePath; + outDir = path.join(basePath, 'built'); + process.chdir(basePath); + write = (fileName: string, content: string) => { support.write(fileName, content); }; + write('tsconfig-base.json', `{ "compilerOptions": { "experimentalDecorators": true, @@ -82,6 +54,7 @@ describe('ngc transformer command-line', () => { "baseUrl": ".", "declaration": true, "target": "es5", + "newLine": "lf", "module": "es2015", "moduleResolution": "node", "lib": ["es6", "dom"], @@ -99,6 +72,25 @@ describe('ngc transformer command-line', () => { expect(exitCode).toBe(0); }); + it('should respect the "newLine" compiler option when printing diagnostics', () => { + writeConfig(`{ + "extends": "./tsconfig-base.json", + "compilerOptions": { + "newLine": "CRLF", + } + }`); + write('test.ts', 'export NOT_VALID = true;'); + + // Stub the error spy because we don't want to call through and print the + // expected error diagnostic. + errorSpy.and.stub(); + + const exitCode = main(['-p', basePath], errorSpy); + expect(errorSpy).toHaveBeenCalledWith( + `test.ts(1,1): error TS1128: Declaration or statement expected.\r\n`); + expect(exitCode).toBe(1); + }); + describe('errors', () => { beforeEach(() => { errorSpy.and.stub(); }); @@ -111,7 +103,7 @@ describe('ngc transformer command-line', () => { const exitCode = main(['-p', basePath], errorSpy); expect(errorSpy).toHaveBeenCalledWith( - `error TS6053: File '` + path.join(basePath, 'test.ts') + `' not found.` + + `error TS6053: File '` + path.posix.join(basePath, 'test.ts') + `' not found.` + '\n'); expect(exitCode).toEqual(1); }); @@ -250,19 +242,9 @@ describe('ngc transformer command-line', () => { expect(exitCode).toEqual(0); expect(fs.existsSync(path.resolve(outDir, 'mymodule.ngfactory.js'))).toBe(true); - - if (isInBazel()) { - // In bazel we use the packaged version so the factory is at the root and we - // get the flattened factory. - expect(fs.existsSync( - path.resolve(outDir, 'node_modules', '@angular', 'core', 'core.ngfactory.js'))) - .toBe(true); - } else { - expect(fs.existsSync(path.resolve( - outDir, 'node_modules', '@angular', 'core', 'src', - 'application_module.ngfactory.js'))) - .toBe(true); - } + expect(fs.existsSync( + path.resolve(outDir, 'node_modules', '@angular', 'core', 'core.ngfactory.js'))) + .toBe(true); }); describe('comments', () => { @@ -367,18 +349,9 @@ describe('ngc transformer command-line', () => { const exitCode = main(['-p', path.join(basePath, 'tsconfig.json')], errorSpy); expect(exitCode).toEqual(0); expect(fs.existsSync(path.resolve(outDir, 'mymodule.ngfactory.js'))).toBe(true); - if (isInBazel()) { - // In bazel we use the packaged version so the factory is at the root and we - // get the flattened factory. - expect(fs.existsSync( - path.resolve(outDir, 'node_modules', '@angular', 'core', 'core.ngfactory.js'))) - .toBe(true); - } else { - expect(fs.existsSync(path.resolve( - outDir, 'node_modules', '@angular', 'core', 'src', - 'application_module.ngfactory.js'))) - .toBe(true); - } + expect(fs.existsSync( + path.resolve(outDir, 'node_modules', '@angular', 'core', 'core.ngfactory.js'))) + .toBe(true); }); describe(`emit generated files depending on the source file`, () => { @@ -1103,15 +1076,17 @@ describe('ngc transformer command-line', () => { }); }); - it('should be able to compile multiple libraries with summaries', () => { - // Note: we need to emit the generated code for the libraries - // into the node_modules, as that is the only way that we - // currently support when using summaries. - // TODO(tbosch): add support for `paths` to our CompilerHost.fileNameToModuleName - // and then use `paths` here instead of writing to node_modules. + describe('with external symbol re-exports enabled', () => { - // Angular - write('tsconfig-ng.json', `{ + it('should be able to compile multiple libraries with summaries', () => { + // Note: we need to emit the generated code for the libraries + // into the node_modules, as that is the only way that we + // currently support when using summaries. + // TODO(tbosch): add support for `paths` to our CompilerHost.fileNameToModuleName + // and then use `paths` here instead of writing to node_modules. + + // Angular + write('tsconfig-ng.json', `{ "extends": "./tsconfig-base.json", "angularCompilerOptions": { "generateCodeForLibraries": true, @@ -1127,69 +1102,68 @@ describe('ngc transformer command-line', () => { ] }`); - // Lib 1 - write('lib1/tsconfig-lib1.json', `{ + // Lib 1 + write('lib1/tsconfig-lib1.json', `{ "extends": "../tsconfig-base.json", "angularCompilerOptions": { "generateCodeForLibraries": false, - "enableSummariesForJit": true + "enableSummariesForJit": true, + "createExternalSymbolFactoryReexports": true }, "compilerOptions": { "rootDir": ".", "outDir": "../node_modules/lib1_built" } }`); - write('lib1/module.ts', ` + write('lib1/module.ts', ` import {NgModule} from '@angular/core'; - export function someFactory(): any { return null; } - @NgModule({ providers: [{provide: 'foo', useFactory: someFactory}] }) export class Module {} `); - write('lib1/class1.ts', `export class Class1 {}`); + write('lib1/class1.ts', `export class Class1 {}`); - // Lib 2 - write('lib2/tsconfig-lib2.json', `{ + // Lib 2 + write('lib2/tsconfig-lib2.json', `{ "extends": "../tsconfig-base.json", "angularCompilerOptions": { "generateCodeForLibraries": false, - "enableSummariesForJit": true + "enableSummariesForJit": true, + "createExternalSymbolFactoryReexports": true }, "compilerOptions": { "rootDir": ".", "outDir": "../node_modules/lib2_built" } }`); - write('lib2/module.ts', ` + write('lib2/module.ts', ` export {Module} from 'lib1_built/module'; `); - write('lib2/class2.ts', ` - import {Class1} from 'lib1_built/class1'; + write('lib2/class2.ts', ` + import {Class1} from 'lib1_built/class1'; + export class Class2 { + constructor(class1: Class1) {} + } + `); - export class Class2 { - constructor(class1: Class1) {} - } - `); - - // Application - write('app/tsconfig-app.json', `{ + // Application + write('app/tsconfig-app.json', `{ "extends": "../tsconfig-base.json", "angularCompilerOptions": { "generateCodeForLibraries": false, - "enableSummariesForJit": true + "enableSummariesForJit": true, + "createExternalSymbolFactoryReexports": true }, "compilerOptions": { "rootDir": ".", "outDir": "../built/app" } }`); - write('app/main.ts', ` + write('app/main.ts', ` import {NgModule, Inject} from '@angular/core'; import {Module} from 'lib2_built/module'; - @NgModule({ imports: [Module] }) @@ -1198,10 +1172,149 @@ describe('ngc transformer command-line', () => { } `); - if (!isInBazel()) { - // This is not necessary in bazel as it uses the npm_package - expect(main(['-p', path.join(basePath, 'tsconfig-ng.json')], errorSpy)).toBe(0); - } + expect(main(['-p', path.join(basePath, 'lib1', 'tsconfig-lib1.json')], errorSpy)).toBe(0); + expect(main(['-p', path.join(basePath, 'lib2', 'tsconfig-lib2.json')], errorSpy)).toBe(0); + expect(main(['-p', path.join(basePath, 'app', 'tsconfig-app.json')], errorSpy)).toBe(0); + + // library 1 + // make `shouldExist` / `shouldNotExist` relative to `node_modules` + outDir = path.resolve(basePath, 'node_modules'); + shouldExist('lib1_built/module.js'); + shouldExist('lib1_built/module.ngsummary.json'); + shouldExist('lib1_built/module.ngsummary.js'); + shouldExist('lib1_built/module.ngsummary.d.ts'); + shouldExist('lib1_built/module.ngfactory.js'); + shouldExist('lib1_built/module.ngfactory.d.ts'); + + // library 2 + // make `shouldExist` / `shouldNotExist` relative to `node_modules` + outDir = path.resolve(basePath, 'node_modules'); + shouldExist('lib2_built/module.js'); + shouldExist('lib2_built/module.ngsummary.json'); + shouldExist('lib2_built/module.ngsummary.js'); + shouldExist('lib2_built/module.ngsummary.d.ts'); + shouldExist('lib2_built/module.ngfactory.js'); + shouldExist('lib2_built/module.ngfactory.d.ts'); + + shouldExist('lib2_built/class2.ngsummary.json'); + shouldNotExist('lib2_built/class2.ngsummary.js'); + shouldNotExist('lib2_built/class2.ngsummary.d.ts'); + shouldExist('lib2_built/class2.ngfactory.js'); + shouldExist('lib2_built/class2.ngfactory.d.ts'); + + // app + // make `shouldExist` / `shouldNotExist` relative to `built` + outDir = path.resolve(basePath, 'built'); + shouldExist('app/main.js'); + }); + + it('should create external symbol re-exports', () => { + writeConfig(`{ + "extends": "./tsconfig-base.json", + "angularCompilerOptions": { + "generateCodeForLibraries": false, + "createExternalSymbolFactoryReexports": true + } + }`); + + write('test.ts', ` + import {Injectable, NgZone} from '@angular/core'; + + @Injectable({providedIn: 'root'}) + export class MyService { + constructor(public ngZone: NgZone) {} + } + `); + + expect(main(['-p', basePath], errorSpy)).toBe(0); + + shouldExist('test.js'); + shouldExist('test.metadata.json'); + shouldExist('test.ngsummary.json'); + shouldExist('test.ngfactory.js'); + shouldExist('test.ngfactory.d.ts'); + + const summaryJson = require(path.join(outDir, 'test.ngsummary.json')); + const factoryOutput = fs.readFileSync(path.join(outDir, 'test.ngfactory.js'), 'utf8'); + + expect(summaryJson['symbols'][0].name).toBe('MyService'); + expect(summaryJson['symbols'][1]) + .toEqual(jasmine.objectContaining({name: 'NgZone', importAs: 'NgZone_1'})); + + expect(factoryOutput).toContain(`export { NgZone as NgZone_1 } from "@angular/core";`); + }); + }); + + it('should be able to compile multiple libraries with summaries', () => { + // Lib 1 + write('lib1/tsconfig-lib1.json', `{ + "extends": "../tsconfig-base.json", + "angularCompilerOptions": { + "generateCodeForLibraries": false, + "enableSummariesForJit": true + }, + "compilerOptions": { + "rootDir": ".", + "outDir": "../node_modules/lib1_built" + } + }`); + write('lib1/module.ts', ` + import {NgModule} from '@angular/core'; + + export function someFactory(): any { return null; } + + @NgModule({ + providers: [{provide: 'foo', useFactory: someFactory}] + }) + export class Module {} + `); + write('lib1/class1.ts', `export class Class1 {}`); + + // Lib 2 + write('lib2/tsconfig-lib2.json', `{ + "extends": "../tsconfig-base.json", + "angularCompilerOptions": { + "generateCodeForLibraries": false, + "enableSummariesForJit": true + }, + "compilerOptions": { + "rootDir": ".", + "outDir": "../node_modules/lib2_built" + } + }`); + write('lib2/module.ts', `export {Module} from 'lib1_built/module';`); + write('lib2/class2.ts', ` + import {Class1} from 'lib1_built/class1'; + + export class Class2 { + constructor(class1: Class1) {} + } + `); + + // Application + write('app/tsconfig-app.json', `{ + "extends": "../tsconfig-base.json", + "angularCompilerOptions": { + "generateCodeForLibraries": false, + "enableSummariesForJit": true + }, + "compilerOptions": { + "rootDir": ".", + "outDir": "../built/app" + } + }`); + write('app/main.ts', ` + import {NgModule, Inject} from '@angular/core'; + import {Module} from 'lib2_built/module'; + + @NgModule({ + imports: [Module] + }) + export class AppModule { + constructor(@Inject('foo') public foo: any) {} + } + `); + expect(main(['-p', path.join(basePath, 'lib1', 'tsconfig-lib1.json')], errorSpy)).toBe(0); expect(main(['-p', path.join(basePath, 'lib2', 'tsconfig-lib2.json')], errorSpy)).toBe(0); expect(main(['-p', path.join(basePath, 'app', 'tsconfig-app.json')], errorSpy)).toBe(0); @@ -1220,17 +1333,24 @@ describe('ngc transformer command-line', () => { // make `shouldExist` / `shouldNotExist` relative to `node_modules` outDir = path.resolve(basePath, 'node_modules'); shouldExist('lib2_built/module.js'); + + // "module.ts" re-exports an external symbol and will therefore + // have a summary JSON file and its corresponding JIT summary. shouldExist('lib2_built/module.ngsummary.json'); shouldExist('lib2_built/module.ngsummary.js'); shouldExist('lib2_built/module.ngsummary.d.ts'); - shouldExist('lib2_built/module.ngfactory.js'); - shouldExist('lib2_built/module.ngfactory.d.ts'); + // "module.ts" only re-exports an external symbol and the AOT compiler does not + // need to generate anything. Therefore there should be no factory files. + shouldNotExist('lib2_built/module.ngfactory.js'); + shouldNotExist('lib2_built/module.ngfactory.d.ts'); shouldExist('lib2_built/class2.ngsummary.json'); shouldNotExist('lib2_built/class2.ngsummary.js'); shouldNotExist('lib2_built/class2.ngsummary.d.ts'); - shouldExist('lib2_built/class2.ngfactory.js'); - shouldExist('lib2_built/class2.ngfactory.d.ts'); + // We don't expect factories here because the "class2.ts" file + // just exports a class that does not produce any AOT code. + shouldNotExist('lib2_built/class2.ngfactory.js'); + shouldNotExist('lib2_built/class2.ngfactory.d.ts'); // app // make `shouldExist` / `shouldNotExist` relative to `built` @@ -1238,110 +1358,6 @@ describe('ngc transformer command-line', () => { shouldExist('app/main.js'); }); - if (!isInBazel()) { - // This is an unnecessary test bazel as it always uses flat modules - it('should be able to compile libraries with summaries and flat modules', () => { - writeFiles(); - compile(); - - // libraries - // make `shouldExist` / `shouldNotExist` relative to `node_modules` - outDir = path.resolve(basePath, 'node_modules'); - shouldExist('flat_module/index.ngfactory.js'); - shouldExist('flat_module/index.ngsummary.json'); - - // app - // make `shouldExist` / `shouldNotExist` relative to `built` - outDir = path.resolve(basePath, 'built'); - shouldExist('app/main.ngfactory.js'); - - const factory = fs.readFileSync(path.resolve(outDir, 'app/main.ngfactory.js')).toString(); - // reference to the module itself - expect(factory).toMatch(/from "flat_module"/); - // no reference to a deep file - expect(factory).not.toMatch(/from "flat_module\//); - - function writeFiles() { - createFlatModuleInNodeModules(); - - // Angular + flat module - write('tsconfig-lib.json', `{ - "extends": "./tsconfig-base.json", - "angularCompilerOptions": { - "generateCodeForLibraries": true - }, - "compilerOptions": { - "outDir": "." - }, - "include": ["node_modules/@angular/core/**/*", "node_modules/flat_module/**/*"], - "exclude": [ - "node_modules/@angular/core/test/**", - "node_modules/@angular/core/testing/**" - ] - }`); - - // Application - write('app/tsconfig-app.json', `{ - "extends": "../tsconfig-base.json", - "angularCompilerOptions": { - "generateCodeForLibraries": false - }, - "compilerOptions": { - "rootDir": ".", - "outDir": "../built/app" - } - }`); - write('app/main.ts', ` - import {NgModule} from '@angular/core'; - import {FlatModule} from 'flat_module'; - - @NgModule({ - imports: [FlatModule] - }) - export class AppModule {} - `); - } - - function createFlatModuleInNodeModules() { - // compile the flat module - writeFlatModule('index.js'); - expect(main(['-p', basePath], errorSpy)).toBe(0); - - // move the flat module output into node_modules - const flatModuleNodeModulesPath = path.resolve(basePath, 'node_modules', 'flat_module'); - fs.renameSync(outDir, flatModuleNodeModulesPath); - fs.renameSync( - path.resolve(basePath, 'src/flat.component.html'), - path.resolve(flatModuleNodeModulesPath, 'src/flat.component.html')); - // and remove the sources. - fs.renameSync(path.resolve(basePath, 'src'), path.resolve(basePath, 'flat_module_src')); - fs.unlinkSync(path.resolve(basePath, 'public-api.ts')); - - // add a flatModuleIndexRedirect - write('node_modules/flat_module/redirect.metadata.json', `{ - "__symbolic": "module", - "version": 3, - "metadata": {}, - "exports": [ - { - "from": "./index" - } - ], - "flatModuleIndexRedirect": true, - "importAs": "flat_module" - }`); - write('node_modules/flat_module/redirect.d.ts', `export * from './index';`); - // add a package.json to use the redirect - write('node_modules/flat_module/package.json', `{"typings": "./redirect.d.ts"}`); - } - - function compile() { - expect(main(['-p', path.join(basePath, 'tsconfig-lib.json')], errorSpy)).toBe(0); - expect(main(['-p', path.join(basePath, 'app', 'tsconfig-app.json')], errorSpy)).toBe(0); - } - }); - } - describe('enableResourceInlining', () => { it('should inline templateUrl and styleUrl in JS and metadata', () => { writeConfig(`{ diff --git a/packages/compiler-cli/test/ngcc/ngcc_spec.ts b/packages/compiler-cli/test/ngcc/ngcc_spec.ts index 1f4f1c5e44..be09793aca 100644 --- a/packages/compiler-cli/test/ngcc/ngcc_spec.ts +++ b/packages/compiler-cli/test/ngcc/ngcc_spec.ts @@ -12,13 +12,9 @@ import {join} from 'path'; const Module = require('module'); import {mainNgcc} from '../../src/ngcc/src/main'; +import {getAngularPackagesFromRunfiles} from '../runfile_helpers'; describe('ngcc main()', () => { - if (!isInBazel()) { - // These tests should be excluded from the non-Bazel build. - return; - } - beforeEach(createMockFileSystem); afterEach(restoreRealFileSystem); @@ -45,8 +41,7 @@ describe('ngcc main()', () => { function createMockFileSystem() { - const packagesPath = join(process.env.TEST_SRCDIR !, 'angular/packages'); - mockFs({'/node_modules/@angular': loadPackages(packagesPath)}); + mockFs({'/node_modules/@angular': loadAngularPackages()}); spyOn(Module, '_resolveFilename').and.callFake(mockResolve); } @@ -55,27 +50,16 @@ function restoreRealFileSystem() { } -/** - * Load the built Angular packages into an in-memory structure. - * @param packagesPath the path to the folder containing the built packages. - */ -function loadPackages(packagesPath: string): Directory { +/** Load the built Angular packages into an in-memory structure. */ +function loadAngularPackages(): Directory { const packagesDirectory: Directory = {}; - readdirSync(packagesPath).forEach(name => { - const packagePath = join(packagesPath, name); - if (!statSync(packagePath).isDirectory()) { - return; - } - const npmPackagePath = join(packagePath, 'npm_package'); - if (!existsSync(npmPackagePath)) { - return; - } - packagesDirectory[name] = loadDirectory(npmPackagePath); - }); + + getAngularPackagesFromRunfiles().forEach( + ({name, pkgPath}) => { packagesDirectory[name] = loadDirectory(pkgPath); }); + return packagesDirectory; } - /** * Load real files from the filesystem into an "in-memory" structure, * which can be used with `mock-fs`. @@ -100,10 +84,6 @@ interface Directory { [pathSegment: string]: string|Directory; } -function isInBazel() { - return process.env.TEST_SRCDIR != null; -} - function mockResolve(p: string): string|null { if (existsSync(p)) { const stat = statSync(p); @@ -122,4 +102,4 @@ function mockResolve(p: string): string|null { } } return null; -} \ No newline at end of file +} diff --git a/packages/compiler-cli/test/ngtools_api_spec.ts b/packages/compiler-cli/test/ngtools_api_spec.ts index 3fd3832659..6ceeb355be 100644 --- a/packages/compiler-cli/test/ngtools_api_spec.ts +++ b/packages/compiler-cli/test/ngtools_api_spec.ts @@ -7,7 +7,7 @@ */ import {__NGTOOLS_PRIVATE_API_2 as NgTools_InternalApi_NG_2} from '@angular/compiler-cli'; -import {fixmeIvy} from '@angular/private/testing'; +import {fixmeIvy, ivyEnabled} from '@angular/private/testing'; import * as path from 'path'; import * as ts from 'typescript'; @@ -19,7 +19,7 @@ describe('ngtools_api (deprecated)', () => { beforeEach(() => { testSupport = setup(); }); function createProgram(rootNames: string[]) { - const options = testSupport.createCompilerOptions(); + const options = testSupport.createCompilerOptions({enableIvy: ivyEnabled && 'ngtsc'}); const host = ts.createCompilerHost(options, true); const program = ts.createProgram(rootNames.map(p => path.resolve(testSupport.basePath, p)), options, host); @@ -37,7 +37,7 @@ describe('ngtools_api (deprecated)', () => { export class ErrorComp2 {} @NgModule({ - declarations: [ErrorComp2, NonExistentComp], + declarations: [ErrorComp2], imports: [RouterModule.forRoot([{loadChildren: './child#ChildModule'}])] }) export class MainModule {} @@ -60,9 +60,10 @@ describe('ngtools_api (deprecated)', () => { }); } - fixmeIvy('FW-629: ngtsc lists lazy routes').it('should list lazy routes recursively', () => { + it('should list lazy routes recursively', () => { writeSomeRoutes(); - const {program, host, options} = createProgram(['src/main.ts']); + const {program, host, options} = + createProgram(['src/main.ts', 'src/child.ts', 'src/child2.ts']); const routes = NgTools_InternalApi_NG_2.listLazyRoutes({ program, host, @@ -70,14 +71,15 @@ describe('ngtools_api (deprecated)', () => { entryModule: 'src/main#MainModule', }); expect(routes).toEqual({ - './child#ChildModule': path.resolve(testSupport.basePath, 'src/child.ts'), - './child2#ChildModule2': path.resolve(testSupport.basePath, 'src/child2.ts'), + './child#ChildModule': path.posix.join(testSupport.basePath, 'src/child.ts'), + './child2#ChildModule2': path.posix.join(testSupport.basePath, 'src/child2.ts'), }); }); it('should allow to emit the program after analyzing routes', () => { writeSomeRoutes(); - const {program, host, options} = createProgram(['src/main.ts']); + const {program, host, options} = + createProgram(['src/main.ts', 'src/child.ts', 'src/child2.ts']); NgTools_InternalApi_NG_2.listLazyRoutes({ program, host, diff --git a/packages/compiler-cli/test/ngtsc/BUILD.bazel b/packages/compiler-cli/test/ngtsc/BUILD.bazel index 0019ee03e5..23900a055c 100644 --- a/packages/compiler-cli/test/ngtsc/BUILD.bazel +++ b/packages/compiler-cli/test/ngtsc/BUILD.bazel @@ -7,7 +7,11 @@ ts_library( deps = [ "//packages/compiler", "//packages/compiler-cli", + "//packages/compiler-cli/src/ngtsc/routing", + "//packages/compiler-cli/src/ngtsc/util", "//packages/compiler-cli/test:test_utils", + "@ngdeps//@types/source-map", + "@ngdeps//source-map", "@ngdeps//typescript", ], ) diff --git a/packages/compiler-cli/test/ngtsc/env.ts b/packages/compiler-cli/test/ngtsc/env.ts index 6fbf828c73..ae4bdbcf60 100644 --- a/packages/compiler-cli/test/ngtsc/env.ts +++ b/packages/compiler-cli/test/ngtsc/env.ts @@ -6,24 +6,29 @@ * found in the LICENSE file at https://angular.io/license */ +import {CustomTransformers} from '@angular/compiler-cli'; import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; -import {main, mainDiagnosticsForTest} from '../../src/main'; -import {TestSupport, isInBazel, setup} from '../test_support'; +import {createCompilerHost, createProgram} from '../../ngtools2'; +import {main, mainDiagnosticsForTest, readNgcCommandLineAndConfiguration} from '../../src/main'; +import {LazyRoute} from '../../src/ngtsc/routing'; +import {resolveNpmTreeArtifact} from '../runfile_helpers'; +import {TestSupport, setup} from '../test_support'; function setupFakeCore(support: TestSupport): void { if (!process.env.TEST_SRCDIR) { throw new Error('`setupFakeCore` must be run within a Bazel test'); } - const fakeCore = path.join( - process.env.TEST_SRCDIR, 'angular/packages/compiler-cli/test/ngtsc/fake_core/npm_package'); + + const fakeNpmPackageDir = + resolveNpmTreeArtifact('angular/packages/compiler-cli/test/ngtsc/fake_core/npm_package'); const nodeModulesPath = path.join(support.basePath, 'node_modules'); const angularCoreDirectory = path.join(nodeModulesPath, '@angular/core'); - fs.symlinkSync(fakeCore, angularCoreDirectory); + fs.symlinkSync(fakeNpmPackageDir, angularCoreDirectory, 'dir'); } /** @@ -39,10 +44,6 @@ export class NgtscTestEnvironment { * Set up a new testing environment. */ static setup(): NgtscTestEnvironment { - if (!NgtscTestEnvironment.supported) { - throw new Error(`Attempting to setup ngtsc tests in an unsupported environment`); - } - const support = setup(); const outDir = path.join(support.basePath, 'built'); process.chdir(support.basePath); @@ -62,6 +63,7 @@ export class NgtscTestEnvironment { "baseUrl": ".", "declaration": true, "target": "es5", + "newLine": "lf", "module": "es2015", "moduleResolution": "node", "lib": ["es6", "dom"], @@ -111,9 +113,9 @@ export class NgtscTestEnvironment { /** * Run the compiler to completion, and assert that no errors occurred. */ - driveMain(): void { + driveMain(customTransformers?: CustomTransformers): void { const errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error); - const exitCode = main(['-p', this.basePath], errorSpy); + const exitCode = main(['-p', this.basePath], errorSpy, undefined, customTransformers); expect(errorSpy).not.toHaveBeenCalled(); expect(exitCode).toBe(0); } @@ -126,5 +128,10 @@ export class NgtscTestEnvironment { return mainDiagnosticsForTest(['-p', this.basePath]) as ReadonlyArray; } - static get supported(): boolean { return isInBazel(); } + driveRoutes(entryPoint?: string): LazyRoute[] { + const {rootNames, options} = readNgcCommandLineAndConfiguration(['-p', this.basePath]); + const host = createCompilerHost({options}); + const program = createProgram({rootNames, host, options}); + return program.listLazyRoutes(entryPoint); + } } diff --git a/packages/compiler-cli/test/ngtsc/fake_core/index.ts b/packages/compiler-cli/test/ngtsc/fake_core/index.ts index 831831738d..f7115fe6b8 100644 --- a/packages/compiler-cli/test/ngtsc/fake_core/index.ts +++ b/packages/compiler-cli/test/ngtsc/fake_core/index.ts @@ -64,3 +64,15 @@ export interface SimpleChanges { [propName: string]: any; } export type ɵNgModuleDefWithMeta = any; export type ɵDirectiveDefWithMeta = any; + +export enum ViewEncapsulation { + Emulated = 0, + Native = 1, + None = 2, + ShadowDom = 3 +} + +export enum ChangeDetectionStrategy { + OnPush = 0, + Default = 1 +} \ No newline at end of file diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 93677ad278..41f8515b79 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -6,16 +6,27 @@ * found in the LICENSE file at https://angular.io/license */ +import {LazyRoute} from '@angular/compiler-cli/src/ngtsc/routing'; +import * as path from 'path'; +import * as ts from 'typescript'; + import {NgtscTestEnvironment} from './env'; const trim = (input: string): string => input.replace(/\s+/g, ' ').trim(); -describe('ngtsc behavioral tests', () => { - if (!NgtscTestEnvironment.supported) { - // These tests should be excluded from the non-Bazel build. - return; - } +const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`); +const viewQueryRegExp = (descend: boolean, ref?: string): RegExp => { + const maybeRef = ref ? `, ${ref}` : ``; + return new RegExp(`i0\\.ɵviewQuery\\(\\w+, ${descend}${maybeRef}\\)`); +}; + +const contentQueryRegExp = (predicate: string, descend: boolean, ref?: string): RegExp => { + const maybeRef = ref ? `, ${ref}` : ``; + return new RegExp(`i0\\.ɵcontentQuery\\(dirIndex, ${predicate}, ${descend}${maybeRef}\\)`); +}; + +describe('ngtsc behavioral tests', () => { let env !: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(); }); @@ -64,7 +75,89 @@ describe('ngtsc behavioral tests', () => { expect(dtsContents).toContain('static ngInjectableDef: i0.ɵInjectableDef>;'); }); - it('should compile Components without errors', () => { + it('should compile Injectables with providedIn without errors', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + + @Injectable() + export class Dep {} + + @Injectable({ providedIn: 'root' }) + export class Service { + constructor(dep: Dep) {} + } + `); + + env.driveMain(); + + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('Dep.ngInjectableDef ='); + expect(jsContents).toContain('Service.ngInjectableDef ='); + expect(jsContents) + .toContain('return new (t || Service)(i0.inject(Dep)); }, providedIn: \'root\' });'); + expect(jsContents).not.toContain('__decorate'); + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents).toContain('static ngInjectableDef: i0.ɵInjectableDef;'); + expect(dtsContents).toContain('static ngInjectableDef: i0.ɵInjectableDef;'); + }); + + it('should compile Injectables with providedIn and factory without errors', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + + @Injectable({ providedIn: 'root', useFactory: () => new Service() }) + export class Service { + constructor() {} + } + `); + + env.driveMain(); + + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('Service.ngInjectableDef ='); + expect(jsContents).toContain('(r = new t());'); + expect(jsContents).toContain('(r = (function () { return new Service(); })());'); + expect(jsContents).toContain('factory: function Service_Factory(t) { var r = null; if (t) {'); + expect(jsContents).toContain('return r; }, providedIn: \'root\' });'); + expect(jsContents).not.toContain('__decorate'); + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents).toContain('static ngInjectableDef: i0.ɵInjectableDef;'); + }); + + it('should compile Injectables with providedIn and factory with deps without errors', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + + @Injectable() + export class Dep {} + + @Injectable({ providedIn: 'root', useFactory: (dep: Dep) => new Service(dep), deps: [Dep] }) + export class Service { + constructor(dep: Dep) {} + } + `); + + env.driveMain(); + + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('Service.ngInjectableDef ='); + expect(jsContents).toContain('factory: function Service_Factory(t) { var r = null; if (t) {'); + expect(jsContents).toContain('(r = new t(i0.inject(Dep)));'); + expect(jsContents) + .toContain('(r = (function (dep) { return new Service(dep); })(i0.inject(Dep)));'); + expect(jsContents).toContain('return r; }, providedIn: \'root\' });'); + expect(jsContents).not.toContain('__decorate'); + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents).toContain('static ngInjectableDef: i0.ɵInjectableDef;'); + }); + + it('should compile Components (inline template) without errors', () => { env.tsconfig(); env.write('test.ts', ` import {Component} from '@angular/core'; @@ -85,10 +178,61 @@ describe('ngtsc behavioral tests', () => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain( - 'static ngComponentDef: i0.ɵComponentDefWithMeta'); + 'static ngComponentDef: i0.ɵComponentDefWithMeta'); }); - it('should compile Components without errors', () => { + it('should compile Components (dynamic inline template) without errors', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test-cmp', + template: 'this is ' + 'a test', + }) + export class TestCmp {} + `); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('TestCmp.ngComponentDef = i0.ɵdefineComponent'); + expect(jsContents).not.toContain('__decorate'); + + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) + .toContain( + 'static ngComponentDef: i0.ɵComponentDefWithMeta'); + }); + + it('should compile Components (function call inline template) without errors', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component} from '@angular/core'; + + function getTemplate() { + return 'this is a test'; + } + @Component({ + selector: 'test-cmp', + template: getTemplate(), + }) + export class TestCmp {} + `); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('TestCmp.ngComponentDef = i0.ɵdefineComponent'); + expect(jsContents).not.toContain('__decorate'); + + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) + .toContain( + 'static ngComponentDef: i0.ɵComponentDefWithMeta'); + }); + + it('should compile Components (external template) without errors', () => { env.tsconfig(); env.write('test.ts', ` import {Component} from '@angular/core'; @@ -107,6 +251,27 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toContain('Hello World'); }); + it('should add @nocollapse to static fields when closure annotations are requested', () => { + env.tsconfig({ + 'annotateForClosureCompiler': true, + }); + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test-cmp', + templateUrl: './dir/test.html', + }) + export class TestCmp {} + `); + env.write('dir/test.html', '

    Hello World

    '); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('/** @nocollapse */ TestCmp.ngComponentDef'); + }); + it('should compile Components with a templateUrl in a different rootDir', () => { env.tsconfig({}, ['./extraRootDir']); env.write('extraRootDir/test.html', '

    Hello World

    '); @@ -170,12 +335,12 @@ describe('ngtsc behavioral tests', () => { expect(jsContents) .toContain( 'i0.ɵdefineNgModule({ type: TestModule, bootstrap: [TestCmp], ' + - 'declarations: [TestCmp], imports: [], exports: [] })'); + 'declarations: [TestCmp] })'); const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain( - 'static ngComponentDef: i0.ɵComponentDefWithMeta'); + 'static ngComponentDef: i0.ɵComponentDefWithMeta'); expect(dtsContents) .toContain( 'static ngModuleDef: i0.ɵNgModuleDefWithMeta'); @@ -223,6 +388,92 @@ describe('ngtsc behavioral tests', () => { expect(dtsContents).toContain('static ngInjectorDef: i0.ɵInjectorDef'); }); + it('should compile NgModules with factory providers without errors', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component, NgModule} from '@angular/core'; + + export class Token {} + + @NgModule({}) + export class OtherModule {} + + @Component({ + selector: 'test-cmp', + template: 'this is a test', + }) + export class TestCmp {} + + @NgModule({ + declarations: [TestCmp], + providers: [{provide: Token, useFactory: () => new Token()}], + imports: [OtherModule], + }) + export class TestModule {} + `); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('i0.ɵdefineNgModule({ type: TestModule,'); + expect(jsContents) + .toContain( + `TestModule.ngInjectorDef = i0.defineInjector({ factory: ` + + `function TestModule_Factory(t) { return new (t || TestModule)(); }, providers: [{ provide: ` + + `Token, useFactory: function () { return new Token(); } }], imports: [[OtherModule]] });`); + + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) + .toContain( + 'static ngModuleDef: i0.ɵNgModuleDefWithMeta'); + expect(dtsContents).toContain('static ngInjectorDef: i0.ɵInjectorDef'); + }); + + it('should compile NgModules with factory providers and deps without errors', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component, NgModule} from '@angular/core'; + + export class Dep {} + + export class Token { + constructor(dep: Dep) {} + } + + @NgModule({}) + export class OtherModule {} + + @Component({ + selector: 'test-cmp', + template: 'this is a test', + }) + export class TestCmp {} + + @NgModule({ + declarations: [TestCmp], + providers: [{provide: Token, useFactory: (dep: Dep) => new Token(dep), deps: [Dep]}], + imports: [OtherModule], + }) + export class TestModule {} + `); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('i0.ɵdefineNgModule({ type: TestModule,'); + expect(jsContents) + .toContain( + `TestModule.ngInjectorDef = i0.defineInjector({ factory: ` + + `function TestModule_Factory(t) { return new (t || TestModule)(); }, providers: [{ provide: ` + + `Token, useFactory: function (dep) { return new Token(dep); }, deps: [Dep] }], imports: [[OtherModule]] });`); + + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) + .toContain( + 'static ngModuleDef: i0.ɵNgModuleDefWithMeta'); + expect(dtsContents).toContain('static ngInjectorDef: i0.ɵInjectorDef'); + }); + it('should compile NgModules with references to local components', () => { env.tsconfig(); env.write('test.ts', ` @@ -246,8 +497,8 @@ describe('ngtsc behavioral tests', () => { const dtsContents = env.getContents('test.d.ts'); expect(jsContents).toContain('import { Foo } from \'./foo\';'); - expect(jsContents).not.toMatch(/as i[0-9] from '.\/foo'/); - expect(dtsContents).toContain('as i1 from \'./foo\';'); + expect(jsContents).not.toMatch(/as i[0-9] from ".\/foo"/); + expect(dtsContents).toContain('as i1 from "./foo";'); }); it('should compile NgModules with references to absolute components', () => { @@ -274,8 +525,8 @@ describe('ngtsc behavioral tests', () => { const dtsContents = env.getContents('test.d.ts'); expect(jsContents).toContain('import { Foo } from \'foo\';'); - expect(jsContents).not.toMatch(/as i[0-9] from 'foo'/); - expect(dtsContents).toContain('as i1 from \'foo\';'); + expect(jsContents).not.toMatch(/as i[0-9] from "foo"/); + expect(dtsContents).toContain('as i1 from "foo";'); }); it('should compile Pipes without errors', () => { @@ -299,8 +550,7 @@ describe('ngtsc behavioral tests', () => { .toContain( 'TestPipe.ngPipeDef = i0.ɵdefinePipe({ name: "test-pipe", type: TestPipe, ' + 'factory: function TestPipe_Factory(t) { return new (t || TestPipe)(); }, pure: false })'); - expect(dtsContents) - .toContain('static ngPipeDef: i0.ɵPipeDefWithMeta;'); + expect(dtsContents).toContain('static ngPipeDef: i0.ɵPipeDefWithMeta;'); }); it('should compile pure Pipes without errors', () => { @@ -323,8 +573,7 @@ describe('ngtsc behavioral tests', () => { .toContain( 'TestPipe.ngPipeDef = i0.ɵdefinePipe({ name: "test-pipe", type: TestPipe, ' + 'factory: function TestPipe_Factory(t) { return new (t || TestPipe)(); }, pure: true })'); - expect(dtsContents) - .toContain('static ngPipeDef: i0.ɵPipeDefWithMeta;'); + expect(dtsContents).toContain('static ngPipeDef: i0.ɵPipeDefWithMeta;'); }); it('should compile Pipes with dependencies', () => { @@ -375,6 +624,231 @@ describe('ngtsc behavioral tests', () => { 'i0.ɵNgModuleDefWithMeta'); }); + describe('multiple decorators on classes', () => { + it('should compile @Injectable on Components, Directives, Pipes, and Modules', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component, Directive, Injectable, NgModule, Pipe} from '@angular/core'; + + @Component({selector: 'test', template: 'test'}) + @Injectable() + export class TestCmp {} + + @Directive({selector: 'test'}) + @Injectable() + export class TestDir {} + + @Pipe({name: 'test'}) + @Injectable() + export class TestPipe {} + + @NgModule({declarations: [TestCmp, TestDir, TestPipe]}) + @Injectable() + export class TestNgModule {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + const dtsContents = env.getContents('test.d.ts'); + + // Validate that each class has the primary definition. + expect(jsContents).toContain('TestCmp.ngComponentDef ='); + expect(jsContents).toContain('TestDir.ngDirectiveDef ='); + expect(jsContents).toContain('TestPipe.ngPipeDef ='); + expect(jsContents).toContain('TestNgModule.ngModuleDef ='); + + // Validate that each class also has an injectable definition. + expect(jsContents).toContain('TestCmp.ngInjectableDef ='); + expect(jsContents).toContain('TestDir.ngInjectableDef ='); + expect(jsContents).toContain('TestPipe.ngInjectableDef ='); + expect(jsContents).toContain('TestNgModule.ngInjectableDef ='); + + // Validate that each class's .d.ts declaration has the primary definition. + expect(dtsContents).toContain('ComponentDefWithMeta { + env.tsconfig(); + env.write('test.ts', ` + import {Component, Directive} from '@angular/core'; + + @Component({selector: 'test', template: 'test'}) + @Directive({selector: 'test'}) + class ShouldNotCompile {} + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(1); + expect(errors[0].messageText).toContain('Two incompatible decorators on class'); + }); + + + + it('should leave decorators present on jit: true directives', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Directive, Inject} from '@angular/core'; + + @Directive({ + selector: 'test', + jit: true, + }) + export class Test { + constructor(@Inject('foo') foo: string) {} + } + `); + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('Directive({'); + expect(jsContents).toContain('__param(0, Inject'); + }); + }); + + describe('compiling invalid @Injectables', () => { + describe('with strictInjectionParameters = true', () => { + it('should give a compile-time error if an invalid @Injectable is used with no arguments', + () => { + env.tsconfig({strictInjectionParameters: true}); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + + @Injectable() + export class Test { + constructor(private notInjectable: string) {} + } + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(1); + expect(errors[0].messageText).toContain('No suitable injection token for parameter'); + }); + + it('should give a compile-time error if an invalid @Injectable is used with an argument', + () => { + env.tsconfig({strictInjectionParameters: true}); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + + @Injectable() + export class Test { + constructor(private notInjectable: string) {} + } + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(1); + expect(errors[0].messageText).toContain('No suitable injection token for parameter'); + }); + + it('should not give a compile-time error if an invalid @Injectable is used with useValue', + () => { + env.tsconfig({strictInjectionParameters: true}); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + + @Injectable({ + providedIn: 'root', + useValue: '42', + }) + export class Test { + constructor(private notInjectable: string) {} + } + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toMatch(/if \(t\).*throw new Error.* else .* '42'/ms); + }); + }); + + describe('with strictInjectionParameters = false', () => { + it('should compile an @Injectable on a class with a non-injectable constructor', () => { + env.tsconfig({strictInjectionParameters: false}); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + + @Injectable() + export class Test { + constructor(private notInjectable: string) {} + } + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('factory: function Test_Factory(t) { throw new Error('); + }); + + it('should compile an @Injectable provided in the root on a class with a non-injectable constructor', + () => { + env.tsconfig({strictInjectionParameters: false}); + env.write('test.ts', ` + import {Injectable} from '@angular/core'; + @Injectable({providedIn: 'root'}) + export class Test { + constructor(private notInjectable: string) {} + } + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('factory: function Test_Factory(t) { throw new Error('); + }); + + }); + }); + + describe('former View Engine AST transform bugs', () => { + it('should compile array literals behind conditionals', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '{{value ? "yes" : [no]}}', + }) + class TestCmp { + value = true; + no = 'no'; + } + `); + + env.driveMain(); + expect(env.getContents('test.js')).toContain('i0.ɵpureFunction1'); + }); + + it('should compile array literals inside function arguments', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '{{fn([test])}}', + }) + class TestCmp { + fn(arg: any): string { + return 'test'; + } + + test = 'test'; + } + `); + + env.driveMain(); + expect(env.getContents('test.js')).toContain('i0.ɵpureFunction1'); + }); + }); + describe('unwrapping ModuleWithProviders functions', () => { it('should extract the generic type and include it in the module\'s declaration', () => { env.tsconfig(); @@ -400,7 +874,7 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toContain('imports: [[RouterModule.forRoot()]]'); const dtsContents = env.getContents('test.d.ts'); - expect(dtsContents).toContain(`import * as i1 from 'router';`); + expect(dtsContents).toContain(`import * as i1 from "router";`); expect(dtsContents) .toContain('i0.ɵNgModuleDefWithMeta'); }); @@ -418,10 +892,12 @@ describe('ngtsc behavioral tests', () => { env.write('node_modules/router/index.d.ts', ` import {ModuleWithProviders} from '@angular/core'; import * as internal from './internal'; + export {InternalRouterModule} from './internal'; - declare class RouterModule { + declare export class RouterModule { static forRoot(): ModuleWithProviders; } + `); env.write('node_modules/router/internal.d.ts', ` @@ -434,7 +910,7 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toContain('imports: [[RouterModule.forRoot()]]'); const dtsContents = env.getContents('test.d.ts'); - expect(dtsContents).toContain(`import * as i1 from 'router';`); + expect(dtsContents).toContain(`import * as i1 from "router";`); expect(dtsContents) .toContain( 'i0.ɵNgModuleDefWithMeta'); @@ -468,7 +944,7 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toContain('imports: [[RouterModule.forRoot()]]'); const dtsContents = env.getContents('test.d.ts'); - expect(dtsContents).toContain(`import * as i1 from 'router';`); + expect(dtsContents).toContain(`import * as i1 from "router";`); expect(dtsContents) .toContain( 'i0.ɵNgModuleDefWithMeta'); @@ -513,14 +989,6 @@ describe('ngtsc behavioral tests', () => { }); it('should generate queries for components', () => { - - // Helper functions to construct RegExps for output validation - const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`); - const queryRegExp = (id: number | null, descend: boolean, ref?: string): RegExp => { - const maybeRef = ref ? `, ${ref}` : ``; - return new RegExp(`i0\\.ɵquery\\(${id}, \\w+, ${descend}${maybeRef}\\)`); - }; - env.tsconfig(); env.write(`test.ts`, ` import {Component, ContentChild, ContentChildren, TemplateRef, ViewChild} from '@angular/core'; @@ -547,13 +1015,10 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toMatch(varRegExp('test1')); expect(jsContents).toMatch(varRegExp('test2')); expect(jsContents).toMatch(varRegExp('accessor')); - expect(jsContents).toContain(`i0.ɵquery(null, TemplateRef, false)`); - expect(jsContents) - .toMatch(queryRegExp( - null, true, 'TemplateRef')); // match `i0.ɵquery(null, _c0, true, TemplateRef)` - expect(jsContents).toMatch(queryRegExp(null, true)); // match `i0.ɵquery(null, _c0, true)` - expect(jsContents).toMatch(queryRegExp(0, true)); // match `i0.ɵquery(0, _c0, true)` - expect(jsContents).toMatch(queryRegExp(1, true)); // match `i0.ɵquery(1, _c0, true)` + // match `i0.ɵcontentQuery(dirIndex, _c1, true, TemplateRef)` + expect(jsContents).toMatch(contentQueryRegExp('\\w+', true, 'TemplateRef')); + // match `i0.ɵviewQuery(_c2, true)` + expect(jsContents).toMatch(viewQueryRegExp(true)); }); it('should handle queries that use forwardRef', () => { @@ -574,8 +1039,29 @@ describe('ngtsc behavioral tests', () => { env.driveMain(); const jsContents = env.getContents('test.js'); - expect(jsContents).toContain(`i0.ɵquery(null, TemplateRef, true)`); - expect(jsContents).toContain(`i0.ɵquery(null, ViewContainerRef, true)`); + // match `i0.ɵcontentQuery(dirIndex, TemplateRef, true)` + expect(jsContents).toMatch(contentQueryRegExp('TemplateRef', true)); + // match `i0.ɵcontentQuery(dirIndex, ViewContainerRef, true)` + expect(jsContents).toMatch(contentQueryRegExp('ViewContainerRef', true)); + }); + + it('should compile expressions that write keys', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component, ContentChild, TemplateRef, ViewContainerRef, forwardRef} from '@angular/core'; + + @Component({ + selector: 'test', + template: '
    ', + }) + class TestCmp { + test: any; + key: string; + } + `); + + env.driveMain(); + expect(env.getContents('test.js')).toContain('test[key] = $event'); }); it('should generate host listeners for components', () => { @@ -588,11 +1074,14 @@ describe('ngtsc behavioral tests', () => { template: 'Test' }) class FooCmp { + @HostListener('click') + onClick(event: any): void {} + @HostListener('document:click', ['$event.target']) - onClick(eventTarget: HTMLElement): void {} + onDocumentClick(eventTarget: HTMLElement): void {} @HostListener('window:scroll') - onScroll(event: any): void {} + onWindowScroll(event: any): void {} } `); @@ -601,14 +1090,73 @@ describe('ngtsc behavioral tests', () => { const hostBindingsFn = ` hostBindings: function FooCmp_HostBindings(rf, ctx, elIndex) { if (rf & 1) { - i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick($event.target); }); - i0.ɵlistener("scroll", function FooCmp_scroll_HostBindingHandler($event) { return ctx.onScroll(); }); + i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick(); }); + i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onDocumentClick($event.target); }, false, i0.ɵresolveDocument); + i0.ɵlistener("scroll", function FooCmp_scroll_HostBindingHandler($event) { return ctx.onWindowScroll(); }, false, i0.ɵresolveWindow); } } `; expect(trim(jsContents)).toContain(trim(hostBindingsFn)); }); + it('should throw in case unknown global target is provided', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component, HostListener} from '@angular/core'; + + @Component({ + selector: 'test', + template: 'Test' + }) + class FooCmp { + @HostListener('UnknownTarget:click') + onClick(event: any): void {} + } + `); + const errors = env.driveDiagnostics(); + expect(trim(errors[0].messageText as string)) + .toContain( + `Unexpected global target 'UnknownTarget' defined for 'click' event. Supported list of global targets: window,document,body.`); + }); + + it('should throw in case pipes are used in host listeners', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '...', + host: { + '(click)': 'doSmth() | myPipe' + } + }) + class FooCmp {} + `); + const errors = env.driveDiagnostics(); + expect(trim(errors[0].messageText as string)) + .toContain('Cannot have a pipe in an action expression'); + }); + + it('should throw in case pipes are used in host listeners', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '...', + host: { + '[id]': 'id | myPipe' + } + }) + class FooCmp {} + `); + const errors = env.driveDiagnostics(); + expect(trim(errors[0].messageText as string)) + .toContain('Host binding expression cannot contain pipes'); + }); + it('should generate host bindings for directives', () => { env.tsconfig(); env.write(`test.ts`, ` @@ -620,6 +1168,7 @@ describe('ngtsc behavioral tests', () => { host: { '[attr.hello]': 'foo', '(click)': 'onClick($event)', + '(body:click)': 'onBodyClick($event)', '[prop]': 'bar', }, }) @@ -641,6 +1190,7 @@ describe('ngtsc behavioral tests', () => { if (rf & 1) { i0.ɵallocHostVars(2); i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick($event); }); + i0.ɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onBodyClick($event); }, false, i0.ɵresolveBody); i0.ɵlistener("change", function FooCmp_change_HostBindingHandler($event) { return ctx.onChange(ctx.arg1, ctx.arg2, ctx.arg3); }); i0.ɵelementStyling(_c0, null, null, ctx); } @@ -655,6 +1205,31 @@ describe('ngtsc behavioral tests', () => { expect(trim(jsContents)).toContain(trim(hostBindingsFn)); }); + it('should accept enum values as host bindings', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component, HostBinding, HostListener, TemplateRef} from '@angular/core'; + + enum HostBindings { + Hello = 'foo' + } + + @Component({ + selector: 'test', + template: 'Test', + host: { + '[attr.hello]': HostBindings.Hello, + }, + }) + class FooCmp { + foo = 'test'; + } + `); + + env.driveMain(); + expect(env.getContents('test.js')).toContain('"hello", i0.ɵbind(ctx.foo)'); + }); + it('should generate host listeners for directives within hostBindings section', () => { env.tsconfig(); env.write(`test.ts`, ` @@ -790,6 +1365,88 @@ describe('ngtsc behavioral tests', () => { expect(jsContents).toContain('interpolation1("", ctx.text, "")'); }); + it('should handle `encapsulation` field', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component, ViewEncapsulation} from '@angular/core'; + @Component({ + selector: 'comp-a', + template: '...', + encapsulation: ViewEncapsulation.None + }) + class CompA {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('encapsulation: 2'); + }); + + it('should throw if `encapsulation` contains invalid value', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component} from '@angular/core'; + @Component({ + selector: 'comp-a', + template: '...', + encapsulation: 'invalid-value' + }) + class CompA {} + `); + const errors = env.driveDiagnostics(); + expect(errors[0].messageText) + .toContain('encapsulation must be a member of ViewEncapsulation enum from @angular/core'); + }); + + it('should handle `changeDetection` field', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component, ChangeDetectionStrategy} from '@angular/core'; + @Component({ + selector: 'comp-a', + template: '...', + changeDetection: ChangeDetectionStrategy.OnPush + }) + class CompA {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('changeDetection: 0'); + }); + + it('should throw if `changeDetection` contains invalid value', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component} from '@angular/core'; + @Component({ + selector: 'comp-a', + template: '...', + changeDetection: 'invalid-value' + }) + class CompA {} + `); + const errors = env.driveDiagnostics(); + expect(errors[0].messageText) + .toContain( + 'changeDetection must be a member of ChangeDetectionStrategy enum from @angular/core'); + }); + + it('should ignore empty bindings', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + @Component({ + selector: 'test', + template: '
    ' + }) + class FooCmp {} + `); + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).not.toContain('i0.ɵelementProperty'); + }); + it('should correctly recognize local symbols', () => { env.tsconfig(); env.write('module.ts', ` @@ -837,7 +1494,25 @@ describe('ngtsc behavioral tests', () => { env.driveMain(); const jsContents = env.getContents('test.js'); - expect(jsContents).toContain(`exportAs: "foo"`); + expect(jsContents).toContain(`exportAs: ["foo"]`); + }); + + it('should generate multiple exportAs declarations', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component, Directive} from '@angular/core'; + + @Directive({ + selector: '[test]', + exportAs: 'foo, bar', + }) + class Dir {} + `); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain(`exportAs: ["foo", "bar"]`); }); it('should generate correct factory stubs for a test module', () => { @@ -875,6 +1550,29 @@ describe('ngtsc behavioral tests', () => { expect(emptyFactory).toContain(`export var ɵNonEmptyModule = true;`); }); + it('should generate correct imports in factory stubs when compiling @angular/core', () => { + env.tsconfig({'allowEmptyCodegenFiles': true}); + + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class TestModule {} + `); + + // Trick the compiler into thinking it's compiling @angular/core. + env.write('r3_symbols.ts', 'export const ITS_JUST_ANGULAR = true;'); + + env.driveMain(); + + const factoryContents = env.getContents('test.ngfactory.js'); + expect(normalize(factoryContents)).toBe(normalize(` + import * as i0 from "./r3_symbols"; + import { TestModule } from './test'; + export var TestModuleNgFactory = new i0.NgModuleFactory(TestModule); + `)); + }); + it('should generate a summary stub for decorated classes in the input file only', () => { env.tsconfig({'allowEmptyCodegenFiles': true}); @@ -1050,14 +1748,52 @@ describe('ngtsc behavioral tests', () => { declarations: [Cmp, DirA, DirB], }) class Module {} - `); + `); env.driveMain(); const jsContents = env.getContents('test.js'); expect(jsContents).toMatch(/directives: \[DirA,\s+DirB\]/); }); - describe('duplicate local refs', () => { + describe('cycle detection', () => { + it('should detect a simple cycle and use remote component scoping', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Component, NgModule} from '@angular/core'; + import {NormalComponent} from './cyclic'; + + @Component({ + selector: 'cyclic-component', + template: 'Importing this causes a cycle', + }) + export class CyclicComponent {} + + @NgModule({ + declarations: [NormalComponent, CyclicComponent], + }) + export class Module {} + `); + + env.write('cyclic.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'normal-component', + template: '', + }) + export class NormalComponent {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents) + .toContain( + 'i0.ɵsetComponentScope(NormalComponent, [i1.NormalComponent, CyclicComponent], [])'); + expect(jsContents).not.toContain('/*__PURE__*/ i0.ɵsetComponentScope'); + }); + }); + + describe('multiple local refs', () => { const getComponentScript = (template: string): string => ` import {Component, Directive, NgModule} from '@angular/core'; @@ -1068,37 +1804,17 @@ describe('ngtsc behavioral tests', () => { class Module {} `; - // Components with templates listed below should - // throw the "ref is already defined" error - const invalidCases = [ + const cases = [ `
    `, - ` -
    -
    -
    - `, - ` -
    -
    -
    -
    -
    -
    - `, `
    - ` - ]; - - // Components with templates listed below should not throw - // the error, since refs are located in different scopes - const validCases = [ + `, `
    @@ -1115,18 +1831,8 @@ describe('ngtsc behavioral tests', () => { ` ]; - invalidCases.forEach(template => { - it('should throw in case of duplicate refs', () => { - env.tsconfig(); - env.write('test.ts', getComponentScript(template)); - const errors = env.driveDiagnostics(); - expect(errors[0].messageText) - .toContain('Internal Error: The name ref is already defined in scope'); - }); - }); - - validCases.forEach(template => { - it('should not throw in case refs are in different scopes', () => { + cases.forEach(template => { + it('should not throw', () => { env.tsconfig(); env.write('test.ts', getComponentScript(template)); const errors = env.driveDiagnostics(); @@ -1167,40 +1873,81 @@ describe('ngtsc behavioral tests', () => { // Success is enough to indicate that this passes. }); - it('should not emit multiple references to the same directive', () => { - env.tsconfig(); - env.write('node_modules/external/index.d.ts', ` - import {ɵDirectiveDefWithMeta, ɵNgModuleDefWithMeta} from '@angular/core'; + describe('when processing external directives', () => { + it('should not emit multiple references to the same directive', () => { + env.tsconfig(); + env.write('node_modules/external/index.d.ts', ` + import {ɵDirectiveDefWithMeta, ɵNgModuleDefWithMeta} from '@angular/core'; - export declare class ExternalDir { - static ngDirectiveDef: ɵDirectiveDefWithMeta; - } + export declare class ExternalDir { + static ngDirectiveDef: ɵDirectiveDefWithMeta; + } - export declare class ExternalModule { - static ngModuleDef: ɵNgModuleDefWithMeta; - } - `); - env.write('test.ts', ` - import {Component, Directive, NgModule} from '@angular/core'; - import {ExternalModule} from 'external'; + export declare class ExternalModule { + static ngModuleDef: ɵNgModuleDefWithMeta; + } + `); + env.write('test.ts', ` + import {Component, Directive, NgModule} from '@angular/core'; + import {ExternalModule} from 'external'; - @Component({ - template: '
    ', - }) - class Cmp {} + @Component({ + template: '
    ', + }) + class Cmp {} - @NgModule({ - declarations: [Cmp], - // Multiple imports of the same module used to result in duplicate directive references - // in the output. - imports: [ExternalModule, ExternalModule], - }) - class Module {} - `); + @NgModule({ + declarations: [Cmp], + // Multiple imports of the same module used to result in duplicate directive references + // in the output. + imports: [ExternalModule, ExternalModule], + }) + class Module {} + `); - env.driveMain(); - const jsContents = env.getContents('test.js'); - expect(jsContents).toMatch(/directives: \[i1\.ExternalDir\]/); + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toMatch(/directives: \[i1\.ExternalDir\]/); + }); + + it('should import directives by their external name', () => { + env.tsconfig(); + env.write('node_modules/external/index.d.ts', ` + import {ɵDirectiveDefWithMeta, ɵNgModuleDefWithMeta} from '@angular/core'; + import {InternalDir} from './internal'; + + export {InternalDir as ExternalDir} from './internal'; + + export declare class ExternalModule { + static ngModuleDef: ɵNgModuleDefWithMeta; + } + `); + env.write('node_modules/external/internal.d.ts', ` + + export declare class InternalDir { + static ngDirectiveDef: ɵDirectiveDefWithMeta; + } + `); + env.write('test.ts', ` + import {Component, Directive, NgModule} from '@angular/core'; + import {ExternalModule} from 'external'; + + @Component({ + template: '
    ', + }) + class Cmp {} + + @NgModule({ + declarations: [Cmp], + imports: [ExternalModule], + }) + class Module {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + expect(jsContents).toMatch(/directives: \[i1\.ExternalDir\]/); + }); }); describe('flat module indices', () => { @@ -1226,5 +1973,975 @@ describe('ngtsc behavioral tests', () => { const dtsContents = env.getContents('flat.d.ts'); expect(dtsContents).toContain('/// '); }); + + it('should generate a proper flat module index file when nested', () => { + env.tsconfig({ + 'flatModuleOutFile': './public-api/index.js', + }); + + env.write('test.ts', `export const SOME_EXPORT = 'some-export'`); + env.driveMain(); + + expect(env.getContents('./public-api/index.js')).toContain(`export * from '../test';`); + }); + + it('should report an error when a flat module index is requested but no entrypoint can be determined', + () => { + env.tsconfig({'flatModuleOutFile': 'flat.js'}); + env.write('test.ts', 'export class Foo {}'); + env.write('test2.ts', 'export class Bar {}'); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(1); + expect(errors[0].messageText) + .toBe( + 'Angular compiler option "flatModuleOutFile" requires one and only one .ts file in the "files" field.'); + }); + + it('should report an error when a visible directive is not exported', () => { + env.tsconfig({'flatModuleOutFile': 'flat.js'}); + env.write('test.ts', ` + import {Directive, NgModule} from '@angular/core'; + + // The directive is not exported. + @Directive({selector: 'test'}) + class Dir {} + + // The module is, which makes the directive visible. + @NgModule({declarations: [Dir], exports: [Dir]}) + export class Module {} + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(1); + expect(errors[0].messageText) + .toBe( + 'Unsupported private class Dir. This class is visible ' + + 'to consumers via Module -> Dir, but is not exported from the top-level library ' + + 'entrypoint.'); + + // Verify that the error is for the correct class. + const id = expectTokenAtPosition(errors[0].file !, errors[0].start !, ts.isIdentifier); + expect(id.text).toBe('Dir'); + expect(ts.isClassDeclaration(id.parent)).toBe(true); + }); + + it('should report an error when a deeply visible directive is not exported', () => { + env.tsconfig({'flatModuleOutFile': 'flat.js'}); + env.write('test.ts', ` + import {Directive, NgModule} from '@angular/core'; + + // The directive is not exported. + @Directive({selector: 'test'}) + class Dir {} + + // Neither is the module which declares it - meaning the directive is not visible here. + @NgModule({declarations: [Dir], exports: [Dir]}) + class DirModule {} + + // The module is, which makes the directive visible. + @NgModule({exports: [DirModule]}) + export class Module {} + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(2); + expect(errors[0].messageText) + .toBe( + 'Unsupported private class DirModule. This class is ' + + 'visible to consumers via Module -> DirModule, but is not exported from the top-level ' + + 'library entrypoint.'); + expect(errors[1].messageText) + .toBe( + 'Unsupported private class Dir. This class is visible ' + + 'to consumers via Module -> DirModule -> Dir, but is not exported from the top-level ' + + 'library entrypoint.'); + }); + + it('should report an error when a deeply visible module is not exported', () => { + env.tsconfig({'flatModuleOutFile': 'flat.js'}); + env.write('test.ts', ` + import {Directive, NgModule} from '@angular/core'; + + // The directive is exported. + @Directive({selector: 'test'}) + export class Dir {} + + // The module which declares it is not. + @NgModule({declarations: [Dir], exports: [Dir]}) + class DirModule {} + + // The module is, which makes the module and directive visible. + @NgModule({exports: [DirModule]}) + export class Module {} + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(1); + expect(errors[0].messageText) + .toBe( + 'Unsupported private class DirModule. This class is ' + + 'visible to consumers via Module -> DirModule, but is not exported from the top-level ' + + 'library entrypoint.'); + }); + + it('should not report an error when a non-exported module is imported by a visible one', () => { + env.tsconfig({'flatModuleOutFile': 'flat.js'}); + env.write('test.ts', ` + import {Directive, NgModule} from '@angular/core'; + + // The directive is not exported. + @Directive({selector: 'test'}) + class Dir {} + + // Neither is the module which declares it. + @NgModule({declarations: [Dir], exports: [Dir]}) + class DirModule {} + + // This module is, but it doesn't re-export the module, so it doesn't make the module and + // directive visible. + @NgModule({imports: [DirModule]}) + export class Module {} + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(0); + }); + + it('should not report an error when re-exporting an external symbol', () => { + env.tsconfig({'flatModuleOutFile': 'flat.js'}); + env.write('test.ts', ` + import {Directive, NgModule} from '@angular/core'; + import {ExternalModule} from 'external'; + + // This module makes ExternalModule and ExternalDir visible. + @NgModule({exports: [ExternalModule]}) + export class Module {} + `); + env.write('node_modules/external/index.d.ts', ` + import {ɵDirectiveDefWithMeta, ɵNgModuleDefWithMeta} from '@angular/core'; + + export declare class ExternalDir { + static ngDirectiveDef: ɵDirectiveDefWithMeta; + } + + export declare class ExternalModule { + static ngModuleDef: ɵNgModuleDefWithMeta; + } + `); + + const errors = env.driveDiagnostics(); + expect(errors.length).toBe(0); + }); + }); + + it('should execute custom transformers', () => { + let beforeCount = 0; + let afterCount = 0; + + env.tsconfig(); + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + class Module {} + `); + + env.driveMain({ + beforeTs: [() => (sourceFile: ts.SourceFile) => { + beforeCount++; + return sourceFile; + }], + afterTs: [() => (sourceFile: ts.SourceFile) => { + afterCount++; + return sourceFile; + }], + }); + + expect(beforeCount).toBe(1); + expect(afterCount).toBe(1); + }); + + describe('sanitization', () => { + it('should generate sanitizers for unsafe attributes in hostBindings fn in Directives', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component, Directive, HostBinding} from '@angular/core'; + + @Directive({ + selector: '[unsafeAttrs]' + }) + class UnsafeAttrsDirective { + @HostBinding('attr.href') + attrHref: string; + + @HostBinding('attr.src') + attrSrc: string; + + @HostBinding('attr.action') + attrAction: string; + + @HostBinding('attr.profile') + attrProfile: string; + + @HostBinding('attr.innerHTML') + attrInnerHTML: string; + + @HostBinding('attr.title') + attrSafeTitle: string; + } + + @Component({ + selector: 'foo', + template: '
    Link Title' + }) + class FooCmp {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + const hostBindingsFn = ` + hostBindings: function UnsafeAttrsDirective_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + i0.ɵallocHostVars(6); + } + if (rf & 2) { + i0.ɵelementAttribute(elIndex, "href", i0.ɵbind(ctx.attrHref), i0.ɵsanitizeUrlOrResourceUrl); + i0.ɵelementAttribute(elIndex, "src", i0.ɵbind(ctx.attrSrc), i0.ɵsanitizeUrlOrResourceUrl); + i0.ɵelementAttribute(elIndex, "action", i0.ɵbind(ctx.attrAction), i0.ɵsanitizeUrl); + i0.ɵelementAttribute(elIndex, "profile", i0.ɵbind(ctx.attrProfile), i0.ɵsanitizeResourceUrl); + i0.ɵelementAttribute(elIndex, "innerHTML", i0.ɵbind(ctx.attrInnerHTML), i0.ɵsanitizeHtml); + i0.ɵelementAttribute(elIndex, "title", i0.ɵbind(ctx.attrSafeTitle)); + } + } + `; + expect(trim(jsContents)).toContain(trim(hostBindingsFn)); + }); + + it('should generate sanitizers for unsafe properties in hostBindings fn in Directives', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component, Directive, HostBinding} from '@angular/core'; + + @Directive({ + selector: '[unsafeProps]' + }) + class UnsafePropsDirective { + @HostBinding('href') + propHref: string; + + @HostBinding('src') + propSrc: string; + + @HostBinding('action') + propAction: string; + + @HostBinding('profile') + propProfile: string; + + @HostBinding('innerHTML') + propInnerHTML: string; + + @HostBinding('title') + propSafeTitle: string; + } + + @Component({ + selector: 'foo', + template: 'Link Title' + }) + class FooCmp {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + const hostBindingsFn = ` + hostBindings: function UnsafePropsDirective_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + i0.ɵallocHostVars(6); + } + if (rf & 2) { + i0.ɵelementProperty(elIndex, "href", i0.ɵbind(ctx.propHref), i0.ɵsanitizeUrlOrResourceUrl, true); + i0.ɵelementProperty(elIndex, "src", i0.ɵbind(ctx.propSrc), i0.ɵsanitizeUrlOrResourceUrl, true); + i0.ɵelementProperty(elIndex, "action", i0.ɵbind(ctx.propAction), i0.ɵsanitizeUrl, true); + i0.ɵelementProperty(elIndex, "profile", i0.ɵbind(ctx.propProfile), i0.ɵsanitizeResourceUrl, true); + i0.ɵelementProperty(elIndex, "innerHTML", i0.ɵbind(ctx.propInnerHTML), i0.ɵsanitizeHtml, true); + i0.ɵelementProperty(elIndex, "title", i0.ɵbind(ctx.propSafeTitle), null, true); + } + } + `; + expect(trim(jsContents)).toContain(trim(hostBindingsFn)); + }); + + it('should not generate sanitizers for URL properties in hostBindings fn in Component', () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'foo', + template: 'Link Title', + host: { + '[src]': 'srcProp', + '[href]': 'hrefProp', + '[title]': 'titleProp', + '[attr.src]': 'srcAttr', + '[attr.href]': 'hrefAttr', + '[attr.title]': 'titleAttr', + } + }) + class FooCmp {} + `); + + env.driveMain(); + const jsContents = env.getContents('test.js'); + const hostBindingsFn = ` + hostBindings: function FooCmp_HostBindings(rf, ctx, elIndex) { + if (rf & 1) { + i0.ɵallocHostVars(6); + } + if (rf & 2) { + i0.ɵelementProperty(elIndex, "src", i0.ɵbind(ctx.srcProp), null, true); + i0.ɵelementProperty(elIndex, "href", i0.ɵbind(ctx.hrefProp), null, true); + i0.ɵelementProperty(elIndex, "title", i0.ɵbind(ctx.titleProp), null, true); + i0.ɵelementAttribute(elIndex, "src", i0.ɵbind(ctx.srcAttr)); + i0.ɵelementAttribute(elIndex, "href", i0.ɵbind(ctx.hrefAttr)); + i0.ɵelementAttribute(elIndex, "title", i0.ɵbind(ctx.titleAttr)); + } + } + `; + expect(trim(jsContents)).toContain(trim(hostBindingsFn)); + }); + }); + + describe('listLazyRoutes()', () => { + // clang-format off + const lazyRouteMatching = ( + route: string, fromModulePath: RegExp, fromModuleName: string, toModulePath: RegExp, + toModuleName: string) => { + return { + route, + module: jasmine.objectContaining({ + name: fromModuleName, + filePath: jasmine.stringMatching(fromModulePath), + }), + referencedModule: jasmine.objectContaining({ + name: toModuleName, + filePath: jasmine.stringMatching(toModulePath), + }), + } as unknown as LazyRoute; + }; + // clang-format on + + beforeEach(() => { + env.tsconfig(); + env.write('node_modules/@angular/router/index.d.ts', ` + import {ModuleWithProviders} from '@angular/core'; + + export declare var ROUTES; + export declare class RouterModule { + static forRoot(arg1: any, arg2: any): ModuleWithProviders; + static forChild(arg1: any): ModuleWithProviders; + } + `); + }); + + describe('when called without arguments', () => { + it('should list all routes', () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forRoot([ + {path: '1', loadChildren: './lazy/lazy-1#Lazy1Module'}, + {path: '2', loadChildren: './lazy/lazy-2#Lazy2Module'}, + ]), + ], + }) + export class TestModule {} + `); + env.write('lazy/lazy-1.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy1Module {} + `); + env.write('lazy/lazy-2.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '3', loadChildren: './lazy-3#Lazy3Module'}, + ]), + ], + }) + export class Lazy2Module {} + `); + env.write('lazy/lazy-3.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy3Module {} + `); + + const routes = env.driveRoutes(); + expect(routes).toEqual([ + lazyRouteMatching( + './lazy-3#Lazy3Module', /\/lazy\/lazy-2\.ts$/, 'Lazy2Module', /\/lazy\/lazy-3\.ts$/, + 'Lazy3Module'), + lazyRouteMatching( + './lazy/lazy-1#Lazy1Module', /\/test\.ts$/, 'TestModule', /\/lazy\/lazy-1\.ts$/, + 'Lazy1Module'), + lazyRouteMatching( + './lazy/lazy-2#Lazy2Module', /\/test\.ts$/, 'TestModule', /\/lazy\/lazy-2\.ts$/, + 'Lazy2Module'), + ]); + }); + + it('should detect lazy routes in simple children routes', () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @Component({ + selector: 'foo', + template: '
    Foo
    ' + }) + class FooCmp {} + + @NgModule({ + imports: [ + RouterModule.forRoot([ + {path: '', children: [ + {path: 'foo', component: FooCmp}, + {path: 'lazy', loadChildren: './lazy#LazyModule'} + ]}, + ]), + ], + }) + export class TestModule {} + `); + env.write('lazy.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({}) + export class LazyModule {} + `); + + const routes = env.driveRoutes(); + expect(routes).toEqual([ + lazyRouteMatching( + './lazy#LazyModule', /\/test\.ts$/, 'TestModule', /\/lazy\.ts$/, 'LazyModule'), + ]); + }); + + it('should detect lazy routes in all root directories', () => { + env.tsconfig({}, ['./foo/other-root-dir', './bar/other-root-dir']); + env.write('src/test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forRoot([ + {path: '', loadChildren: './lazy-foo#LazyFooModule'}, + ]), + ], + }) + export class TestModule {} + `); + env.write('foo/other-root-dir/src/lazy-foo.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: './lazy-bar#LazyBarModule'}, + ]), + ], + }) + export class LazyFooModule {} + `); + env.write('bar/other-root-dir/src/lazy-bar.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: './lazier-bar#LazierBarModule'}, + ]), + ], + }) + export class LazyBarModule {} + `); + env.write('bar/other-root-dir/src/lazier-bar.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class LazierBarModule {} + `); + + const routes = env.driveRoutes(); + + expect(routes).toEqual([ + lazyRouteMatching( + './lazy-foo#LazyFooModule', /\/test\.ts$/, 'TestModule', + /\/foo\/other-root-dir\/src\/lazy-foo\.ts$/, 'LazyFooModule'), + lazyRouteMatching( + './lazy-bar#LazyBarModule', /\/foo\/other-root-dir\/src\/lazy-foo\.ts$/, + 'LazyFooModule', /\/bar\/other-root-dir\/src\/lazy-bar\.ts$/, 'LazyBarModule'), + lazyRouteMatching( + './lazier-bar#LazierBarModule', /\/bar\/other-root-dir\/src\/lazy-bar\.ts$/, + 'LazyBarModule', /\/bar\/other-root-dir\/src\/lazier-bar\.ts$/, 'LazierBarModule'), + ]); + }); + }); + + describe('when called with entry module', () => { + it('should throw if the entry module hasn\'t been analyzed', () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: './lazy#LazyModule'}, + ]), + ], + }) + export class TestModule {} + `); + + const entryModule1 = path.join(env.basePath, 'test#TestModule'); + const entryModule2 = path.join(env.basePath, 'not-test#TestModule'); + const entryModule3 = path.join(env.basePath, 'test#NotTestModule'); + + expect(() => env.driveRoutes(entryModule1)).not.toThrow(); + expect(() => env.driveRoutes(entryModule2)) + .toThrowError(`Failed to list lazy routes: Unknown module '${entryModule2}'.`); + expect(() => env.driveRoutes(entryModule3)) + .toThrowError(`Failed to list lazy routes: Unknown module '${entryModule3}'.`); + }); + + it('should list all transitive lazy routes', () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + import {Test1Module as Test1ModuleRenamed} from './test-1'; + import {Test2Module} from './test-2'; + + @NgModule({ + exports: [ + Test1ModuleRenamed, + ], + imports: [ + Test2Module, + RouterModule.forRoot([ + {path: '', loadChildren: './lazy/lazy#LazyModule'}, + ]), + ], + }) + export class TestModule {} + `); + env.write('test-1.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: 'one', loadChildren: './lazy-1/lazy-1#Lazy1Module'}, + ]), + ], + }) + export class Test1Module {} + `); + env.write('test-2.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + exports: [ + RouterModule.forChild([ + {path: 'two', loadChildren: './lazy-2/lazy-2#Lazy2Module'}, + ]), + ], + }) + export class Test2Module {} + `); + env.write('lazy/lazy.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class LazyModule {} + `); + env.write('lazy-1/lazy-1.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy1Module {} + `); + env.write('lazy-2/lazy-2.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy2Module {} + `); + + const routes = env.driveRoutes(path.join(env.basePath, 'test#TestModule')); + + expect(routes).toEqual([ + lazyRouteMatching( + './lazy/lazy#LazyModule', /\/test\.ts$/, 'TestModule', /\/lazy\/lazy\.ts$/, + 'LazyModule'), + lazyRouteMatching( + './lazy-1/lazy-1#Lazy1Module', /\/test-1\.ts$/, 'Test1Module', + /\/lazy-1\/lazy-1\.ts$/, 'Lazy1Module'), + lazyRouteMatching( + './lazy-2/lazy-2#Lazy2Module', /\/test-2\.ts$/, 'Test2Module', + /\/lazy-2\/lazy-2\.ts$/, 'Lazy2Module'), + ]); + }); + + it('should ignore exports that do not refer to an `NgModule`', () => { + env.write('test-1.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + import {Test2Component, Test2Module} from './test-2'; + + @NgModule({ + exports: [ + Test2Component, + Test2Module, + ], + imports: [ + RouterModule.forRoot([ + {path: '', loadChildren: './lazy-1/lazy-1#Lazy1Module'}, + ]), + ], + }) + export class Test1Module {} + `); + env.write('test-2.ts', ` + import {Component, NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @Component({ + selector: 'test-2', + template: '', + }) + export class Test2Component {} + + @NgModule({ + declarations: [ + Test2Component, + ], + exports: [ + Test2Component, + RouterModule.forChild([ + {path: 'two', loadChildren: './lazy-2/lazy-2#Lazy2Module'}, + ]), + ], + }) + export class Test2Module {} + `); + env.write('lazy-1/lazy-1.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy1Module {} + `); + env.write('lazy-2/lazy-2.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy2Module {} + `); + + const routes = env.driveRoutes(path.join(env.basePath, 'test-1#Test1Module')); + + expect(routes).toEqual([ + lazyRouteMatching( + './lazy-1/lazy-1#Lazy1Module', /\/test-1\.ts$/, 'Test1Module', + /\/lazy-1\/lazy-1\.ts$/, 'Lazy1Module'), + lazyRouteMatching( + './lazy-2/lazy-2#Lazy2Module', /\/test-2\.ts$/, 'Test2Module', + /\/lazy-2\/lazy-2\.ts$/, 'Lazy2Module'), + ]); + }); + + it('should support `ModuleWithProviders`', () => { + env.write('test.ts', ` + import {ModuleWithProviders, NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: './lazy-2/lazy-2#Lazy2Module'}, + ]), + ], + }) + export class TestRoutingModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: TestRoutingModule, + providers: [], + }; + } + } + + @NgModule({ + imports: [ + TestRoutingModule.forRoot(), + RouterModule.forRoot([ + {path: '', loadChildren: './lazy-1/lazy-1#Lazy1Module'}, + ]), + ], + }) + export class TestModule {} + `); + env.write('lazy-1/lazy-1.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy1Module {} + `); + env.write('lazy-2/lazy-2.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy2Module {} + `); + + const routes = env.driveRoutes(path.join(env.basePath, 'test#TestModule')); + + expect(routes).toEqual([ + lazyRouteMatching( + './lazy-1/lazy-1#Lazy1Module', /\/test\.ts$/, 'TestModule', /\/lazy-1\/lazy-1\.ts$/, + 'Lazy1Module'), + lazyRouteMatching( + './lazy-2/lazy-2#Lazy2Module', /\/test\.ts$/, 'TestRoutingModule', + /\/lazy-2\/lazy-2\.ts$/, 'Lazy2Module'), + ]); + }); + + it('should only process each module once', () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: './lazy/lazy#LazyModule'}, + ]), + ], + }) + export class SharedModule {} + + @NgModule({ + imports: [ + SharedModule, + RouterModule.forRoot([ + {path: '', loadChildren: './lazy/lazy#LazyModule'}, + ]), + ], + }) + export class TestModule {} + `); + env.write('lazy/lazy.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: '../lazier/lazier#LazierModule'}, + ]), + ], + }) + export class LazyModule {} + `); + env.write('lazier/lazier.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class LazierModule {} + `); + + const routes = env.driveRoutes(path.join(env.basePath, 'test#TestModule')); + + // `LazyModule` is referenced in both `SharedModule` and `TestModule`, + // but it is only processed once (hence one `LazierModule` entry). + expect(routes).toEqual([ + lazyRouteMatching( + './lazy/lazy#LazyModule', /\/test\.ts$/, 'TestModule', /\/lazy\/lazy\.ts$/, + 'LazyModule'), + lazyRouteMatching( + './lazy/lazy#LazyModule', /\/test\.ts$/, 'SharedModule', /\/lazy\/lazy\.ts$/, + 'LazyModule'), + lazyRouteMatching( + '../lazier/lazier#LazierModule', /\/lazy\/lazy\.ts$/, 'LazyModule', + /\/lazier\/lazier\.ts$/, 'LazierModule'), + ]); + }); + + it('should detect lazy routes in all root directories', () => { + env.tsconfig({}, ['./foo/other-root-dir', './bar/other-root-dir']); + env.write('src/test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forRoot([ + {path: '', loadChildren: './lazy-foo#LazyFooModule'}, + ]), + ], + }) + export class TestModule {} + `); + env.write('foo/other-root-dir/src/lazy-foo.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: './lazy-bar#LazyBarModule'}, + ]), + ], + }) + export class LazyFooModule {} + `); + env.write('bar/other-root-dir/src/lazy-bar.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forChild([ + {path: '', loadChildren: './lazier-bar#LazierBarModule'}, + ]), + ], + }) + export class LazyBarModule {} + `); + env.write('bar/other-root-dir/src/lazier-bar.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class LazierBarModule {} + `); + + const routes = env.driveRoutes(path.join(env.basePath, 'src/test#TestModule')); + + expect(routes).toEqual([ + lazyRouteMatching( + './lazy-foo#LazyFooModule', /\/test\.ts$/, 'TestModule', + /\/foo\/other-root-dir\/src\/lazy-foo\.ts$/, 'LazyFooModule'), + lazyRouteMatching( + './lazy-bar#LazyBarModule', /\/foo\/other-root-dir\/src\/lazy-foo\.ts$/, + 'LazyFooModule', /\/bar\/other-root-dir\/src\/lazy-bar\.ts$/, 'LazyBarModule'), + lazyRouteMatching( + './lazier-bar#LazierBarModule', /\/bar\/other-root-dir\/src\/lazy-bar\.ts$/, + 'LazyBarModule', /\/bar\/other-root-dir\/src\/lazier-bar\.ts$/, 'LazierBarModule'), + ]); + }); + + it('should ignore modules not (transitively) referenced by the entry module', () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forRoot([ + {path: '', loadChildren: './lazy/lazy#Lazy1Module'}, + ]), + ], + }) + export class Test1Module {} + + @NgModule({ + imports: [ + RouterModule.forRoot([ + {path: '', loadChildren: './lazy/lazy#Lazy2Module'}, + ]), + ], + }) + export class Test2Module {} + `); + env.write('lazy/lazy.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class Lazy1Module {} + + @NgModule({}) + export class Lazy2Module {} + `); + + const routes = env.driveRoutes(path.join(env.basePath, 'test#Test1Module')); + + expect(routes).toEqual([ + lazyRouteMatching( + './lazy/lazy#Lazy1Module', /\/test\.ts$/, 'Test1Module', /\/lazy\/lazy\.ts$/, + 'Lazy1Module'), + ]); + }); + + it('should ignore routes to unknown modules', () => { + env.write('test.ts', ` + import {NgModule} from '@angular/core'; + import {RouterModule} from '@angular/router'; + + @NgModule({ + imports: [ + RouterModule.forRoot([ + {path: '', loadChildren: './unknown/unknown#UnknownModule'}, + {path: '', loadChildren: './lazy/lazy#LazyModule'}, + ]), + ], + }) + export class TestModule {} + `); + env.write('lazy/lazy.ts', ` + import {NgModule} from '@angular/core'; + + @NgModule({}) + export class LazyModule {} + `); + + const routes = env.driveRoutes(path.join(env.basePath, 'test#TestModule')); + + expect(routes).toEqual([ + lazyRouteMatching( + './lazy/lazy#LazyModule', /\/test\.ts$/, 'TestModule', /\/lazy\/lazy\.ts$/, + 'LazyModule'), + ]); + }); + }); }); }); + +function expectTokenAtPosition( + sf: ts.SourceFile, pos: number, guard: (node: ts.Node) => node is T): T { + // getTokenAtPosition is part of TypeScript's private API. + const node = (ts as any).getTokenAtPosition(sf, pos) as ts.Node; + expect(guard(node)).toBe(true); + return node as T; +} + +function normalize(input: string): string { + return input.replace(/\s+/g, ' ').trim(); +} diff --git a/packages/compiler-cli/test/ngtsc/sourcemap_utils.ts b/packages/compiler-cli/test/ngtsc/sourcemap_utils.ts new file mode 100644 index 0000000000..91d6568f9b --- /dev/null +++ b/packages/compiler-cli/test/ngtsc/sourcemap_utils.ts @@ -0,0 +1,103 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {MappingItem, SourceMapConsumer} from 'source-map'; +import {NgtscTestEnvironment} from './env'; + +class TestSourceFile { + private lineStarts: number[]; + + constructor(public url: string, public contents: string) { + this.lineStarts = this.getLineStarts(); + } + + getSegment(key: 'generated'|'original', start: MappingItem|any, end: MappingItem|any): string { + const startLine = start[key + 'Line']; + const startCol = start[key + 'Column']; + const endLine = end[key + 'Line']; + const endCol = end[key + 'Column']; + return this.contents.substring( + this.lineStarts[startLine - 1] + startCol, this.lineStarts[endLine - 1] + endCol); + } + + getSourceMapFileName(generatedContents: string): string { + const match = /\/\/# sourceMappingURL=(.+)/.exec(generatedContents); + if (!match) { + throw new Error('Generated contents does not contain a sourceMappingURL'); + } + return match[1]; + } + + private getLineStarts(): number[] { + const lineStarts = [0]; + let currentPos = 0; + const lines = this.contents.split('\n'); + lines.forEach(line => { + currentPos += line.length + 1; + lineStarts.push(currentPos); + }); + return lineStarts; + } +} + +/** + * A mapping of a segment of generated text to a segment of source text. + */ +export interface SegmentMapping { + /** The generated text in this segment. */ + generated: string; + /** The source text in this segment. */ + source: string; + /** The URL of the source file for this segment. */ + sourceUrl: string; +} + +/** + * Process a generated file to extract human understandable segment mappings. + * These mappings are easier to compare in unit tests that the raw SourceMap mappings. + * @param env the environment that holds the source and generated files. + * @param generatedFileName The name of the generated file to process. + * @returns An array of segment mappings for each mapped segment in the given generated file. + */ +export function getMappedSegments( + env: NgtscTestEnvironment, generatedFileName: string): SegmentMapping[] { + const generated = new TestSourceFile(generatedFileName, env.getContents(generatedFileName)); + const sourceMapFileName = generated.getSourceMapFileName(generated.contents); + + const sources = new Map(); + const mappings: MappingItem[] = []; + + const mapContents = env.getContents(sourceMapFileName); + const sourceMapConsumer = new SourceMapConsumer(JSON.parse(mapContents)); + sourceMapConsumer.eachMapping(item => { + if (!sources.has(item.source)) { + sources.set(item.source, new TestSourceFile(item.source, env.getContents(item.source))); + } + mappings.push(item); + }); + + const segments: SegmentMapping[] = []; + let currentMapping = mappings.shift(); + while (currentMapping) { + const nextMapping = mappings.shift(); + if (nextMapping) { + const source = sources.get(currentMapping.source) !; + const segment = { + generated: generated.getSegment('generated', currentMapping, nextMapping), + source: source.getSegment('original', currentMapping, nextMapping), + sourceUrl: source.url + }; + if (segment.generated !== segment.source) { + segments.push(segment); + } + } + currentMapping = nextMapping; + } + + return segments; +} diff --git a/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts new file mode 100644 index 0000000000..f740352b5e --- /dev/null +++ b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts @@ -0,0 +1,544 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {inspect} from 'util'; + +import {tsSourceMapBug29300Fixed} from '../../src/ngtsc/util/src/ts_source_map_bug_29300'; + +import {NgtscTestEnvironment} from './env'; +import {SegmentMapping, getMappedSegments} from './sourcemap_utils'; + +describe('template source-mapping', () => { + let env !: NgtscTestEnvironment; + + beforeEach(() => { env = NgtscTestEnvironment.setup(); }); + + describe('Inline templates', () => { + describe('(element creation)', () => { + it('should map simple element with content', () => { + const mappings = compileAndMap('

    Heading 1

    '); + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementStart(0, "h1")', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {source: 'Heading 1', generated: 'i0.ɵtext(1, "Heading 1")', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + + it('should map void element', () => { + const mappings = compileAndMap('
    '); + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelement(0, "hr")', sourceUrl: '../test.ts'}); + }); + }); + + describe('(interpolations)', () => { + it('should map a mix of interpolated and static content', () => { + const mappings = compileAndMap('

    Hello {{ name }}

    '); + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementStart(0, "h3")', sourceUrl: '../test.ts'}); + expect(mappings).toContain({ + source: 'Hello {{ name }}', + generated: 'i0.ɵtextBinding(1, i0.ɵinterpolation1("Hello ", ctx.name, ""))', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + + it('should map a complex interpolated expression', () => { + const mappings = compileAndMap('

    {{ greeting + " " + name }}

    '); + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementStart(0, "h2")', sourceUrl: '../test.ts'}); + expect(mappings).toContain({ + source: '{{ greeting + " " + name }}', + generated: + 'i0.ɵtextBinding(1, i0.ɵinterpolation1("", ((ctx.greeting + " ") + ctx.name), ""))', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + + it('should map interpolated properties', () => { + const mappings = compileAndMap('
    '); + expect(mappings).toContain({ + source: '
    ', + generated: 'i0.ɵelement(0, "div", _c0)', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain({ + source: 'id="{{name}}"', + generated: 'i0.ɵelementProperty(0, "id", i0.ɵinterpolation1("", ctx.name, ""))', + sourceUrl: '../test.ts' + }); + }); + + it('should map interpolation with pipe', () => { + const mappings = compileAndMap('
    {{200.3 | percent : 2 }}
    '); + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementStart(0, "div")', sourceUrl: '../test.ts'}); + expect(mappings).toContain({ + source: '{{200.3 | percent : 2 }}', + generated: + 'i0.ɵtextBinding(1, i0.ɵinterpolation1("", i0.ɵpipeBind2(2, 1, 200.3, 2), ""))', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + }); + + describe('(property bindings)', () => { + it('should map a simple input binding expression', () => { + const mappings = compileAndMap('
    '); + expect(mappings).toContain({ + source: '
    ', + generated: 'i0.ɵelement(0, "div", _c0)', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain({ + source: '[attr]="name"', + generated: 'i0.ɵelementProperty(0, "attr", i0.ɵbind(ctx.name))', + sourceUrl: '../test.ts' + }); + }); + + it('should map a complex input binding expression', () => { + const mappings = compileAndMap('
    '); + expect(mappings).toContain({ + source: '
    ', + generated: 'i0.ɵelement(0, "div", _c0)', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain({ + source: '[attr]="greeting + name"', + generated: 'i0.ɵelementProperty(0, "attr", i0.ɵbind((ctx.greeting + ctx.name)))', + sourceUrl: '../test.ts' + }); + }); + + it('should map a longhand input binding expression', () => { + const mappings = compileAndMap('
    '); + expect(mappings).toContain({ + source: '
    ', + generated: 'i0.ɵelement(0, "div", _c0)', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain({ + source: 'bind-attr="name"', + generated: 'i0.ɵelementProperty(0, "attr", i0.ɵbind(ctx.name))', + sourceUrl: '../test.ts' + }); + }); + + it('should map a simple output binding expression', () => { + const mappings = compileAndMap(''); + expect(mappings).toContain({ + source: '', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + + it('should map a complex output binding expression', () => { + const mappings = + compileAndMap(``); + expect(mappings).toContain({ + source: `', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + + it('should map a longhand output binding expression', () => { + const mappings = compileAndMap(''); + expect(mappings).toContain({ + source: '', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + + it('should map a two-way binding expression', () => { + const mappings = compileAndMap('Name: '); + expect(mappings).toContain({ + source: '', + generated: 'i0.ɵelementStart(1, "input", _c0)', + sourceUrl: '../test.ts' + }); + // TODO: improve mappings here + expect(mappings).toContain({ + source: '[(ngModel)]="name"', + generated: + 'i0.ɵlistener("ngModelChange", function TestCmp_Template_input_ngModelChange_1_listener($event) { return ctx.name = $event; })', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain({ + source: '', + generated: 'i0.ɵelementEnd()', + sourceUrl: '../test.ts' + }); + }); + + it('should map a longhand two-way binding expression', () => { + const mappings = compileAndMap('Name: '); + expect(mappings).toContain({ + source: '', + generated: 'i0.ɵelementStart(1, "input", _c0)', + sourceUrl: '../test.ts' + }); + // TODO: improve mappings here + expect(mappings).toContain({ + source: 'bindon-ngModel="name"', + generated: + 'i0.ɵlistener("ngModelChange", function TestCmp_Template_input_ngModelChange_1_listener($event) { return ctx.name = $event; })', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain({ + source: '', + generated: 'i0.ɵelementEnd()', + sourceUrl: '../test.ts' + }); + }); + + it('should map a class input binding', () => { + const mappings = compileAndMap('
    Message
    '); + expect(mappings).toContain({ + source: '
    ', + generated: 'i0.ɵelementStart(0, "div")', + sourceUrl: '../test.ts' + }); + + // TODO: Add better mappings for binding + + expect(mappings).toContain( + {source: 'Message', generated: 'i0.ɵtext(1, "Message")', sourceUrl: '../test.ts'}); + + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + }); + + describe('(structural directives)', () => { + it('should map *ngIf scenario', () => { + const mappings = compileAndMap('
    {{ name }}
    '); + + expect(mappings).toContain({ + source: '
    ', + generated: 'i0.ɵelementStart(0, "div")', + sourceUrl: '../test.ts' + }); + + // TODO - map the bindings better + + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + + // TODO: the `ctx_r...` appears to be dependent upon previous tests!!! + + // expect(mappings).toContain({ + // source: '{{ name }}', + // generated: 'i0.ɵtextBinding(1, i0.ɵinterpolation1("", ctx_r0.name, ""))', + // sourceUrl: '../test.ts' + // }); + }); + + it('should map ng-template [ngIf] scenario', () => { + const mappings = compileAndMap( + `\n` + + `
    {{ name }}
    \n` + + `
    \n` + + `
    `); + + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementStart(0, "div")', sourceUrl: '../test.ts'}); + + // TODO - map the bindings better + + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + + // TODO: the `ctx_r...` appears to be dependent upon previous tests!!! + + // expect(mappings).toContain({ + // source: '{{ name }}', + // generated: 'i0.ɵtextBinding(1, i0.ɵinterpolation1("", ctx_r0.name, ""))', + // sourceUrl: '../test.ts' + // }); + }); + + it('should map *ngFor scenario', () => { + const mappings = compileAndMap( + '
    {{ item }}
    '); + + expect(mappings).toContain({ + source: '
    ', + generated: 'i0.ɵelementStart(0, "div")', + sourceUrl: '../test.ts' + }); + + // TODO - map the bindings better + + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + + }); + + it('should map ng-template [ngFor] scenario', () => { + const mappings = + compileAndMap(`{{ item }}`); + + // TODO - map the bindings better + }); + }); + + describe('(content projection)', () => { + it('should map default and selected projection', () => { + const mappings = compileAndMap( + `

    \n` + + `
    `); + + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementStart(0, "h3")', sourceUrl: '../test.ts'}); + expect(mappings).toContain({ + source: '', + generated: 'i0.ɵprojection(1, 1)', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain( + {source: '

    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementStart(2, "div")', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {source: '', generated: 'i0.ɵprojection(3)', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {source: '
    ', generated: 'i0.ɵelementEnd()', sourceUrl: '../test.ts'}); + }); + }); + + it('should create (simple string) inline template source-mapping', () => { + const mappings = compileAndMap('
    this is a test
    {{ 1 + 2 }}
    '); + + // Creation mode + expect(mappings).toContain( + {generated: 'i0.ɵelementStart(0, "div")', source: '
    ', sourceUrl: '../test.ts'}); + expect(mappings).toContain({ + generated: 'i0.ɵtext(1, "this is a test")', + source: 'this is a test', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain( + {generated: 'i0.ɵelementEnd()', source: '
    ', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {generated: 'i0.ɵelementStart(2, "div")', source: '
    ', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {generated: 'i0.ɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {generated: 'i0.ɵelementEnd()', source: '
    ', sourceUrl: '../test.ts'}); + + // Update mode + expect(mappings).toContain({ + generated: 'i0.ɵtextBinding(3, i0.ɵinterpolation1("", (1 + 2), ""))', + source: '{{ 1 + 2 }}', + sourceUrl: '../test.ts' + }); + }); + + it('should create (simple backtick string) inline template source-mapping', () => { + const mappings = compileAndMap('
    this is a test
    {{ 1 + 2 }}
    '); + + // Creation mode + expect(mappings).toContain( + {generated: 'i0.ɵelementStart(0, "div")', source: '
    ', sourceUrl: '../test.ts'}); + expect(mappings).toContain({ + generated: 'i0.ɵtext(1, "this is a test")', + source: 'this is a test', + sourceUrl: '../test.ts' + }); + expect(mappings).toContain( + {generated: 'i0.ɵelementEnd()', source: '
    ', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {generated: 'i0.ɵelementStart(2, "div")', source: '
    ', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {generated: 'i0.ɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../test.ts'}); + expect(mappings).toContain( + {generated: 'i0.ɵelementEnd()', source: '
    ', sourceUrl: '../test.ts'}); + + // Update mode + expect(mappings).toContain({ + generated: 'i0.ɵtextBinding(3, i0.ɵinterpolation1("", (1 + 2), ""))', + source: '{{ 1 + 2 }}', + sourceUrl: '../test.ts' + }); + }); + + it('should create correct inline template source-mapping when the source contains escape sequences', + () => { + // Note that the escaped double quotes, which need un-escaping to be parsed correctly. + const mappings = compileAndMap('
    this is a test
    '); + + expect(mappings).toContain({ + generated: 'i0.ɵelementStart(0, "div", _c0)', + source: '
    ', + sourceUrl: '../test.ts' + }); + + const c2Mapping = + mappings.find(mapping => /var _c0 = \[1, "some-class"\];/.test(mapping.generated)); + expect(c2Mapping).toBeDefined(); + }); + }); + + if (tsSourceMapBug29300Fixed()) { + describe('External templates (where TS supports source-mapping)', () => { + it('should create external template source-mapping', () => { + const mappings = + compileAndMap('
    this is a test
    {{ 1 + 2 }}
    ', './dir/test.html'); + + // Creation mode + expect(mappings).toContain({ + generated: 'i0.ɵelementStart(0, "div")', + source: '
    ', + sourceUrl: '../dir/test.html' + }); + expect(mappings).toContain({ + generated: 'i0.ɵtext(1, "this is a test")', + source: 'this is a test', + sourceUrl: '../dir/test.html' + }); + expect(mappings).toContain( + {generated: 'i0.ɵelementEnd()', source: '
    ', sourceUrl: '../dir/test.html'}); + expect(mappings).toContain({ + generated: 'i0.ɵelementStart(2, "div")', + source: '
    ', + sourceUrl: '../dir/test.html' + }); + expect(mappings).toContain( + {generated: 'i0.ɵtext(3)', source: '{{ 1 + 2 }}', sourceUrl: '../dir/test.html'}); + expect(mappings).toContain( + {generated: 'i0.ɵelementEnd()', source: '
    ', sourceUrl: '../dir/test.html'}); + + // Update mode + expect(mappings).toContain({ + generated: 'i0.ɵtextBinding(3, i0.ɵinterpolation1("", (1 + 2), ""))', + source: '{{ 1 + 2 }}', + sourceUrl: '../dir/test.html' + }); + }); + + it('should create correct mappings when templateUrl is in a different rootDir', () => { + const mappings = compileAndMap( + '
    this is a test
    {{ 1 + 2 }}
    ', 'extraRootDir/test.html'); + + // Creation mode + expect(mappings).toContain({ + generated: 'i0.ɵelementStart(0, "div")', + source: '
    ', + sourceUrl: '../extraRootDir/test.html' + }); + expect(mappings).toContain({ + generated: 'i0.ɵtext(1, "this is a test")', + source: 'this is a test', + sourceUrl: '../extraRootDir/test.html' + }); + expect(mappings).toContain({ + generated: 'i0.ɵelementEnd()', + source: '
    ', + sourceUrl: '../extraRootDir/test.html' + }); + expect(mappings).toContain({ + generated: 'i0.ɵelementStart(2, "div")', + source: '
    ', + sourceUrl: '../extraRootDir/test.html' + }); + expect(mappings).toContain({ + generated: 'i0.ɵtext(3)', + source: '{{ 1 + 2 }}', + sourceUrl: '../extraRootDir/test.html' + }); + expect(mappings).toContain({ + generated: 'i0.ɵelementEnd()', + source: '
    ', + sourceUrl: '../extraRootDir/test.html' + }); + + // Update mode + expect(mappings).toContain({ + generated: 'i0.ɵtextBinding(3, i0.ɵinterpolation1("", (1 + 2), ""))', + source: '{{ 1 + 2 }}', + sourceUrl: '../extraRootDir/test.html' + }); + }); + }); + } + + function compileAndMap(template: string, templateUrl: string | null = null) { + const templateConfig = templateUrl ? `templateUrl: '${templateUrl}'` : + ('template: `' + template.replace(/`/g, '\\`') + '`'); + env.tsconfig({sourceMap: true}); + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test-cmp', + ${templateConfig} + }) + export class TestCmp {} + `); + if (templateUrl) { + env.write(templateUrl, template); + } + env.driveMain(); + return getMappedSegments(env, 'test.js'); + } + + /** + * Helper function for debugging failed mappings. + * This lays out the segment mappings in the console to make it easier to compare. + */ + function dumpMappings(mappings: SegmentMapping[]) { + mappings.forEach(map => { + // tslint:disable-next-line:no-console + console.log( + padValue(map.sourceUrl, 20, 0) + ' : ' + padValue(inspect(map.source), 100, 23) + ' : ' + + inspect(map.generated)); + }); + function padValue(value: string, max: number, start: number) { + const padding = value.length > max ? ('\n' + + ' '.repeat(max + start)) : + ' '.repeat(max - value.length); + return value + padding; + } + } +}); diff --git a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts index fde7bd21f2..69eccd0404 100644 --- a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts @@ -42,11 +42,6 @@ export declare class CommonModule { } describe('ngtsc type checking', () => { - if (!NgtscTestEnvironment.supported) { - // These tests should be excluded from the non-Bazel build. - return; - } - let env !: NgtscTestEnvironment; beforeEach(() => { diff --git a/packages/compiler-cli/test/perform_watch_spec.ts b/packages/compiler-cli/test/perform_watch_spec.ts index 76de99d25f..d40531418c 100644 --- a/packages/compiler-cli/test/perform_watch_spec.ts +++ b/packages/compiler-cli/test/perform_watch_spec.ts @@ -71,9 +71,10 @@ describe('perform watch', () => { `, }); - const mainTsPath = path.resolve(testSupport.basePath, 'src', 'main.ts'); - const utilTsPath = path.resolve(testSupport.basePath, 'src', 'util.ts'); - const mainNgFactory = path.resolve(outDir, 'src', 'main.ngfactory.js'); + const mainTsPath = path.posix.join(testSupport.basePath, 'src', 'main.ts'); + const utilTsPath = path.posix.join(testSupport.basePath, 'src', 'util.ts'); + const mainNgFactory = path.posix.join(outDir, 'src', 'main.ngfactory.js'); + performWatchCompilation(host); expect(fs.existsSync(mainNgFactory)).toBe(true); expect(fileExistsSpy !).toHaveBeenCalledWith(mainTsPath); diff --git a/packages/compiler-cli/test/runfile_helpers.ts b/packages/compiler-cli/test/runfile_helpers.ts new file mode 100644 index 0000000000..7842adb289 --- /dev/null +++ b/packages/compiler-cli/test/runfile_helpers.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as fs from 'fs'; +import * as path from 'path'; + +/** + * Gets all built Angular NPM package artifacts by querying the Bazel runfiles. + * In case there is a runfiles manifest (e.g. on Windows), the packages are resolved + * through the manifest because the runfiles are not symlinked and cannot be searched + * within the real filesystem. + */ +export function getAngularPackagesFromRunfiles() { + // Path to the Bazel runfiles manifest if present. This file is present if runfiles are + // not symlinked into the runfiles directory. + const runfilesManifestPath = process.env.RUNFILES_MANIFEST_FILE; + + if (!runfilesManifestPath) { + const packageRunfilesDir = path.join(process.env.RUNFILES !, 'angular/packages'); + + return fs.readdirSync(packageRunfilesDir) + .map(name => ({name, pkgPath: path.join(packageRunfilesDir, name, 'npm_package/')})) + .filter(({pkgPath}) => fs.existsSync(pkgPath)); + } + + return fs.readFileSync(runfilesManifestPath, 'utf8') + .split('\n') + .map(mapping => mapping.split(' ')) + .filter(([runfilePath]) => runfilePath.match(/^angular\/packages\/[\w-]+\/npm_package$/)) + .map(([runfilePath, realPath]) => ({ + name: path.relative('angular/packages', runfilePath).split(path.sep)[0], + pkgPath: realPath, + })); +} + +/** + * Resolves a NPM package from the Bazel runfiles. We need to resolve the Bazel tree + * artifacts using a "resolve file" because the NodeJS module resolution does not allow + * resolving to directory paths. + */ +export function resolveNpmTreeArtifact(manifestPath: string, resolveFile = 'package.json') { + return path.dirname(require.resolve(path.posix.join(manifestPath, resolveFile))); +} diff --git a/packages/compiler-cli/test/test_support.ts b/packages/compiler-cli/test/test_support.ts index bfcefb60db..8322b8b1d3 100644 --- a/packages/compiler-cli/test/test_support.ts +++ b/packages/compiler-cli/test/test_support.ts @@ -7,26 +7,13 @@ */ import * as fs from 'fs'; -import * as os from 'os'; import * as path from 'path'; import * as ts from 'typescript'; import * as ng from '../index'; +import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from './runfile_helpers'; -// TEST_TMPDIR is set by bazel. -const tmpdir = process.env.TEST_TMPDIR || os.tmpdir(); - -function getNgRootDir() { - const moduleFilename = module.filename.replace(/\\/g, '/'); - const distIndex = moduleFilename.indexOf('/dist/all'); - return moduleFilename.substr(0, distIndex); -} - -export function writeTempFile(name: string, contents: string): string { - const id = (Math.random() * 1000000).toFixed(0); - const fn = path.join(tmpdir, `tmp.${id}.${name}`); - fs.writeFileSync(fn, contents); - return fn; -} +// TEST_TMPDIR is always set by Bazel. +const tmpdir = process.env.TEST_TMPDIR !; export function makeTempDir(): string { let dir: string; @@ -65,6 +52,7 @@ function createTestSupportFor(basePath: string) { 'baseUrl': basePath, 'declaration': true, 'target': ts.ScriptTarget.ES5, + 'newLine': ts.NewLineKind.LineFeed, 'module': ts.ModuleKind.ES2015, 'moduleResolution': ts.ModuleResolutionKind.NodeJs, 'lib': Object.freeze([ @@ -76,15 +64,33 @@ function createTestSupportFor(basePath: string) { }; - return {basePath, write, writeFiles, createCompilerOptions, shouldExist, shouldNotExist}; + return { + // We normalize the basePath into a posix path, so that multiple assertions which compare + // paths don't need to normalize the path separators each time. + basePath: normalizeSeparators(basePath), + write, + writeFiles, + createCompilerOptions, + shouldExist, + shouldNotExist + }; + + function ensureDirExists(absolutePathToDir: string) { + if (fs.existsSync(absolutePathToDir)) { + if (!fs.statSync(absolutePathToDir).isDirectory()) { + throw new Error(`'${absolutePathToDir}' exists and is not a directory.`); + } + } else { + const parentDir = path.dirname(absolutePathToDir); + ensureDirExists(parentDir); + fs.mkdirSync(absolutePathToDir); + } + } function write(fileName: string, content: string) { - const dir = path.dirname(fileName); - if (dir != '.') { - const newDir = path.resolve(basePath, dir); - if (!fs.existsSync(newDir)) fs.mkdirSync(newDir); - } - fs.writeFileSync(path.resolve(basePath, fileName), content, {encoding: 'utf-8'}); + const absolutePathToFile = path.resolve(basePath, fileName); + ensureDirExists(path.dirname(absolutePathToFile)); + fs.writeFileSync(absolutePathToFile, content); } function writeFiles(...mockDirs: {[fileName: string]: string}[]) { @@ -109,70 +115,36 @@ function createTestSupportFor(basePath: string) { } } -export function setupBazelTo(basePath: string) { - if (!process.env.TEST_SRCDIR) { - throw new Error('`setupBazelTo()` must only be called from in a Bazel job.'); - } - const sources = process.env.TEST_SRCDIR; - const packages = path.join(sources, 'angular/packages'); - const nodeModulesPath = path.join(basePath, 'node_modules'); +export function setupBazelTo(tmpDirPath: string) { + const nodeModulesPath = path.join(tmpDirPath, 'node_modules'); const angularDirectory = path.join(nodeModulesPath, '@angular'); + fs.mkdirSync(nodeModulesPath); - - // Link the built angular packages fs.mkdirSync(angularDirectory); - const packageNames = fs.readdirSync(packages).filter( - name => fs.statSync(path.join(packages, name)).isDirectory() && - fs.existsSync(path.join(packages, name, 'npm_package'))); - for (const pkg of packageNames) { - fs.symlinkSync(path.join(packages, `${pkg}/npm_package`), path.join(angularDirectory, pkg)); - } - // Link rxjs - const rxjsSource = path.join(sources, 'rxjs'); - const rxjsDest = path.join(nodeModulesPath, 'rxjs'); - if (fs.existsSync(rxjsSource)) { - fs.symlinkSync(rxjsSource, rxjsDest); - } + getAngularPackagesFromRunfiles().forEach( + ({pkgPath, name}) => { fs.symlinkSync(pkgPath, path.join(angularDirectory, name), 'dir'); }); // Link typescript - const typescriptSource = path.join(sources, 'ngdeps/node_modules/typescript'); + const typeScriptSource = resolveNpmTreeArtifact('ngdeps/node_modules/typescript'); const typescriptDest = path.join(nodeModulesPath, 'typescript'); - if (fs.existsSync(typescriptSource)) { - fs.symlinkSync(typescriptSource, typescriptDest); + fs.symlinkSync(typeScriptSource, typescriptDest, 'dir'); + + // Link "rxjs" if it has been set up as a runfile. "rxjs" is linked optionally because + // not all compiler-cli tests need "rxjs" set up. + try { + const rxjsSource = resolveNpmTreeArtifact('rxjs', 'index.js'); + const rxjsDest = path.join(nodeModulesPath, 'rxjs'); + fs.symlinkSync(rxjsSource, rxjsDest, 'dir'); + } catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') throw e; } } -function setupBazel(): TestSupport { - const basePath = makeTempDir(); - setupBazelTo(basePath); - return createTestSupportFor(basePath); -} - -function setupTestSh(): TestSupport { - const basePath = makeTempDir(); - - const ngRootDir = getNgRootDir(); - const nodeModulesPath = path.resolve(basePath, 'node_modules'); - fs.mkdirSync(nodeModulesPath); - fs.symlinkSync( - path.resolve(ngRootDir, 'dist', 'all', '@angular'), - path.resolve(nodeModulesPath, '@angular')); - fs.symlinkSync( - path.resolve(ngRootDir, 'node_modules', 'rxjs'), path.resolve(nodeModulesPath, 'rxjs')); - fs.symlinkSync( - path.resolve(ngRootDir, 'node_modules', 'typescript'), - path.resolve(nodeModulesPath, 'typescript')); - - return createTestSupportFor(basePath); -} - -export function isInBazel() { - return process.env.TEST_SRCDIR != null; -} - export function setup(): TestSupport { - return isInBazel() ? setupBazel() : setupTestSh(); + const tmpDirPath = makeTempDir(); + setupBazelTo(tmpDirPath); + return createTestSupportFor(tmpDirPath); } export function expectNoDiagnostics(options: ng.CompilerOptions, diags: ng.Diagnostics) { @@ -188,3 +160,7 @@ export function expectNoDiagnosticsInProgram(options: ng.CompilerOptions, p: ng. ...p.getNgSemanticDiagnostics() ]); } + +export function normalizeSeparators(path: string): string { + return path.replace(/\\/g, '/'); +} diff --git a/packages/compiler-cli/test/transformers/compiler_host_spec.ts b/packages/compiler-cli/test/transformers/compiler_host_spec.ts index 357bdc543f..c411a638ac 100644 --- a/packages/compiler-cli/test/transformers/compiler_host_spec.ts +++ b/packages/compiler-cli/test/transformers/compiler_host_spec.ts @@ -196,7 +196,21 @@ describe('NgCompilerHost', () => { const host = createHost({ngHost}); expect(host.resourceNameToFileName('a', 'b')).toBe('someResult'); }); - + it('should resolve Sass imports to generated .css files', () => { + const host = createHost({files: {'tmp': {'src': {'a': {'style.css': 'h1: bold'}}}}}); + expect(host.resourceNameToFileName('./a/style.scss', '/tmp/src/index.ts')) + .toBe('/tmp/src/a/style.css'); + }); + it('should resolve Less imports to generated .css files', () => { + const host = createHost({files: {'tmp': {'src': {'a': {'style.css': 'h1: bold'}}}}}); + expect(host.resourceNameToFileName('./a/style.less', '/tmp/src/index.ts')) + .toBe('/tmp/src/a/style.css'); + }); + it('should resolve Stylus imports to generated .css files', () => { + const host = createHost({files: {'tmp': {'src': {'a': {'style.css': 'h1: bold'}}}}}); + expect(host.resourceNameToFileName('./a/style.styl', '/tmp/src/index.ts')) + .toBe('/tmp/src/a/style.css'); + }); }); describe('getSourceFile', () => { diff --git a/packages/compiler-cli/test/transformers/program_spec.ts b/packages/compiler-cli/test/transformers/program_spec.ts index 951b1ffbd1..94db5e3542 100644 --- a/packages/compiler-cli/test/transformers/program_spec.ts +++ b/packages/compiler-cli/test/transformers/program_spec.ts @@ -14,8 +14,8 @@ import * as ts from 'typescript'; import {formatDiagnostics} from '../../src/perform_compile'; import {CompilerHost, EmitFlags, LazyRoute} from '../../src/transformers/api'; import {checkVersion, createSrcToOutPathMapper} from '../../src/transformers/program'; -import {GENERATED_FILES, StructureIsReused, tsStructureIsReused} from '../../src/transformers/util'; -import {TestSupport, expectNoDiagnosticsInProgram, isInBazel, setup} from '../test_support'; +import {StructureIsReused, tsStructureIsReused} from '../../src/transformers/util'; +import {TestSupport, expectNoDiagnosticsInProgram, setup} from '../test_support'; describe('ng program', () => { let testSupport: TestSupport; @@ -53,7 +53,7 @@ describe('ng program', () => { expectNoDiagnosticsInProgram(options, program); fs.symlinkSync( path.resolve(testSupport.basePath, 'built', `${libName}_src`), - path.resolve(testSupport.basePath, 'node_modules', libName)); + path.resolve(testSupport.basePath, 'node_modules', libName), 'dir'); program.emit({emitFlags: ng.EmitFlags.DTS | ng.EmitFlags.JS | ng.EmitFlags.Metadata}); } @@ -214,9 +214,9 @@ describe('ng program', () => { // compile without libraries const p2 = compile(p1, options, undefined, host).program; - expect(written.has(path.resolve(testSupport.basePath, 'built/src/index.js'))).toBe(true); + expect(written.has(path.posix.join(testSupport.basePath, 'built/src/index.js'))).toBe(true); let ngFactoryContent = - written.get(path.resolve(testSupport.basePath, 'built/src/index.ngfactory.js')); + written.get(path.posix.join(testSupport.basePath, 'built/src/index.ngfactory.js')); expect(ngFactoryContent).toMatch(/Start/); // no change -> no emit @@ -226,10 +226,10 @@ describe('ng program', () => { // change a user file written.clear(); - fileCache.delete(path.resolve(testSupport.basePath, 'src/index.ts')); + fileCache.delete(path.posix.join(testSupport.basePath, 'src/index.ts')); const p4 = compile(p3, options, undefined, host).program; expect(written.size).toBe(1); - expect(written.has(path.resolve(testSupport.basePath, 'built/src/index.js'))).toBe(true); + expect(written.has(path.posix.join(testSupport.basePath, 'built/src/index.js'))).toBe(true); // change a file that is input to generated files written.clear(); @@ -237,14 +237,14 @@ describe('ng program', () => { const p5 = compile(p4, options, undefined, host).program; expect(written.size).toBe(1); ngFactoryContent = - written.get(path.resolve(testSupport.basePath, 'built/src/index.ngfactory.js')); + written.get(path.posix.join(testSupport.basePath, 'built/src/index.ngfactory.js')); expect(ngFactoryContent).toMatch(/Hello/); // change a file and create an intermediate program that is not emitted written.clear(); - fileCache.delete(path.resolve(testSupport.basePath, 'src/index.ts')); + fileCache.delete(path.posix.join(testSupport.basePath, 'src/index.ts')); const p6 = ng.createProgram({ - rootNames: [path.resolve(testSupport.basePath, 'src/index.ts')], + rootNames: [path.posix.join(testSupport.basePath, 'src/index.ts')], options: testSupport.createCompilerOptions(options), host, oldProgram: p5 }); @@ -481,10 +481,11 @@ describe('ng program', () => { const enum ShouldBe { Empty, EmptyExport, NoneEmpty } function assertGenFile( fileName: string, checks: {originalFileName: string, shouldBe: ShouldBe}) { - const writeData = written.get(path.join(testSupport.basePath, fileName)); + const writeData = written.get(path.posix.join(testSupport.basePath, fileName)); expect(writeData).toBeTruthy(); - expect(writeData !.original !.some( - sf => sf.fileName === path.join(testSupport.basePath, checks.originalFileName))) + expect( + writeData !.original !.some( + sf => sf.fileName === path.posix.join(testSupport.basePath, checks.originalFileName))) .toBe(true); switch (checks.shouldBe) { case ShouldBe.Empty: @@ -575,29 +576,30 @@ describe('ng program', () => { describe('createSrcToOutPathMapper', () => { it('should return identity mapping if no outDir is present', () => { - const mapper = createSrcToOutPathMapper(undefined, undefined, undefined); + const mapper = createSrcToOutPathMapper(undefined, undefined, undefined, path.posix); expect(mapper('/tmp/b/y.js')).toBe('/tmp/b/y.js'); }); it('should return identity mapping if first src and out fileName have same dir', () => { - const mapper = createSrcToOutPathMapper('/tmp', '/tmp/a/x.ts', '/tmp/a/x.js'); + const mapper = createSrcToOutPathMapper('/tmp', '/tmp/a/x.ts', '/tmp/a/x.js', path.posix); expect(mapper('/tmp/b/y.js')).toBe('/tmp/b/y.js'); }); it('should adjust the filename if the outDir is inside of the rootDir', () => { - const mapper = createSrcToOutPathMapper('/tmp/out', '/tmp/a/x.ts', '/tmp/out/a/x.js'); + const mapper = + createSrcToOutPathMapper('/tmp/out', '/tmp/a/x.ts', '/tmp/out/a/x.js', path.posix); expect(mapper('/tmp/b/y.js')).toBe('/tmp/out/b/y.js'); }); it('should adjust the filename if the outDir is outside of the rootDir', () => { - const mapper = createSrcToOutPathMapper('/out', '/tmp/a/x.ts', '/out/a/x.js'); + const mapper = createSrcToOutPathMapper('/out', '/tmp/a/x.ts', '/out/a/x.js', path.posix); expect(mapper('/tmp/b/y.js')).toBe('/out/b/y.js'); }); it('should adjust the filename if the common prefix of sampleSrc and sampleOut is outside of outDir', () => { - const mapper = - createSrcToOutPathMapper('/dist/common', '/src/common/x.ts', '/dist/common/x.js'); + const mapper = createSrcToOutPathMapper( + '/dist/common', '/src/common/x.ts', '/dist/common/x.js', path.posix); expect(mapper('/src/common/y.js')).toBe('/dist/common/y.js'); }); @@ -668,16 +670,23 @@ describe('ng program', () => { expectNoDiagnosticsInProgram(options, program); expect(normalizeRoutes(program.listLazyRoutes())).toEqual([ { - module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, - referencedModule: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, + module: + {name: 'MainModule', filePath: path.posix.join(testSupport.basePath, 'src/main.ts')}, + referencedModule: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, route: './child#ChildModule' }, { - module: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, - referencedModule: - {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, + module: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, + referencedModule: { + name: 'ChildModule2', + filePath: path.posix.join(testSupport.basePath, 'src/child2.ts') + }, route: './child2#ChildModule2' }, ]); @@ -718,26 +727,37 @@ describe('ng program', () => { expectNoDiagnosticsInProgram(options, program); expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([ { - module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, - referencedModule: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, + module: + {name: 'MainModule', filePath: path.posix.join(testSupport.basePath, 'src/main.ts')}, + referencedModule: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, route: './child#ChildModule' }, { - module: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, - referencedModule: - {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, + module: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, + referencedModule: { + name: 'ChildModule2', + filePath: path.posix.join(testSupport.basePath, 'src/child2.ts') + }, route: './child2#ChildModule2' }, ]); expect(normalizeRoutes(program.listLazyRoutes('src/child#ChildModule'))).toEqual([ { - module: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, - referencedModule: - {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, + module: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, + referencedModule: { + name: 'ChildModule2', + filePath: path.posix.join(testSupport.basePath, 'src/child2.ts') + }, route: './child2#ChildModule2' }, ]); @@ -764,10 +784,11 @@ describe('ng program', () => { const {program, options} = createProgram(['src/main.ts']); expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([ { - module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, + module: + {name: 'MainModule', filePath: path.posix.join(testSupport.basePath, 'src/main.ts')}, referencedModule: { name: undefined as any as string, // TODO: Review use of `any` here (#19904) - filePath: path.resolve(testSupport.basePath, 'src/child.ts') + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') }, route: './child' }, @@ -816,18 +837,21 @@ describe('ng program', () => { { module: { name: 'NestedMainModule', - filePath: path.resolve(testSupport.basePath, 'src/nested/main.ts') + filePath: path.posix.join(testSupport.basePath, 'src/nested/main.ts') }, referencedModule: { name: 'NestedChildModule', - filePath: path.resolve(testSupport.basePath, 'src/nested/child.ts') + filePath: path.posix.join(testSupport.basePath, 'src/nested/child.ts') }, route: './child#NestedChildModule' }, { - module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, - referencedModule: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, + module: + {name: 'MainModule', filePath: path.posix.join(testSupport.basePath, 'src/main.ts')}, + referencedModule: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, route: './child#ChildModule' }, ]); @@ -853,16 +877,23 @@ describe('ng program', () => { expectNoDiagnosticsInProgram(options, program); expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([ { - module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, - referencedModule: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, + module: + {name: 'MainModule', filePath: path.posix.join(testSupport.basePath, 'src/main.ts')}, + referencedModule: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, route: './child#ChildModule' }, { - module: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, - referencedModule: - {name: 'ChildModule2', filePath: path.resolve(testSupport.basePath, 'src/child2.ts')}, + module: { + name: 'ChildModule', + filePath: path.posix.join(testSupport.basePath, 'src/child.ts') + }, + referencedModule: { + name: 'ChildModule2', + filePath: path.posix.join(testSupport.basePath, 'src/child2.ts') + }, route: './child2#ChildModule2' }, ]); @@ -920,9 +951,10 @@ describe('ng program', () => { }); const program = createProgram(['src/main.ts'], {collectAllErrors: true}).program; expect(normalizeRoutes(program.listLazyRoutes('src/main#MainModule'))).toEqual([{ - module: {name: 'MainModule', filePath: path.resolve(testSupport.basePath, 'src/main.ts')}, + module: + {name: 'MainModule', filePath: path.posix.join(testSupport.basePath, 'src/main.ts')}, referencedModule: - {name: 'ChildModule', filePath: path.resolve(testSupport.basePath, 'src/child.ts')}, + {name: 'ChildModule', filePath: path.posix.join(testSupport.basePath, 'src/child.ts')}, route: './child#ChildModule' }]); }); diff --git a/packages/compiler-cli/tsconfig-tools.json b/packages/compiler-cli/tsconfig-tools.json deleted file mode 100644 index 752f6bf1ed..0000000000 --- a/packages/compiler-cli/tsconfig-tools.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig-build.json", - - "compilerOptions": { - "outDir": "../../dist/tools/@angular/compiler-cli", - "paths": { - "@angular/compiler": ["../../dist/tools/@angular/compiler"] - } - } -} \ No newline at end of file diff --git a/packages/compiler/BUILD.bazel b/packages/compiler/BUILD.bazel index 024344d9a4..a2d2e78bc4 100644 --- a/packages/compiler/BUILD.bazel +++ b/packages/compiler/BUILD.bazel @@ -10,7 +10,6 @@ ts_library( "src/**/*.ts", ], ), - module_name = "@angular/compiler", ) ng_package( @@ -27,6 +26,7 @@ ng_package( # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", "//packages/language-service/test:__pkg__", ], deps = [ diff --git a/packages/compiler/design/architecture.md b/packages/compiler/design/architecture.md index 9c140c6ffd..776207b34c 100644 --- a/packages/compiler/design/architecture.md +++ b/packages/compiler/design/architecture.md @@ -68,7 +68,7 @@ GreetComponent = tslib_1.__decorate([ ], GreetComponent); ``` -which translates the decorator into a form that is is executed at runtime. A `.d.ts` file is also emitted that might look something like +which translates the decorator into a form that is executed at runtime. A `.d.ts` file is also emitted that might look something like ```ts export class GreetComponent { @@ -146,7 +146,7 @@ TypeScript supports the following extension points to alter its output. You can, 1. Modify the TypeScript source it sees (`CompilerHost.getSourceFile`) 2. Alter the list of transforms (`CustomTransformers`) -3. Intercept the the output before it is written (`WriteFileCallback`) +3. Intercept the output before it is written (`WriteFileCallback`) It is not recommended to alter the source code as this complicates the managing of source maps, makes it difficult to support incremental parsing, and is not supported by TypeScript's language service plug-in model. diff --git a/packages/compiler/rollup.config.js b/packages/compiler/rollup.config.js deleted file mode 100644 index a735cc2adc..0000000000 --- a/packages/compiler/rollup.config.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../dist/packages-dist/compiler/fesm5/compiler.js', - dest: '../../dist/packages-dist/compiler/bundles/compiler.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/compiler'}, - moduleName: 'ng.compiler', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/compiler/src/aot/compiler.ts b/packages/compiler/src/aot/compiler.ts index f76e0fe06c..f7b5c59e25 100644 --- a/packages/compiler/src/aot/compiler.ts +++ b/packages/compiler/src/aot/compiler.ts @@ -553,7 +553,7 @@ export class AotCompiler { null; const {json, exportAs} = serializeSummaries( srcFileName, forJitOutputCtx, this._summaryResolver, this._symbolResolver, symbolSummaries, - typeData); + typeData, this._options.createExternalSymbolFactoryReexports); exportAs.forEach((entry) => { ngFactoryCtx.statements.push( o.variable(entry.exportAs).set(ngFactoryCtx.importExpr(entry.symbol)).toDeclStmt(null, [ diff --git a/packages/compiler/src/aot/compiler_options.ts b/packages/compiler/src/aot/compiler_options.ts index f8fbdf2800..4a0e3f9532 100644 --- a/packages/compiler/src/aot/compiler_options.ts +++ b/packages/compiler/src/aot/compiler_options.ts @@ -20,4 +20,5 @@ export interface AotCompilerOptions { allowEmptyCodegenFiles?: boolean; strictInjectionParameters?: boolean; enableIvy?: boolean|'ngtsc'|'tsc'; + createExternalSymbolFactoryReexports?: boolean; } diff --git a/packages/compiler/src/aot/summary_serializer.ts b/packages/compiler/src/aot/summary_serializer.ts index 1b6d44885d..f8981565a9 100644 --- a/packages/compiler/src/aot/summary_serializer.ts +++ b/packages/compiler/src/aot/summary_serializer.ts @@ -21,7 +21,9 @@ export function serializeSummaries( summary: CompileTypeSummary, metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata | CompileTypeMetadata - }[]): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} { + }[], + createExternalSymbolReexports = + false): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} { const toJsonSerializer = new ToJsonSerializer(symbolResolver, summaryResolver, srcFileName); // for symbols, we use everything except for the class metadata itself @@ -36,7 +38,7 @@ export function serializeSummaries( toJsonSerializer.addSummary( {symbol: summary.type.reference, metadata: undefined, type: summary}); }); - const {json, exportAs} = toJsonSerializer.serialize(); + const {json, exportAs} = toJsonSerializer.serialize(createExternalSymbolReexports); if (forJitCtx) { const forJitSerializer = new ForJitSerializer(forJitCtx, symbolResolver, summaryResolver); types.forEach(({summary, metadata}) => { forJitSerializer.addSourceType(summary, metadata); }); @@ -178,7 +180,14 @@ class ToJsonSerializer extends ValueTransformer { } } - serialize(): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} { + /** + * @param createExternalSymbolReexports Whether external static symbols should be re-exported. + * This can be enabled if external symbols should be re-exported by the current module in + * order to avoid dynamically generated module dependencies which can break strict dependency + * enforcements (as in Google3). Read more here: https://github.com/angular/angular/issues/25644 + */ + serialize(createExternalSymbolReexports: boolean): + {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} { const exportAs: {symbol: StaticSymbol, exportAs: string}[] = []; const json = JSON.stringify({ moduleName: this.moduleName, @@ -189,8 +198,18 @@ class ToJsonSerializer extends ValueTransformer { if (this.summaryResolver.isLibraryFile(symbol.filePath)) { const reexportSymbol = this.reexportedBy.get(symbol); if (reexportSymbol) { + // In case the given external static symbol is already manually exported by the + // user, we just proxy the external static symbol reference to the manual export. + // This ensures that the AOT compiler imports the external symbol through the + // user export and does not introduce another dependency which is not needed. importAs = this.indexBySymbol.get(reexportSymbol) !; - } else { + } else if (createExternalSymbolReexports) { + // In this case, the given external static symbol is *not* manually exported by + // the user, and we manually create a re-export in the factory file so that we + // don't introduce another module dependency. This is useful when running within + // Bazel so that the AOT compiler does not introduce any module dependencies + // which can break the strict dependency enforcement. (e.g. as in Google3) + // Read more about this here: https://github.com/angular/angular/issues/25644 const summary = this.unprocessedSymbolSummariesBySymbol.get(symbol); if (!summary || !summary.metadata || summary.metadata.__symbolic !== 'interface') { importAs = `${symbol.name}_${index}`; diff --git a/packages/compiler/src/chars.ts b/packages/compiler/src/chars.ts index 4e510a2d58..28ce8b9c22 100644 --- a/packages/compiler/src/chars.ts +++ b/packages/compiler/src/chars.ts @@ -7,6 +7,7 @@ */ export const $EOF = 0; +export const $BSPACE = 8; export const $TAB = 9; export const $LF = 10; export const $VTAB = 11; @@ -36,6 +37,7 @@ export const $GT = 62; export const $QUESTION = 63; export const $0 = 48; +export const $7 = 55; export const $9 = 57; export const $A = 65; @@ -51,6 +53,7 @@ export const $CARET = 94; export const $_ = 95; export const $a = 97; +export const $b = 98; export const $e = 101; export const $f = 102; export const $n = 110; @@ -87,3 +90,11 @@ export function isAsciiLetter(code: number): boolean { export function isAsciiHexDigit(code: number): boolean { return code >= $a && code <= $f || code >= $A && code <= $F || isDigit(code); } + +export function isNewLine(code: number): boolean { + return code === $LF || code === $CR; +} + +export function isOctalDigit(code: number): boolean { + return $0 <= code && code <= $7; +} diff --git a/packages/compiler/src/compiler.ts b/packages/compiler/src/compiler.ts index 5155c670c1..dbc9f643f4 100644 --- a/packages/compiler/src/compiler.ts +++ b/packages/compiler/src/compiler.ts @@ -74,9 +74,11 @@ export * from './ml_parser/html_parser'; export * from './ml_parser/html_tags'; export * from './ml_parser/interpolation_config'; export * from './ml_parser/tags'; +export {LexerRange} from './ml_parser/lexer'; export {NgModuleCompiler} from './ng_module_compiler'; export {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinMethod, BuiltinType, BuiltinTypeName, BuiltinVar, CastExpr, ClassField, ClassMethod, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, StatementVisitor, ThrowStmt, TryCatchStmt, Type, TypeVisitor, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, StmtModifier, Statement, TypeofExpr, collectExternalReferences} from './output/output_ast'; export {EmitterVisitorContext} from './output/abstract_emitter'; +export {JitEvaluator} from './output/output_jit'; export * from './output/ts_emitter'; export * from './parse_util'; export * from './schema/dom_element_schema_registry'; @@ -91,13 +93,13 @@ export * from './render3/view/api'; export {BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element as TmplAstElement, Node as TmplAstNode, Reference as TmplAstReference, Template as TmplAstTemplate, Text as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable,} from './render3/r3_ast'; export * from './render3/view/t2_api'; export * from './render3/view/t2_binder'; -export {jitExpression} from './render3/r3_jit'; +export {Identifiers as R3Identifiers} from './render3/r3_identifiers'; export {R3DependencyMetadata, R3FactoryMetadata, R3ResolvedDependencyType} from './render3/r3_factory'; export {compileInjector, compileNgModule, R3InjectorMetadata, R3NgModuleMetadata} from './render3/r3_module_compiler'; export {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler'; export {makeBindingParser, parseTemplate} from './render3/view/template'; export {R3Reference} from './render3/util'; -export {compileBaseDefFromMetadata, R3BaseRefMetaData, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings} from './render3/view/compiler'; +export {compileBaseDefFromMetadata, R3BaseRefMetaData, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler'; export {publishFacade} from './jit_compiler_facade'; // This file only reexports content of the `src` folder. Keep it that way. diff --git a/packages/compiler/src/compiler_facade_interface.ts b/packages/compiler/src/compiler_facade_interface.ts index 372483897a..ad281c618e 100644 --- a/packages/compiler/src/compiler_facade_interface.ts +++ b/packages/compiler/src/compiler_facade_interface.ts @@ -38,6 +38,8 @@ export interface CompilerFacade { compileComponent( angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any; + createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan; + R3ResolvedDependencyType: typeof R3ResolvedDependencyType; } @@ -95,6 +97,7 @@ export interface R3NgModuleMetadataFacade { imports: Function[]; exports: Function[]; emitInline: boolean; + schemas: {name: string}[]|null; } export interface R3InjectorMetadataFacade { @@ -109,7 +112,7 @@ export interface R3DirectiveMetadataFacade { name: string; type: any; typeArgumentCount: number; - typeSourceSpan: null; + typeSourceSpan: ParseSourceSpan; deps: R3DependencyMetadataFacade[]|null; selector: string|null; queries: R3QueryMetadataFacade[]; @@ -119,7 +122,7 @@ export interface R3DirectiveMetadataFacade { inputs: string[]; outputs: string[]; usesInheritance: boolean; - exportAs: string|null; + exportAs: string[]|null; providers: Provider[]|null; } @@ -148,3 +151,9 @@ export interface R3QueryMetadataFacade { descendants: boolean; read: any|null; } + +export interface ParseSourceSpan { + start: any; + end: any; + details: any; +} diff --git a/packages/compiler/src/compiler_util/expression_converter.ts b/packages/compiler/src/compiler_util/expression_converter.ts index 84d3c8639e..f902f0884c 100644 --- a/packages/compiler/src/compiler_util/expression_converter.ts +++ b/packages/compiler/src/compiler_util/expression_converter.ts @@ -9,6 +9,7 @@ import * as cdAst from '../expression_parser/ast'; import {Identifiers} from '../identifiers'; import * as o from '../output/output_ast'; +import {ParseSourceSpan} from '../parse_util'; export class EventHandlerVars { static event = o.variable('$event'); } @@ -65,7 +66,8 @@ export type InterpolationFunction = (args: o.Expression[]) => o.Expression; */ export function convertActionBinding( localResolver: LocalResolver | null, implicitReceiver: o.Expression, action: cdAst.AST, - bindingId: string, interpolationFunction?: InterpolationFunction): ConvertActionBindingResult { + bindingId: string, interpolationFunction?: InterpolationFunction, + baseSourceSpan?: ParseSourceSpan): ConvertActionBindingResult { if (!localResolver) { localResolver = new DefaultLocalResolver(); } @@ -92,8 +94,8 @@ export function convertActionBinding( }, action); - const visitor = - new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, interpolationFunction); + const visitor = new _AstToIrVisitor( + localResolver, implicitReceiver, bindingId, interpolationFunction, baseSourceSpan); const actionStmts: o.Statement[] = []; flattenStatements(actionWithoutBuiltins.visit(visitor, _Mode.Statement), actionStmts); prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts); @@ -243,7 +245,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor { constructor( private _localResolver: LocalResolver, private _implicitReceiver: o.Expression, - private bindingId: string, private interpolationFunction: InterpolationFunction|undefined) {} + private bindingId: string, private interpolationFunction: InterpolationFunction|undefined, + private baseSourceSpan?: ParseSourceSpan) {} visitBinary(ast: cdAst.Binary, mode: _Mode): any { let op: o.BinaryOperator; @@ -300,7 +303,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor { return convertToStatementIfNeeded( mode, new o.BinaryOperatorExpr( - op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression))); + op, this._visit(ast.left, _Mode.Expression), this._visit(ast.right, _Mode.Expression), + undefined, this.convertSourceSpan(ast.span))); } visitChain(ast: cdAst.Chain, mode: _Mode): any { @@ -313,7 +317,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor { return convertToStatementIfNeeded( mode, value.conditional( this._visit(ast.trueExp, _Mode.Expression), - this._visit(ast.falseExp, _Mode.Expression))); + this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span))); } visitPipe(ast: cdAst.BindingPipe, mode: _Mode): any { @@ -327,7 +331,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor { if (ast instanceof BuiltinFunctionCall) { fnResult = ast.converter(convertedArgs); } else { - fnResult = this._visit(ast.target !, _Mode.Expression).callFn(convertedArgs); + fnResult = this._visit(ast.target !, _Mode.Expression) + .callFn(convertedArgs, this.convertSourceSpan(ast.span)); } return convertToStatementIfNeeded(mode, fnResult); } @@ -351,7 +356,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor { } return ast.expressions.length <= 9 ? o.importExpr(Identifiers.inlineInterpolate).callFn(args) : - o.importExpr(Identifiers.interpolate).callFn([args[0], o.literalArr(args.slice(1))]); + o.importExpr(Identifiers.interpolate).callFn([ + args[0], o.literalArr(args.slice(1), undefined, this.convertSourceSpan(ast.span)) + ]); } visitKeyedRead(ast: cdAst.KeyedRead, mode: _Mode): any { @@ -386,7 +393,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor { ast.value === null || ast.value === undefined || ast.value === true || ast.value === true ? o.INFERRED_TYPE : undefined; - return convertToStatementIfNeeded(mode, o.literal(ast.value, type)); + return convertToStatementIfNeeded( + mode, o.literal(ast.value, type, this.convertSourceSpan(ast.span))); } private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); } @@ -398,7 +406,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor { throw new Error( `Invalid call to $any, expected 1 argument but received ${args.length || 'none'}`); } - return (args[0] as o.Expression).cast(o.DYNAMIC_TYPE); + return (args[0] as o.Expression).cast(o.DYNAMIC_TYPE, this.convertSourceSpan(ast.span)); } const leftMostSafe = this.leftMostSafeNode(ast); @@ -415,7 +423,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor { } } if (result == null) { - result = receiver.callMethod(ast.name, args); + result = receiver.callMethod(ast.name, args, this.convertSourceSpan(ast.span)); } return convertToStatementIfNeeded(mode, result); } @@ -665,6 +673,27 @@ class _AstToIrVisitor implements cdAst.AstVisitor { throw new Error(`Temporary ${temporary.name} released out of order`); } } + + /** + * Creates an absolute `ParseSourceSpan` from the relative `ParseSpan`. + * + * `ParseSpan` objects are relative to the start of the expression. + * This method converts these to full `ParseSourceSpan` objects that + * show where the span is within the overall source file. + * + * @param span the relative span to convert. + * @returns a `ParseSourceSpan` for the the given span or null if no + * `baseSourceSpan` was provided to this class. + */ + private convertSourceSpan(span: cdAst.ParseSpan) { + if (this.baseSourceSpan) { + const start = this.baseSourceSpan.start.moveBy(span.start); + const end = this.baseSourceSpan.start.moveBy(span.end); + return new ParseSourceSpan(start, end); + } else { + return null; + } + } } function flattenStatements(arg: any, output: o.Statement[]) { diff --git a/packages/compiler/src/directive_normalizer.ts b/packages/compiler/src/directive_normalizer.ts index 06613f361f..38e54961ba 100644 --- a/packages/compiler/src/directive_normalizer.ts +++ b/packages/compiler/src/directive_normalizer.ts @@ -113,12 +113,11 @@ export class DirectiveNormalizer { templateAbsUrl: string): PreparsedTemplate { const isInline = !!prenormData.template; const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation !); + const templateUrl = templateSourceUrl( + {reference: prenormData.ngModuleType}, {type: {reference: prenormData.componentType}}, + {isInline, templateUrl: templateAbsUrl}); const rootNodesAndErrors = this._htmlParser.parse( - template, - templateSourceUrl( - {reference: prenormData.ngModuleType}, {type: {reference: prenormData.componentType}}, - {isInline, templateUrl: templateAbsUrl}), - true, interpolationConfig); + template, templateUrl, {tokenizeExpansionForms: true, interpolationConfig}); if (rootNodesAndErrors.errors.length > 0) { const errorString = rootNodesAndErrors.errors.join('\n'); throw syntaxError(`Template parse errors:\n${errorString}`); diff --git a/packages/compiler/src/expression_parser/ast.ts b/packages/compiler/src/expression_parser/ast.ts index c511a4dc23..208cda0ca2 100644 --- a/packages/compiler/src/expression_parser/ast.ts +++ b/packages/compiler/src/expression_parser/ast.ts @@ -477,8 +477,9 @@ export class AstMemoryEfficientTransformer implements AstVisitor { visitMethodCall(ast: MethodCall, context: any): AST { const receiver = ast.receiver.visit(this); - if (receiver !== ast.receiver) { - return new MethodCall(ast.span, receiver, ast.name, this.visitAll(ast.args)); + const args = this.visitAll(ast.args); + if (receiver !== ast.receiver || args !== ast.args) { + return new MethodCall(ast.span, receiver, ast.name, args); } return ast; } @@ -546,7 +547,7 @@ export class AstMemoryEfficientTransformer implements AstVisitor { const condition = ast.condition.visit(this); const trueExp = ast.trueExp.visit(this); const falseExp = ast.falseExp.visit(this); - if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== falseExp) { + if (condition !== ast.condition || trueExp !== ast.trueExp || falseExp !== ast.falseExp) { return new Conditional(ast.span, condition, trueExp, falseExp); } return ast; @@ -698,7 +699,8 @@ export class ParsedEvent { // Animation events have a phase constructor( public name: string, public targetOrPhase: string, public type: ParsedEventType, - public handler: AST, public sourceSpan: ParseSourceSpan) {} + public handler: AST, public sourceSpan: ParseSourceSpan, + public handlerSpan: ParseSourceSpan) {} } export class ParsedVariable { diff --git a/packages/compiler/src/i18n/i18n_html_parser.ts b/packages/compiler/src/i18n/i18n_html_parser.ts index b0c3397c03..57fcceafe3 100644 --- a/packages/compiler/src/i18n/i18n_html_parser.ts +++ b/packages/compiler/src/i18n/i18n_html_parser.ts @@ -8,7 +8,8 @@ import {MissingTranslationStrategy} from '../core'; import {HtmlParser} from '../ml_parser/html_parser'; -import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config'; +import {DEFAULT_INTERPOLATION_CONFIG} from '../ml_parser/interpolation_config'; +import {TokenizeOptions} from '../ml_parser/lexer'; import {ParseTreeResult} from '../ml_parser/parser'; import {Console} from '../util'; @@ -41,11 +42,9 @@ export class I18NHtmlParser implements HtmlParser { } } - parse( - source: string, url: string, parseExpansionForms: boolean = false, - interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ParseTreeResult { - const parseResult = - this._htmlParser.parse(source, url, parseExpansionForms, interpolationConfig); + parse(source: string, url: string, options: TokenizeOptions = {}): ParseTreeResult { + const interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG; + const parseResult = this._htmlParser.parse(source, url, {interpolationConfig, ...options}); if (parseResult.errors.length) { return new ParseTreeResult(parseResult.rootNodes, parseResult.errors); diff --git a/packages/compiler/src/i18n/message_bundle.ts b/packages/compiler/src/i18n/message_bundle.ts index e685478367..882ac54eb3 100644 --- a/packages/compiler/src/i18n/message_bundle.ts +++ b/packages/compiler/src/i18n/message_bundle.ts @@ -27,7 +27,8 @@ export class MessageBundle { updateFromTemplate(html: string, url: string, interpolationConfig: InterpolationConfig): ParseError[] { - const htmlParserResult = this._htmlParser.parse(html, url, true, interpolationConfig); + const htmlParserResult = + this._htmlParser.parse(html, url, {tokenizeExpansionForms: true, interpolationConfig}); if (htmlParserResult.errors.length) { return htmlParserResult.errors; diff --git a/packages/compiler/src/i18n/serializers/xliff.ts b/packages/compiler/src/i18n/serializers/xliff.ts index e1efddd9d5..58d9a6083c 100644 --- a/packages/compiler/src/i18n/serializers/xliff.ts +++ b/packages/compiler/src/i18n/serializers/xliff.ts @@ -185,7 +185,7 @@ class XliffParser implements ml.Visitor { this._unitMlString = null; this._msgIdToHtml = {}; - const xml = new XmlParser().parse(xliff, url, false); + const xml = new XmlParser().parse(xliff, url); this._errors = xml.errors; ml.visitAll(this, xml.rootNodes, null); @@ -268,7 +268,7 @@ class XmlToI18n implements ml.Visitor { private _errors !: I18nError[]; convert(message: string, url: string) { - const xmlIcu = new XmlParser().parse(message, url, true); + const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true}); this._errors = xmlIcu.errors; const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? diff --git a/packages/compiler/src/i18n/serializers/xliff2.ts b/packages/compiler/src/i18n/serializers/xliff2.ts index f43382349f..a8ba85d597 100644 --- a/packages/compiler/src/i18n/serializers/xliff2.ts +++ b/packages/compiler/src/i18n/serializers/xliff2.ts @@ -203,7 +203,7 @@ class Xliff2Parser implements ml.Visitor { this._unitMlString = null; this._msgIdToHtml = {}; - const xml = new XmlParser().parse(xliff, url, false); + const xml = new XmlParser().parse(xliff, url); this._errors = xml.errors; ml.visitAll(this, xml.rootNodes, null); @@ -293,7 +293,7 @@ class XmlToI18n implements ml.Visitor { private _errors !: I18nError[]; convert(message: string, url: string) { - const xmlIcu = new XmlParser().parse(message, url, true); + const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true}); this._errors = xmlIcu.errors; const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? diff --git a/packages/compiler/src/i18n/serializers/xtb.ts b/packages/compiler/src/i18n/serializers/xtb.ts index c544bc9d70..441c03fa04 100644 --- a/packages/compiler/src/i18n/serializers/xtb.ts +++ b/packages/compiler/src/i18n/serializers/xtb.ts @@ -88,7 +88,7 @@ class XtbParser implements ml.Visitor { // We can not parse the ICU messages at this point as some messages might not originate // from Angular that could not be lex'd. - const xml = new XmlParser().parse(xtb, url, false); + const xml = new XmlParser().parse(xtb, url); this._errors = xml.errors; ml.visitAll(this, xml.rootNodes); @@ -159,7 +159,7 @@ class XmlToI18n implements ml.Visitor { private _errors !: I18nError[]; convert(message: string, url: string) { - const xmlIcu = new XmlParser().parse(message, url, true); + const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true}); this._errors = xmlIcu.errors; const i18nNodes = this._errors.length > 0 || xmlIcu.rootNodes.length == 0 ? diff --git a/packages/compiler/src/i18n/translation_bundle.ts b/packages/compiler/src/i18n/translation_bundle.ts index cb6fb4f01c..30da42a421 100644 --- a/packages/compiler/src/i18n/translation_bundle.ts +++ b/packages/compiler/src/i18n/translation_bundle.ts @@ -83,7 +83,7 @@ class I18nToHtmlVisitor implements i18n.Visitor { // text to html const url = srcMsg.nodes[0].sourceSpan.start.file.url; - const html = new HtmlParser().parse(text, url, true); + const html = new HtmlParser().parse(text, url, {tokenizeExpansionForms: true}); return { nodes: html.rootNodes, diff --git a/packages/compiler/src/injectable_compiler_2.ts b/packages/compiler/src/injectable_compiler_2.ts index c2484b3ebc..e1c7b869de 100644 --- a/packages/compiler/src/injectable_compiler_2.ts +++ b/packages/compiler/src/injectable_compiler_2.ts @@ -22,7 +22,7 @@ export interface R3InjectableMetadata { name: string; type: o.Expression; typeArgumentCount: number; - ctorDeps: R3DependencyMetadata[]|null; + ctorDeps: R3DependencyMetadata[]|'invalid'|null; providedIn: o.Expression; useClass?: o.Expression; useFactory?: o.Expression; @@ -46,11 +46,14 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef { // used to instantiate the class with dependencies injected, or deps are not specified and // the factory of the class is used to instantiate it. // - // A special case exists for useClass: Type where Type is the injectable type itself, in which - // case omitting deps just uses the constructor dependencies instead. + // A special case exists for useClass: Type where Type is the injectable type itself and no + // deps are specified, in which case 'useClass' is effectively ignored. const useClassOnSelf = meta.useClass.isEquivalent(meta.type); - const deps = meta.userDeps || (useClassOnSelf && meta.ctorDeps) || undefined; + let deps: R3DependencyMetadata[]|undefined = undefined; + if (meta.userDeps !== undefined) { + deps = meta.userDeps; + } if (deps !== undefined) { // factory: () => new meta.useClass(...deps) @@ -60,6 +63,8 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef { delegateDeps: deps, delegateType: R3FactoryDelegateType.Class, }); + } else if (useClassOnSelf) { + result = compileFactoryFunction(factoryMeta); } else { result = compileFactoryFunction({ ...factoryMeta, diff --git a/packages/compiler/src/jit/compiler.ts b/packages/compiler/src/jit/compiler.ts index dd245fb2d1..8fd53b03c8 100644 --- a/packages/compiler/src/jit/compiler.ts +++ b/packages/compiler/src/jit/compiler.ts @@ -15,7 +15,7 @@ import {CompileMetadataResolver} from '../metadata_resolver'; import {NgModuleCompiler} from '../ng_module_compiler'; import * as ir from '../output/output_ast'; import {interpretStatements} from '../output/output_interpreter'; -import {jitStatements} from '../output/output_jit'; +import {JitEvaluator} from '../output/output_jit'; import {CompiledStylesheet, StyleCompiler} from '../style_compiler'; import {SummaryResolver} from '../summary_resolver'; import {TemplateAst} from '../template_parser/template_ast'; @@ -49,8 +49,8 @@ export class JitCompiler { private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler, private _ngModuleCompiler: NgModuleCompiler, private _summaryResolver: SummaryResolver, - private _reflector: CompileReflector, private _compilerConfig: CompilerConfig, - private _console: Console, + private _reflector: CompileReflector, private _jitEvaluator: JitEvaluator, + private _compilerConfig: CompilerConfig, private _console: Console, private getExtraNgModuleProviders: (ngModule: any) => CompileProviderMetadata[]) {} compileModuleSync(moduleType: Type): object { @@ -322,7 +322,8 @@ export class JitCompiler { if (!this._compilerConfig.useJit) { return interpretStatements(statements, this._reflector); } else { - return jitStatements(sourceUrl, statements, this._reflector, this._compilerConfig.jitDevMode); + return this._jitEvaluator.evaluateStatements( + sourceUrl, statements, this._reflector, this._compilerConfig.jitDevMode); } } } diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index 717efa833d..9d36aa3098 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -12,14 +12,16 @@ import {ConstantPool} from './constant_pool'; import {HostBinding, HostListener, Input, Output, Type} from './core'; import {compileInjectable} from './injectable_compiler_2'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './ml_parser/interpolation_config'; -import {Expression, LiteralExpr, WrappedNodeExpr} from './output/output_ast'; +import {DeclareVarStmt, Expression, LiteralExpr, Statement, StmtModifier, WrappedNodeExpr} from './output/output_ast'; +import {JitEvaluator} from './output/output_jit'; +import {ParseError, ParseSourceSpan, r3JitTypeSourceSpan} from './parse_util'; import {R3DependencyMetadata, R3ResolvedDependencyType} from './render3/r3_factory'; -import {jitExpression} from './render3/r3_jit'; +import {R3JitReflector} from './render3/r3_jit'; import {R3InjectorMetadata, R3NgModuleMetadata, compileInjector, compileNgModule} from './render3/r3_module_compiler'; import {compilePipeFromMetadata} from './render3/r3_pipe_compiler'; import {R3Reference} from './render3/util'; import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api'; -import {compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings} from './render3/view/compiler'; +import {compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler'; import {makeBindingParser, parseTemplate} from './render3/view/template'; import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry'; @@ -27,6 +29,8 @@ export class CompilerFacadeImpl implements CompilerFacade { R3ResolvedDependencyType = R3ResolvedDependencyType as any; private elementSchemaRegistry = new DomElementSchemaRegistry(); + constructor(private jitEvaluator = new JitEvaluator()) {} + compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, facade: R3PipeMetadataFacade): any { const res = compilePipeFromMetadata({ @@ -36,7 +40,7 @@ export class CompilerFacadeImpl implements CompilerFacade { pipeName: facade.pipeName, pure: facade.pure, }); - return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); + return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); } compileInjectable( @@ -55,7 +59,7 @@ export class CompilerFacadeImpl implements CompilerFacade { userDeps: convertR3DependencyMetadataArray(facade.userDeps) || undefined, }); - return jitExpression(expression, angularCoreEnv, sourceMapUrl, statements); + return this.jitExpression(expression, angularCoreEnv, sourceMapUrl, statements); } compileInjector( @@ -69,7 +73,7 @@ export class CompilerFacadeImpl implements CompilerFacade { imports: new WrappedNodeExpr(facade.imports), }; const res = compileInjector(meta); - return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); + return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements); } compileNgModule( @@ -82,9 +86,10 @@ export class CompilerFacadeImpl implements CompilerFacade { imports: facade.imports.map(wrapReference), exports: facade.exports.map(wrapReference), emitInline: true, + schemas: facade.schemas ? facade.schemas.map(wrapReference) : null, }; const res = compileNgModule(meta); - return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); + return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []); } compileDirective( @@ -96,7 +101,7 @@ export class CompilerFacadeImpl implements CompilerFacade { const meta: R3DirectiveMetadata = convertDirectiveFacadeToMetadata(facade); const res = compileDirectiveFromMetadata(meta, constantPool, bindingParser); const preStatements = [...constantPool.statements, ...res.statements]; - return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements); + return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements); } compileComponent( @@ -111,7 +116,7 @@ export class CompilerFacadeImpl implements CompilerFacade { // Parse the template and check for errors. const template = parseTemplate( facade.template, sourceMapUrl, - {preserveWhitespaces: facade.preserveWhitespaces || false, interpolationConfig}); + {preserveWhitespaces: facade.preserveWhitespaces, interpolationConfig}); if (template.errors !== undefined) { const errors = template.errors.map(err => err.toString()).join(', '); throw new Error(`Errors during JIT compilation of template for ${facade.name}: ${errors}`); @@ -139,8 +144,37 @@ export class CompilerFacadeImpl implements CompilerFacade { }, constantPool, makeBindingParser(interpolationConfig)); const preStatements = [...constantPool.statements, ...res.statements]; + return this.jitExpression( + res.expression, angularCoreEnv, `ng:///${facade.name}.js`, preStatements); + } - return jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements); + createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan { + return r3JitTypeSourceSpan(kind, typeName, sourceUrl); + } + + /** + * JIT compiles an expression and returns the result of executing that expression. + * + * @param def the definition which will be compiled and executed to get the value to patch + * @param context an object map of @angular/core symbol names to symbols which will be available + * in the context of the compiled expression + * @param sourceUrl a URL to use for the source map of the compiled expression + * @param preStatements a collection of statements that should be evaluated before the expression. + */ + private jitExpression( + def: Expression, context: {[key: string]: any}, sourceUrl: string, + preStatements: Statement[]): any { + // The ConstantPool may contain Statements which declare variables used in the final expression. + // Therefore, its statements need to precede the actual JIT operation. The final statement is a + // declaration of $def which is set to the expression being compiled. + const statements: Statement[] = [ + ...preStatements, + new DeclareVarStmt('$def', def, undefined, [StmtModifier.Exported]), + ]; + + const res = this.jitEvaluator.evaluateStatements( + sourceUrl, statements, new R3JitReflector(context), /* enableSourceMaps */ true); + return res['$def']; } } @@ -189,10 +223,10 @@ function convertDirectiveFacadeToMetadata(facade: R3DirectiveMetadataFacade): R3 return { ...facade as R3DirectiveMetadataFacadeNoPropAndWhitespace, - typeSourceSpan: null !, + typeSourceSpan: facade.typeSourceSpan, type: new WrappedNodeExpr(facade.type), deps: convertR3DependencyMetadataArray(facade.deps), - host: extractHostBindings(facade.host, facade.propMetadata), + host: extractHostBindings(facade.host, facade.propMetadata, facade.typeSourceSpan), inputs: {...inputsFromMetadata, ...inputsFromType}, outputs: {...outputsFromMetadata, ...outputsFromType}, queries: facade.queries.map(convertToR3QueryMetadata), @@ -244,16 +278,20 @@ function convertR3DependencyMetadataArray(facades: R3DependencyMetadataFacade[] return facades == null ? null : facades.map(convertR3DependencyMetadata); } -function extractHostBindings(host: {[key: string]: string}, propMetadata: {[key: string]: any[]}): { +function extractHostBindings( + host: {[key: string]: string}, propMetadata: {[key: string]: any[]}, + sourceSpan: ParseSourceSpan): { attributes: StringMap, listeners: StringMap, properties: StringMap, } { // First parse the declarations from the metadata. - const {attributes, listeners, properties, animations} = parseHostBindings(host || {}); + const bindings = parseHostBindings(host || {}); - if (Object.keys(animations).length > 0) { - throw new Error(`Animation bindings are as-of-yet unsupported in Ivy`); + // After that check host bindings for errors + const errors = verifyHostBindings(bindings, sourceSpan); + if (errors.length) { + throw new Error(errors.map((error: ParseError) => error.msg).join('\n')); } // Next, loop over the properties of the object, looking for @HostBinding and @HostListener. @@ -261,15 +299,15 @@ function extractHostBindings(host: {[key: string]: string}, propMetadata: {[key: if (propMetadata.hasOwnProperty(field)) { propMetadata[field].forEach(ann => { if (isHostBinding(ann)) { - properties[ann.hostPropertyName || field] = field; + bindings.properties[ann.hostPropertyName || field] = field; } else if (isHostListener(ann)) { - listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`; + bindings.listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`; } }); } } - return {attributes, listeners, properties}; + return bindings; } function isHostBinding(value: any): value is HostBinding { diff --git a/packages/compiler/src/ml_parser/html_parser.ts b/packages/compiler/src/ml_parser/html_parser.ts index 60702f25b0..5e788523db 100644 --- a/packages/compiler/src/ml_parser/html_parser.ts +++ b/packages/compiler/src/ml_parser/html_parser.ts @@ -7,7 +7,7 @@ */ import {getHtmlTagDefinition} from './html_tags'; -import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './interpolation_config'; +import {TokenizeOptions} from './lexer'; import {ParseTreeResult, Parser} from './parser'; export {ParseTreeResult, TreeError} from './parser'; @@ -15,9 +15,7 @@ export {ParseTreeResult, TreeError} from './parser'; export class HtmlParser extends Parser { constructor() { super(getHtmlTagDefinition); } - parse( - source: string, url: string, parseExpansionForms: boolean = false, - interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ParseTreeResult { - return super.parse(source, url, parseExpansionForms, interpolationConfig); + parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult { + return super.parse(source, url, options); } } diff --git a/packages/compiler/src/ml_parser/lexer.ts b/packages/compiler/src/ml_parser/lexer.ts index 22fd6fc994..1c92f03072 100644 --- a/packages/compiler/src/ml_parser/lexer.ts +++ b/packages/compiler/src/ml_parser/lexer.ts @@ -25,6 +25,7 @@ export enum TokenType { CDATA_START, CDATA_END, ATTR_NAME, + ATTR_QUOTE, ATTR_VALUE, DOC_TYPE, EXPANSION_FORM_START, @@ -36,11 +37,12 @@ export enum TokenType { } export class Token { - constructor(public type: TokenType, public parts: string[], public sourceSpan: ParseSourceSpan) {} + constructor( + public type: TokenType|null, public parts: string[], public sourceSpan: ParseSourceSpan) {} } export class TokenError extends ParseError { - constructor(errorMsg: string, public tokenType: TokenType, span: ParseSourceSpan) { + constructor(errorMsg: string, public tokenType: TokenType|null, span: ParseSourceSpan) { super(span, errorMsg); } } @@ -49,14 +51,56 @@ export class TokenizeResult { constructor(public tokens: Token[], public errors: TokenError[]) {} } +export interface LexerRange { + startPos: number; + startLine: number; + startCol: number; + endPos: number; +} + +/** + * Options that modify how the text is tokenized. + */ +export interface TokenizeOptions { + /** Whether to tokenize ICU messages (considered as text nodes when false). */ + tokenizeExpansionForms?: boolean; + /** How to tokenize interpolation markers. */ + interpolationConfig?: InterpolationConfig; + /** + * The start and end point of the text to parse within the `source` string. + * The entire `source` string is parsed if this is not provided. + * */ + range?: LexerRange; + /** + * If this text is stored in a JavaScript string, then we have to deal with escape sequences. + * + * **Example 1:** + * + * ``` + * "abc\"def\nghi" + * ``` + * + * - The `\"` must be converted to `"`. + * - The `\n` must be converted to a new line character in a token, + * but it should not increment the current line for source mapping. + * + * **Example 2:** + * + * ``` + * "abc\ + * def" + * ``` + * + * The line continuation (`\` followed by a newline) should be removed from a token + * but the new line should increment the current line for source mapping. + */ + escapedString?: boolean; +} + export function tokenize( source: string, url: string, getTagDefinition: (tagName: string) => TagDefinition, - tokenizeExpansionForms: boolean = false, - interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): TokenizeResult { - return new _Tokenizer( - new ParseSourceFile(source, url), getTagDefinition, tokenizeExpansionForms, - interpolationConfig) - .tokenize(); + options: TokenizeOptions = {}): TokenizeResult { + return new _Tokenizer(new ParseSourceFile(source, url), getTagDefinition, options).tokenize(); } const _CR_OR_CRLF_REGEXP = /\r\n?/g; @@ -77,17 +121,17 @@ class _ControlFlowError { // See http://www.w3.org/TR/html51/syntax.html#writing class _Tokenizer { private _input: string; - private _length: number; - // Note: this is always lowercase! + private _end: number; + private _tokenizeIcu: boolean; + private _interpolationConfig: InterpolationConfig; + private _escapedString: boolean; private _peek: number = -1; private _nextPeek: number = -1; - private _index: number = -1; - private _line: number = 0; - private _column: number = -1; - // TODO(issue/24571): remove '!'. - private _currentTokenStart !: ParseLocation; - // TODO(issue/24571): remove '!'. - private _currentTokenType !: TokenType; + private _index: number; + private _line: number; + private _column: number; + private _currentTokenStart: ParseLocation|null = null; + private _currentTokenType: TokenType|null = null; private _expansionCaseStack: TokenType[] = []; private _inInterpolation: boolean = false; @@ -102,11 +146,31 @@ class _Tokenizer { */ constructor( private _file: ParseSourceFile, private _getTagDefinition: (tagName: string) => TagDefinition, - private _tokenizeIcu: boolean, - private _interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG) { + options: TokenizeOptions) { + this._tokenizeIcu = options.tokenizeExpansionForms || false; + this._interpolationConfig = options.interpolationConfig || DEFAULT_INTERPOLATION_CONFIG; + this._escapedString = options.escapedString || false; this._input = _file.content; - this._length = _file.content.length; - this._advance(); + if (options.range) { + this._end = options.range.endPos; + this._index = options.range.startPos; + this._line = options.range.startLine; + this._column = options.range.startCol; + } else { + this._end = this._input.length; + this._index = 0; + this._line = 0; + this._column = 0; + } + try { + this._initPeek(); + } catch (e) { + if (e instanceof _ControlFlowError) { + this.errors.push(e.error); + } else { + throw e; + } + } } private _processCarriageReturns(content: string): string { @@ -197,11 +261,21 @@ class _Tokenizer { } private _endToken(parts: string[], end: ParseLocation = this._getLocation()): Token { + if (this._currentTokenStart === null) { + throw new TokenError( + 'Programming error - attempted to end a token when there was no start to the token', + this._currentTokenType, this._getSpan(end, end)); + } + if (this._currentTokenType === null) { + throw new TokenError( + 'Programming error - attempted to end a token which has no token type', null, + this._getSpan(this._currentTokenStart, end)); + } const token = new Token(this._currentTokenType, parts, new ParseSourceSpan(this._currentTokenStart, end)); this.tokens.push(token); - this._currentTokenStart = null !; - this._currentTokenType = null !; + this._currentTokenStart = null; + this._currentTokenType = null; return token; } @@ -215,20 +289,47 @@ class _Tokenizer { return new _ControlFlowError(error); } - private _advance() { - if (this._index >= this._length) { + private _advance(processingEscapeSequence?: boolean) { + if (this._index >= this._end) { throw this._createError(_unexpectedCharacterErrorMsg(chars.$EOF), this._getSpan()); } - if (this._peek === chars.$LF) { + // The actual character in the input might be different to the _peek if we are processing + // escape characters. We only want to track "real" new lines. + const actualChar = this._input.charCodeAt(this._index); + if (actualChar === chars.$LF) { this._line++; this._column = 0; - } else if (this._peek !== chars.$LF && this._peek !== chars.$CR) { + } else if (!chars.isNewLine(actualChar)) { this._column++; } this._index++; - this._peek = this._index >= this._length ? chars.$EOF : this._input.charCodeAt(this._index); + this._initPeek(processingEscapeSequence); + } + + /** + * Initialize the _peek and _nextPeek properties based on the current _index. + * @param processingEscapeSequence whether we are in the middle of processing an escape sequence. + */ + private _initPeek(processingEscapeSequence?: boolean) { + this._peek = this._index >= this._end ? chars.$EOF : this._input.charCodeAt(this._index); this._nextPeek = - this._index + 1 >= this._length ? chars.$EOF : this._input.charCodeAt(this._index + 1); + this._index + 1 >= this._end ? chars.$EOF : this._input.charCodeAt(this._index + 1); + if (this._peek === chars.$BACKSLASH && processingEscapeSequence !== true && + this._escapedString) { + this._processEscapeSequence(); + } + } + + /** + * Advance the specific number of characters. + * @param count The number of characters to advance. + * @param processingEscapeSequence Whether we want `advance()` to process escape sequences. + */ + private _advanceN(count: number, processingEscapeSequence?: boolean) { + while (count) { + this._advance(processingEscapeSequence); + count--; + } } private _attemptCharCode(charCode: number): boolean { @@ -257,7 +358,7 @@ class _Tokenizer { private _attemptStr(chars: string): boolean { const len = chars.length; - if (this._index + len > this._length) { + if (this._index + len > this._end) { return false; } const initialPosition = this._savePosition(); @@ -313,9 +414,11 @@ class _Tokenizer { if (decodeEntities && this._peek === chars.$AMPERSAND) { return this._decodeEntity(); } else { - const index = this._index; + // Don't rely upon reading directly from `_input` as the actual char value + // may have been generated from an escape sequence. + const char = String.fromCodePoint(this._peek); this._advance(); - return this._input[index]; + return char; } } @@ -334,7 +437,7 @@ class _Tokenizer { try { const charCode = parseInt(strNum, isHex ? 16 : 10); return String.fromCharCode(charCode); - } catch (e) { + } catch { const entity = this._input.substring(start.offset + 1, this._index - 1); throw this._createError(_unknownEntityErrorMsg(entity), this._getSpan(start)); } @@ -355,6 +458,122 @@ class _Tokenizer { } } + /** + * Process the escape sequence that starts at the current position in the text. + * + * This method is called from `_advance()` to ensure that escape sequences are + * always processed correctly however tokens are being consumed. + * + * But note that this method also calls `_advance()` (re-entering) to move through + * the characters within an escape sequence. In that case it tells `_advance()` not + * to attempt to process further escape sequences by passing `true` as its first + * argument. + */ + private _processEscapeSequence(): void { + this._advance(true); // advance past the backslash + + // First check for standard control char sequences + if (this._peekChar() === chars.$n) { + this._peek = chars.$LF; + } else if (this._peekChar() === chars.$r) { + this._peek = chars.$CR; + } else if (this._peekChar() === chars.$v) { + this._peek = chars.$VTAB; + } else if (this._peekChar() === chars.$t) { + this._peek = chars.$TAB; + } else if (this._peekChar() === chars.$b) { + this._peek = chars.$BSPACE; + } else if (this._peekChar() === chars.$f) { + this._peek = chars.$FF; + } + + // Now consider more complex sequences + + else if (this._peekChar() === chars.$u) { + // Unicode code-point sequence + this._advance(true); // advance past the `u` char + if (this._peekChar() === chars.$LBRACE) { + // Variable length Unicode, e.g. `\x{123}` + this._advance(true); // advance past the `{` char + // Advance past the variable number of hex digits until we hit a `}` char + const start = this._getLocation(); + while (this._peekChar() !== chars.$RBRACE) { + this._advance(true); + } + this._decodeHexDigits(start, this._index - start.offset); + } else { + // Fixed length Unicode, e.g. `\u1234` + this._parseFixedHexSequence(4); + } + } + + else if (this._peekChar() === chars.$x) { + // Hex char code, e.g. `\x2F` + this._advance(true); // advance past the `x` char + this._parseFixedHexSequence(2); + } + + else if (chars.isOctalDigit(this._peekChar())) { + // Octal char code, e.g. `\012`, + const start = this._index; + let length = 1; + // Note that we work with `_nextPeek` because, although we check the next character + // after the sequence to find the end of the sequence, + // we do not want to advance that far to check the character, otherwise we will + // have to back up. + while (chars.isOctalDigit(this._nextPeek) && length < 3) { + this._advance(true); + length++; + } + const octal = this._input.substr(start, length); + this._peek = parseInt(octal, 8); + } + + else if (chars.isNewLine(this._peekChar())) { + // Line continuation `\` followed by a new line + this._advance(true); // advance over the newline + } + + // If none of the `if` blocks were executed then we just have an escaped normal character. + // In that case we just, effectively, skip the backslash from the character. + } + + private _parseFixedHexSequence(length: number) { + const start = this._getLocation(); + this._advanceN(length - 1, true); + this._decodeHexDigits(start, length); + } + + private _decodeHexDigits(start: ParseLocation, length: number) { + const hex = this._input.substr(start.offset, length); + const charCode = parseInt(hex, 16); + if (!isNaN(charCode)) { + this._peek = charCode; + } else { + throw this._createError( + 'Invalid hexadecimal escape sequence', this._getSpan(start, this._getLocation())); + } + } + + /** + * This little helper is to solve a problem where the TS compiler will narrow + * the type of `_peek` after an `if` statment, even if there is a call to a + * method that might mutate the `_peek`. + * + * For example: + * + * ``` + * if (this._peek === 10) { + * this._advance(); // mutates _peek + * if (this._peek === 20) { + * ... + * ``` + * + * The second if statement fails TS compilation because the compiler has determined + * that `_peek` is `10` and so can never be equal to `20`. + */ + private _peekChar(): number { return this._peek; } + private _consumeRawText( decodeEntities: boolean, firstCharOfEnd: number, attemptEndRest: () => boolean): Token { let tagCloseStart: ParseLocation; @@ -491,23 +710,29 @@ class _Tokenizer { } private _consumeAttributeValue() { - this._beginToken(TokenType.ATTR_VALUE); let value: string; if (this._peek === chars.$SQ || this._peek === chars.$DQ) { + this._beginToken(TokenType.ATTR_QUOTE); const quoteChar = this._peek; this._advance(); + this._endToken([String.fromCodePoint(quoteChar)]); + this._beginToken(TokenType.ATTR_VALUE); const parts: string[] = []; while (this._peek !== quoteChar) { parts.push(this._readChar(true)); } value = parts.join(''); + this._endToken([this._processCarriageReturns(value)]); + this._beginToken(TokenType.ATTR_QUOTE); this._advance(); + this._endToken([String.fromCodePoint(quoteChar)]); } else { + this._beginToken(TokenType.ATTR_VALUE); const valueStart = this._index; this._requireCharCodeUntilFn(isNameEnd, 1); value = this._input.substring(valueStart, this._index); + this._endToken([this._processCarriageReturns(value)]); } - this._endToken([this._processCarriageReturns(value)]); } private _consumeTagOpenEnd() { diff --git a/packages/compiler/src/ml_parser/parser.ts b/packages/compiler/src/ml_parser/parser.ts index 3a06bc182d..845adea5a7 100644 --- a/packages/compiler/src/ml_parser/parser.ts +++ b/packages/compiler/src/ml_parser/parser.ts @@ -9,7 +9,6 @@ import {ParseError, ParseSourceSpan} from '../parse_util'; import * as html from './ast'; -import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './interpolation_config'; import * as lex from './lexer'; import {TagDefinition, getNsPrefix, isNgContainer, mergeNsAndName} from './tags'; @@ -30,11 +29,8 @@ export class ParseTreeResult { export class Parser { constructor(public getTagDefinition: (tagName: string) => TagDefinition) {} - parse( - source: string, url: string, parseExpansionForms: boolean = false, - interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ParseTreeResult { - const tokensAndErrors = - lex.tokenize(source, url, this.getTagDefinition, parseExpansionForms, interpolationConfig); + parse(source: string, url: string, options?: lex.TokenizeOptions): ParseTreeResult { + const tokensAndErrors = lex.tokenize(source, url, this.getTagDefinition, options); const treeAndErrors = new _TreeBuilder(tokensAndErrors.tokens, this.getTagDefinition).build(); @@ -330,12 +326,19 @@ class _TreeBuilder { let end = attrName.sourceSpan.end; let value = ''; let valueSpan: ParseSourceSpan = undefined !; + if (this._peek.type === lex.TokenType.ATTR_QUOTE) { + this._advance(); + } if (this._peek.type === lex.TokenType.ATTR_VALUE) { const valueToken = this._advance(); value = valueToken.parts[0]; end = valueToken.sourceSpan.end; valueSpan = valueToken.sourceSpan; } + if (this._peek.type === lex.TokenType.ATTR_QUOTE) { + const quoteToken = this._advance(); + end = quoteToken.sourceSpan.end; + } return new html.Attribute( fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, end), valueSpan); } diff --git a/packages/compiler/src/ml_parser/xml_parser.ts b/packages/compiler/src/ml_parser/xml_parser.ts index 57f49eb105..dc6dffb042 100644 --- a/packages/compiler/src/ml_parser/xml_parser.ts +++ b/packages/compiler/src/ml_parser/xml_parser.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {TokenizeOptions} from './lexer'; import {ParseTreeResult, Parser} from './parser'; import {getXmlTagDefinition} from './xml_tags'; @@ -14,7 +15,7 @@ export {ParseTreeResult, TreeError} from './parser'; export class XmlParser extends Parser { constructor() { super(getXmlTagDefinition); } - parse(source: string, url: string, parseExpansionForms: boolean = false): ParseTreeResult { - return super.parse(source, url, parseExpansionForms); + parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult { + return super.parse(source, url, options); } } diff --git a/packages/compiler/src/output/output_jit.ts b/packages/compiler/src/output/output_jit.ts index 3c077aa911..c6ad4abd55 100644 --- a/packages/compiler/src/output/output_jit.ts +++ b/packages/compiler/src/output/output_jit.ts @@ -13,39 +13,79 @@ import {EmitterVisitorContext} from './abstract_emitter'; import {AbstractJsEmitterVisitor} from './abstract_js_emitter'; import * as o from './output_ast'; -function evalExpression( - sourceUrl: string, ctx: EmitterVisitorContext, vars: {[key: string]: any}, - createSourceMap: boolean): any { - let fnBody = `${ctx.toSource()}\n//# sourceURL=${sourceUrl}`; - const fnArgNames: string[] = []; - const fnArgValues: any[] = []; - for (const argName in vars) { - fnArgNames.push(argName); - fnArgValues.push(vars[argName]); +/** + * A helper class to manage the evaluation of JIT generated code. + */ +export class JitEvaluator { + /** + * + * @param sourceUrl The URL of the generated code. + * @param statements An array of Angular statement AST nodes to be evaluated. + * @param reflector A helper used when converting the statements to executable code. + * @param createSourceMaps If true then create a source-map for the generated code and include it + * inline as a source-map comment. + * @returns A map of all the variables in the generated code. + */ + evaluateStatements( + sourceUrl: string, statements: o.Statement[], reflector: CompileReflector, + createSourceMaps: boolean): {[key: string]: any} { + const converter = new JitEmitterVisitor(reflector); + const ctx = EmitterVisitorContext.createRoot(); + converter.visitAllStatements(statements, ctx); + converter.createReturnStmt(ctx); + return this.evaluateCode(sourceUrl, ctx, converter.getArgs(), createSourceMaps); } - if (createSourceMap) { - // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise - // E.g. ``` - // function anonymous(a,b,c - // /**/) { ... }``` - // We don't want to hard code this fact, so we auto detect it via an empty function first. - const emptyFn = new Function(...fnArgNames.concat('return null;')).toString(); - const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1; - fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`; + + /** + * Evaluate a piece of JIT generated code. + * @param sourceUrl The URL of this generated code. + * @param ctx A context object that contains an AST of the code to be evaluated. + * @param vars A map containing the names and values of variables that the evaluated code might + * reference. + * @param createSourceMap If true then create a source-map for the generated code and include it + * inline as a source-map comment. + * @returns The result of evaluating the code. + */ + evaluateCode( + sourceUrl: string, ctx: EmitterVisitorContext, vars: {[key: string]: any}, + createSourceMap: boolean): any { + let fnBody = `${ctx.toSource()}\n//# sourceURL=${sourceUrl}`; + const fnArgNames: string[] = []; + const fnArgValues: any[] = []; + for (const argName in vars) { + fnArgValues.push(vars[argName]); + fnArgNames.push(argName); + } + if (createSourceMap) { + // using `new Function(...)` generates a header, 1 line of no arguments, 2 lines otherwise + // E.g. ``` + // function anonymous(a,b,c + // /**/) { ... }``` + // We don't want to hard code this fact, so we auto detect it via an empty function first. + const emptyFn = new Function(...fnArgNames.concat('return null;')).toString(); + const headerLines = emptyFn.slice(0, emptyFn.indexOf('return null;')).split('\n').length - 1; + fnBody += `\n${ctx.toSourceMapGenerator(sourceUrl, headerLines).toJsComment()}`; + } + const fn = new Function(...fnArgNames.concat(fnBody)); + return this.executeFunction(fn, fnArgValues); } - return new Function(...fnArgNames.concat(fnBody))(...fnArgValues); -} - -export function jitStatements( - sourceUrl: string, statements: o.Statement[], reflector: CompileReflector, - createSourceMaps: boolean): {[key: string]: any} { - const converter = new JitEmitterVisitor(reflector); - const ctx = EmitterVisitorContext.createRoot(); - converter.visitAllStatements(statements, ctx); - converter.createReturnStmt(ctx); - return evalExpression(sourceUrl, ctx, converter.getArgs(), createSourceMaps); + + /** + * Execute a JIT generated function by calling it. + * + * This method can be overridden in tests to capture the functions that are generated + * by this `JitEvaluator` class. + * + * @param fn A function to execute. + * @param args The arguments to pass to the function being executed. + * @returns The return value of the executed function. + */ + executeFunction(fn: Function, args: any[]) { return fn(...args); } } +/** + * An Angular AST visitor that converts AST nodes into executable JavaScript code. + */ export class JitEmitterVisitor extends AbstractJsEmitterVisitor { private _evalArgNames: string[] = []; private _evalArgValues: any[] = []; diff --git a/packages/compiler/src/parse_util.ts b/packages/compiler/src/parse_util.ts index 12dd1fb4e5..4e1fc7d5c5 100644 --- a/packages/compiler/src/parse_util.ts +++ b/packages/compiler/src/parse_util.ts @@ -139,3 +139,19 @@ export function typeSourceSpan(kind: string, type: CompileIdentifierMetadata): P return new ParseSourceSpan( new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1)); } + +/** + * Generates Source Span object for a given R3 Type for JIT mode. + * + * @param kind Component or Directive. + * @param typeName name of the Component or Directive. + * @param sourceUrl reference to Component or Directive source. + * @returns instance of ParseSourceSpan that represent a given Component or Directive. + */ +export function r3JitTypeSourceSpan( + kind: string, typeName: string, sourceUrl: string): ParseSourceSpan { + const sourceFileName = `in ${kind} ${typeName} in ${sourceUrl}`; + const sourceFile = new ParseSourceFile('', sourceFileName); + return new ParseSourceSpan( + new ParseLocation(sourceFile, -1, -1, -1), new ParseLocation(sourceFile, -1, -1, -1)); +} \ No newline at end of file diff --git a/packages/compiler/src/render3/r3_ast.ts b/packages/compiler/src/render3/r3_ast.ts index ba7eaeb6bf..7595fefc7f 100644 --- a/packages/compiler/src/render3/r3_ast.ts +++ b/packages/compiler/src/render3/r3_ast.ts @@ -50,13 +50,15 @@ export class BoundAttribute implements Node { export class BoundEvent implements Node { constructor( public name: string, public type: ParsedEventType, public handler: AST, - public target: string|null, public phase: string|null, public sourceSpan: ParseSourceSpan) {} + public target: string|null, public phase: string|null, public sourceSpan: ParseSourceSpan, + public handlerSpan: ParseSourceSpan) {} static fromParsedEvent(event: ParsedEvent) { const target: string|null = event.type === ParsedEventType.Regular ? event.targetOrPhase : null; const phase: string|null = event.type === ParsedEventType.Animation ? event.targetOrPhase : null; - return new BoundEvent(event.name, event.type, event.handler, target, phase, event.sourceSpan); + return new BoundEvent( + event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan); } visit(visitor: Visitor): Result { return visitor.visitBoundEvent(this); } @@ -67,7 +69,12 @@ export class Element implements Node { public name: string, public attributes: TextAttribute[], public inputs: BoundAttribute[], public outputs: BoundEvent[], public children: Node[], public references: Reference[], public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null, - public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nAST) {} + public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nAST) { + // If the element is empty then the source span should include any closing tag + if (children.length === 0 && startSourceSpan && endSourceSpan) { + this.sourceSpan = {...sourceSpan, end: endSourceSpan.end}; + } + } visit(visitor: Visitor): Result { return visitor.visitElement(this); } } diff --git a/packages/compiler/src/render3/r3_factory.ts b/packages/compiler/src/render3/r3_factory.ts index d1f0a8a5e4..4808322ef4 100644 --- a/packages/compiler/src/render3/r3_factory.ts +++ b/packages/compiler/src/render3/r3_factory.ts @@ -40,9 +40,11 @@ export interface R3ConstructorFactoryMetadata { * Regardless of whether `fnOrClass` is a constructor function or a user-defined factory, it * may have 0 or more parameters, which will be injected according to the `R3DependencyMetadata` * for those parameters. If this is `null`, then the type's constructor is nonexistent and will - * be inherited from `fnOrClass` which is interpreted as the current type. + * be inherited from `fnOrClass` which is interpreted as the current type. If this is `'invalid'`, + * then one or more of the parameters wasn't resolvable and any attempt to use these deps will + * result in a runtime error. */ - deps: R3DependencyMetadata[]|null; + deps: R3DependencyMetadata[]|'invalid'|null; /** * An expression for the function which will be used to inject dependencies. The API of this @@ -152,7 +154,9 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): let ctorExpr: o.Expression|null = null; if (meta.deps !== null) { // There is a constructor (either explicitly or implicitly defined). - ctorExpr = new o.InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.injectFn)); + if (meta.deps !== 'invalid') { + ctorExpr = new o.InstantiateExpr(typeForCtor, injectDependencies(meta.deps, meta.injectFn)); + } } else { const baseFactory = o.variable(`ɵ${meta.name}_BaseFactory`); const getInheritedFactory = o.importExpr(R3.getInheritedFactory); @@ -173,7 +177,13 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): function makeConditionalFactory(nonCtorExpr: o.Expression): o.ReadVarExpr { const r = o.variable('r'); body.push(r.set(o.NULL_EXPR).toDeclStmt()); - body.push(o.ifStmt(t, [r.set(ctorExprFinal).toStmt()], [r.set(nonCtorExpr).toStmt()])); + let ctorStmt: o.Statement|null = null; + if (ctorExprFinal !== null) { + ctorStmt = r.set(ctorExprFinal).toStmt(); + } else { + ctorStmt = makeErrorStmt(meta.name); + } + body.push(o.ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()])); return r; } @@ -207,10 +217,16 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): retExpr = ctorExpr; } + if (retExpr !== null) { + body.push(new o.ReturnStatement(retExpr)); + } else { + body.push(makeErrorStmt(meta.name)); + } + return { factory: o.fn( - [new o.FnParam('t', o.DYNAMIC_TYPE)], [...body, new o.ReturnStatement(retExpr)], - o.INFERRED_TYPE, undefined, `${meta.name}_Factory`), + [new o.FnParam('t', o.DYNAMIC_TYPE)], body, o.INFERRED_TYPE, undefined, + `${meta.name}_Factory`), statements, }; } @@ -292,6 +308,13 @@ export function dependenciesFromGlobalMetadata( return deps; } +function makeErrorStmt(name: string): o.Statement { + return new o.ThrowStmt(new o.InstantiateExpr(new o.ReadVarExpr('Error'), [ + o.literal( + `${name} has a constructor which is not compatible with Dependency Injection. It should probably not be @Injectable().`) + ])); +} + function isDelegatedMetadata(meta: R3FactoryMetadata): meta is R3DelegatedFactoryMetadata| R3DelegatedFnOrClassMetadata { return (meta as any).delegateType !== undefined; diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index 33422adde6..2b156e1354 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -31,6 +31,12 @@ export class Identifiers { static elementProperty: o.ExternalReference = {name: 'ɵelementProperty', moduleName: CORE}; + static componentHostSyntheticProperty: + o.ExternalReference = {name: 'ɵcomponentHostSyntheticProperty', moduleName: CORE}; + + static componentHostSyntheticListener: + o.ExternalReference = {name: 'ɵcomponentHostSyntheticListener', moduleName: CORE}; + static elementAttribute: o.ExternalReference = {name: 'ɵelementAttribute', moduleName: CORE}; static elementClassProp: o.ExternalReference = {name: 'ɵelementClassProp', moduleName: CORE}; @@ -110,7 +116,6 @@ export class Identifiers { static i18nPostprocess: o.ExternalReference = {name: 'ɵi18nPostprocess', moduleName: CORE}; static load: o.ExternalReference = {name: 'ɵload', moduleName: CORE}; - static loadQueryList: o.ExternalReference = {name: 'ɵloadQueryList', moduleName: CORE}; static pipe: o.ExternalReference = {name: 'ɵpipe', moduleName: CORE}; @@ -128,6 +133,10 @@ export class Identifiers { static templateRefExtractor: o.ExternalReference = {name: 'ɵtemplateRefExtractor', moduleName: CORE}; + static resolveWindow: o.ExternalReference = {name: 'ɵresolveWindow', moduleName: CORE}; + static resolveDocument: o.ExternalReference = {name: 'ɵresolveDocument', moduleName: CORE}; + static resolveBody: o.ExternalReference = {name: 'ɵresolveBody', moduleName: CORE}; + static defineBase: o.ExternalReference = {name: 'ɵdefineBase', moduleName: CORE}; static BaseDef: o.ExternalReference = { @@ -137,6 +146,8 @@ export class Identifiers { static defineComponent: o.ExternalReference = {name: 'ɵdefineComponent', moduleName: CORE}; + static setComponentScope: o.ExternalReference = {name: 'ɵsetComponentScope', moduleName: CORE}; + static ComponentDefWithMeta: o.ExternalReference = { name: 'ɵComponentDefWithMeta', moduleName: CORE, @@ -173,10 +184,11 @@ export class Identifiers { static definePipe: o.ExternalReference = {name: 'ɵdefinePipe', moduleName: CORE}; - static query: o.ExternalReference = {name: 'ɵquery', moduleName: CORE}; static queryRefresh: o.ExternalReference = {name: 'ɵqueryRefresh', moduleName: CORE}; - static registerContentQuery: - o.ExternalReference = {name: 'ɵregisterContentQuery', moduleName: CORE}; + static viewQuery: o.ExternalReference = {name: 'ɵviewQuery', moduleName: CORE}; + static loadViewQuery: o.ExternalReference = {name: 'ɵloadViewQuery', moduleName: CORE}; + static contentQuery: o.ExternalReference = {name: 'ɵcontentQuery', moduleName: CORE}; + static loadContentQuery: o.ExternalReference = {name: 'ɵloadContentQuery', moduleName: CORE}; static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE}; @@ -206,4 +218,6 @@ export class Identifiers { o.ExternalReference = {name: 'ɵsanitizeResourceUrl', moduleName: CORE}; static sanitizeScript: o.ExternalReference = {name: 'ɵsanitizeScript', moduleName: CORE}; static sanitizeUrl: o.ExternalReference = {name: 'ɵsanitizeUrl', moduleName: CORE}; + static sanitizeUrlOrResourceUrl: + o.ExternalReference = {name: 'ɵsanitizeUrlOrResourceUrl', moduleName: CORE}; } diff --git a/packages/compiler/src/render3/r3_jit.ts b/packages/compiler/src/render3/r3_jit.ts index 2626dbbdbe..6c73d6a6a8 100644 --- a/packages/compiler/src/render3/r3_jit.ts +++ b/packages/compiler/src/render3/r3_jit.ts @@ -7,9 +7,7 @@ */ import {CompileReflector} from '../compile_reflector'; -import {ConstantPool} from '../constant_pool'; import * as o from '../output/output_ast'; -import {jitStatements} from '../output/output_jit'; /** * Implementation of `CompileReflector` which resolves references to @angular/core @@ -17,7 +15,7 @@ import {jitStatements} from '../output/output_jit'; * * Only supports `resolveExternalReference`, all other methods throw. */ -class R3JitReflector implements CompileReflector { +export class R3JitReflector implements CompileReflector { constructor(private context: {[key: string]: any}) {} resolveExternalReference(ref: o.ExternalReference): any { @@ -48,27 +46,3 @@ class R3JitReflector implements CompileReflector { componentModuleUrl(type: any, cmpMetadata: any): string { throw new Error('Not implemented.'); } } - -/** - * JIT compiles an expression and returns the result of executing that expression. - * - * @param def the definition which will be compiled and executed to get the value to patch - * @param context an object map of @angular/core symbol names to symbols which will be available in - * the context of the compiled expression - * @param sourceUrl a URL to use for the source map of the compiled expression - * @param constantPool an optional `ConstantPool` which contains constants used in the expression - */ -export function jitExpression( - def: o.Expression, context: {[key: string]: any}, sourceUrl: string, - preStatements: o.Statement[]): any { - // The ConstantPool may contain Statements which declare variables used in the final expression. - // Therefore, its statements need to precede the actual JIT operation. The final statement is a - // declaration of $def which is set to the expression being compiled. - const statements: o.Statement[] = [ - ...preStatements, - new o.DeclareVarStmt('$def', def, undefined, [o.StmtModifier.Exported]), - ]; - - const res = jitStatements(sourceUrl, statements, new R3JitReflector(context), false); - return res['$def']; -} diff --git a/packages/compiler/src/render3/r3_module_compiler.ts b/packages/compiler/src/render3/r3_module_compiler.ts index fa6020a411..4a4a3f51d9 100644 --- a/packages/compiler/src/render3/r3_module_compiler.ts +++ b/packages/compiler/src/render3/r3_module_compiler.ts @@ -57,21 +57,51 @@ export interface R3NgModuleMetadata { * does not allow components to be tree-shaken, but is useful for JIT mode. */ emitInline: boolean; + + /** + * The set of schemas that declare elements to be allowed in the NgModule. + */ + schemas: R3Reference[]|null; } /** * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`. */ export function compileNgModule(meta: R3NgModuleMetadata): R3NgModuleDef { - const {type: moduleType, bootstrap, declarations, imports, exports} = meta; - const expression = o.importExpr(R3.defineNgModule).callFn([mapToMapExpression({ - type: moduleType, - bootstrap: o.literalArr(bootstrap.map(ref => ref.value)), - declarations: o.literalArr(declarations.map(ref => ref.value)), - imports: o.literalArr(imports.map(ref => ref.value)), - exports: o.literalArr(exports.map(ref => ref.value)), - })]); + const {type: moduleType, bootstrap, declarations, imports, exports, schemas} = meta; + const definitionMap = { + type: moduleType + } as{ + type: o.Expression, + bootstrap: o.LiteralArrayExpr, + declarations: o.LiteralArrayExpr, + imports: o.LiteralArrayExpr, + exports: o.LiteralArrayExpr, + schemas: o.LiteralArrayExpr + }; + // Only generate the keys in the metadata if the arrays have values. + if (bootstrap.length) { + definitionMap.bootstrap = o.literalArr(bootstrap.map(ref => ref.value)); + } + + if (declarations.length) { + definitionMap.declarations = o.literalArr(declarations.map(ref => ref.value)); + } + + if (imports.length) { + definitionMap.imports = o.literalArr(imports.map(ref => ref.value)); + } + + if (exports.length) { + definitionMap.exports = o.literalArr(exports.map(ref => ref.value)); + } + + if (schemas && schemas.length) { + definitionMap.schemas = o.literalArr(schemas.map(ref => ref.value)); + } + + const expression = o.importExpr(R3.defineNgModule).callFn([mapToMapExpression(definitionMap)]); const type = new o.ExpressionType(o.importExpr(R3.NgModuleDefWithMeta, [ new o.ExpressionType(moduleType), tupleTypeOf(declarations), tupleTypeOf(imports), tupleTypeOf(exports) diff --git a/packages/compiler/src/render3/r3_template_transform.ts b/packages/compiler/src/render3/r3_template_transform.ts index 33a24fb424..be274ccf19 100644 --- a/packages/compiler/src/render3/r3_template_transform.ts +++ b/packages/compiler/src/render3/r3_template_transform.ts @@ -240,7 +240,11 @@ class HtmlAstToIvyAst implements html.Visitor { literal.push(new t.TextAttribute( prop.name, prop.expression.source || '', prop.sourceSpan, undefined, i18n)); } else { - const bep = this.bindingParser.createBoundElementProperty(elementName, prop); + // we skip validation here, since we do this check at runtime due to the fact that we need + // to make sure a given prop is not an input of some Directive (thus should not be a subject + // of this check) and Directive matching happens at runtime + const bep = this.bindingParser.createBoundElementProperty( + elementName, prop, /* skipValidation */ true); bound.push(t.BoundAttribute.fromBoundElementProperty(bep, i18n)); } }); @@ -280,13 +284,15 @@ class HtmlAstToIvyAst implements html.Visitor { } else if (bindParts[KW_ON_IDX]) { const events: ParsedEvent[] = []; this.bindingParser.parseEvent( - bindParts[IDENT_KW_IDX], value, srcSpan, matchableAttributes, events); + bindParts[IDENT_KW_IDX], value, srcSpan, attribute.valueSpan || srcSpan, + matchableAttributes, events); addEvents(events, boundEvents); } else if (bindParts[KW_BINDON_IDX]) { this.bindingParser.parsePropertyBinding( bindParts[IDENT_KW_IDX], value, false, srcSpan, matchableAttributes, parsedProperties); this.parseAssignmentEvent( - bindParts[IDENT_KW_IDX], value, srcSpan, matchableAttributes, boundEvents); + bindParts[IDENT_KW_IDX], value, srcSpan, attribute.valueSpan, matchableAttributes, + boundEvents); } else if (bindParts[KW_AT_IDX]) { this.bindingParser.parseLiteralAttr( name, value, srcSpan, matchableAttributes, parsedProperties); @@ -296,7 +302,8 @@ class HtmlAstToIvyAst implements html.Visitor { bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, matchableAttributes, parsedProperties); this.parseAssignmentEvent( - bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, matchableAttributes, boundEvents); + bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, attribute.valueSpan, + matchableAttributes, boundEvents); } else if (bindParts[IDENT_PROPERTY_IDX]) { this.bindingParser.parsePropertyBinding( @@ -306,7 +313,8 @@ class HtmlAstToIvyAst implements html.Visitor { } else if (bindParts[IDENT_EVENT_IDX]) { const events: ParsedEvent[] = []; this.bindingParser.parseEvent( - bindParts[IDENT_EVENT_IDX], value, srcSpan, matchableAttributes, events); + bindParts[IDENT_EVENT_IDX], value, srcSpan, attribute.valueSpan || srcSpan, + matchableAttributes, events); addEvents(events, boundEvents); } } else { @@ -343,10 +351,12 @@ class HtmlAstToIvyAst implements html.Visitor { private parseAssignmentEvent( name: string, expression: string, sourceSpan: ParseSourceSpan, - targetMatchableAttrs: string[][], boundEvents: t.BoundEvent[]) { + valueSpan: ParseSourceSpan|undefined, targetMatchableAttrs: string[][], + boundEvents: t.BoundEvent[]) { const events: ParsedEvent[] = []; this.bindingParser.parseEvent( - `${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, events); + `${name}Change`, `${expression}=$event`, sourceSpan, valueSpan || sourceSpan, + targetMatchableAttrs, events); addEvents(events, boundEvents); } diff --git a/packages/compiler/src/render3/util.ts b/packages/compiler/src/render3/util.ts index c006c298f5..493ed0e90e 100644 --- a/packages/compiler/src/render3/util.ts +++ b/packages/compiler/src/render3/util.ts @@ -52,3 +52,31 @@ export interface R3Reference { value: o.Expression; type: o.Expression; } + +const ANIMATE_SYMBOL_PREFIX = '@'; +export function prepareSyntheticPropertyName(name: string) { + return `${ANIMATE_SYMBOL_PREFIX}${name}`; +} + +export function prepareSyntheticListenerName(name: string, phase: string) { + return `${ANIMATE_SYMBOL_PREFIX}${name}.${phase}`; +} + +export function isSyntheticPropertyOrListener(name: string) { + return name.charAt(0) == ANIMATE_SYMBOL_PREFIX; +} + +export function getSyntheticPropertyName(name: string) { + // this will strip out listener phase values... + // @foo.start => @foo + const i = name.indexOf('.'); + name = i > 0 ? name.substring(0, i) : name; + if (name.charAt(0) !== ANIMATE_SYMBOL_PREFIX) { + name = ANIMATE_SYMBOL_PREFIX + name; + } + return name; +} + +export function prepareSyntheticListenerFunctionName(name: string, phase: string) { + return `animation_${name}_${phase}`; +} \ No newline at end of file diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index bc12edc082..afe470a482 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -104,7 +104,7 @@ export interface R3DirectiveMetadata { * Reference name under which to export the directive's type in a template, * if any. */ - exportAs: string|null; + exportAs: string[]|null; /** * The list of providers defined in the directive. diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index 9b37d76c2b..a79cb4186a 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -9,27 +9,28 @@ import {StaticSymbol} from '../../aot/static_symbol'; import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileQueryMetadata, CompileTokenMetadata, identifierName, sanitizeIdentifier} from '../../compile_metadata'; import {CompileReflector} from '../../compile_reflector'; -import {BindingForm, convertActionBinding, convertPropertyBinding} from '../../compiler_util/expression_converter'; +import {BindingForm, convertPropertyBinding} from '../../compiler_util/expression_converter'; import {ConstantPool, DefinitionKind} from '../../constant_pool'; import * as core from '../../core'; -import {AST, ParsedEvent} from '../../expression_parser/ast'; +import {AST, ParsedEvent, ParsedEventType, ParsedProperty} from '../../expression_parser/ast'; import {LifecycleHooks} from '../../lifecycle_reflector'; import {DEFAULT_INTERPOLATION_CONFIG} from '../../ml_parser/interpolation_config'; import * as o from '../../output/output_ast'; -import {typeSourceSpan} from '../../parse_util'; +import {ParseError, ParseSourceSpan, typeSourceSpan} from '../../parse_util'; import {CssSelector, SelectorMatcher} from '../../selector'; import {ShadowCss} from '../../shadow_css'; import {CONTENT_ATTR, HOST_ATTR} from '../../style_compiler'; import {BindingParser} from '../../template_parser/binding_parser'; import {OutputContext, error} from '../../util'; +import {BoundEvent} from '../r3_ast'; import {compileFactoryFunction, dependenciesFromGlobalMetadata} from '../r3_factory'; import {Identifiers as R3} from '../r3_identifiers'; import {Render3ParseResult} from '../r3_template_transform'; -import {typeWithParameters} from '../util'; +import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util'; import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3QueryMetadata} from './api'; -import {StylingBuilder, StylingInstruction} from './styling_builder'; -import {BindingScope, TemplateDefinitionBuilder, ValueConverter, renderFlagCheckIfStmt} from './template'; +import {Instruction, StylingBuilder} from './styling_builder'; +import {BindingScope, TemplateDefinitionBuilder, ValueConverter, makeBindingParser, prepareEventListenerParameters, renderFlagCheckIfStmt, resolveSanitizationFn} from './template'; import {CONTEXT_NAME, DefinitionMap, RENDER_FLAGS, TEMPORARY_NAME, asLiteral, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator} from './util'; const EMPTY_ARRAY: any[] = []; @@ -38,8 +39,8 @@ const EMPTY_ARRAY: any[] = []; // If there is a match, the first matching group will contain the attribute name to bind. const ATTR_REGEX = /attr\.([^\]]+)/; -function getStylingPrefix(propName: string): string { - return propName.substring(0, 5).toLowerCase(); +function getStylingPrefix(name: string): string { + return name.substring(0, 5); // style or class } function baseDirectiveFields( @@ -63,9 +64,10 @@ function baseDirectiveFields( }); definitionMap.set('factory', result.factory); - definitionMap.set('contentQueries', createContentQueriesFunction(meta, constantPool)); - - definitionMap.set('contentQueriesRefresh', createContentQueriesRefreshFunction(meta)); + if (meta.queries.length > 0) { + // e.g. `contentQueries: (rf, ctx, dirIndex) => { ... } + definitionMap.set('contentQueries', createContentQueriesFunction(meta, constantPool)); + } // Initialize hostVarsCount to number of bound host properties (interpolations illegal), // except 'style' and 'class' properties, since they should *not* allocate host var slots @@ -100,14 +102,11 @@ function baseDirectiveFields( } } - // e.g. `attributes: ['role', 'listbox']` - definitionMap.set('attributes', createHostAttributesArray(allOtherAttributes)); - // e.g. `hostBindings: (rf, ctx, elIndex) => { ... } definitionMap.set( - 'hostBindings', - createHostBindingsFunction( - meta, elVarExp, contextVarExp, styleBuilder, bindingParser, constantPool, hostVarsCount)); + 'hostBindings', createHostBindingsFunction( + meta, elVarExp, contextVarExp, allOtherAttributes, styleBuilder, + bindingParser, constantPool, hostVarsCount)); // e.g 'inputs: {a: 'a'}` definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true)); @@ -116,7 +115,7 @@ function baseDirectiveFields( definitionMap.set('outputs', conditionallyCreateMapObjectLiteral(meta.outputs)); if (meta.exportAs !== null) { - definitionMap.set('exportAs', o.literal(meta.exportAs)); + definitionMap.set('exportAs', o.literalArr(meta.exportAs.map(e => o.literal(e)))); } return {definitionMap, statements: result.statements}; @@ -127,7 +126,7 @@ function baseDirectiveFields( */ function addFeatures( definitionMap: DefinitionMap, meta: R3DirectiveMetadata | R3ComponentMetadata) { - // e.g. `features: [NgOnChangesFeature]` + // e.g. `features: [NgOnChangesFeature()]` const features: o.Expression[] = []; const providers = meta.providers; @@ -144,7 +143,7 @@ function addFeatures( features.push(o.importExpr(R3.InheritDefinitionFeature)); } if (meta.lifecycle.usesOnChanges) { - features.push(o.importExpr(R3.NgOnChangesFeature)); + features.push(o.importExpr(R3.NgOnChangesFeature).callFn(EMPTY_ARRAY)); } if (features.length) { definitionMap.set('features', o.literalArr(features)); @@ -161,9 +160,9 @@ export function compileDirectiveFromMetadata( addFeatures(definitionMap, meta); const expression = o.importExpr(R3.defineDirective).callFn([definitionMap.toLiteralMap()]); - // On the type side, remove newlines from the selector as it will need to fit into a TypeScript - // string literal, which must be on one line. - const selectorForType = (meta.selector || '').replace(/\n/g, ''); + if (!meta.selector) { + throw new Error(`Directive ${meta.name} has no selector, please add it!`); + } const type = createTypeForDef(meta, R3.DirectiveDefWithMeta); return {expression, type, statements}; @@ -256,11 +255,18 @@ export function compileComponentFromMetadata( const template = meta.template; const templateBuilder = new TemplateDefinitionBuilder( constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, null, null, templateName, - meta.viewQueries, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, R3.namespaceHTML, + directiveMatcher, directivesUsed, meta.pipes, pipesUsed, R3.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds); const templateFunctionExpression = templateBuilder.buildTemplateFunction(template.nodes, []); + // We need to provide this so that dynamically generated components know what + // projected content blocks to pass through to the component when it is instantiated. + const ngContentSelectors = templateBuilder.getNgContentSelectors(); + if (ngContentSelectors) { + definitionMap.set('ngContentSelectors', ngContentSelectors); + } + // e.g. `consts: 2` definitionMap.set('consts', o.literal(templateBuilder.getConstCount())); @@ -480,22 +486,15 @@ function selectorsFromGlobalMetadata( return o.NULL_EXPR; } -function createQueryDefinition( - query: R3QueryMetadata, constantPool: ConstantPool, idx: number | null): o.Expression { - const predicate = getQueryPredicate(query, constantPool); - - // e.g. r3.query(null, somePredicate, false) or r3.query(0, ['div'], false) +function prepareQueryParams(query: R3QueryMetadata, constantPool: ConstantPool): o.Expression[] { const parameters = [ - o.literal(idx, o.INFERRED_TYPE), - predicate, + getQueryPredicate(query, constantPool), o.literal(query.descendants), ]; - if (query.read) { parameters.push(query.read); } - - return o.importExpr(R3.query).callFn(parameters); + return parameters; } // Turn a directive selector into an R3-compatible selector for directive def @@ -503,76 +502,48 @@ function createDirectiveSelector(selector: string | null): o.Expression { return asLiteral(core.parseSelectorToR3Selector(selector)); } -function createHostAttributesArray(attributes: any): o.Expression|null { +function convertAttributesToExpressions(attributes: any): o.Expression[] { const values: o.Expression[] = []; for (let key of Object.getOwnPropertyNames(attributes)) { const value = attributes[key]; values.push(o.literal(key), o.literal(value)); } - if (values.length > 0) { - return o.literalArr(values); - } - return null; + return values; } -// Return a contentQueries function or null if one is not necessary. +// Define and update any content queries function createContentQueriesFunction( - meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression|null { - if (meta.queries.length) { - const statements: o.Statement[] = meta.queries.map((query: R3QueryMetadata) => { - const queryDefinition = createQueryDefinition(query, constantPool, null); - return o.importExpr(R3.registerContentQuery) - .callFn([queryDefinition, o.variable('dirIndex')]) - .toStmt(); - }); - const typeName = meta.name; - const parameters = [new o.FnParam('dirIndex', o.NUMBER_TYPE)]; - return o.fn( - parameters, statements, o.INFERRED_TYPE, null, - typeName ? `${typeName}_ContentQueries` : null); + meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression { + const createStatements: o.Statement[] = []; + const updateStatements: o.Statement[] = []; + const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME); + + for (const query of meta.queries) { + // creation, e.g. r3.contentQuery(dirIndex, somePredicate, true); + const args = [o.variable('dirIndex'), ...prepareQueryParams(query, constantPool) as any]; + createStatements.push(o.importExpr(R3.contentQuery).callFn(args).toStmt()); + + // update, e.g. (r3.queryRefresh(tmp = r3.loadContentQuery()) && (ctx.someDir = tmp)); + const temporary = tempAllocator(); + const getQueryList = o.importExpr(R3.loadContentQuery).callFn([]); + const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]); + const updateDirective = o.variable(CONTEXT_NAME) + .prop(query.propertyName) + .set(query.first ? temporary.prop('first') : temporary); + updateStatements.push(refresh.and(updateDirective).toStmt()); } - return null; -} - -// Return a contentQueriesRefresh function or null if one is not necessary. -function createContentQueriesRefreshFunction(meta: R3DirectiveMetadata): o.Expression|null { - if (meta.queries.length > 0) { - const statements: o.Statement[] = []; - const typeName = meta.name; - const parameters = [ - new o.FnParam('dirIndex', o.NUMBER_TYPE), - new o.FnParam('queryStartIndex', o.NUMBER_TYPE), - ]; - const directiveInstanceVar = o.variable('instance'); - // var $tmp$: any; - const temporary = temporaryAllocator(statements, TEMPORARY_NAME); - - // const $instance$ = $r3$.ɵload(dirIndex); - statements.push(directiveInstanceVar.set(o.importExpr(R3.load).callFn([o.variable('dirIndex')])) - .toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final])); - - meta.queries.forEach((query: R3QueryMetadata, idx: number) => { - const loadQLArg = o.variable('queryStartIndex'); - const getQueryList = o.importExpr(R3.loadQueryList).callFn([ - idx > 0 ? loadQLArg.plus(o.literal(idx)) : loadQLArg - ]); - const assignToTemporary = temporary().set(getQueryList); - const callQueryRefresh = o.importExpr(R3.queryRefresh).callFn([assignToTemporary]); - - const updateDirective = directiveInstanceVar.prop(query.propertyName) - .set(query.first ? temporary().prop('first') : temporary()); - const refreshQueryAndUpdateDirective = callQueryRefresh.and(updateDirective); - - statements.push(refreshQueryAndUpdateDirective.toStmt()); - }); - - return o.fn( - parameters, statements, o.INFERRED_TYPE, null, - typeName ? `${typeName}_ContentQueriesRefresh` : null); - } - - return null; + const contentQueriesFnName = meta.name ? `${meta.name}_ContentQueries` : null; + return o.fn( + [ + new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null), + new o.FnParam('dirIndex', null) + ], + [ + renderFlagCheckIfStmt(core.RenderFlags.Create, createStatements), + renderFlagCheckIfStmt(core.RenderFlags.Update, updateStatements) + ], + o.INFERRED_TYPE, null, contentQueriesFnName); } function stringAsType(str: string): o.Type { @@ -604,7 +575,7 @@ function createTypeForDef(meta: R3DirectiveMetadata, typeBase: o.ExternalReferen return o.expressionType(o.importExpr(typeBase, [ typeWithParameters(meta.type, meta.typeArgumentCount), stringAsType(selectorForType), - meta.exportAs !== null ? stringAsType(meta.exportAs) : o.NONE_TYPE, + meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : o.NONE_TYPE, stringMapAsType(meta.inputs), stringMapAsType(meta.outputs), stringArrayAsType(meta.queries.map(q => q.propertyName)), @@ -618,22 +589,21 @@ function createViewQueriesFunction( const updateStatements: o.Statement[] = []; const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME); - for (let i = 0; i < meta.viewQueries.length; i++) { - const query = meta.viewQueries[i]; - - // creation, e.g. r3.Q(0, somePredicate, true); - const queryDefinition = createQueryDefinition(query, constantPool, i); + meta.viewQueries.forEach((query: R3QueryMetadata) => { + // creation, e.g. r3.viewQuery(somePredicate, true); + const queryDefinition = + o.importExpr(R3.viewQuery).callFn(prepareQueryParams(query, constantPool)); createStatements.push(queryDefinition.toStmt()); - // update, e.g. (r3.qR(tmp = r3.ɵload(0)) && (ctx.someDir = tmp)); + // update, e.g. (r3.queryRefresh(tmp = r3.loadViewQuery()) && (ctx.someDir = tmp)); const temporary = tempAllocator(); - const getQueryList = o.importExpr(R3.load).callFn([o.literal(i)]); + const getQueryList = o.importExpr(R3.loadViewQuery).callFn([]); const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]); const updateDirective = o.variable(CONTEXT_NAME) .prop(query.propertyName) .set(query.first ? temporary.prop('first') : temporary); updateStatements.push(refresh.and(updateDirective).toStmt()); - } + }); const viewQueryFnName = meta.name ? `${meta.name}_Query` : null; return o.fn( @@ -648,8 +618,8 @@ function createViewQueriesFunction( // Return a host binding function or null if one is not necessary. function createHostBindingsFunction( meta: R3DirectiveMetadata, elVarExp: o.ReadVarExpr, bindingContext: o.ReadVarExpr, - styleBuilder: StylingBuilder, bindingParser: BindingParser, constantPool: ConstantPool, - hostVarsCount: number): o.Expression|null { + staticAttributesAndValues: any[], styleBuilder: StylingBuilder, bindingParser: BindingParser, + constantPool: ConstantPool, hostVarsCount: number): o.Expression|null { const createStatements: o.Statement[] = []; const updateStatements: o.Statement[] = []; @@ -657,6 +627,23 @@ function createHostBindingsFunction( const hostBindingSourceSpan = meta.typeSourceSpan; const directiveSummary = metadataAsSummary(meta); + let valueConverter: ValueConverter; + const getValueConverter = () => { + if (!valueConverter) { + const hostVarsCountFn = (numSlots: number): number => { + const originalVarsCount = totalHostVarsCount; + totalHostVarsCount += numSlots; + return originalVarsCount; + }; + valueConverter = new ValueConverter( + constantPool, + () => error('Unexpected node'), // new nodes are illegal here + hostVarsCountFn, + () => error('Unexpected pipe')); // pipes are illegal here + } + return valueConverter; + }; + // Calculate host event bindings const eventBindings = bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan); @@ -667,79 +654,88 @@ function createHostBindingsFunction( // Calculate the host property bindings const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan); + (bindings || []).forEach((binding: ParsedProperty) => { + const name = binding.name; + const stylingInputWasSet = + styleBuilder.registerInputBasedOnName(name, binding.expression, binding.sourceSpan); + if (!stylingInputWasSet) { + // resolve literal arrays and literal objects + const value = binding.expression.visit(getValueConverter()); + const bindingExpr = bindingFn(bindingContext, value); - const bindingFn = (implicit: any, value: AST) => { - return convertPropertyBinding( - null, implicit, value, 'b', BindingForm.TrySimple, () => error('Unexpected interpolation')); - }; - if (bindings) { - const hostVarsCountFn = (numSlots: number): number => { - const originalVarsCount = totalHostVarsCount; - totalHostVarsCount += numSlots; - return originalVarsCount; - }; - const valueConverter = new ValueConverter( - constantPool, - /* new nodes are illegal here */ () => error('Unexpected node'), hostVarsCountFn, - /* pipes are illegal here */ () => error('Unexpected pipe')); + const {bindingName, instruction, isAttribute} = getBindingNameAndInstruction(binding); - for (const binding of bindings) { - const name = binding.name; - const stylePrefix = getStylingPrefix(name); - if (stylePrefix === 'style') { - const {propertyName, unit} = parseNamedProperty(name); - styleBuilder.registerStyleInput(propertyName, binding.expression, unit, binding.sourceSpan); - } else if (stylePrefix === 'class') { - styleBuilder.registerClassInput( - parseNamedProperty(name).propertyName, binding.expression, binding.sourceSpan); - } else { - // resolve literal arrays and literal objects - const value = binding.expression.visit(valueConverter); - const bindingExpr = bindingFn(bindingContext, value); + const securityContexts = + bindingParser.calcPossibleSecurityContexts(meta.selector || '', bindingName, isAttribute) + .filter(context => context !== core.SecurityContext.NONE); - const {bindingName, instruction, extraParams} = getBindingNameAndInstruction(name); - - const instructionParams: o.Expression[] = [ - elVarExp, o.literal(bindingName), o.importExpr(R3.bind).callFn([bindingExpr.currValExpr]) - ]; - - updateStatements.push(...bindingExpr.stmts); - updateStatements.push( - o.importExpr(instruction).callFn(instructionParams.concat(extraParams)).toStmt()); + let sanitizerFn: o.ExternalExpr|null = null; + if (securityContexts.length) { + if (securityContexts.length === 2 && + securityContexts.indexOf(core.SecurityContext.URL) > -1 && + securityContexts.indexOf(core.SecurityContext.RESOURCE_URL) > -1) { + // Special case for some URL attributes (such as "src" and "href") that may be a part + // of different security contexts. In this case we use special santitization function and + // select the actual sanitizer at runtime based on a tag name that is provided while + // invoking sanitization function. + sanitizerFn = o.importExpr(R3.sanitizeUrlOrResourceUrl); + } else { + sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute); + } } + + const instructionParams: o.Expression[] = [ + elVarExp, o.literal(bindingName), o.importExpr(R3.bind).callFn([bindingExpr.currValExpr]) + ]; + if (sanitizerFn) { + instructionParams.push(sanitizerFn); + } + if (!isAttribute) { + if (!sanitizerFn) { + // append `null` in front of `nativeOnly` flag if no sanitizer fn defined + instructionParams.push(o.literal(null)); + } + // host bindings must have nativeOnly prop set to true + instructionParams.push(o.literal(true)); + } + + updateStatements.push(...bindingExpr.stmts); + updateStatements.push(o.importExpr(instruction).callFn(instructionParams).toStmt()); + } + }); + + // since we're dealing with directives/components and both have hostBinding + // functions, we need to generate a special hostAttrs instruction that deals + // with both the assignment of styling as well as static attributes to the host + // element. The instruction below will instruct all initial styling (styling + // that is inside of a host binding within a directive/component) to be attached + // to the host element alongside any of the provided host attributes that were + // collected earlier. + const hostAttrs = convertAttributesToExpressions(staticAttributesAndValues); + const hostInstruction = styleBuilder.buildHostAttrsInstruction(null, hostAttrs, constantPool); + if (hostInstruction) { + createStatements.push(createStylingStmt(hostInstruction, bindingContext, bindingFn)); + } + + if (styleBuilder.hasBindings) { + // singular style/class bindings (things like `[style.prop]` and `[class.name]`) + // MUST be registered on a given element within the component/directive + // templateFn/hostBindingsFn functions. The instruction below will figure out + // what all the bindings are and then generate the statements required to register + // those bindings to the element via `elementStyling`. + const elementStylingInstruction = + styleBuilder.buildElementStylingInstruction(null, constantPool); + if (elementStylingInstruction) { + createStatements.push( + createStylingStmt(elementStylingInstruction, bindingContext, bindingFn)); } - if (styleBuilder.hasBindingsOrInitialValues()) { - // since we're dealing with directives here and directives have a hostBinding - // function, we need to generate special instructions that deal with styling - // (both bindings and initial values). The instruction below will instruct - // all initial styling (styling that is inside of a host binding within a - // directive) to be attached to the host element of the directive. - const hostAttrsInstruction = - styleBuilder.buildDirectiveHostAttrsInstruction(null, constantPool); - if (hostAttrsInstruction) { - createStatements.push(createStylingStmt(hostAttrsInstruction, bindingContext, bindingFn)); - } - - // singular style/class bindings (things like `[style.prop]` and `[class.name]`) - // MUST be registered on a given element within the component/directive - // templateFn/hostBindingsFn functions. The instruction below will figure out - // what all the bindings are and then generate the statements required to register - // those bindings to the element via `elementStyling`. - const elementStylingInstruction = - styleBuilder.buildElementStylingInstruction(null, constantPool); - if (elementStylingInstruction) { - createStatements.push( - createStylingStmt(elementStylingInstruction, bindingContext, bindingFn)); - } - - // finally each binding that was registered in the statement above will need to be added to - // the update block of a component/directive templateFn/hostBindingsFn so that the bindings - // are evaluated and updated for the element. - styleBuilder.buildUpdateLevelInstructions(valueConverter).forEach(instruction => { - updateStatements.push(createStylingStmt(instruction, bindingContext, bindingFn)); - }); - } + // finally each binding that was registered in the statement above will need to be added to + // the update block of a component/directive templateFn/hostBindingsFn so that the bindings + // are evaluated and updated for the element. + styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(instruction => { + updateStatements.push(createStylingStmt(instruction, bindingContext, bindingFn)); + }); } if (totalHostVarsCount) { @@ -767,18 +763,23 @@ function createHostBindingsFunction( return null; } +function bindingFn(implicit: any, value: AST) { + return convertPropertyBinding( + null, implicit, value, 'b', BindingForm.TrySimple, () => error('Unexpected interpolation')); +} + function createStylingStmt( - instruction: StylingInstruction, bindingContext: any, bindingFn: Function): o.Statement { + instruction: Instruction, bindingContext: any, bindingFn: Function): o.Statement { const params = instruction.buildParams(value => bindingFn(bindingContext, value).currValExpr); return o.importExpr(instruction.reference, null, instruction.sourceSpan) .callFn(params, instruction.sourceSpan) .toStmt(); } -function getBindingNameAndInstruction(bindingName: string): - {bindingName: string, instruction: o.ExternalReference, extraParams: o.Expression[]} { +function getBindingNameAndInstruction(binding: ParsedProperty): + {bindingName: string, instruction: o.ExternalReference, isAttribute: boolean} { + let bindingName = binding.name; let instruction !: o.ExternalReference; - const extraParams: o.Expression[] = []; // Check to see if this is an attr binding or a property binding const attrMatches = bindingName.match(ATTR_REGEX); @@ -786,30 +787,35 @@ function getBindingNameAndInstruction(bindingName: string): bindingName = attrMatches[1]; instruction = R3.elementAttribute; } else { - instruction = R3.elementProperty; - extraParams.push( - o.literal(null), // TODO: This should be a sanitizer fn (FW-785) - o.literal(true) // host bindings must have nativeOnly prop set to true - ); + if (binding.isAnimation) { + bindingName = prepareSyntheticPropertyName(bindingName); + // host bindings that have a synthetic property (e.g. @foo) should always be rendered + // in the context of the component and not the parent. Therefore there is a special + // compatibility instruction available for this purpose. + instruction = R3.componentHostSyntheticProperty; + } else { + instruction = R3.elementProperty; + } } - return {bindingName, instruction, extraParams}; + return {bindingName, instruction, isAttribute: !!attrMatches}; } function createHostListeners( bindingContext: o.Expression, eventBindings: ParsedEvent[], meta: R3DirectiveMetadata): o.Statement[] { return eventBindings.map(binding => { - const bindingExpr = convertActionBinding( - null, bindingContext, binding.handler, 'b', () => error('Unexpected interpolation')); - const bindingName = binding.name && sanitizeIdentifier(binding.name); - const typeName = meta.name; - const functionName = - typeName && bindingName ? `${typeName}_${bindingName}_HostBindingHandler` : null; - const handler = o.fn( - [new o.FnParam('$event', o.DYNAMIC_TYPE)], [...bindingExpr.render3Stmts], o.INFERRED_TYPE, - null, functionName); - return o.importExpr(R3.listener).callFn([o.literal(binding.name), handler]).toStmt(); + let bindingName = binding.name && sanitizeIdentifier(binding.name); + const bindingFnName = binding.type === ParsedEventType.Animation ? + prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) : + bindingName; + const handlerName = + meta.name && bindingName ? `${meta.name}_${bindingFnName}_HostBindingHandler` : null; + const params = prepareEventListenerParameters( + BoundEvent.fromParsedEvent(binding), bindingContext, handlerName); + const instruction = + binding.type == ParsedEventType.Animation ? R3.componentHostSyntheticListener : R3.listener; + return o.importExpr(instruction).callFn(params).toStmt(); }); } @@ -832,30 +838,28 @@ function typeMapToExpressionMap( return new Map(entries); } -const HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))|(\@[-\w]+)$/; - +const HOST_REG_EXP = /^(?:\[([^\]]+)\])|(?:\(([^\)]+)\))$/; // Represents the groups in the above regex. const enum HostBindingGroup { - // group 1: "prop" from "[prop]", or "attr.role" from "[attr.role]" + // group 1: "prop" from "[prop]", or "attr.role" from "[attr.role]", or @anim from [@anim] Binding = 1, // group 2: "event" from "(event)" Event = 2, - - // group 3: "@trigger" from "@trigger" - Animation = 3, } -export function parseHostBindings(host: {[key: string]: string}): { - attributes: {[key: string]: string}, - listeners: {[key: string]: string}, - properties: {[key: string]: string}, - animations: {[key: string]: string}, -} { +// Defines Host Bindings structure that contains attributes, listeners, and properties, +// parsed from the `host` object defined for a Type. +export interface ParsedHostBindings { + attributes: {[key: string]: string}; + listeners: {[key: string]: string}; + properties: {[key: string]: string}; +} + +export function parseHostBindings(host: {[key: string]: string}): ParsedHostBindings { const attributes: {[key: string]: string} = {}; const listeners: {[key: string]: string} = {}; const properties: {[key: string]: string} = {}; - const animations: {[key: string]: string} = {}; Object.keys(host).forEach(key => { const value = host[key]; @@ -863,34 +867,38 @@ export function parseHostBindings(host: {[key: string]: string}): { if (matches === null) { attributes[key] = value; } else if (matches[HostBindingGroup.Binding] != null) { + // synthetic properties (the ones that have a `@` as a prefix) + // are still treated the same as regular properties. Therefore + // there is no point in storing them in a separate map. properties[matches[HostBindingGroup.Binding]] = value; } else if (matches[HostBindingGroup.Event] != null) { listeners[matches[HostBindingGroup.Event]] = value; - } else if (matches[HostBindingGroup.Animation] != null) { - animations[matches[HostBindingGroup.Animation]] = value; } }); - return {attributes, listeners, properties, animations}; + return {attributes, listeners, properties}; +} + +/** + * Verifies host bindings and returns the list of errors (if any). Empty array indicates that a + * given set of host bindings has no errors. + * + * @param bindings set of host bindings to verify. + * @param sourceSpan source span where host bindings were defined. + * @returns array of errors associated with a given set of host bindings. + */ +export function verifyHostBindings( + bindings: ParsedHostBindings, sourceSpan: ParseSourceSpan): ParseError[] { + const summary = metadataAsSummary({ host: bindings } as any); + // TODO: abstract out host bindings verification logic and use it instead of + // creating events and properties ASTs to detect errors (FW-996) + const bindingParser = makeBindingParser(); + bindingParser.createDirectiveHostEventAsts(summary, sourceSpan); + bindingParser.createBoundHostProperties(summary, sourceSpan); + return bindingParser.errors; } function compileStyles(styles: string[], selector: string, hostSelector: string): string[] { const shadowCss = new ShadowCss(); return styles.map(style => { return shadowCss !.shimCssText(style, selector, hostSelector); }); } - -function parseNamedProperty(name: string): {propertyName: string, unit: string} { - let unit = ''; - let propertyName = ''; - const index = name.indexOf('.'); - if (index > 0) { - const unitIndex = name.lastIndexOf('.'); - if (unitIndex !== index) { - unit = name.substring(unitIndex + 1, name.length); - propertyName = name.substring(index + 1, unitIndex); - } else { - propertyName = name.substring(index + 1, name.length); - } - } - return {propertyName, unit}; -} diff --git a/packages/compiler/src/render3/view/styling_builder.ts b/packages/compiler/src/render3/view/styling_builder.ts index aebc989304..774214a062 100644 --- a/packages/compiler/src/render3/view/styling_builder.ts +++ b/packages/compiler/src/render3/view/styling_builder.ts @@ -7,7 +7,7 @@ */ import {ConstantPool} from '../../constant_pool'; import {AttributeMarker} from '../../core'; -import {AST, BindingType} from '../../expression_parser/ast'; +import {AST, BindingType, Interpolation} from '../../expression_parser/ast'; import * as o from '../../output/output_ast'; import {ParseSourceSpan} from '../../parse_util'; import * as t from '../r3_ast'; @@ -16,13 +16,15 @@ import {Identifiers as R3} from '../r3_identifiers'; import {parse as parseStyle} from './style_parser'; import {ValueConverter} from './template'; +const IMPORTANT_FLAG = '!important'; /** * A styling expression summary that is to be processed by the compiler */ -export interface StylingInstruction { +export interface Instruction { sourceSpan: ParseSourceSpan|null; reference: o.ExternalReference; + allocateBindingSlots: number; buildParams(convertFn: (value: any) => o.Expression): o.Expression[]; } @@ -30,13 +32,13 @@ export interface StylingInstruction { * An internal record of the input data for a styling binding */ interface BoundStylingEntry { - name: string; + hasOverrideFlag: boolean; + name: string|null; unit: string|null; sourceSpan: ParseSourceSpan; value: AST; } - /** * Produces creation/update instructions for all styling bindings (class and style) * @@ -73,7 +75,7 @@ export class StylingBuilder { * Whether or not there are any styling bindings present * (i.e. `[style]`, `[class]`, `[style.prop]` or `[class.name]`) */ - private _hasBindings = false; + public hasBindings = false; /** the input for [class] (if it exists) */ private _classMapInput: BoundStylingEntry|null = null; @@ -110,8 +112,6 @@ export class StylingBuilder { constructor(private _elementIndexExpr: o.Expression, private _directiveExpr: o.Expression|null) {} - hasBindingsOrInitialValues() { return this._hasBindings || this._hasInitialValues; } - /** * Registers a given input to the styling builder to be later used when producing AOT code. * @@ -125,54 +125,73 @@ export class StylingBuilder { // will therefore skip all style/class resolution that is present // with style="", [style]="" and [style.prop]="", class="", // [class.prop]="". [class]="" assignments - const name = input.name; let binding: BoundStylingEntry|null = null; + let name = input.name; switch (input.type) { case BindingType.Property: - if (name == 'style') { - binding = this.registerStyleInput(null, input.value, '', input.sourceSpan); - } else if (isClassBinding(input.name)) { - binding = this.registerClassInput(null, input.value, input.sourceSpan); - } + binding = this.registerInputBasedOnName(name, input.value, input.sourceSpan); break; case BindingType.Style: - binding = this.registerStyleInput(input.name, input.value, input.unit, input.sourceSpan); + binding = this.registerStyleInput(name, false, input.value, input.sourceSpan, input.unit); break; case BindingType.Class: - binding = this.registerClassInput(input.name, input.value, input.sourceSpan); + binding = this.registerClassInput(name, false, input.value, input.sourceSpan); break; } return binding ? true : false; } + registerInputBasedOnName(name: string, expression: AST, sourceSpan: ParseSourceSpan) { + let binding: BoundStylingEntry|null = null; + const nameToMatch = name.substring(0, 5); // class | style + const isStyle = nameToMatch === 'style'; + const isClass = isStyle ? false : (nameToMatch === 'class'); + if (isStyle || isClass) { + const isMapBased = name.charAt(5) !== '.'; // style.prop or class.prop makes this a no + const property = name.substr(isMapBased ? 5 : 6); // the dot explains why there's a +1 + if (isStyle) { + binding = this.registerStyleInput(property, isMapBased, expression, sourceSpan); + } else { + binding = this.registerClassInput(property, isMapBased, expression, sourceSpan); + } + } + return binding; + } + registerStyleInput( - propertyName: string|null, value: AST, unit: string|null, - sourceSpan: ParseSourceSpan): BoundStylingEntry { - const entry = { name: propertyName, unit, value, sourceSpan } as BoundStylingEntry; - if (propertyName) { - (this._singleStyleInputs = this._singleStyleInputs || []).push(entry); - this._useDefaultSanitizer = this._useDefaultSanitizer || isStyleSanitizable(propertyName); - registerIntoMap(this._stylesIndex, propertyName); - } else { + name: string, isMapBased: boolean, value: AST, sourceSpan: ParseSourceSpan, + unit?: string|null): BoundStylingEntry { + const {property, hasOverrideFlag, unit: bindingUnit} = parseProperty(name); + const entry: BoundStylingEntry = { + name: property, + unit: unit || bindingUnit, value, sourceSpan, hasOverrideFlag + }; + if (isMapBased) { this._useDefaultSanitizer = true; this._styleMapInput = entry; + } else { + (this._singleStyleInputs = this._singleStyleInputs || []).push(entry); + this._useDefaultSanitizer = this._useDefaultSanitizer || isStyleSanitizable(name); + registerIntoMap(this._stylesIndex, property); } this._lastStylingInput = entry; - this._hasBindings = true; + this.hasBindings = true; return entry; } - registerClassInput(className: string|null, value: AST, sourceSpan: ParseSourceSpan): + registerClassInput(name: string, isMapBased: boolean, value: AST, sourceSpan: ParseSourceSpan): BoundStylingEntry { - const entry = { name: className, value, sourceSpan } as BoundStylingEntry; - if (className) { - (this._singleClassInputs = this._singleClassInputs || []).push(entry); - registerIntoMap(this._classesIndex, className); - } else { + const {property, hasOverrideFlag} = parseProperty(name); + const entry: + BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, unit: null}; + if (isMapBased) { this._classMapInput = entry; + } else { + (this._singleClassInputs = this._singleClassInputs || []).push(entry); + registerIntoMap(this._classesIndex, property); } this._lastStylingInput = entry; - this._hasBindings = true; + this.hasBindings = true; return entry; } @@ -225,17 +244,19 @@ export class StylingBuilder { * Builds an instruction with all the expressions and parameters for `elementHostAttrs`. * * The instruction generation code below is used for producing the AOT statement code which is - * responsible for registering initial styles (within a directive hostBindings' creation block) - * to the directive host element. + * responsible for registering initial styles (within a directive hostBindings' creation block), + * as well as any of the provided attribute values, to the directive host element. */ - buildDirectiveHostAttrsInstruction(sourceSpan: ParseSourceSpan|null, constantPool: ConstantPool): - StylingInstruction|null { - if (this._hasInitialValues && this._directiveExpr) { + buildHostAttrsInstruction( + sourceSpan: ParseSourceSpan|null, attrs: o.Expression[], + constantPool: ConstantPool): Instruction|null { + if (this._directiveExpr && (attrs.length || this._hasInitialValues)) { return { sourceSpan, reference: R3.elementHostAttrs, + allocateBindingSlots: 0, buildParams: () => { - const attrs: o.Expression[] = []; + // params => elementHostAttrs(directive, attrs) this.populateInitialStylingAttrs(attrs); return [this._directiveExpr !, getConstantLiteralFromArray(constantPool, attrs)]; } @@ -251,10 +272,11 @@ export class StylingBuilder { * responsible for registering style/class bindings to an element. */ buildElementStylingInstruction(sourceSpan: ParseSourceSpan|null, constantPool: ConstantPool): - StylingInstruction|null { - if (this._hasBindings) { + Instruction|null { + if (this.hasBindings) { return { sourceSpan, + allocateBindingSlots: 0, reference: R3.elementStyling, buildParams: () => { // a string array of every style-based binding @@ -312,40 +334,51 @@ export class StylingBuilder { * which include the `[style]` and `[class]` expression params (if they exist) as well as * the sanitizer and directive reference expression. */ - buildElementStylingMapInstruction(valueConverter: ValueConverter): StylingInstruction|null { + buildElementStylingMapInstruction(valueConverter: ValueConverter): Instruction|null { if (this._classMapInput || this._styleMapInput) { const stylingInput = this._classMapInput ! || this._styleMapInput !; + let totalBindingSlotsRequired = 0; // these values must be outside of the update block so that they can // be evaluted (the AST visit call) during creation time so that any // pipes can be picked up in time before the template is built const mapBasedClassValue = this._classMapInput ? this._classMapInput.value.visit(valueConverter) : null; + if (mapBasedClassValue instanceof Interpolation) { + totalBindingSlotsRequired += mapBasedClassValue.expressions.length; + } + const mapBasedStyleValue = this._styleMapInput ? this._styleMapInput.value.visit(valueConverter) : null; + if (mapBasedStyleValue instanceof Interpolation) { + totalBindingSlotsRequired += mapBasedStyleValue.expressions.length; + } return { sourceSpan: stylingInput.sourceSpan, reference: R3.elementStylingMap, + allocateBindingSlots: totalBindingSlotsRequired, buildParams: (convertFn: (value: any) => o.Expression) => { - const params: o.Expression[] = [this._elementIndexExpr]; - - if (mapBasedClassValue) { - params.push(convertFn(mapBasedClassValue)); - } else if (this._styleMapInput) { - params.push(o.NULL_EXPR); - } - - if (mapBasedStyleValue) { - params.push(convertFn(mapBasedStyleValue)); - } else if (this._directiveExpr) { - params.push(o.NULL_EXPR); - } - + // min params => elementStylingMap(index, classMap) + // max params => elementStylingMap(index, classMap, styleMap, directive) + let expectedNumberOfArgs = 0; if (this._directiveExpr) { - params.push(this._directiveExpr); + expectedNumberOfArgs = 4; + } else if (mapBasedStyleValue) { + expectedNumberOfArgs = 3; + } else if (mapBasedClassValue) { + // index and class = 2 + expectedNumberOfArgs = 2; } + const params: o.Expression[] = [this._elementIndexExpr]; + addParam( + params, mapBasedClassValue, mapBasedClassValue ? convertFn(mapBasedClassValue) : null, + 2, expectedNumberOfArgs); + addParam( + params, mapBasedStyleValue, mapBasedStyleValue ? convertFn(mapBasedStyleValue) : null, + 3, expectedNumberOfArgs); + addParam(params, this._directiveExpr, this._directiveExpr, 4, expectedNumberOfArgs); return params; } }; @@ -355,15 +388,21 @@ export class StylingBuilder { private _buildSingleInputs( reference: o.ExternalReference, inputs: BoundStylingEntry[], mapIndex: Map, - allowUnits: boolean, valueConverter: ValueConverter): StylingInstruction[] { + allowUnits: boolean, valueConverter: ValueConverter): Instruction[] { + let totalBindingSlotsRequired = 0; return inputs.map(input => { - const bindingIndex: number = mapIndex.get(input.name) !; + const bindingIndex: number = mapIndex.get(input.name !) !; const value = input.value.visit(valueConverter); + totalBindingSlotsRequired += (value instanceof Interpolation) ? value.expressions.length : 0; return { sourceSpan: input.sourceSpan, - reference, + allocateBindingSlots: totalBindingSlotsRequired, reference, buildParams: (convertFn: (value: any) => o.Expression) => { + // min params => elementStlyingProp(elmIndex, bindingIndex, value) + // max params => elementStlyingProp(elmIndex, bindingIndex, value, overrideFlag) + const params = [this._elementIndexExpr, o.literal(bindingIndex), convertFn(value)]; + if (allowUnits) { if (input.unit) { params.push(o.literal(input.unit)); @@ -374,14 +413,21 @@ export class StylingBuilder { if (this._directiveExpr) { params.push(this._directiveExpr); + } else if (input.hasOverrideFlag) { + params.push(o.NULL_EXPR); } + + if (input.hasOverrideFlag) { + params.push(o.literal(true)); + } + return params; } }; }); } - private _buildClassInputs(valueConverter: ValueConverter): StylingInstruction[] { + private _buildClassInputs(valueConverter: ValueConverter): Instruction[] { if (this._singleClassInputs) { return this._buildSingleInputs( R3.elementClassProp, this._singleClassInputs, this._classesIndex, false, valueConverter); @@ -389,7 +435,7 @@ export class StylingBuilder { return []; } - private _buildStyleInputs(valueConverter: ValueConverter): StylingInstruction[] { + private _buildStyleInputs(valueConverter: ValueConverter): Instruction[] { if (this._singleStyleInputs) { return this._buildSingleInputs( R3.elementStyleProp, this._singleStyleInputs, this._stylesIndex, true, valueConverter); @@ -397,11 +443,14 @@ export class StylingBuilder { return []; } - private _buildApplyFn(): StylingInstruction { + private _buildApplyFn(): Instruction { return { sourceSpan: this._lastStylingInput ? this._lastStylingInput.sourceSpan : null, reference: R3.elementStylingApply, + allocateBindingSlots: 0, buildParams: () => { + // min params => elementStylingApply(elmIndex) + // max params => elementStylingApply(elmIndex, directive) const params: o.Expression[] = [this._elementIndexExpr]; if (this._directiveExpr) { params.push(this._directiveExpr); @@ -416,8 +465,8 @@ export class StylingBuilder { * into the update block of a template function or a directive hostBindings function. */ buildUpdateLevelInstructions(valueConverter: ValueConverter) { - const instructions: StylingInstruction[] = []; - if (this._hasBindings) { + const instructions: Instruction[] = []; + if (this.hasBindings) { const mapInstruction = this.buildElementStylingMapInstruction(valueConverter); if (mapInstruction) { instructions.push(mapInstruction); @@ -430,10 +479,6 @@ export class StylingBuilder { } } -function isClassBinding(name: string): boolean { - return name == 'className' || name == 'class'; -} - function registerIntoMap(map: Map, key: string) { if (!map.has(key)) { map.set(key, map.size); @@ -459,11 +504,31 @@ function getConstantLiteralFromArray( * predicate and totalExpectedArgs values */ function addParam( - params: o.Expression[], predicate: boolean, value: o.Expression, argNumber: number, + params: o.Expression[], predicate: any, value: o.Expression | null, argNumber: number, totalExpectedArgs: number) { - if (predicate) { + if (predicate && value) { params.push(value); } else if (argNumber < totalExpectedArgs) { params.push(o.NULL_EXPR); } } + +export function parseProperty(name: string): + {property: string, unit: string, hasOverrideFlag: boolean} { + let hasOverrideFlag = false; + const overrideIndex = name.indexOf(IMPORTANT_FLAG); + if (overrideIndex !== -1) { + name = overrideIndex > 0 ? name.substring(0, overrideIndex) : ''; + hasOverrideFlag = true; + } + + let unit = ''; + let property = name; + const unitIndex = name.lastIndexOf('.'); + if (unitIndex > 0) { + unit = name.substr(unitIndex + 1); + property = name.substring(0, unitIndex); + } + + return {property, unit, hasOverrideFlag}; +} diff --git a/packages/compiler/src/render3/view/t2_api.ts b/packages/compiler/src/render3/view/t2_api.ts index 0b6f104316..e484760e86 100644 --- a/packages/compiler/src/render3/view/t2_api.ts +++ b/packages/compiler/src/render3/view/t2_api.ts @@ -58,7 +58,7 @@ export interface DirectiveMeta { * * Null otherwise */ - exportAs: string|null; + exportAs: string[]|null; } /** diff --git a/packages/compiler/src/render3/view/t2_binder.ts b/packages/compiler/src/render3/view/t2_binder.ts index 6d73a35c8a..2cde692372 100644 --- a/packages/compiler/src/render3/view/t2_binder.ts +++ b/packages/compiler/src/render3/view/t2_binder.ts @@ -259,7 +259,10 @@ class DirectiveBinder implements Visitor { dirTarget = directives.find(dir => dir.isComponent) || null; } else { // This is a reference to a directive exported via exportAs. One should exist. - dirTarget = directives.find(dir => dir.exportAs === ref.value) || null; + dirTarget = + directives.find( + dir => dir.exportAs !== null && dir.exportAs.some(value => value === ref.value)) || + null; // Check if a matching directive was found, and error if it wasn't. if (dirTarget === null) { diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index 188c0e4712..cd0f9474ce 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -18,6 +18,7 @@ import * as html from '../../ml_parser/ast'; import {HtmlParser} from '../../ml_parser/html_parser'; import {WhitespaceVisitor} from '../../ml_parser/html_whitespaces'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../ml_parser/interpolation_config'; +import {LexerRange} from '../../ml_parser/lexer'; import {isNgContainer as checkIsNgContainer, splitNsName} from '../../ml_parser/tags'; import {mapLiteral} from '../../output/map_util'; import * as o from '../../output/output_ast'; @@ -29,15 +30,25 @@ import {error} from '../../util'; import * as t from '../r3_ast'; import {Identifiers as R3} from '../r3_identifiers'; import {htmlAstToRender3Ast} from '../r3_template_transform'; +import {prepareSyntheticListenerFunctionName, prepareSyntheticListenerName, prepareSyntheticPropertyName} from '../util'; -import {R3QueryMetadata} from './api'; import {I18nContext} from './i18n/context'; import {I18nMetaVisitor} from './i18n/meta'; import {getSerializedI18nContent} from './i18n/serializer'; import {I18N_ICU_MAPPING_PREFIX, assembleBoundTextPlaceholders, assembleI18nBoundString, formatI18nPlaceholderName, getTranslationConstPrefix, getTranslationDeclStmts, icuFromI18nMessage, isI18nRootNode, isSingleI18nIcu, metaFromI18nMessage, placeholdersToParams, wrapI18nPlaceholder} from './i18n/util'; -import {StylingBuilder, StylingInstruction} from './styling_builder'; +import {Instruction, StylingBuilder} from './styling_builder'; import {CONTEXT_NAME, IMPLICIT_REFERENCE, NON_BINDABLE_ATTR, REFERENCE_PREFIX, RENDER_FLAGS, asLiteral, getAttrsForDirectiveMatching, invalid, trimTrailingNulls, unsupported} from './util'; +// Default selector used by `` if none specified +const DEFAULT_NG_CONTENT_SELECTOR = '*'; + +// Selector attribute name of `` +const NG_CONTENT_SELECT_ATTR = 'select'; + +// List of supported global targets for event listeners +const GLOBAL_TARGET_RESOLVERS = new Map( + [['window', R3.resolveWindow], ['document', R3.resolveDocument], ['body', R3.resolveBody]]); + function mapBindingToInstruction(type: BindingType): o.ExternalReference|undefined { switch (type) { case BindingType.Property: @@ -58,11 +69,40 @@ export function renderFlagCheckIfStmt( return o.ifStmt(o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(flags), null, false), statements); } -// Default selector used by `` if none specified -const DEFAULT_NG_CONTENT_SELECTOR = '*'; +export function prepareEventListenerParameters( + eventAst: t.BoundEvent, bindingContext: o.Expression, handlerName: string | null = null, + scope: BindingScope | null = null): o.Expression[] { + const {type, name, target, phase, handler} = eventAst; + if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) { + throw new Error(`Unexpected global target '${target}' defined for '${name}' event. + Supported list of global targets: ${Array.from(GLOBAL_TARGET_RESOLVERS.keys())}.`); + } -// Selector attribute name of `` -const NG_CONTENT_SELECT_ATTR = 'select'; + const bindingExpr = convertActionBinding( + scope, bindingContext, handler, 'b', () => error('Unexpected interpolation'), + eventAst.handlerSpan); + + const statements = []; + if (scope) { + statements.push(...scope.restoreViewStatement()); + statements.push(...scope.variableDeclarations()); + } + statements.push(...bindingExpr.render3Stmts); + + const eventName: string = + type === ParsedEventType.Animation ? prepareSyntheticListenerName(name, phase !) : name; + const fnName = handlerName && sanitizeIdentifier(handlerName); + const fnArgs = [new o.FnParam('$event', o.DYNAMIC_TYPE)]; + const handlerFn = o.fn(fnArgs, statements, o.INFERRED_TYPE, null, fnName); + + const params: o.Expression[] = [o.literal(eventName), handlerFn]; + if (target) { + params.push( + o.literal(false), // `useCapture` flag, defaults to `false` + o.importExpr(GLOBAL_TARGET_RESOLVERS.get(target) !)); + } + return params; +} export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver { private _dataIndex = 0; @@ -122,14 +162,10 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver private constantPool: ConstantPool, parentBindingScope: BindingScope, private level = 0, private contextName: string|null, private i18nContext: I18nContext|null, private templateIndex: number|null, private templateName: string|null, - private viewQueries: R3QueryMetadata[], private directiveMatcher: SelectorMatcher|null, - private directives: Set, private pipeTypeByName: Map, - private pipes: Set, private _namespace: o.ExternalReference, - private relativeContextFilePath: string, private i18nUseExternalIds: boolean) { - // view queries can take up space in data and allocation happens earlier (in the "viewQuery" - // function) - this._dataIndex = viewQueries.length; - + private directiveMatcher: SelectorMatcher|null, private directives: Set, + private pipeTypeByName: Map, private pipes: Set, + private _namespace: o.ExternalReference, private relativeContextFilePath: string, + private i18nUseExternalIds: boolean) { this._bindingScope = parentBindingScope.nestedScope(level); // Turn the relative context file path into an identifier by replacing non-alphanumeric @@ -328,7 +364,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver if (this.i18nUseExternalIds) { const prefix = getTranslationConstPrefix(`EXTERNAL_`); const uniqueSuffix = this.constantPool.uniqueName(suffix); - name = `${prefix}${messageId}$$${uniqueSuffix}`; + name = `${prefix}${sanitizeIdentifier(messageId)}$$${uniqueSuffix}`; } else { const prefix = getTranslationConstPrefix(suffix); name = this.constantPool.uniqueName(prefix); @@ -490,9 +526,9 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const {name, value} = attr; if (name === NON_BINDABLE_ATTR) { isNonBindableMode = true; - } else if (name == 'style') { + } else if (name === 'style') { stylingBuilder.registerStyleAttr(value); - } else if (name == 'class') { + } else if (name === 'class') { stylingBuilder.registerClassAttr(value); } else if (attr.i18n) { i18nAttrs.push(attr); @@ -515,8 +551,9 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const allOtherInputs: t.BoundAttribute[] = []; element.inputs.forEach((input: t.BoundAttribute) => { - if (!stylingBuilder.registerBoundInput(input)) { - if (input.type == BindingType.Property) { + const stylingInputWasSet = stylingBuilder.registerBoundInput(input); + if (!stylingInputWasSet) { + if (input.type === BindingType.Property) { if (input.i18n) { i18nAttrs.push(input); } else { @@ -528,12 +565,14 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } }); - outputAttrs.forEach(attr => attributes.push(o.literal(attr.name), o.literal(attr.value))); + outputAttrs.forEach(attr => { + attributes.push(...getAttributeNameLiterals(attr.name), o.literal(attr.value)); + }); // this will build the instructions so that they fall into the following syntax // add attributes for directive matching purposes - attributes.push(...this.prepareSyntheticAndSelectOnlyAttrs( - allOtherInputs, element.outputs, stylingBuilder)); + attributes.push( + ...this.prepareSelectOnlyAttrs(allOtherInputs, element.outputs, stylingBuilder)); parameters.push(this.toAttrsParam(attributes)); // local refs (ex.:
    ) @@ -563,11 +602,11 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return element.children.length > 0; }; - const createSelfClosingInstruction = !stylingBuilder.hasBindingsOrInitialValues() && - !isNgContainer && element.outputs.length === 0 && i18nAttrs.length === 0 && !hasChildren(); + const createSelfClosingInstruction = !stylingBuilder.hasBindings && !isNgContainer && + element.outputs.length === 0 && i18nAttrs.length === 0 && !hasChildren(); const createSelfClosingI18nInstruction = !createSelfClosingInstruction && - !stylingBuilder.hasBindingsOrInitialValues() && hasTextChildrenOnly(element.children); + !stylingBuilder.hasBindings && hasTextChildrenOnly(element.children); if (createSelfClosingInstruction) { this.creationInstruction(element.sourceSpan, R3.element, trimTrailingNulls(parameters)); @@ -580,10 +619,6 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver this.creationInstruction(element.sourceSpan, R3.disableBindings); } - if (isI18nRootElement) { - this.i18nStart(element.sourceSpan, element.i18n !, createSelfClosingI18nInstruction); - } - // process i18n element attributes if (i18nAttrs.length) { let hasBindings: boolean = false; @@ -617,6 +652,12 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } } + // Note: it's important to keep i18n/i18nStart instructions after i18nAttributes ones, + // to make sure i18nAttributes instruction targets current element at runtime. + if (isI18nRootElement) { + this.i18nStart(element.sourceSpan, element.i18n !, createSelfClosingI18nInstruction); + } + // The style bindings code is placed into two distinct blocks within the template function AOT // code: creation and update. The creation code contains the `elementStyling` instructions // which will apply the collected binding values to the element. `elementStyling` is @@ -632,7 +673,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver element.outputs.forEach((outputAst: t.BoundEvent) => { this.creationInstruction( outputAst.sourceSpan, R3.listener, - this.prepareListenerParameter(element.name, outputAst)); + this.prepareListenerParameter(element.name, outputAst, elementIndex)); }); } @@ -641,39 +682,66 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // `elementStylingMap`, `elementClassProp` and `elementStylingApply` are all generated // and assign in the code below. stylingBuilder.buildUpdateLevelInstructions(this._valueConverter).forEach(instruction => { + this._bindingSlots += instruction.allocateBindingSlots; this.processStylingInstruction(implicit, instruction, false); }); + // the reason why `undefined` is used is because the renderer understands this as a + // special value to symbolize that there is no RHS to this binding + // TODO (matsko): revisit this once FW-959 is approached + const emptyValueBindInstruction = o.importExpr(R3.bind).callFn([o.literal(undefined)]); + // Generate element input bindings allOtherInputs.forEach((input: t.BoundAttribute) => { + const instruction = mapBindingToInstruction(input.type); if (input.type === BindingType.Animation) { const value = input.value.visit(this._valueConverter); - // setProperty without a value doesn't make any sense - if (value.name || value.value) { + // animation bindings can be presented in the following formats: + // 1. [@binding]="fooExp" + // 2. [@binding]="{value:fooExp, params:{...}}" + // 3. [@binding] + // 4. @binding + // All formats will be valid for when a synthetic binding is created. + // The reasoning for this is because the renderer should get each + // synthetic binding value in the order of the array that they are + // defined in... + const hasValue = value instanceof LiteralPrimitive ? !!value.value : true; + this.allocateBindingSlots(value); + const bindingName = prepareSyntheticPropertyName(input.name); + this.updateInstruction(input.sourceSpan, R3.elementProperty, () => { + return [ + o.literal(elementIndex), o.literal(bindingName), + (hasValue ? this.convertPropertyBinding(implicit, value) : emptyValueBindInstruction) + ]; + }); + } else if (instruction) { + const value = input.value.visit(this._valueConverter); + if (value !== undefined) { + const params: any[] = []; + const [attrNamespace, attrName] = splitNsName(input.name); + const isAttributeBinding = input.type === BindingType.Attribute; + const sanitizationRef = resolveSanitizationFn(input.securityContext, isAttributeBinding); + if (sanitizationRef) params.push(sanitizationRef); + if (attrNamespace) { + const namespaceLiteral = o.literal(attrNamespace); + + if (sanitizationRef) { + params.push(namespaceLiteral); + } else { + // If there wasn't a sanitization ref, we need to add + // an extra param so that we can pass in the namespace. + params.push(o.literal(null), namespaceLiteral); + } + } this.allocateBindingSlots(value); - const name = prepareSyntheticAttributeName(input.name); - this.updateInstruction(input.sourceSpan, R3.elementProperty, () => { + this.updateInstruction(input.sourceSpan, instruction, () => { return [ - o.literal(elementIndex), o.literal(name), this.convertPropertyBinding(implicit, value) + o.literal(elementIndex), o.literal(attrName), + this.convertPropertyBinding(implicit, value), ...params ]; }); } - } else if (instruction) { - const params: any[] = []; - const sanitizationRef = resolveSanitizationFn(input, input.securityContext); - if (sanitizationRef) params.push(sanitizationRef); - - // TODO(chuckj): runtime: security context - const value = input.value.visit(this._valueConverter); - this.allocateBindingSlots(value); - - this.updateInstruction(input.sourceSpan, instruction, () => { - return [ - o.literal(elementIndex), o.literal(input.name), - this.convertPropertyBinding(implicit, value), ...params - ]; - }); } else { this._unsupported(`binding type ${input.type}`); } @@ -707,14 +775,16 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } const tagName = sanitizeIdentifier(template.tagName || ''); - const contextName = tagName ? `${this.contextName}_${tagName}` : ''; - const templateName = - contextName ? `${contextName}_Template_${templateIndex}` : `Template_${templateIndex}`; + const contextName = `${tagName ? this.contextName + '_' + tagName : ''}_${templateIndex}`; + const templateName = `${contextName}_Template`; const parameters: o.Expression[] = [ o.literal(templateIndex), o.variable(templateName), - o.literal(template.tagName), + + // We don't care about the tag's namespace here, because we infer + // it based on the parent nodes inside the template instruction. + o.literal(template.tagName ? splitNsName(template.tagName)[1] : template.tagName), ]; // find directives matching on a given node @@ -724,7 +794,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver const attrsExprs: o.Expression[] = []; template.attributes.forEach( (a: t.TextAttribute) => { attrsExprs.push(asLiteral(a.name), asLiteral(a.value)); }); - attrsExprs.push(...this.prepareSyntheticAndSelectOnlyAttrs(template.inputs, template.outputs)); + attrsExprs.push(...this.prepareSelectOnlyAttrs(template.inputs, template.outputs)); parameters.push(this.toAttrsParam(attrsExprs)); // local refs (ex.: ) @@ -733,30 +803,16 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver parameters.push(o.importExpr(R3.templateRefExtractor)); } - // handle property bindings e.g. p(1, 'forOf', ɵbind(ctx.items)); - const context = o.variable(CONTEXT_NAME); - template.inputs.forEach(input => { - const value = input.value.visit(this._valueConverter); - this.allocateBindingSlots(value); - this.updateInstruction(template.sourceSpan, R3.elementProperty, () => { - return [ - o.literal(templateIndex), o.literal(input.name), - this.convertPropertyBinding(context, value) - ]; - }); - }); - // Create the template function const templateVisitor = new TemplateDefinitionBuilder( this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, - templateIndex, templateName, [], this.directiveMatcher, this.directives, - this.pipeTypeByName, this.pipes, this._namespace, this.fileBasedI18nSuffix, - this.i18nUseExternalIds); + templateIndex, templateName, this.directiveMatcher, this.directives, this.pipeTypeByName, + this.pipes, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds); // Nested templates must not be visited until after their parent templates have completed // processing, so they are queued here until after the initial pass. Otherwise, we wouldn't // be able to support bindings in nested templates to local refs that occur after the - // template definition. e.g.
    {{ foo }}
    + // template definition. e.g.
    {{ foo }}
    this._nestedTemplateFns.push(() => { const templateFunctionExpr = templateVisitor.buildTemplateFunction( template.children, template.variables, @@ -776,11 +832,24 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return trimTrailingNulls(parameters); }); + // handle property bindings e.g. ɵelementProperty(1, 'ngForOf', ɵbind(ctx.items)); + const context = o.variable(CONTEXT_NAME); + template.inputs.forEach(input => { + const value = input.value.visit(this._valueConverter); + this.allocateBindingSlots(value); + this.updateInstruction(template.sourceSpan, R3.elementProperty, () => { + return [ + o.literal(templateIndex), o.literal(input.name), + this.convertPropertyBinding(context, value) + ]; + }); + }); + // Generate listeners for directive output template.outputs.forEach((outputAst: t.BoundEvent) => { this.creationInstruction( outputAst.sourceSpan, R3.listener, - this.prepareListenerParameter('ng_template', outputAst)); + this.prepareListenerParameter('ng_template', outputAst, templateIndex)); }); } @@ -866,6 +935,12 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver getVarCount() { return this._pureFunctionSlots; } + getNgContentSelectors(): o.Expression|null { + return this._hasNgContent ? + this.constantPool.getConstLiteral(asLiteral(this._ngContentSelectors), true) : + null; + } + private bindingContext() { return `${this._bindingContext++}`; } // Bindings must only be resolved after all local refs have been visited, so all @@ -882,7 +957,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver } private processStylingInstruction( - implicit: any, instruction: StylingInstruction|null, createMode: boolean) { + implicit: any, instruction: Instruction|null, createMode: boolean) { if (instruction) { const paramsFn = () => instruction.buildParams(value => this.convertPropertyBinding(implicit, value, true)); @@ -912,7 +987,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return originalSlots; } - private allocateBindingSlots(value: AST) { + private allocateBindingSlots(value: AST|null) { this._bindingSlots += value instanceof Interpolation ? value.expressions.length : 1; } @@ -961,26 +1036,26 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver * STYLES, style1, value1, style2, value2, * SELECT_ONLY, name1, name2, name2, ...] * ``` + * + * Note that this function will fully ignore all synthetic (@foo) attribute values + * because those values are intended to always be generated as property instructions. */ - private prepareSyntheticAndSelectOnlyAttrs( + private prepareSelectOnlyAttrs( inputs: t.BoundAttribute[], outputs: t.BoundEvent[], styles?: StylingBuilder): o.Expression[] { + const alreadySeen = new Set(); const attrExprs: o.Expression[] = []; - const nonSyntheticInputs: t.BoundAttribute[] = []; - if (inputs.length) { - const EMPTY_STRING_EXPR = asLiteral(''); - inputs.forEach(input => { - if (input.type === BindingType.Animation) { - // @attributes are for Renderer2 animation @triggers, but this feature - // may be supported differently in future versions of angular. However, - // @triggers should always just be treated as regular attributes (it's up - // to the renderer to detect and use them in a special way). - attrExprs.push(asLiteral(prepareSyntheticAttributeName(input.name)), EMPTY_STRING_EXPR); - } else { - nonSyntheticInputs.push(input); + function addAttrExpr(key: string | number, value?: o.Expression): void { + if (typeof key === 'string') { + if (!alreadySeen.has(key)) { + attrExprs.push(...getAttributeNameLiterals(key)); + value !== undefined && attrExprs.push(value); + alreadySeen.add(key); } - }); + } else { + attrExprs.push(o.literal(key)); + } } // it's important that this occurs before SelectOnly because once `elementStart` @@ -990,10 +1065,30 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver styles.populateInitialStylingAttrs(attrExprs); } - if (nonSyntheticInputs.length || outputs.length) { - attrExprs.push(o.literal(core.AttributeMarker.SelectOnly)); - nonSyntheticInputs.forEach((i: t.BoundAttribute) => attrExprs.push(asLiteral(i.name))); - outputs.forEach((o: t.BoundEvent) => attrExprs.push(asLiteral(o.name))); + if (inputs.length || outputs.length) { + const attrsStartIndex = attrExprs.length; + + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i]; + if (input.type !== BindingType.Animation) { + addAttrExpr(input.name); + } + } + + for (let i = 0; i < outputs.length; i++) { + const output = outputs[i]; + if (output.type !== ParsedEventType.Animation) { + addAttrExpr(output.name); + } + } + + // this is a cheap way of adding the marker only after all the input/output + // values have been filtered (by not including the animation ones) and added + // to the expressions. The marker is important because it tells the runtime + // code that this is where attributes without values start... + if (attrExprs.length) { + attrExprs.splice(attrsStartIndex, 0, o.literal(core.AttributeMarker.SelectOnly)); + } } return attrExprs; @@ -1033,32 +1128,18 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver return this.constantPool.getConstLiteral(asLiteral(refsParam), true); } - private prepareListenerParameter(tagName: string, outputAst: t.BoundEvent): () => o.Expression[] { - let eventName: string = outputAst.name; - if (outputAst.type === ParsedEventType.Animation) { - eventName = prepareSyntheticAttributeName(`${outputAst.name}.${outputAst.phase}`); - } - const evNameSanitized = sanitizeIdentifier(eventName); - const tagNameSanitized = sanitizeIdentifier(tagName); - const functionName = `${this.templateName}_${tagNameSanitized}_${evNameSanitized}_listener`; - + private prepareListenerParameter(tagName: string, outputAst: t.BoundEvent, index: number): + () => o.Expression[] { return () => { - - const listenerScope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel); - - const bindingExpr = convertActionBinding( - listenerScope, o.variable(CONTEXT_NAME), outputAst.handler, 'b', - () => error('Unexpected interpolation')); - - const statements = [ - ...listenerScope.restoreViewStatement(), ...listenerScope.variableDeclarations(), - ...bindingExpr.render3Stmts - ]; - - const handler = o.fn( - [new o.FnParam('$event', o.DYNAMIC_TYPE)], statements, o.INFERRED_TYPE, null, - functionName); - return [o.literal(eventName), handler]; + const eventName: string = outputAst.name; + const bindingFnName = outputAst.type === ParsedEventType.Animation ? + // synthetic @listener.foo values are treated the exact same as are standard listeners + prepareSyntheticListenerFunctionName(eventName, outputAst.phase !) : + sanitizeIdentifier(eventName); + const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`; + const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel); + const context = o.variable(CONTEXT_NAME); + return prepareEventListenerParameters(outputAst, context, handlerName, scope); }; } } @@ -1192,6 +1273,26 @@ function getLiteralFactory( return o.importExpr(identifier).callFn(args); } +/** + * Gets an array of literals that can be added to an expression + * to represent the name and namespace of an attribute. E.g. + * `:xlink:href` turns into `[AttributeMarker.NamespaceURI, 'xlink', 'href']`. + * + * @param name Name of the attribute, including the namespace. + */ +function getAttributeNameLiterals(name: string): o.LiteralExpr[] { + const [attributeNamespace, attributeName] = splitNsName(name); + const nameLiteral = o.literal(attributeName); + + if (attributeNamespace) { + return [ + o.literal(core.AttributeMarker.NamespaceURI), o.literal(attributeNamespace), nameLiteral + ]; + } + + return [nameLiteral]; +} + /** * Function which is executed whenever a variable is referenced for the first time in a given * scope. @@ -1297,8 +1398,14 @@ export class BindingScope implements LocalResolver { set(retrievalLevel: number, name: string, lhs: o.ReadVarExpr, priority: number = DeclarationPriority.DEFAULT, declareLocalCallback?: DeclareLocalVarCallback, localRef?: true): BindingScope { - !this.map.has(name) || - error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`); + if (this.map.has(name)) { + if (localRef) { + // Do not throw an error if it's a local ref and do not update existing value, + // so the first defined ref is always returned. + return this; + } + error(`The name ${name} is already defined in scope to be ${this.map.get(name)}`); + } this.map.set(name, { retrievalLevel: retrievalLevel, lhs: lhs, @@ -1424,7 +1531,7 @@ function createCssSelector(tag: string, attributes: {[name: string]: string}): C cssSelector.addAttribute(name, value); if (name.toLowerCase() === 'class') { - const classes = value.trim().split(/\s+/g); + const classes = value.trim().split(/\s+/); classes.forEach(className => cssSelector.addClassName(className)); } }); @@ -1457,20 +1564,64 @@ function interpolate(args: o.Expression[]): o.Expression { return o.importExpr(R3.interpolationV).callFn([o.literalArr(args)]); } +/** + * Options that can be used to modify how a template is parsed by `parseTemplate()`. + */ +export interface ParseTemplateOptions { + /** + * Include whitespace nodes in the parsed output. + */ + preserveWhitespaces?: boolean; + /** + * How to parse interpolation markers. + */ + interpolationConfig?: InterpolationConfig; + /** + * The start and end point of the text to parse within the `source` string. + * The entire `source` string is parsed if this is not provided. + * */ + range?: LexerRange; + /** + * If this text is stored in a JavaScript string, then we have to deal with escape sequences. + * + * **Example 1:** + * + * ``` + * "abc\"def\nghi" + * ``` + * + * - The `\"` must be converted to `"`. + * - The `\n` must be converted to a new line character in a token, + * but it should not increment the current line for source mapping. + * + * **Example 2:** + * + * ``` + * "abc\ + * def" + * ``` + * + * The line continuation (`\` followed by a newline) should be removed from a token + * but the new line should increment the current line for source mapping. + */ + escapedString?: boolean; +} + /** * Parse a template into render3 `Node`s and additional metadata, with no other dependencies. * * @param template text of the template to parse * @param templateUrl URL to use for source mapping of the parsed template + * @param options options to modify how the template is parsed */ export function parseTemplate( template: string, templateUrl: string, - options: {preserveWhitespaces?: boolean, interpolationConfig?: InterpolationConfig} = {}): - {errors?: ParseError[], nodes: t.Node[]} { + options: ParseTemplateOptions = {}): {errors?: ParseError[], nodes: t.Node[]} { const {interpolationConfig, preserveWhitespaces} = options; const bindingParser = makeBindingParser(interpolationConfig); const htmlParser = new HtmlParser(); - const parseResult = htmlParser.parse(template, templateUrl, true, interpolationConfig); + const parseResult = + htmlParser.parse(template, templateUrl, {...options, tokenizeExpansionForms: true}); if (parseResult.errors && parseResult.errors.length > 0) { return {errors: parseResult.errors, nodes: []}; @@ -1513,7 +1664,7 @@ export function makeBindingParser( new Parser(new Lexer()), interpolationConfig, new DomElementSchemaRegistry(), null, []); } -function resolveSanitizationFn(input: t.BoundAttribute, context: core.SecurityContext) { +export function resolveSanitizationFn(context: core.SecurityContext, isAttribute?: boolean) { switch (context) { case core.SecurityContext.HTML: return o.importExpr(R3.sanitizeHtml); @@ -1523,7 +1674,7 @@ function resolveSanitizationFn(input: t.BoundAttribute, context: core.SecurityCo // the compiler does not fill in an instruction for [style.prop?] binding // values because the style algorithm knows internally what props are subject // to sanitization (only [attr.style] values are explicitly sanitized) - return input.type === BindingType.Attribute ? o.importExpr(R3.sanitizeStyle) : null; + return isAttribute ? o.importExpr(R3.sanitizeStyle) : null; case core.SecurityContext.URL: return o.importExpr(R3.sanitizeUrl); case core.SecurityContext.RESOURCE_URL: @@ -1533,16 +1684,14 @@ function resolveSanitizationFn(input: t.BoundAttribute, context: core.SecurityCo } } -function prepareSyntheticAttributeName(name: string) { - return '@' + name; -} - function isSingleElementTemplate(children: t.Node[]): children is[t.Element] { return children.length === 1 && children[0] instanceof t.Element; } -function hasTextChildrenOnly(children: t.Node[]): boolean { - return !children.find( - child => - !(child instanceof t.Text || child instanceof t.BoundText || child instanceof t.Icu)); +function isTextNode(node: t.Node): boolean { + return node instanceof t.Text || node instanceof t.BoundText || node instanceof t.Icu; +} + +function hasTextChildrenOnly(children: t.Node[]): boolean { + return children.every(isTextNode); } diff --git a/packages/compiler/src/template_parser/binding_parser.ts b/packages/compiler/src/template_parser/binding_parser.ts index 9c137277dd..71d786bb96 100644 --- a/packages/compiler/src/template_parser/binding_parser.ts +++ b/packages/compiler/src/template_parser/binding_parser.ts @@ -83,7 +83,8 @@ export class BindingParser { Object.keys(dirMeta.hostListeners).forEach(propName => { const expression = dirMeta.hostListeners[propName]; if (typeof expression === 'string') { - this.parseEvent(propName, expression, sourceSpan, [], targetEvents); + // TODO: pass a more accurate handlerSpan for this event. + this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents); } else { this._reportError( `Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, @@ -238,8 +239,9 @@ export class BindingParser { } } - createBoundElementProperty(elementSelector: string, boundProp: ParsedProperty): - BoundElementProperty { + createBoundElementProperty( + elementSelector: string, boundProp: ParsedProperty, + skipValidation: boolean = false): BoundElementProperty { if (boundProp.isAnimation) { return new BoundElementProperty( boundProp.name, BindingType.Animation, SecurityContext.NONE, boundProp.expression, null, @@ -252,11 +254,13 @@ export class BindingParser { const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR); let securityContexts: SecurityContext[] = undefined !; - // Check check for special cases (prefix style, attr, class) + // Check for special cases (prefix style, attr, class) if (parts.length > 1) { if (parts[0] == ATTRIBUTE_PREFIX) { boundPropertyName = parts[1]; - this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true); + if (!skipValidation) { + this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, true); + } securityContexts = calcPossibleSecurityContexts( this._schemaRegistry, elementSelector, boundPropertyName, true); @@ -286,7 +290,9 @@ export class BindingParser { securityContexts = calcPossibleSecurityContexts( this._schemaRegistry, elementSelector, boundPropertyName, false); bindingType = BindingType.Property; - this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, false); + if (!skipValidation) { + this._validatePropertyOrAttributeName(boundPropertyName, boundProp.sourceSpan, false); + } } return new BoundElementProperty( @@ -295,18 +301,26 @@ export class BindingParser { } parseEvent( - name: string, expression: string, sourceSpan: ParseSourceSpan, + name: string, expression: string, sourceSpan: ParseSourceSpan, handlerSpan: ParseSourceSpan, targetMatchableAttrs: string[][], targetEvents: ParsedEvent[]) { if (isAnimationLabel(name)) { name = name.substr(1); - this._parseAnimationEvent(name, expression, sourceSpan, targetEvents); + this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents); } else { - this._parseRegularEvent(name, expression, sourceSpan, targetMatchableAttrs, targetEvents); + this._parseRegularEvent( + name, expression, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents); } } + calcPossibleSecurityContexts(selector: string, propName: string, isAttribute: boolean): + SecurityContext[] { + const prop = this._schemaRegistry.getMappedPropName(propName); + return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute); + } + private _parseAnimationEvent( - name: string, expression: string, sourceSpan: ParseSourceSpan, targetEvents: ParsedEvent[]) { + name: string, expression: string, sourceSpan: ParseSourceSpan, handlerSpan: ParseSourceSpan, + targetEvents: ParsedEvent[]) { const matches = splitAtPeriod(name, [name, '']); const eventName = matches[0]; const phase = matches[1].toLowerCase(); @@ -314,9 +328,9 @@ export class BindingParser { switch (phase) { case 'start': case 'done': - const ast = this._parseAction(expression, sourceSpan); - targetEvents.push( - new ParsedEvent(eventName, phase, ParsedEventType.Animation, ast, sourceSpan)); + const ast = this._parseAction(expression, handlerSpan); + targetEvents.push(new ParsedEvent( + eventName, phase, ParsedEventType.Animation, ast, sourceSpan, handlerSpan)); break; default: @@ -333,13 +347,14 @@ export class BindingParser { } private _parseRegularEvent( - name: string, expression: string, sourceSpan: ParseSourceSpan, + name: string, expression: string, sourceSpan: ParseSourceSpan, handlerSpan: ParseSourceSpan, targetMatchableAttrs: string[][], targetEvents: ParsedEvent[]) { // long format: 'target: eventName' const [target, eventName] = splitAtColon(name, [null !, name]); - const ast = this._parseAction(expression, sourceSpan); + const ast = this._parseAction(expression, handlerSpan); targetMatchableAttrs.push([name !, ast.source !]); - targetEvents.push(new ParsedEvent(eventName, target, ParsedEventType.Regular, ast, sourceSpan)); + targetEvents.push( + new ParsedEvent(eventName, target, ParsedEventType.Regular, ast, sourceSpan, handlerSpan)); // Don't detect directives for event names for now, // so don't add the event name to the matchableAttrs } @@ -440,4 +455,4 @@ export function calcPossibleSecurityContexts( elementName => registry.securityContext(elementName, propName, isAttribute))); }); return ctxs.length === 0 ? [SecurityContext.NONE] : Array.from(new Set(ctxs)).sort(); -} +} \ No newline at end of file diff --git a/packages/compiler/src/template_parser/template_ast.ts b/packages/compiler/src/template_parser/template_ast.ts index df201b6766..7f6672c55b 100644 --- a/packages/compiler/src/template_parser/template_ast.ts +++ b/packages/compiler/src/template_parser/template_ast.ts @@ -114,7 +114,8 @@ export class BoundEventAst implements TemplateAst { constructor( public name: string, public target: string|null, public phase: string|null, - public handler: AST, public sourceSpan: ParseSourceSpan) { + public handler: AST, public sourceSpan: ParseSourceSpan, + public handlerSpan: ParseSourceSpan) { this.fullName = BoundEventAst.calcFullName(this.name, this.target, this.phase); this.isAnimation = !!this.phase; } @@ -134,7 +135,8 @@ export class BoundEventAst implements TemplateAst { const target: string|null = event.type === ParsedEventType.Regular ? event.targetOrPhase : null; const phase: string|null = event.type === ParsedEventType.Animation ? event.targetOrPhase : null; - return new BoundEventAst(event.name, target, phase, event.handler, event.sourceSpan); + return new BoundEventAst( + event.name, target, phase, event.handler, event.sourceSpan, event.handlerSpan); } visit(visitor: TemplateAstVisitor, context: any): any { diff --git a/packages/compiler/src/template_parser/template_parser.ts b/packages/compiler/src/template_parser/template_parser.ts index a646856cc8..2251272104 100644 --- a/packages/compiler/src/template_parser/template_parser.ts +++ b/packages/compiler/src/template_parser/template_parser.ts @@ -114,8 +114,10 @@ export class TemplateParser { directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[], schemas: SchemaMetadata[], templateUrl: string, preserveWhitespaces: boolean): TemplateParseResult { let htmlParseResult = typeof template === 'string' ? - this._htmlParser !.parse( - template, templateUrl, true, this.getInterpolationConfig(component)) : + this._htmlParser !.parse(template, templateUrl, { + tokenizeExpansionForms: true, + interpolationConfig: this.getInterpolationConfig(component) + }) : template; if (!preserveWhitespaces) { @@ -439,13 +441,15 @@ class TemplateParseVisitor implements html.Visitor { } else if (bindParts[KW_ON_IDX]) { this._bindingParser.parseEvent( - bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, boundEvents); + bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, + targetMatchableAttrs, boundEvents); } else if (bindParts[KW_BINDON_IDX]) { this._bindingParser.parsePropertyBinding( bindParts[IDENT_KW_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps); this._parseAssignmentEvent( - bindParts[IDENT_KW_IDX], value, srcSpan, targetMatchableAttrs, boundEvents); + bindParts[IDENT_KW_IDX], value, srcSpan, attr.valueSpan || srcSpan, + targetMatchableAttrs, boundEvents); } else if (bindParts[KW_AT_IDX]) { this._bindingParser.parseLiteralAttr( @@ -456,7 +460,8 @@ class TemplateParseVisitor implements html.Visitor { bindParts[IDENT_BANANA_BOX_IDX], value, false, srcSpan, targetMatchableAttrs, targetProps); this._parseAssignmentEvent( - bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, targetMatchableAttrs, boundEvents); + bindParts[IDENT_BANANA_BOX_IDX], value, srcSpan, attr.valueSpan || srcSpan, + targetMatchableAttrs, boundEvents); } else if (bindParts[IDENT_PROPERTY_IDX]) { this._bindingParser.parsePropertyBinding( @@ -465,7 +470,8 @@ class TemplateParseVisitor implements html.Visitor { } else if (bindParts[IDENT_EVENT_IDX]) { this._bindingParser.parseEvent( - bindParts[IDENT_EVENT_IDX], value, srcSpan, targetMatchableAttrs, boundEvents); + bindParts[IDENT_EVENT_IDX], value, srcSpan, attr.valueSpan || srcSpan, + targetMatchableAttrs, boundEvents); } } else { hasBinding = this._bindingParser.parsePropertyInterpolation( @@ -505,10 +511,11 @@ class TemplateParseVisitor implements html.Visitor { } private _parseAssignmentEvent( - name: string, expression: string, sourceSpan: ParseSourceSpan, + name: string, expression: string, sourceSpan: ParseSourceSpan, valueSpan: ParseSourceSpan, targetMatchableAttrs: string[][], targetEvents: ParsedEvent[]) { this._bindingParser.parseEvent( - `${name}Change`, `${expression}=$event`, sourceSpan, targetMatchableAttrs, targetEvents); + `${name}Change`, `${expression}=$event`, sourceSpan, valueSpan, targetMatchableAttrs, + targetEvents); } private _parseDirectives(selectorMatcher: SelectorMatcher, elementCssSelector: CssSelector): @@ -897,4 +904,4 @@ function isEmptyExpression(ast: AST): boolean { ast = ast.ast; } return ast instanceof EmptyExpr; -} \ No newline at end of file +} diff --git a/packages/compiler/test/BUILD.bazel b/packages/compiler/test/BUILD.bazel index 9a90d09782..75c16aac68 100644 --- a/packages/compiler/test/BUILD.bazel +++ b/packages/compiler/test/BUILD.bazel @@ -41,6 +41,7 @@ ts_library( "//packages/compiler/test/ml_parser/util", "//packages/compiler/testing", "//packages/core", + "//packages/core/src/compiler", "//packages/core/testing", "//packages/platform-browser", "//packages/platform-browser-dynamic", diff --git a/packages/compiler/test/aot/compiler_spec.ts b/packages/compiler/test/aot/compiler_spec.ts index 0338985f67..9d020e581c 100644 --- a/packages/compiler/test/aot/compiler_spec.ts +++ b/packages/compiler/test/aot/compiler_spec.ts @@ -486,130 +486,142 @@ describe('compiler (unbundled Angular)', () => { inheritanceWithSummariesSpecs(() => angularSummaryFiles); - it('should not reexport type symbols mentioned in constructors', () => { - const libInput: MockDirectory = { - 'lib': { - 'base.ts': ` - export class AValue {} - export type AType = {}; + describe('external symbol re-exports enabled', () => { - export class AClass { - constructor(a: AType, b: AValue) {} - } - ` - } - }; - const appInput: MockDirectory = { - 'app': { - 'main.ts': ` - export {AClass} from '../lib/base'; - ` - } - }; + it('should not reexport type symbols mentioned in constructors', () => { + const libInput: MockDirectory = { + 'lib': { + 'base.ts': ` + export class AValue {} + export type AType = {}; + + export class AClass { + constructor(a: AType, b: AValue) {} + } + ` + } + }; + const appInput: MockDirectory = { + 'app': { + 'main.ts': ` + export {AClass} from '../lib/base'; + ` + } + }; - const {outDir: libOutDir} = compile([libInput, angularSummaryFiles], {useSummaries: true}); - const {genFiles: appGenFiles} = - compile([appInput, libOutDir, angularSummaryFiles], {useSummaries: true}); - const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; - const appNgFactoryTs = toTypeScript(appNgFactory); - expect(appNgFactoryTs).not.toContain('AType'); - expect(appNgFactoryTs).toContain('AValue'); - }); + const {outDir: libOutDir} = compile( + [libInput, angularSummaryFiles], + {useSummaries: true, createExternalSymbolFactoryReexports: true}); + const {genFiles: appGenFiles} = compile( + [appInput, libOutDir, angularSummaryFiles], + {useSummaries: true, createExternalSymbolFactoryReexports: true}); + const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; + const appNgFactoryTs = toTypeScript(appNgFactory); + expect(appNgFactoryTs).not.toContain('AType'); + expect(appNgFactoryTs).toContain('AValue'); + }); - it('should not reexport complex function calls', () => { - const libInput: MockDirectory = { - 'lib': { - 'base.ts': ` - export class AClass { - constructor(arg: any) {} + it('should not reexport complex function calls', () => { + const libInput: MockDirectory = { + 'lib': { + 'base.ts': ` + export class AClass { + constructor(arg: any) {} + + static create(arg: any = null): AClass { return new AClass(arg); } + + call(arg: any) {} + } + + export function simple(arg: any) { return [arg]; } + + export const ctor_arg = {}; + export const ctor_call = new AClass(ctor_arg); + + export const static_arg = {}; + export const static_call = AClass.create(static_arg); + + export const complex_arg = {}; + export const complex_call = AClass.create().call(complex_arg); + + export const simple_arg = {}; + export const simple_call = simple(simple_arg); + ` + } + }; + const appInput: MockDirectory = { + 'app': { + 'main.ts': ` + import {ctor_call, static_call, complex_call, simple_call} from '../lib/base'; + + export const calls = [ctor_call, static_call, complex_call, simple_call]; + `, + } + }; - static create(arg: any = null): AClass { return new AClass(arg); } + const {outDir: libOutDir} = compile( + [libInput, angularSummaryFiles], + {useSummaries: true, createExternalSymbolFactoryReexports: true}); + const {genFiles: appGenFiles} = compile( + [appInput, libOutDir, angularSummaryFiles], + {useSummaries: true, createExternalSymbolFactoryReexports: true}); + const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; + const appNgFactoryTs = toTypeScript(appNgFactory); - call(arg: any) {} - } + // metadata of ctor calls is preserved, so we reexport the argument + expect(appNgFactoryTs).toContain('ctor_arg'); + expect(appNgFactoryTs).toContain('ctor_call'); - export function simple(arg: any) { return [arg]; } + // metadata of static calls is preserved, so we reexport the argument + expect(appNgFactoryTs).toContain('static_arg'); + expect(appNgFactoryTs).toContain('AClass'); + expect(appNgFactoryTs).toContain('static_call'); - export const ctor_arg = {}; - export const ctor_call = new AClass(ctor_arg); + // metadata of complex calls is elided, so we don't reexport the argument + expect(appNgFactoryTs).not.toContain('complex_arg'); + expect(appNgFactoryTs).toContain('complex_call'); - export const static_arg = {}; - export const static_call = AClass.create(static_arg); + // metadata of simple calls is preserved, so we reexport the argument + expect(appNgFactoryTs).toContain('simple_arg'); + expect(appNgFactoryTs).toContain('simple_call'); + }); - export const complex_arg = {}; - export const complex_call = AClass.create().call(complex_arg); + it('should not reexport already exported symbols except for lowered symbols', () => { + const libInput: MockDirectory = { + 'lib': { + 'base.ts': ` + export const exportedVar = 1; - export const simple_arg = {}; - export const simple_call = simple(simple_arg); - ` - } - }; - const appInput: MockDirectory = { - 'app': { - 'main.ts': ` - import {ctor_call, static_call, complex_call, simple_call} from '../lib/base'; + // A symbol introduced by lowering expressions + export const ɵ1 = 'lowered symbol'; + ` + } + }; + const appInput: MockDirectory = { + 'app': { + 'main.ts': `export * from '../lib/base';`, + } + }; - export const calls = [ctor_call, static_call, complex_call, simple_call]; - `, - } - }; + const {outDir: libOutDir} = compile( + [libInput, angularSummaryFiles], + {useSummaries: true, createExternalSymbolFactoryReexports: true}); + const {genFiles: appGenFiles} = compile( + [appInput, libOutDir, angularSummaryFiles], + {useSummaries: true, createExternalSymbolFactoryReexports: true}); + const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; + const appNgFactoryTs = toTypeScript(appNgFactory); - const {outDir: libOutDir} = compile([libInput, angularSummaryFiles], {useSummaries: true}); - const {genFiles: appGenFiles} = - compile([appInput, libOutDir, angularSummaryFiles], {useSummaries: true}); - const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; - const appNgFactoryTs = toTypeScript(appNgFactory); + // we don't need to reexport exported symbols via the .ngfactory + // as we can refer to them via the reexport. + expect(appNgFactoryTs).not.toContain('exportedVar'); - // metadata of ctor calls is preserved, so we reexport the argument - expect(appNgFactoryTs).toContain('ctor_arg'); - expect(appNgFactoryTs).toContain('ctor_call'); - - // metadata of static calls is preserved, so we reexport the argument - expect(appNgFactoryTs).toContain('static_arg'); - expect(appNgFactoryTs).toContain('AClass'); - expect(appNgFactoryTs).toContain('static_call'); - - // metadata of complex calls is elided, so we don't reexport the argument - expect(appNgFactoryTs).not.toContain('complex_arg'); - expect(appNgFactoryTs).toContain('complex_call'); - - // metadata of simple calls is preserved, so we reexport the argument - expect(appNgFactoryTs).toContain('simple_arg'); - expect(appNgFactoryTs).toContain('simple_call'); - }); - - it('should not reexport already exported symbols except for lowered symbols', () => { - const libInput: MockDirectory = { - 'lib': { - 'base.ts': ` - export const exportedVar = 1; - - // A symbol introduced by lowering expressions - export const ɵ1 = 'lowered symbol'; - ` - } - }; - const appInput: MockDirectory = { - 'app': { - 'main.ts': `export * from '../lib/base';`, - } - }; - - const {outDir: libOutDir} = compile([libInput, angularSummaryFiles], {useSummaries: true}); - const {genFiles: appGenFiles} = - compile([appInput, libOutDir, angularSummaryFiles], {useSummaries: true}); - const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; - const appNgFactoryTs = toTypeScript(appNgFactory); - - // we don't need to reexport exported symbols via the .ngfactory - // as we can refer to them via the reexport. - expect(appNgFactoryTs).not.toContain('exportedVar'); - - // although ɵ1 is reexported via `export *`, we still need to reexport it - // via the .ngfactory as tsickle expands `export *` into named exports, - // and doesn't know about our lowered symbols as we introduce them - // after the typecheck phase. - expect(appNgFactoryTs).toContain('ɵ1'); + // although ɵ1 is reexported via `export *`, we still need to reexport it + // via the .ngfactory as tsickle expands `export *` into named exports, + // and doesn't know about our lowered symbols as we introduce them + // after the typecheck phase. + expect(appNgFactoryTs).toContain('ɵ1'); + }); }); }); @@ -741,12 +753,14 @@ describe('compiler (unbundled Angular)', () => { compile([lib1Input, getAngularSummaryFiles()], {useSummaries: true}); const {outDir: lib2OutDir} = compile([lib1OutDir, lib2Input, getAngularSummaryFiles()], {useSummaries: true}); - const {genFiles} = - compile([lib2OutDir, appInput, getAngularSummaryFiles()], {useSummaries: true}); + const {genFiles} = compile( + [lib1OutDir, lib2OutDir, appInput, getAngularSummaryFiles()], {useSummaries: true}); + const mainNgFactory = genFiles.find(gf => gf.srcFileUrl === '/app/main.ts') !; const flags = NodeFlags.TypeDirective | NodeFlags.Component | NodeFlags.OnDestroy; - expect(toTypeScript(mainNgFactory)) - .toContain(`${flags},(null as any),0,i1.Extends,[i2.AParam_2]`); + const mainNgFactorySource = toTypeScript(mainNgFactory); + expect(mainNgFactorySource).toContain(`import * as i2 from '/lib1/base';`); + expect(mainNgFactorySource).toContain(`${flags},(null as any),0,i1.Extends,[i2.AParam]`); }); describe('Injectable', () => { diff --git a/packages/compiler/test/aot/jit_summaries_spec.ts b/packages/compiler/test/aot/jit_summaries_spec.ts index 025aa243ee..08bbdd27df 100644 --- a/packages/compiler/test/aot/jit_summaries_spec.ts +++ b/packages/compiler/test/aot/jit_summaries_spec.ts @@ -18,7 +18,8 @@ describe('aot summaries for jit', () => { angularSummaryFiles = compile(angularFiles, {useSummaries: false, emit: true}).outDir; }); - function compileApp(rootDir: MockDirectory, options: {useSummaries?: boolean} = {}): + function compileApp( + rootDir: MockDirectory, options: {useSummaries?: boolean}& AotCompilerOptions = {}): {genFiles: GeneratedFile[], outDir: MockDirectory} { return compile( [rootDir, options.useSummaries ? angularSummaryFiles : angularFiles], @@ -255,7 +256,7 @@ describe('aot summaries for jit', () => { }); it('should create and use reexports for imported NgModules ' + - 'across compilation units', + 'across compilation units if symbol re-exports are enabled', () => { const lib1In = { 'lib1': { @@ -275,7 +276,10 @@ describe('aot summaries for jit', () => { `, } }; - const {outDir: lib2In, genFiles: lib1Gen} = compileApp(lib1In, {useSummaries: true}); + const {outDir: lib2In, genFiles: lib1Gen} = compileApp(lib1In, { + useSummaries: true, + createExternalSymbolFactoryReexports: true, + }); lib2In['lib2'] = { 'module.ts': ` @@ -292,7 +296,10 @@ describe('aot summaries for jit', () => { export const reexports: any[] = [ reexports_lib1 ]; `, }; - const {outDir: lib3In, genFiles: lib2Gen} = compileApp(lib2In, {useSummaries: true}); + const {outDir: lib3In, genFiles: lib2Gen} = compileApp(lib2In, { + useSummaries: true, + createExternalSymbolFactoryReexports: true, + }); const lib2ModuleNgSummary = lib2Gen.find(f => f.genFileUrl === '/lib2/module.ngsummary.ts') !; @@ -325,7 +332,10 @@ describe('aot summaries for jit', () => { `, }; - const lib3Gen = compileApp(lib3In, {useSummaries: true}).genFiles; + const lib3Gen = compileApp(lib3In, { + useSummaries: true, + createExternalSymbolFactoryReexports: true + }).genFiles; const lib3ModuleNgSummary = lib3Gen.find(f => f.genFileUrl === '/lib3/module.ngsummary.ts') !; const lib3ReexportNgSummary = @@ -349,4 +359,107 @@ describe('aot summaries for jit', () => { .toContain( `export {ReexportModule_2NgSummary as ReexportModule_3NgSummary} from '/lib2/reexport.ngsummary'`); }); + + it('should not create reexports for external symbols imported by NgModules', () => { + const lib1In = { + 'lib1': { + 'module.ts': ` + import { NgModule } from '@angular/core'; + + @NgModule() + export class Lib1Module {}`, + 'reexport.ts': ` + import { NgModule } from '@angular/core'; + + @NgModule() + export class ReexportModule {} + + export const reexports: any[] = [ ReexportModule ];`, + } + }; + const {outDir: lib1Out} = compileApp(lib1In, {useSummaries: true}); + + const lib2In = { + ...lib1Out, + 'lib2': { + 'module.ts': ` + import { NgModule } from '@angular/core'; + import { Lib1Module } from '../lib1/module'; + + @NgModule({ + imports: [Lib1Module] + }) + export class Lib2Module {}`, + 'reexport.ts': ` + import { reexports as reexports_lib1 } from '../lib1/reexport'; + export const reexports: any[] = [ reexports_lib1 ];`, + }, + }; + + const {outDir: lib2Out, genFiles: lib2Gen} = compileApp(lib2In, {useSummaries: true}); + + const lib2ModuleNgSummary = lib2Gen.find(f => f.genFileUrl === '/lib2/module.ngsummary.ts') !; + const lib2ReexportNgSummary = + lib2Gen.find(f => f.genFileUrl === '/lib2/reexport.ngsummary.ts') !; + + // ngsummaries should not add reexports by default for imported NgModules from a direct + // dependency + expect(toTypeScript(lib2ModuleNgSummary)) + .toContain( + `export {Lib1ModuleNgSummary as Lib1ModuleNgSummary} from '/lib1/module.ngsummary'`); + // ngsummaries should not add reexports by default for reexported values from a direct + // dependency. + expect(toTypeScript(lib2ReexportNgSummary)) + .toContain( + `export {ReexportModuleNgSummary as ReexportModuleNgSummary} from '/lib1/reexport.ngsummary'`); + + const lib3In = { + ...lib1Out, + ...lib2Out, + 'lib3': { + 'module.ts': ` + import { NgModule } from '@angular/core'; + import { Lib2Module } from '../lib2/module'; + import { reexports } from '../lib2/reexport'; + + @NgModule({ + imports: [Lib2Module, reexports] + }) + export class Lib3Module {} + `, + 'reexport.ts': ` + import { reexports as reexports_lib2 } from '../lib2/reexport'; + export const reexports: any[] = [ reexports_lib2 ]; + `, + }, + }; + + const lib3Gen = compileApp(lib3In, {useSummaries: true}).genFiles; + const lib3ModuleNgSummary = lib3Gen.find(f => f.genFileUrl === '/lib3/module.ngsummary.ts') !; + const lib3ReexportNgSummary = + lib3Gen.find(f => f.genFileUrl === '/lib3/reexport.ngsummary.ts') !; + + // ngsummary.ts files should use the external symbols which are manually re-exported from + // "lib2" from their original symbol location. With re-exported external symbols this would + // be different because there would be no *direct* dependency on "lib1" at all. + const lib3ModuleNgSummarySource = toTypeScript(lib3ModuleNgSummary); + expect(lib3ModuleNgSummarySource).toContain(`import * as i1 from '/lib1/module';`); + expect(lib3ModuleNgSummarySource).toContain(`import * as i3 from '/lib1/reexport';`); + expect(lib3ModuleNgSummarySource) + .toMatch(/export function Lib3ModuleNgSummary\(\).*modules:\[{reference:i1\.Lib1Module,/s); + expect(lib3ModuleNgSummarySource) + .toMatch(/export function Lib3ModuleNgSummary\(\).*reference:i3\.ReexportModule,/s); + // ngsummaries should re-export all used summaries directly. With external symbol re-exports + // enabled, the the "lib1" summaries would be re-exported through "lib2" in order to avoid + // a *direct* dependency on "lib1". + expect(lib3ModuleNgSummarySource) + .toContain( + `export {Lib1ModuleNgSummary as Lib1ModuleNgSummary} from '/lib1/module.ngsummary';`); + expect(lib3ModuleNgSummarySource) + .toContain( + `export {ReexportModuleNgSummary as ReexportModuleNgSummary} from '/lib1/reexport.ngsummary';`); + expect(toTypeScript(lib3ReexportNgSummary)) + .toContain( + `export {ReexportModuleNgSummary as ReexportModuleNgSummary} from '/lib1/reexport.ngsummary';`); + }); }); diff --git a/packages/compiler/test/aot/summary_resolver_spec.ts b/packages/compiler/test/aot/summary_resolver_spec.ts index 75ad8f4195..d518319c2d 100644 --- a/packages/compiler/test/aot/summary_resolver_spec.ts +++ b/packages/compiler/test/aot/summary_resolver_spec.ts @@ -30,14 +30,15 @@ const EXT = /(\.d)?\.ts$/; summaryResolver = new AotSummaryResolver(host, symbolCache); } - function serialize(symbols: ResolvedStaticSymbol[]): string { + function serialize( + symbols: ResolvedStaticSymbol[], enableExternalSymbolReexports = false): string { // Note: Don't use the top level host / summaryResolver as they might not be created yet const mockSummaryResolver = new MockSummaryResolver([]); const symbolResolver = new StaticSymbolResolver( new MockStaticSymbolResolverHost({}), symbolCache, mockSummaryResolver); return serializeSummaries( 'someFile.ts', createMockOutputContext(), mockSummaryResolver, symbolResolver, - symbols, []) + symbols, [], enableExternalSymbolReexports) .json; } @@ -67,12 +68,12 @@ const EXT = /(\.d)?\.ts$/; expect(summaryResolver.getSymbolsOf('/a.d.ts')).toEqual([asymbol]); }); - it('should fill importAs for deep symbols', () => { + it('should fill importAs for deep symbols if external symbol re-exports are enabled', () => { const libSymbol = symbolCache.get('/lib.d.ts', 'Lib'); const srcSymbol = symbolCache.get('/src.ts', 'Src'); init({ '/src.ngsummary.json': - serialize([{symbol: srcSymbol, metadata: 1}, {symbol: libSymbol, metadata: 2}]) + serialize([{symbol: srcSymbol, metadata: 1}, {symbol: libSymbol, metadata: 2}], true) }); summaryResolver.getSymbolsOf('/src.d.ts'); diff --git a/packages/compiler/test/aot/summary_serializer_spec.ts b/packages/compiler/test/aot/summary_serializer_spec.ts index 26cae7dd97..3410c60921 100644 --- a/packages/compiler/test/aot/summary_serializer_spec.ts +++ b/packages/compiler/test/aot/summary_serializer_spec.ts @@ -317,63 +317,6 @@ import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_res expect(summaries[1].metadata).toBe('someString'); }); - it('should not create "importAs" names for ctor arguments which are types of reexported classes in libraries', - () => { - init(); - const externalSerialized = serializeSummaries( - 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, - [ - { - symbol: symbolCache.get('/tmp/external.ts', 'type'), - metadata: {__symbolic: 'interface'} - }, - { - symbol: symbolCache.get('/tmp/external.ts', 'value'), - metadata: {__symbolic: 'class'} - }, - { - symbol: symbolCache.get('/tmp/external.ts', 'reexportClass'), - metadata: { - __symbolic: 'class', - 'members': { - '__ctor__': [{ - '__symbolic': 'constructor', - 'parameters': [ - symbolCache.get('/tmp/external.ts', 'type'), - symbolCache.get('/tmp/external.ts', 'value'), - ] - }] - } - - } - }, - ], - []); - expect(externalSerialized.exportAs).toEqual([]); - init({ - '/tmp/external.ngsummary.json': externalSerialized.json, - }); - const serialized = serializeSummaries( - 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{ - symbol: symbolCache.get('/tmp/test.ts', 'mainClass'), - metadata: symbolCache.get('/tmp/external.d.ts', 'reexportClass'), - }], - []); - const importAs = - deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json) - .importAs; - expect(importAs).toEqual([ - { - symbol: symbolCache.get('/tmp/external.d.ts', 'reexportClass'), - importAs: symbolCache.get('/tmp/test.d.ts', 'mainClass'), - }, - { - symbol: symbolCache.get('/tmp/external.d.ts', 'value'), - importAs: symbolCache.get('someFile.ngfactory.d.ts', 'value_3'), - } - ]); - }); - it('should use existing reexports for "importAs" for symbols of libraries', () => { init(); const externalSerialized = serializeSummaries( @@ -406,31 +349,6 @@ import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_res }]); }); - it('should create reexports in the ngfactory for symbols of libraries', () => { - init(); - const serialized = serializeSummaries( - 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{ - symbol: symbolCache.get('/tmp/test.ts', 'main'), - metadata: [ - symbolCache.get('/tmp/external.d.ts', 'lib'), - symbolCache.get('/tmp/external.d.ts', 'lib', ['someMember']), - ] - }], - []); - // Note: no entry for the symbol with members! - expect(serialized.exportAs).toEqual([ - {symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), exportAs: 'lib_1'} - ]); - - const deserialized = - deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json); - // Note: no entry for the symbol with members! - expect(deserialized.importAs).toEqual([{ - symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), - importAs: symbolCache.get('someFile.ngfactory.d.ts', 'lib_1') - }]); - }); - describe('with resolved symbols', () => { it('should be able to serialize a call', () => { init(); @@ -466,5 +384,141 @@ import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_res expect(serialized.json).not.toContain('error'); }); }); + + + describe('symbol re-exports enabled', () => { + + it('should not create "importAs" names for ctor arguments which are types of reexported classes in libraries', + () => { + init(); + const externalSerialized = serializeSummaries( + 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, + [ + { + symbol: symbolCache.get('/tmp/external.ts', 'type'), + metadata: {__symbolic: 'interface'} + }, + { + symbol: symbolCache.get('/tmp/external.ts', 'value'), + metadata: {__symbolic: 'class'} + }, + { + symbol: symbolCache.get('/tmp/external.ts', 'reexportClass'), + metadata: { + __symbolic: 'class', + 'members': { + '__ctor__': [{ + '__symbolic': 'constructor', + 'parameters': [ + symbolCache.get('/tmp/external.ts', 'type'), + symbolCache.get('/tmp/external.ts', 'value'), + ] + }] + } + + } + }, + ], + [], true); + expect(externalSerialized.exportAs).toEqual([]); + init({ + '/tmp/external.ngsummary.json': externalSerialized.json, + }); + const serialized = serializeSummaries( + 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{ + symbol: symbolCache.get('/tmp/test.ts', 'mainClass'), + metadata: symbolCache.get('/tmp/external.d.ts', 'reexportClass'), + }], + [], true); + const importAs = + deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json) + .importAs; + expect(importAs).toEqual([ + { + symbol: symbolCache.get('/tmp/external.d.ts', 'reexportClass'), + importAs: symbolCache.get('/tmp/test.d.ts', 'mainClass'), + }, + { + symbol: symbolCache.get('/tmp/external.d.ts', 'value'), + importAs: symbolCache.get('someFile.ngfactory.d.ts', 'value_3'), + } + ]); + }); + + it('should create reexports in the ngfactory for symbols of libraries', () => { + init(); + const serialized = serializeSummaries( + 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{ + symbol: symbolCache.get('/tmp/test.ts', 'main'), + metadata: [ + symbolCache.get('/tmp/external.d.ts', 'lib'), + symbolCache.get('/tmp/external.d.ts', 'lib', ['someMember']), + ] + }], + [], true); + // Note: no entry for the symbol with members! + expect(serialized.exportAs).toEqual([ + {symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), exportAs: 'lib_1'} + ]); + + const deserialized = + deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json); + // Note: no entry for the symbol with members! + expect(deserialized.importAs).toEqual([{ + symbol: symbolCache.get('/tmp/external.d.ts', 'lib'), + importAs: symbolCache.get('someFile.ngfactory.d.ts', 'lib_1') + }]); + }); + }); + + it('should use existing reexports for "importAs" for symbols of libraries', () => { + init(); + const externalSerialized = serializeSummaries( + 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, + [ + {symbol: symbolCache.get('/tmp/external.ts', 'value'), metadata: 'aValue'}, + { + symbol: symbolCache.get('/tmp/external.ts', 'reexportValue'), + metadata: symbolCache.get('/tmp/external.ts', 'value') + }, + ], + [], false); + expect(externalSerialized.exportAs).toEqual([]); + init({ + '/tmp/external.ngsummary.json': externalSerialized.json, + }); + const serialized = serializeSummaries( + 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{ + symbol: symbolCache.get('/tmp/test.ts', 'mainValue'), + metadata: symbolCache.get('/tmp/external.d.ts', 'reexportValue'), + }], + []); + expect(serialized.exportAs).toEqual([]); + const importAs = + deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json) + .importAs; + expect(importAs).toEqual([{ + symbol: symbolCache.get('/tmp/external.d.ts', 'value'), + importAs: symbolCache.get('/tmp/test.d.ts', 'mainValue'), + }]); + }); + + it('should not create reexports in the ngfactory for external symbols', () => { + init(); + const serialized = serializeSummaries( + 'someFile.ts', createMockOutputContext(), summaryResolver, symbolResolver, [{ + symbol: symbolCache.get('/tmp/test.ts', 'main'), + metadata: [ + symbolCache.get('/tmp/external.d.ts', 'lib'), + symbolCache.get('/tmp/external.d.ts', 'lib', ['someMember']), + ] + }], + [], false); + expect(serialized.exportAs.length).toBe(0, 'Expected no external symbols to be re-exported.'); + const deserialized = + deserializeSummaries(symbolCache, summaryResolver, 'someFile.d.ts', serialized.json); + expect(deserialized.importAs.length) + .toBe(0, 'Expected no symbols that can be imported from a re-exported location'); + }); }); } diff --git a/packages/compiler/test/compiler_facade_interface_spec.ts b/packages/compiler/test/compiler_facade_interface_spec.ts index 070131f036..cb40b6711c 100644 --- a/packages/compiler/test/compiler_facade_interface_spec.ts +++ b/packages/compiler/test/compiler_facade_interface_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import * as core from '../../core/src/render3/jit/compiler_facade_interface'; +import * as core from '../../core/src/compiler/compiler_facade_interface'; import {R3ResolvedDependencyType} from '../public_api'; import * as compiler from '../src/compiler_facade_interface'; diff --git a/packages/compiler/test/i18n/extractor_merger_spec.ts b/packages/compiler/test/i18n/extractor_merger_spec.ts index 7d8f489436..697d8fedae 100644 --- a/packages/compiler/test/i18n/extractor_merger_spec.ts +++ b/packages/compiler/test/i18n/extractor_merger_spec.ts @@ -501,7 +501,7 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; function parseHtml(html: string): html.Node[] { const htmlParser = new HtmlParser(); - const parseResult = htmlParser.parse(html, 'extractor spec', true); + const parseResult = htmlParser.parse(html, 'extractor spec', {tokenizeExpansionForms: true}); if (parseResult.errors.length > 1) { throw new Error(`unexpected parse errors: ${parseResult.errors.join('\n')}`); } diff --git a/packages/compiler/test/i18n/i18n_parser_spec.ts b/packages/compiler/test/i18n/i18n_parser_spec.ts index 4b9994ee27..b71dc0a22f 100644 --- a/packages/compiler/test/i18n/i18n_parser_spec.ts +++ b/packages/compiler/test/i18n/i18n_parser_spec.ts @@ -330,7 +330,7 @@ export function _extractMessages( html: string, implicitTags: string[] = [], implicitAttrs: {[k: string]: string[]} = {}): Message[] { const htmlParser = new HtmlParser(); - const parseResult = htmlParser.parse(html, 'extractor spec', true); + const parseResult = htmlParser.parse(html, 'extractor spec', {tokenizeExpansionForms: true}); if (parseResult.errors.length > 1) { throw Error(`unexpected parse errors: ${parseResult.errors.join('\n')}`); } diff --git a/packages/compiler/test/ml_parser/ast_serializer_spec.ts b/packages/compiler/test/ml_parser/ast_serializer_spec.ts index b880e37909..055b0a7a1c 100644 --- a/packages/compiler/test/ml_parser/ast_serializer_spec.ts +++ b/packages/compiler/test/ml_parser/ast_serializer_spec.ts @@ -35,13 +35,13 @@ import {serializeNodes} from './util/util'; it('should support expansion', () => { const html = '{number, plural, =0 {none} =1 {one} other {many}}'; - const ast = parser.parse(html, 'url', true); + const ast = parser.parse(html, 'url', {tokenizeExpansionForms: true}); expect(serializeNodes(ast.rootNodes)).toEqual([html]); }); it('should support comment', () => { const html = ''; - const ast = parser.parse(html, 'url', true); + const ast = parser.parse(html, 'url', {tokenizeExpansionForms: true}); expect(serializeNodes(ast.rootNodes)).toEqual([html]); }); @@ -51,9 +51,9 @@ import {serializeNodes} from './util/util';

    {number, plural, =0 {{sex, select, other {?}}}} -

    +

    `; - const ast = parser.parse(html, 'url', true); + const ast = parser.parse(html, 'url', {tokenizeExpansionForms: true}); expect(serializeNodes(ast.rootNodes)).toEqual([html]); }); }); diff --git a/packages/compiler/test/ml_parser/html_parser_spec.ts b/packages/compiler/test/ml_parser/html_parser_spec.ts index 23bbc0168c..573001455b 100644 --- a/packages/compiler/test/ml_parser/html_parser_spec.ts +++ b/packages/compiler/test/ml_parser/html_parser_spec.ts @@ -300,7 +300,7 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe it('should parse out expansion forms', () => { const parsed = parser.parse( `
    before{messages.length, plural, =0 {You have no messages} =1 {One {{message}}}}after
    `, - 'TestComp', true); + 'TestComp', {tokenizeExpansionForms: true}); expect(humanizeDom(parsed)).toEqual([ [html.Element, 'div', 0], @@ -324,8 +324,9 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe }); it('should parse out expansion forms', () => { - const parsed = - parser.parse(`
    {a, plural, =0 {b}}
    `, 'TestComp', true); + const parsed = parser.parse( + `
    {a, plural, =0 {b}}
    `, 'TestComp', + {tokenizeExpansionForms: true}); expect(humanizeDom(parsed)).toEqual([ [html.Element, 'div', 0], @@ -337,7 +338,8 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe it('should parse out nested expansion forms', () => { const parsed = parser.parse( - `{messages.length, plural, =0 { {p.gender, select, male {m}} }}`, 'TestComp', true); + `{messages.length, plural, =0 { {p.gender, select, male {m}} }}`, 'TestComp', + {tokenizeExpansionForms: true}); expect(humanizeDom(parsed)).toEqual([ [html.Expansion, 'messages.length', 'plural', 0], [html.ExpansionCase, '=0', 1], @@ -353,26 +355,31 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe }); it('should error when expansion form is not closed', () => { - const p = parser.parse(`{messages.length, plural, =0 {one}`, 'TestComp', true); + const p = parser.parse( + `{messages.length, plural, =0 {one}`, 'TestComp', {tokenizeExpansionForms: true}); expect(humanizeErrors(p.errors)).toEqual([ [null, 'Invalid ICU message. Missing \'}\'.', '0:34'] ]); }); it('should support ICU expressions with cases that contain numbers', () => { - const p = parser.parse(`{sex, select, male {m} female {f} 0 {other}}`, 'TestComp', true); + const p = parser.parse( + `{sex, select, male {m} female {f} 0 {other}}`, 'TestComp', + {tokenizeExpansionForms: true}); expect(p.errors.length).toEqual(0); }); it('should error when expansion case is not closed', () => { - const p = parser.parse(`{messages.length, plural, =0 {one`, 'TestComp', true); + const p = parser.parse( + `{messages.length, plural, =0 {one`, 'TestComp', {tokenizeExpansionForms: true}); expect(humanizeErrors(p.errors)).toEqual([ [null, 'Invalid ICU message. Missing \'}\'.', '0:29'] ]); }); it('should error when invalid html in the case', () => { - const p = parser.parse(`{messages.length, plural, =0 {}`, 'TestComp', true); + const p = parser.parse( + `{messages.length, plural, =0 {}`, 'TestComp', {tokenizeExpansionForms: true}); expect(humanizeErrors(p.errors)).toEqual([ ['b', 'Only void and foreign elements can be self closed "b"', '0:30'] ]); @@ -404,8 +411,9 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe }); it('should support expansion form', () => { - expect(humanizeDomSourceSpans( - parser.parse('
    {count, plural, =0 {msg}}
    ', 'TestComp', true))) + expect(humanizeDomSourceSpans(parser.parse( + '
    {count, plural, =0 {msg}}
    ', 'TestComp', + {tokenizeExpansionForms: true}))) .toEqual([ [html.Element, 'div', 0, '
    '], [html.Expansion, 'count', 'plural', 1, '{count, plural, =0 {msg}}'], @@ -421,8 +429,15 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe it('should report a value span for an attribute with a value', () => { const ast = parser.parse('
    ', 'TestComp'); const attr = (ast.rootNodes[0] as html.Element).attrs[0]; + expect(attr.valueSpan !.start.offset).toEqual(10); + expect(attr.valueSpan !.end.offset).toEqual(12); + }); + + it('should report a value span for an unquoted attribute value', () => { + const ast = parser.parse('
    ', 'TestComp'); + const attr = (ast.rootNodes[0] as html.Element).attrs[0]; expect(attr.valueSpan !.start.offset).toEqual(9); - expect(attr.valueSpan !.end.offset).toEqual(13); + expect(attr.valueSpan !.end.offset).toEqual(11); }); }); diff --git a/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts b/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts index e74e1a4d25..0682030852 100644 --- a/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts +++ b/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts @@ -17,7 +17,7 @@ import {humanizeNodes} from './ast_spec_utils'; describe('Expander', () => { function expand(template: string): ExpansionResult { const htmlParser = new HtmlParser(); - const res = htmlParser.parse(template, 'url', true); + const res = htmlParser.parse(template, 'url', {tokenizeExpansionForms: true}); return expandNodes(res.rootNodes); } diff --git a/packages/compiler/test/ml_parser/lexer_spec.ts b/packages/compiler/test/ml_parser/lexer_spec.ts index f2fe62a1d5..68dcf391fe 100644 --- a/packages/compiler/test/ml_parser/lexer_spec.ts +++ b/packages/compiler/test/ml_parser/lexer_spec.ts @@ -55,6 +55,28 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u }); }); + describe('content ranges', () => { + it('should only process the text within the range', () => { + expect(tokenizeAndHumanizeSourceSpans( + 'pre 1\npre 2\npre 3 `line 1\nline 2\nline 3` post 1\n post 2\n post 3', + {range: {startPos: 19, startLine: 2, startCol: 7, endPos: 39}})) + .toEqual([ + [lex.TokenType.TEXT, 'line 1\nline 2\nline 3'], + [lex.TokenType.EOF, ''], + ]); + }); + + it('should take into account preceding (non-processed) lines and columns', () => { + expect(tokenizeAndHumanizeLineColumn( + 'pre 1\npre 2\npre 3 `line 1\nline 2\nline 3` post 1\n post 2\n post 3', + {range: {startPos: 19, startLine: 2, startCol: 7, endPos: 39}})) + .toEqual([ + [lex.TokenType.TEXT, '2:7'], + [lex.TokenType.EOF, '4:6'], + ]); + }); + }); + describe('comments', () => { it('should parse comments', () => { expect(tokenizeAndHumanizeParts('')).toEqual([ @@ -216,11 +238,17 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u expect(tokenizeAndHumanizeParts('')).toEqual([ [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, '{{v}}'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_NAME, null, 'b'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, 's{{m}}e'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_NAME, null, 'c'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, 's{{m//c}}e'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.TAG_OPEN_END], [lex.TokenType.EOF], ]); @@ -248,7 +276,9 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u expect(tokenizeAndHumanizeParts('')).toEqual([ [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '\''], [lex.TokenType.ATTR_VALUE, 'b'], + [lex.TokenType.ATTR_QUOTE, '\''], [lex.TokenType.TAG_OPEN_END], [lex.TokenType.EOF], ]); @@ -258,7 +288,9 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u expect(tokenizeAndHumanizeParts('')).toEqual([ [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, 'b'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.TAG_OPEN_END], [lex.TokenType.EOF], ]); @@ -288,7 +320,9 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u expect(tokenizeAndHumanizeParts('')).toEqual([ [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, 'AA'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.TAG_OPEN_END], [lex.TokenType.EOF], ]); @@ -298,9 +332,13 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u expect(tokenizeAndHumanizeParts('')).toEqual([ [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, '&'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_NAME, null, 'b'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, 'c&&d'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.TAG_OPEN_END], [lex.TokenType.EOF], ]); @@ -310,7 +348,9 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u expect(tokenizeAndHumanizeParts('')).toEqual([ [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.ATTR_VALUE, 'b && c &'], + [lex.TokenType.ATTR_QUOTE, '"'], [lex.TokenType.TAG_OPEN_END], [lex.TokenType.EOF], ]); @@ -320,7 +360,9 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u expect(tokenizeAndHumanizeParts('')).toEqual([ [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '\''], [lex.TokenType.ATTR_VALUE, 't\ne\ns\nt'], + [lex.TokenType.ATTR_QUOTE, '\''], [lex.TokenType.TAG_OPEN_END], [lex.TokenType.EOF], ]); @@ -443,10 +485,11 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u }); it('should parse interpolation with custom markers', () => { - expect(tokenizeAndHumanizeParts('{% a %}', null !, {start: '{%', end: '%}'})).toEqual([ - [lex.TokenType.TEXT, '{% a %}'], - [lex.TokenType.EOF], - ]); + expect(tokenizeAndHumanizeParts('{% a %}', {interpolationConfig: {start: '{%', end: '%}'}})) + .toEqual([ + [lex.TokenType.TEXT, '{% a %}'], + [lex.TokenType.EOF], + ]); }); it('should handle CR & LF', () => { @@ -524,13 +567,15 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u }); it('should treat expansion form as text when they are not parsed', () => { - expect(tokenizeAndHumanizeParts('{a, b, =4 {c}}', false)).toEqual([ - [lex.TokenType.TAG_OPEN_START, null, 'span'], - [lex.TokenType.TAG_OPEN_END], - [lex.TokenType.TEXT, '{a, b, =4 {c}}'], - [lex.TokenType.TAG_CLOSE, null, 'span'], - [lex.TokenType.EOF], - ]); + expect(tokenizeAndHumanizeParts( + '{a, b, =4 {c}}', {tokenizeExpansionForms: false})) + .toEqual([ + [lex.TokenType.TAG_OPEN_START, null, 'span'], + [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.TEXT, '{a, b, =4 {c}}'], + [lex.TokenType.TAG_CLOSE, null, 'span'], + [lex.TokenType.EOF], + ]); }); }); @@ -641,7 +686,9 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u describe('expansion forms', () => { it('should parse an expansion form', () => { - expect(tokenizeAndHumanizeParts('{one.two, three, =4 {four} =5 {five} foo {bar} }', true)) + expect( + tokenizeAndHumanizeParts( + '{one.two, three, =4 {four} =5 {five} foo {bar} }', {tokenizeExpansionForms: true})) .toEqual([ [lex.TokenType.EXPANSION_FORM_START], [lex.TokenType.RAW_TEXT, 'one.two'], @@ -664,75 +711,84 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u }); it('should parse an expansion form with text elements surrounding it', () => { - expect(tokenizeAndHumanizeParts('before{one.two, three, =4 {four}}after', true)).toEqual([ - [lex.TokenType.TEXT, 'before'], - [lex.TokenType.EXPANSION_FORM_START], - [lex.TokenType.RAW_TEXT, 'one.two'], - [lex.TokenType.RAW_TEXT, 'three'], - [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], - [lex.TokenType.EXPANSION_CASE_EXP_START], - [lex.TokenType.TEXT, 'four'], - [lex.TokenType.EXPANSION_CASE_EXP_END], - [lex.TokenType.EXPANSION_FORM_END], - [lex.TokenType.TEXT, 'after'], - [lex.TokenType.EOF], - ]); + expect(tokenizeAndHumanizeParts( + 'before{one.two, three, =4 {four}}after', {tokenizeExpansionForms: true})) + .toEqual([ + [lex.TokenType.TEXT, 'before'], + [lex.TokenType.EXPANSION_FORM_START], + [lex.TokenType.RAW_TEXT, 'one.two'], + [lex.TokenType.RAW_TEXT, 'three'], + [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], + [lex.TokenType.EXPANSION_CASE_EXP_START], + [lex.TokenType.TEXT, 'four'], + [lex.TokenType.EXPANSION_CASE_EXP_END], + [lex.TokenType.EXPANSION_FORM_END], + [lex.TokenType.TEXT, 'after'], + [lex.TokenType.EOF], + ]); }); it('should parse an expansion form as a tag single child', () => { - expect(tokenizeAndHumanizeParts('
    {a, b, =4 {c}}
    ', true)).toEqual([ - [lex.TokenType.TAG_OPEN_START, null, 'div'], - [lex.TokenType.TAG_OPEN_END], - [lex.TokenType.TAG_OPEN_START, null, 'span'], - [lex.TokenType.TAG_OPEN_END], - [lex.TokenType.EXPANSION_FORM_START], - [lex.TokenType.RAW_TEXT, 'a'], - [lex.TokenType.RAW_TEXT, 'b'], - [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], - [lex.TokenType.EXPANSION_CASE_EXP_START], - [lex.TokenType.TEXT, 'c'], - [lex.TokenType.EXPANSION_CASE_EXP_END], - [lex.TokenType.EXPANSION_FORM_END], - [lex.TokenType.TAG_CLOSE, null, 'span'], - [lex.TokenType.TAG_CLOSE, null, 'div'], - [lex.TokenType.EOF], - ]); + expect(tokenizeAndHumanizeParts( + '
    {a, b, =4 {c}}
    ', {tokenizeExpansionForms: true})) + .toEqual([ + [lex.TokenType.TAG_OPEN_START, null, 'div'], + [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.TAG_OPEN_START, null, 'span'], + [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.EXPANSION_FORM_START], + [lex.TokenType.RAW_TEXT, 'a'], + [lex.TokenType.RAW_TEXT, 'b'], + [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], + [lex.TokenType.EXPANSION_CASE_EXP_START], + [lex.TokenType.TEXT, 'c'], + [lex.TokenType.EXPANSION_CASE_EXP_END], + [lex.TokenType.EXPANSION_FORM_END], + [lex.TokenType.TAG_CLOSE, null, 'span'], + [lex.TokenType.TAG_CLOSE, null, 'div'], + [lex.TokenType.EOF], + ]); }); it('should parse an expansion forms with elements in it', () => { - expect(tokenizeAndHumanizeParts('{one.two, three, =4 {four a}}', true)).toEqual([ - [lex.TokenType.EXPANSION_FORM_START], - [lex.TokenType.RAW_TEXT, 'one.two'], - [lex.TokenType.RAW_TEXT, 'three'], - [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], - [lex.TokenType.EXPANSION_CASE_EXP_START], - [lex.TokenType.TEXT, 'four '], - [lex.TokenType.TAG_OPEN_START, null, 'b'], - [lex.TokenType.TAG_OPEN_END], - [lex.TokenType.TEXT, 'a'], - [lex.TokenType.TAG_CLOSE, null, 'b'], - [lex.TokenType.EXPANSION_CASE_EXP_END], - [lex.TokenType.EXPANSION_FORM_END], - [lex.TokenType.EOF], - ]); + expect(tokenizeAndHumanizeParts( + '{one.two, three, =4 {four a}}', {tokenizeExpansionForms: true})) + .toEqual([ + [lex.TokenType.EXPANSION_FORM_START], + [lex.TokenType.RAW_TEXT, 'one.two'], + [lex.TokenType.RAW_TEXT, 'three'], + [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], + [lex.TokenType.EXPANSION_CASE_EXP_START], + [lex.TokenType.TEXT, 'four '], + [lex.TokenType.TAG_OPEN_START, null, 'b'], + [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.TEXT, 'a'], + [lex.TokenType.TAG_CLOSE, null, 'b'], + [lex.TokenType.EXPANSION_CASE_EXP_END], + [lex.TokenType.EXPANSION_FORM_END], + [lex.TokenType.EOF], + ]); }); it('should parse an expansion forms containing an interpolation', () => { - expect(tokenizeAndHumanizeParts('{one.two, three, =4 {four {{a}}}}', true)).toEqual([ - [lex.TokenType.EXPANSION_FORM_START], - [lex.TokenType.RAW_TEXT, 'one.two'], - [lex.TokenType.RAW_TEXT, 'three'], - [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], - [lex.TokenType.EXPANSION_CASE_EXP_START], - [lex.TokenType.TEXT, 'four {{a}}'], - [lex.TokenType.EXPANSION_CASE_EXP_END], - [lex.TokenType.EXPANSION_FORM_END], - [lex.TokenType.EOF], - ]); + expect(tokenizeAndHumanizeParts( + '{one.two, three, =4 {four {{a}}}}', {tokenizeExpansionForms: true})) + .toEqual([ + [lex.TokenType.EXPANSION_FORM_START], + [lex.TokenType.RAW_TEXT, 'one.two'], + [lex.TokenType.RAW_TEXT, 'three'], + [lex.TokenType.EXPANSION_CASE_VALUE, '=4'], + [lex.TokenType.EXPANSION_CASE_EXP_START], + [lex.TokenType.TEXT, 'four {{a}}'], + [lex.TokenType.EXPANSION_CASE_EXP_END], + [lex.TokenType.EXPANSION_FORM_END], + [lex.TokenType.EOF], + ]); }); it('should parse nested expansion forms', () => { - expect(tokenizeAndHumanizeParts(`{one.two, three, =4 { {xx, yy, =x {one}} }}`, true)) + expect(tokenizeAndHumanizeParts( + `{one.two, three, =4 { {xx, yy, =x {one}} }}`, {tokenizeExpansionForms: true})) .toEqual([ [lex.TokenType.EXPANSION_FORM_START], [lex.TokenType.RAW_TEXT, 'one.two'], @@ -757,11 +813,12 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u describe('errors', () => { it('should report unescaped "{" on error', () => { - expect(tokenizeAndHumanizeErrors(`

    before { after

    `, true)).toEqual([[ - lex.TokenType.RAW_TEXT, - `Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`, - '0:21', - ]]); + expect(tokenizeAndHumanizeErrors(`

    before { after

    `, {tokenizeExpansionForms: true})) + .toEqual([[ + lex.TokenType.RAW_TEXT, + `Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`, + '0:21', + ]]); }); it('should include 2 lines of context in message', () => { @@ -787,14 +844,276 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u }); }); + describe('(processing escaped strings)', () => { + it('should unescape standard escape sequences', () => { + expect(tokenizeAndHumanizeParts('\\\' \\\' \\\'', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\' \' \''], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\" \\" \\"', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\" \" \"'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\` \\` \\`', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\` \` \`'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\\\ \\\\ \\\\', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\\ \\ \\'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\n \\n \\n', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\n \n \n'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\r \\r \\r', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\n \n \n'], // post processing converts `\r` to `\n` + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\v \\v \\v', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\v \v \v'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\t \\t \\t', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\t \t \t'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\b \\b \\b', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\b \b \b'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\f \\f \\f', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\f \f \f'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts( + '\\\' \\" \\` \\\\ \\n \\r \\v \\t \\b \\f', {escapedString: true})) + .toEqual([ + [lex.TokenType.TEXT, '\' \" \` \\ \n \n \v \t \b \f'], + [lex.TokenType.EOF], + + ]); + }); + + it('should unescape null sequences', () => { + expect(tokenizeAndHumanizeParts('\\0', {escapedString: true})).toEqual([ + [lex.TokenType.EOF], + ]); + // \09 is not an octal number so the \0 is taken as EOF + expect(tokenizeAndHumanizeParts('\\09', {escapedString: true})).toEqual([ + [lex.TokenType.EOF], + ]); + }); + + it('should unescape octal sequences', () => { + // \19 is read as an octal `\1` followed by a normal char `9` + // \1234 is read as an octal `\123` followed by a normal char `4` + // \999 is not an octal number so its backslash just gets removed. + expect(tokenizeAndHumanizeParts( + '\\001 \\01 \\1 \\12 \\223 \\19 \\2234 \\999', {escapedString: true})) + .toEqual([ + [lex.TokenType.TEXT, '\x01 \x01 \x01 \x0A \x93 \x019 \x934 999'], + [lex.TokenType.EOF], + ]); + }); + + it('should unescape hex sequences', () => { + expect(tokenizeAndHumanizeParts('\\x12 \\x4F \\xDC', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\x12 \x4F \xDC'], + [lex.TokenType.EOF], + ]); + }); + + it('should report an error on an invalid hex sequence', () => { + expect(tokenizeAndHumanizeErrors('\\xGG', {escapedString: true})).toEqual([ + [null, 'Invalid hexadecimal escape sequence', '0:2'] + ]); + + expect(tokenizeAndHumanizeErrors('abc \\x xyz', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, 'Invalid hexadecimal escape sequence', '0:6'] + ]); + + expect(tokenizeAndHumanizeErrors('abc\\x', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, 'Unexpected character "EOF"', '0:5'] + ]); + }); + + it('should unescape fixed length Unicode sequences', () => { + expect(tokenizeAndHumanizeParts('\\u0123 \\uABCD', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, '\u0123 \uABCD'], + [lex.TokenType.EOF], + ]); + }); + + it('should error on an invalid fixed length Unicode sequence', () => { + expect(tokenizeAndHumanizeErrors('\\uGGGG', {escapedString: true})).toEqual([ + [null, 'Invalid hexadecimal escape sequence', '0:2'] + ]); + }); + + it('should unescape variable length Unicode sequences', () => { + expect(tokenizeAndHumanizeParts( + '\\u{01} \\u{ABC} \\u{1234} \\u{123AB}', {escapedString: true})) + .toEqual([ + [lex.TokenType.TEXT, '\u{01} \u{ABC} \u{1234} \u{123AB}'], + [lex.TokenType.EOF], + ]); + }); + + it('should error on an invalid variable length Unicode sequence', () => { + expect(tokenizeAndHumanizeErrors('\\u{GG}', {escapedString: true})).toEqual([ + [null, 'Invalid hexadecimal escape sequence', '0:3'] + ]); + }); + + it('should unescape line continuations', () => { + expect(tokenizeAndHumanizeParts('abc\\\ndef', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, 'abcdef'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeParts('\\\nx\\\ny\\\n', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, 'xy'], + [lex.TokenType.EOF], + ]); + }); + + it('should remove backslash from "non-escape" sequences', () => { + expect(tokenizeAndHumanizeParts('\a \g \~', {escapedString: true})).toEqual([ + [lex.TokenType.TEXT, 'a g ~'], + [lex.TokenType.EOF], + ]); + }); + + it('should unescape sequences in plain text', () => { + expect(tokenizeAndHumanizeParts('abc\ndef\\nghi\\tjkl\\`\\\'\\"mno', {escapedString: true})) + .toEqual([ + [lex.TokenType.TEXT, 'abc\ndef\nghi\tjkl`\'"mno'], + [lex.TokenType.EOF], + ]); + }); + + it('should unescape sequences in raw text', () => { + expect(tokenizeAndHumanizeParts( + '', {escapedString: true})) + .toEqual([ + [lex.TokenType.TAG_OPEN_START, null, 'script'], + [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.RAW_TEXT, 'abc\ndef\nghi\tjkl`\'"mno'], + [lex.TokenType.TAG_CLOSE, null, 'script'], + [lex.TokenType.EOF], + ]); + }); + + it('should unescape sequences in escapable raw text', () => { + expect(tokenizeAndHumanizeParts( + 'abc\ndef\\nghi\\tjkl\\`\\\'\\"mno', {escapedString: true})) + .toEqual([ + [lex.TokenType.TAG_OPEN_START, null, 'title'], + [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.ESCAPABLE_RAW_TEXT, 'abc\ndef\nghi\tjkl`\'"mno'], + [lex.TokenType.TAG_CLOSE, null, 'title'], + [lex.TokenType.EOF], + ]); + }); + + it('should parse over escape sequences in tag definitions', () => { + expect(tokenizeAndHumanizeParts('', {escapedString: true})) + .toEqual([ + [lex.TokenType.TAG_OPEN_START, null, 't'], + [lex.TokenType.ATTR_NAME, null, 'a'], + [lex.TokenType.ATTR_QUOTE, '"'], + [lex.TokenType.ATTR_VALUE, 'b'], + [lex.TokenType.ATTR_QUOTE, '"'], + [lex.TokenType.ATTR_NAME, null, 'c'], + [lex.TokenType.ATTR_QUOTE, '\''], + [lex.TokenType.ATTR_VALUE, 'd'], + [lex.TokenType.ATTR_QUOTE, '\''], + [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.EOF], + ]); + }); + + it('should tokenize the correct span when there are escape sequences', () => { + const text = + 'selector: "app-root",\ntemplate: "line 1\\n\\"line 2\\"\\nline 3",\ninputs: []'; + const range = { + startPos: 33, + startLine: 1, + startCol: 10, + endPos: 59, + }; + expect(tokenizeAndHumanizeParts(text, {range, escapedString: true})).toEqual([ + [lex.TokenType.TEXT, 'line 1\n"line 2"\nline 3'], + [lex.TokenType.EOF], + ]); + expect(tokenizeAndHumanizeSourceSpans(text, {range, escapedString: true})).toEqual([ + [lex.TokenType.TEXT, 'line 1\\n\\"line 2\\"\\nline 3'], + [lex.TokenType.EOF, ''], + ]); + }); + + it('should account for escape sequences when computing source spans ', () => { + const text = 'line 1\n' + // <- unescaped line break + 'line 2\\n' + // <- escaped line break + 'line 3\\\n' + // <- line continuation + ''; + + expect(tokenizeAndHumanizeParts(text, {escapedString: true})).toEqual([ + [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.TEXT, 'line 1'], [lex.TokenType.TAG_CLOSE, null, 't'], + [lex.TokenType.TEXT, '\n'], + + [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.TEXT, 'line 2'], [lex.TokenType.TAG_CLOSE, null, 't'], + [lex.TokenType.TEXT, '\n'], + + [lex.TokenType.TAG_OPEN_START, null, 't'], [lex.TokenType.TAG_OPEN_END], + [lex.TokenType.TEXT, 'line 3'], // <- line continuation does not appear in token + [lex.TokenType.TAG_CLOSE, null, 't'], + + [lex.TokenType.EOF] + ]); + expect(tokenizeAndHumanizeLineColumn(text, {escapedString: true})).toEqual([ + [lex.TokenType.TAG_OPEN_START, '0:0'], + [lex.TokenType.TAG_OPEN_END, '0:2'], + [lex.TokenType.TEXT, '0:3'], + [lex.TokenType.TAG_CLOSE, '0:9'], + [lex.TokenType.TEXT, '0:13'], // <- real newline increments the row + + [lex.TokenType.TAG_OPEN_START, '1:0'], + [lex.TokenType.TAG_OPEN_END, '1:2'], + [lex.TokenType.TEXT, '1:3'], + [lex.TokenType.TAG_CLOSE, '1:9'], + [lex.TokenType.TEXT, '1:14'], // <- escaped newline does not increment the row + + [lex.TokenType.TAG_OPEN_START, '1:15'], + [lex.TokenType.TAG_OPEN_END, '1:17'], + [lex.TokenType.TEXT, '1:18'], // <- the line continuation increments the row + [lex.TokenType.TAG_CLOSE, '2:0'], + + [lex.TokenType.EOF, '2:4'], + ]); + expect(tokenizeAndHumanizeSourceSpans(text, {escapedString: true})).toEqual([ + [lex.TokenType.TAG_OPEN_START, ''], + [lex.TokenType.TEXT, 'line 1'], [lex.TokenType.TAG_CLOSE, ''], + [lex.TokenType.TEXT, '\n'], + + [lex.TokenType.TAG_OPEN_START, ''], + [lex.TokenType.TEXT, 'line 2'], [lex.TokenType.TAG_CLOSE, '
    \\'], + [lex.TokenType.TEXT, 'n'], + + [lex.TokenType.TAG_OPEN_START, ''], + [lex.TokenType.TEXT, 'line 3\\\n'], [lex.TokenType.TAG_CLOSE, '
    '], + + [lex.TokenType.EOF, ''] + ]); + }); + }); }); } -function tokenizeWithoutErrors( - input: string, tokenizeExpansionForms: boolean = false, - interpolationConfig?: InterpolationConfig): lex.Token[] { - const tokenizeResult = lex.tokenize( - input, 'someUrl', getHtmlTagDefinition, tokenizeExpansionForms, interpolationConfig); +function tokenizeWithoutErrors(input: string, options?: lex.TokenizeOptions): lex.Token[] { + const tokenizeResult = lex.tokenize(input, 'someUrl', getHtmlTagDefinition, options); if (tokenizeResult.errors.length > 0) { const errorString = tokenizeResult.errors.join('\n'); @@ -804,27 +1123,25 @@ function tokenizeWithoutErrors( return tokenizeResult.tokens; } -function tokenizeAndHumanizeParts( - input: string, tokenizeExpansionForms: boolean = false, - interpolationConfig?: InterpolationConfig): any[] { - return tokenizeWithoutErrors(input, tokenizeExpansionForms, interpolationConfig) - .map(token => [token.type].concat(token.parts)); +function tokenizeAndHumanizeParts(input: string, options?: lex.TokenizeOptions): any[] { + return tokenizeWithoutErrors(input, options).map(token => [token.type].concat(token.parts)); } -function tokenizeAndHumanizeSourceSpans(input: string): any[] { - return tokenizeWithoutErrors(input).map(token => [token.type, token.sourceSpan.toString()]); +function tokenizeAndHumanizeSourceSpans(input: string, options?: lex.TokenizeOptions): any[] { + return tokenizeWithoutErrors(input, options) + .map(token => [token.type, token.sourceSpan.toString()]); } function humanizeLineColumn(location: ParseLocation): string { return `${location.line}:${location.col}`; } -function tokenizeAndHumanizeLineColumn(input: string): any[] { - return tokenizeWithoutErrors(input).map( - token => [token.type, humanizeLineColumn(token.sourceSpan.start)]); +function tokenizeAndHumanizeLineColumn(input: string, options?: lex.TokenizeOptions): any[] { + return tokenizeWithoutErrors(input, options) + .map(token => [token.type, humanizeLineColumn(token.sourceSpan.start)]); } -function tokenizeAndHumanizeErrors(input: string, tokenizeExpansionForms: boolean = false): any[] { - return lex.tokenize(input, 'someUrl', getHtmlTagDefinition, tokenizeExpansionForms) +function tokenizeAndHumanizeErrors(input: string, options?: lex.TokenizeOptions): any[] { + return lex.tokenize(input, 'someUrl', getHtmlTagDefinition, options) .errors.map(e => [e.tokenType, e.msg, humanizeLineColumn(e.span.start)]); } diff --git a/packages/compiler/test/render3/view/util.ts b/packages/compiler/test/render3/view/util.ts index 26f584ea23..a347df7ace 100644 --- a/packages/compiler/test/render3/view/util.ts +++ b/packages/compiler/test/render3/view/util.ts @@ -81,7 +81,8 @@ export function parseR3( input: string, options: {preserveWhitespaces?: boolean} = {}): Render3ParseResult { const htmlParser = new HtmlParser(); - const parseResult = htmlParser.parse(input, 'path:://to/template', true); + const parseResult = + htmlParser.parse(input, 'path:://to/template', {tokenizeExpansionForms: true}); if (parseResult.errors.length > 0) { const msg = parseResult.errors.map(e => e.toString()).join('\n'); diff --git a/packages/compiler/test/template_parser/template_parser_spec.ts b/packages/compiler/test/template_parser/template_parser_spec.ts index 2bab11c9a9..c13d2f1dfe 100644 --- a/packages/compiler/test/template_parser/template_parser_spec.ts +++ b/packages/compiler/test/template_parser/template_parser_spec.ts @@ -420,7 +420,7 @@ class ArrayConsole implements Console { expectVisitedNode( new class extends NullVisitor{visitEvent(ast: BoundEventAst, context: any): any{return ast;}}, - new BoundEventAst('foo', 'bar', 'goo', null !, null !)); + new BoundEventAst('foo', 'bar', 'goo', null !, null !, null !)); }); it('should visit BoundElementPropertyAst', () => { @@ -474,7 +474,7 @@ class ArrayConsole implements Console { new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null !), new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null !, null !), new ReferenceAst('foo', null !, 'bar', null !), new VariableAst('foo', 'bar', null !), - new BoundEventAst('foo', 'bar', 'goo', null !, null !), + new BoundEventAst('foo', 'bar', 'goo', null !, null !, null !), new BoundElementPropertyAst('foo', null !, null !, null !, 'bar', null !), new AttrAst('foo', 'bar', null !), new BoundTextAst(null !, 0, null !), new TextAst('foo', 0, null !), new DirectiveAst(null !, [], [], [], 0, null !), diff --git a/packages/compiler/testing/BUILD.bazel b/packages/compiler/testing/BUILD.bazel index ae9c1a5446..f47ee11d51 100644 --- a/packages/compiler/testing/BUILD.bazel +++ b/packages/compiler/testing/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( ["**/*.ts"], exclude = ["testing.ts"], ), - module_name = "@angular/compiler/testing", deps = [ "//packages:types", "//packages/compiler", diff --git a/packages/compiler/testing/rollup.config.js b/packages/compiler/testing/rollup.config.js deleted file mode 100644 index a3a7211031..0000000000 --- a/packages/compiler/testing/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/core/testing': 'ng.core.testing', - '@angular/compiler': 'ng.compiler', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../../dist/packages-dist/compiler/fesm5/testing.js', - dest: '../../../dist/packages-dist/compiler/bundles/compiler-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/compiler/testing'}, - moduleName: 'ng.compiler.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/compiler/testing/src/output/source_map_util.ts b/packages/compiler/testing/src/output/source_map_util.ts index 6280d0393a..941a735c29 100644 --- a/packages/compiler/testing/src/output/source_map_util.ts +++ b/packages/compiler/testing/src/output/source_map_util.ts @@ -29,7 +29,7 @@ export function originalPositionFor( export function extractSourceMap(source: string): SourceMap|null { let idx = source.lastIndexOf('\n//#'); if (idx == -1) return null; - const smComment = source.slice(idx).trim(); + const smComment = source.slice(idx).split('\n', 2)[1].trim(); const smB64 = smComment.split('sourceMappingURL=data:application/json;base64,')[1]; return smB64 ? JSON.parse(decodeB64String(smB64)) : null; } diff --git a/packages/compiler/tsconfig-tools.json b/packages/compiler/tsconfig-tools.json deleted file mode 100644 index e45b55988d..0000000000 --- a/packages/compiler/tsconfig-tools.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig-build.json", - - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "outDir": "../../dist/tools/@angular/compiler" - } -} \ No newline at end of file diff --git a/packages/core/BUILD.bazel b/packages/core/BUILD.bazel index d321ada18f..78df5ffef1 100644 --- a/packages/core/BUILD.bazel +++ b/packages/core/BUILD.bazel @@ -10,9 +10,13 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/core", deps = [ "//packages:types", + "//packages/core/src/compiler", + "//packages/core/src/di/interface", + "//packages/core/src/interface", + "//packages/core/src/reflection", + "//packages/core/src/util", "@ngdeps//zone.js", "@rxjs", "@rxjs//operators", @@ -33,6 +37,7 @@ ng_package( # Dependencies on the full npm_package cause long re-builds. visibility = [ "//packages/bazel/test/ng_package:__pkg__", + "//packages/compiler-cli/integrationtest:__pkg__", "//packages/compiler-cli/test:__pkg__", "//packages/compiler-cli/test/diagnostics:__pkg__", "//packages/compiler-cli/test/ngcc:__pkg__", diff --git a/packages/core/rollup.config.js b/packages/core/rollup.config.js deleted file mode 100644 index 93e50a2578..0000000000 --- a/packages/core/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/compiler': 'ng.compiler', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../dist/packages-dist/core/fesm5/core.js', - dest: '../../dist/packages-dist/core/bundles/core.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/core'}, - moduleName: 'ng.core', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/core/src/application_module.ts b/packages/core/src/application_module.ts index a809f5c8fb..a28a3905a6 100644 --- a/packages/core/src/application_module.ts +++ b/packages/core/src/application_module.ts @@ -11,13 +11,14 @@ import {ApplicationRef} from './application_ref'; import {APP_ID_RANDOM_PROVIDER} from './application_tokens'; import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection'; import {Console} from './console'; -import {InjectionToken, Injector, StaticProvider} from './di'; +import {Injector, StaticProvider} from './di'; import {Inject, Optional, SkipSelf} from './di/metadata'; import {ErrorHandler} from './error_handler'; import {LOCALE_ID} from './i18n/tokens'; import {ComponentFactoryResolver} from './linker'; import {Compiler} from './linker/compiler'; import {NgModule} from './metadata'; +import {SCHEDULER} from './render3/component_ref'; import {NgZone} from './zone'; export function _iterableDiffersFactory() { @@ -43,6 +44,7 @@ export const APPLICATION_MODULE_PROVIDERS: StaticProvider[] = [ deps: [NgZone, Console, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus] }, + {provide: SCHEDULER, deps: [NgZone], useFactory: zoneSchedulerFactory}, { provide: ApplicationInitStatus, useClass: ApplicationInitStatus, @@ -59,6 +61,25 @@ export const APPLICATION_MODULE_PROVIDERS: StaticProvider[] = [ }, ]; +/** + * Schedule work at next available slot. + * + * In Ivy this is just `requestAnimationFrame`. For compatibility reasons when bootstrapped + * using `platformRef.bootstrap` we need to use `NgZone.onStable` as the scheduling mechanism. + * This overrides the scheduling mechanism in Ivy to `NgZone.onStable`. + * + * @param ngZone NgZone to use for scheduling. + */ +export function zoneSchedulerFactory(ngZone: NgZone): (fn: () => void) => void { + let queue: (() => void)[] = []; + ngZone.onStable.subscribe(() => { + while (queue.length) { + queue.pop() !(); + } + }); + return function(fn: () => void) { queue.push(fn); }; +} + /** * Configures the root injector for an app with * providers of `@angular/core` dependencies that `ApplicationRef` needs diff --git a/packages/core/src/application_ref.ts b/packages/core/src/application_ref.ts index ea3ab5cc2d..8669e889fc 100644 --- a/packages/core/src/application_ref.ts +++ b/packages/core/src/application_ref.ts @@ -14,7 +14,7 @@ import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens import {Console} from './console'; import {Injectable, InjectionToken, Injector, StaticProvider} from './di'; import {ErrorHandler} from './error_handler'; -import {isDevMode} from './is_dev_mode'; +import {Type} from './interface/type'; import {CompilerFactory, CompilerOptions} from './linker/compiler'; import {ComponentFactory, ComponentRef} from './linker/component_factory'; import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from './linker/component_factory_resolver'; @@ -22,11 +22,13 @@ import {InternalNgModuleRef, NgModuleFactory, NgModuleRef} from './linker/ng_mod import {InternalViewRef, ViewRef} from './linker/view_ref'; import {WtfScopeFn, wtfCreateScope, wtfLeave} from './profile/profile'; import {assertNgModuleType} from './render3/assert'; +import {ComponentFactory as R3ComponentFactory} from './render3/component_ref'; import {NgModuleFactory as R3NgModuleFactory} from './render3/ng_module_ref'; import {Testability, TestabilityRegistry} from './testability/testability'; -import {Type} from './type'; -import {scheduleMicroTask, stringify} from './util'; +import {isDevMode} from './util/is_dev_mode'; import {isPromise} from './util/lang'; +import {scheduleMicroTask} from './util/microtask'; +import {stringify} from './util/stringify'; import {NgZone, NoopNgZone} from './zone/ng_zone'; let _platform: PlatformRef; @@ -50,6 +52,16 @@ export function compileNgModuleFactory__POST_R3__( return Promise.resolve(new R3NgModuleFactory(moduleType)); } +let isBoundToModule: (cf: ComponentFactory) => boolean = isBoundToModule__PRE_R3__; + +export function isBoundToModule__PRE_R3__(cf: ComponentFactory): boolean { + return cf instanceof ComponentFactoryBoundToModule; +} + +export function isBoundToModule__POST_R3__(cf: ComponentFactory): boolean { + return (cf as R3ComponentFactory).isBoundToModule; +} + export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken('AllowMultipleToken'); @@ -347,6 +359,94 @@ function optionsReducer(dst: any, objs: T | T[]): T { /** * A reference to an Angular application running on a page. * + * @usageNotes + * + * {@a is-stable-examples} + * ### isStable examples and caveats + * + * Note two important points about `isStable`, demonstrated in the examples below: + * - the application will never be stable if you start any kind + * of recurrent asynchronous task when the application starts + * (for example for a polling process, started with a `setInterval`, a `setTimeout` + * or using RxJS operators like `interval`); + * - the `isStable` Observable runs outside of the Angular zone. + * + * Let's imagine that you start a recurrent task + * (here incrementing a counter, using RxJS `interval`), + * and at the same time subscribe to `isStable`. + * + * ``` + * constructor(appRef: ApplicationRef) { + * appRef.isStable.pipe( + * filter(stable => stable) + * ).subscribe(() => console.log('App is stable now'); + * interval(1000).subscribe(counter => console.log(counter)); + * } + * ``` + * In this example, `isStable` will never emit `true`, + * and the trace "App is stable now" will never get logged. + * + * If you want to execute something when the app is stable, + * you have to wait for the application to be stable + * before starting your polling process. + * + * ``` + * constructor(appRef: ApplicationRef) { + * appRef.isStable.pipe( + * first(stable => stable), + * tap(stable => console.log('App is stable now')), + * switchMap(() => interval(1000)) + * ).subscribe(counter => console.log(counter)); + * } + * ``` + * In this example, the trace "App is stable now" will be logged + * and then the counter starts incrementing every second. + * + * Note also that this Observable runs outside of the Angular zone, + * which means that the code in the subscription + * to this Observable will not trigger the change detection. + * + * Let's imagine that instead of logging the counter value, + * you update a field of your component + * and display it in its template. + * + * ``` + * constructor(appRef: ApplicationRef) { + * appRef.isStable.pipe( + * first(stable => stable), + * switchMap(() => interval(1000)) + * ).subscribe(counter => this.value = counter); + * } + * ``` + * As the `isStable` Observable runs outside the zone, + * the `value` field will be updated properly, + * but the template will not be refreshed! + * + * You'll have to manually trigger the change detection to update the template. + * + * ``` + * constructor(appRef: ApplicationRef, cd: ChangeDetectorRef) { + * appRef.isStable.pipe( + * first(stable => stable), + * switchMap(() => interval(1000)) + * ).subscribe(counter => { + * this.value = counter; + * cd.detectChanges(); + * }); + * } + * ``` + * + * Or make the subscription callback run inside the zone. + * + * ``` + * constructor(appRef: ApplicationRef, zone: NgZone) { + * appRef.isStable.pipe( + * first(stable => stable), + * switchMap(() => interval(1000)) + * ).subscribe(counter => zone.run(() => this.value = counter)); + * } + * ``` + * * @publicApi */ @Injectable() @@ -372,6 +472,8 @@ export class ApplicationRef { /** * Returns an Observable that indicates when the application is stable or unstable. + * + * @see [Usage notes](#is-stable-examples) for examples and caveats when using this API. */ // TODO(issue/24571): remove '!'. public readonly isStable !: Observable; @@ -466,9 +568,7 @@ export class ApplicationRef { this.componentTypes.push(componentFactory.componentType); // Create a factory associated with the current module if it's not bound to some other - const ngModule = componentFactory instanceof ComponentFactoryBoundToModule ? - null : - this._injector.get(NgModuleRef); + const ngModule = isBoundToModule(componentFactory) ? null : this._injector.get(NgModuleRef); const selectorOrNode = rootSelectorOrNode || componentFactory.selector; const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule); diff --git a/packages/core/src/change_detection/change_detection.ts b/packages/core/src/change_detection/change_detection.ts index f8dc1f18ac..158bc238f9 100644 --- a/packages/core/src/change_detection/change_detection.ts +++ b/packages/core/src/change_detection/change_detection.ts @@ -11,16 +11,26 @@ import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ'; import {IterableDifferFactory, IterableDiffers} from './differs/iterable_differs'; import {KeyValueDifferFactory, KeyValueDiffers} from './differs/keyvalue_differs'; -export {SimpleChanges} from '../metadata/lifecycle_hooks'; -export {SimpleChange, WrappedValue, devModeEqual} from './change_detection_util'; +export {WrappedValue, devModeEqual} from './change_detection_util'; export {ChangeDetectorRef} from './change_detector_ref'; export {ChangeDetectionStrategy, ChangeDetectorStatus, isDefaultChangeDetectionStrategy} from './constants'; export {DefaultIterableDifferFactory} from './differs/default_iterable_differ'; export {DefaultIterableDiffer} from './differs/default_iterable_differ'; export {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ'; -export {CollectionChangeRecord, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDifferFactory, IterableDiffers, NgIterable, TrackByFunction} from './differs/iterable_differs'; +export { + CollectionChangeRecord, + IterableChangeRecord, + IterableChanges, + IterableDiffer, + IterableDifferFactory, + IterableDiffers, + NgIterable, + TrackByFunction +} from +'./differs/iterable_differs'; export {KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDifferFactory, KeyValueDiffers} from './differs/keyvalue_differs'; export {PipeTransform} from './pipe_transform'; +export {SimpleChange, SimpleChanges} from '../interface/simple_change'; diff --git a/packages/core/src/change_detection/change_detection_util.ts b/packages/core/src/change_detection/change_detection_util.ts index 24d4bf74a6..df402d9884 100644 --- a/packages/core/src/change_detection/change_detection_util.ts +++ b/packages/core/src/change_detection/change_detection_util.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {getSymbolIterator, looseIdentical} from '../util'; +import {looseIdentical} from '../util/comparison'; +import {getSymbolIterator} from '../util/symbol'; export function devModeEqual(a: any, b: any): boolean { const isListLikeIterableA = isListLikeIterable(a); @@ -80,24 +81,6 @@ export class WrappedValue { static isWrapped(value: any): value is WrappedValue { return value instanceof WrappedValue; } } -/** - * Represents a basic change from a previous to a new value. - * - * 表示从旧值到新值的一次变更。 - * - * @publicApi - */ -export class SimpleChange { - constructor(public previousValue: any, public currentValue: any, public firstChange: boolean) {} - - /** - * Check whether the new value is the first value assigned. - * - * 检查该新值是否从首次赋值得来的。 - */ - isFirstChange(): boolean { return this.firstChange; } -} - export function isListLikeIterable(obj: any): boolean { if (!isJsObject(obj)) return false; return Array.isArray(obj) || diff --git a/packages/core/src/change_detection/change_detector_ref.ts b/packages/core/src/change_detection/change_detector_ref.ts index 9928e7a01b..06ebc7ec72 100644 --- a/packages/core/src/change_detection/change_detector_ref.ts +++ b/packages/core/src/change_detection/change_detector_ref.ts @@ -148,7 +148,10 @@ export abstract class ChangeDetectorRef { */ abstract reattach(): void; - /** @internal */ + /** + * @internal + * @nocollapse + */ static __NG_ELEMENT_ID__: () => ChangeDetectorRef = () => SWITCH_CHANGE_DETECTOR_REF_FACTORY(); } diff --git a/packages/core/src/change_detection/constants.ts b/packages/core/src/change_detection/constants.ts index 60d80cf23a..9d6eed4759 100644 --- a/packages/core/src/change_detection/constants.ts +++ b/packages/core/src/change_detection/constants.ts @@ -17,7 +17,7 @@ export enum ChangeDetectionStrategy { /** * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated * until reactivated by setting the strategy to `Default` (`CheckAlways`). - * Change detection can still be explictly invoked. + * Change detection can still be explicitly invoked. */ OnPush = 0, @@ -46,7 +46,7 @@ export enum ChangeDetectorStatus { Checked, /** - * A state in which change detection continues automatically until explictly + * A state in which change detection continues automatically until explicitly * deactivated. */ CheckAlways, diff --git a/packages/core/src/change_detection/differs/default_iterable_differ.ts b/packages/core/src/change_detection/differs/default_iterable_differ.ts index 9cfccfd065..1d909df30b 100644 --- a/packages/core/src/change_detection/differs/default_iterable_differ.ts +++ b/packages/core/src/change_detection/differs/default_iterable_differ.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {looseIdentical, stringify} from '../../util'; +import {looseIdentical} from '../../util/comparison'; +import {stringify} from '../../util/stringify'; import {isListLikeIterable, iterateListLike} from '../change_detection_util'; + import {IterableChangeRecord, IterableChanges, IterableDiffer, IterableDifferFactory, NgIterable, TrackByFunction} from './iterable_differs'; diff --git a/packages/core/src/change_detection/differs/default_keyvalue_differ.ts b/packages/core/src/change_detection/differs/default_keyvalue_differ.ts index 3408c7ad0f..b0d8f404b7 100644 --- a/packages/core/src/change_detection/differs/default_keyvalue_differ.ts +++ b/packages/core/src/change_detection/differs/default_keyvalue_differ.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {looseIdentical, stringify} from '../../util'; +import {looseIdentical} from '../../util/comparison'; +import {stringify} from '../../util/stringify'; import {isJsObject} from '../change_detection_util'; import {KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDifferFactory} from './keyvalue_differs'; diff --git a/packages/core/src/change_detection/differs/iterable_differs.ts b/packages/core/src/change_detection/differs/iterable_differs.ts index 958ba220b9..6e9f90c06f 100644 --- a/packages/core/src/change_detection/differs/iterable_differs.ts +++ b/packages/core/src/change_detection/differs/iterable_differs.ts @@ -6,12 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {defineInjectable} from '../../di/defs'; +import {defineInjectable} from '../../di/interface/defs'; +import {StaticProvider} from '../../di/interface/provider'; import {Optional, SkipSelf} from '../../di/metadata'; -import {StaticProvider} from '../../di/provider'; import {DefaultIterableDifferFactory} from '../differs/default_iterable_differ'; + /** * A type describing supported iterable types. * @@ -116,8 +117,10 @@ export interface IterableChangeRecord { export interface CollectionChangeRecord extends IterableChangeRecord {} /** - * An optional function passed into {@link NgForOf} that defines how to track - * items in an iterable (e.g. fby index or id) + * An optional function passed into the `NgForOf` directive that defines how to track + * changes for items in an iterable. + * The function takes the iteration index and item ID. + * When supplied, Angular tracks changes by the return value of the function. * * @publicApi */ diff --git a/packages/core/src/compiler/BUILD.bazel b/packages/core/src/compiler/BUILD.bazel new file mode 100644 index 0000000000..eabb68ecff --- /dev/null +++ b/packages/core/src/compiler/BUILD.bazel @@ -0,0 +1,19 @@ +package(default_visibility = [ + "//packages/compiler/test:__pkg__", + "//packages/core:__subpackages__", + "//tools/public_api_guard:__pkg__", +]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "compiler", + srcs = glob( + [ + "**/*.ts", + ], + ), + deps = [ + "//packages/core/src/util", + ], +) diff --git a/packages/core/src/render3/jit/compiler_facade.ts b/packages/core/src/compiler/compiler_facade.ts similarity index 96% rename from packages/core/src/render3/jit/compiler_facade.ts rename to packages/core/src/compiler/compiler_facade.ts index 91a4b269c7..1515cf50e1 100644 --- a/packages/core/src/render3/jit/compiler_facade.ts +++ b/packages/core/src/compiler/compiler_facade.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {global} from '../../util'; +import {global} from '../util/global'; import {CompilerFacade, ExportedCompilerFacade} from './compiler_facade_interface'; export * from './compiler_facade_interface'; diff --git a/packages/core/src/render3/jit/compiler_facade_interface.ts b/packages/core/src/compiler/compiler_facade_interface.ts similarity index 93% rename from packages/core/src/render3/jit/compiler_facade_interface.ts rename to packages/core/src/compiler/compiler_facade_interface.ts index fe230636ff..a5f1802c2e 100644 --- a/packages/core/src/render3/jit/compiler_facade_interface.ts +++ b/packages/core/src/compiler/compiler_facade_interface.ts @@ -38,6 +38,8 @@ export interface CompilerFacade { compileComponent( angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any; + createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan; + R3ResolvedDependencyType: typeof R3ResolvedDependencyType; } @@ -95,6 +97,7 @@ export interface R3NgModuleMetadataFacade { imports: Function[]; exports: Function[]; emitInline: boolean; + schemas: {name: string}[]|null; } export interface R3InjectorMetadataFacade { @@ -109,7 +112,7 @@ export interface R3DirectiveMetadataFacade { name: string; type: any; typeArgumentCount: number; - typeSourceSpan: null; + typeSourceSpan: ParseSourceSpan; deps: R3DependencyMetadataFacade[]|null; selector: string|null; queries: R3QueryMetadataFacade[]; @@ -119,7 +122,7 @@ export interface R3DirectiveMetadataFacade { inputs: string[]; outputs: string[]; usesInheritance: boolean; - exportAs: string|null; + exportAs: string[]|null; providers: Provider[]|null; } @@ -148,3 +151,9 @@ export interface R3QueryMetadataFacade { descendants: boolean; read: any|null; } + +export interface ParseSourceSpan { + start: any; + end: any; + details: any; +} diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index ee0b21204c..ac379e2bb9 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -16,7 +16,7 @@ export * from './version'; export {TypeDecorator} from './util/decorators'; export * from './di'; export {createPlatform, assertPlatform, destroyPlatform, getPlatform, PlatformRef, ApplicationRef, createPlatformFactory, NgProbeToken} from './application_ref'; -export {enableProdMode, isDevMode} from './is_dev_mode'; +export {enableProdMode, isDevMode} from './util/is_dev_mode'; export {APP_ID, PACKAGE_ROOT_URL, PLATFORM_INITIALIZER, PLATFORM_ID, APP_BOOTSTRAP_LISTENER} from './application_tokens'; export {APP_INITIALIZER, ApplicationInitStatus} from './application_init'; export * from './zone'; @@ -29,7 +29,7 @@ export * from './platform_core_providers'; export {TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID, MissingTranslationStrategy} from './i18n/tokens'; export {ApplicationModule} from './application_module'; export {wtfCreateScope, wtfLeave, wtfStartTimeRange, wtfEndTimeRange, WtfScopeFn} from './profile/profile'; -export {Type} from './type'; +export {Type} from './interface/type'; export {EventEmitter} from './event_emitter'; export {ErrorHandler} from './error_handler'; export * from './core_private_export'; diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index 3f2b6a889d..f5086aa77c 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -13,20 +13,22 @@ export {devModeEqual as ɵdevModeEqual} from './change_detection/change_detectio export {isListLikeIterable as ɵisListLikeIterable} from './change_detection/change_detection_util'; export {ChangeDetectorStatus as ɵChangeDetectorStatus, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from './change_detection/constants'; export {Console as ɵConsole} from './console'; -export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/defs'; export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector_compatibility'; +export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/interface/defs'; export {APP_ROOT as ɵAPP_ROOT} from './di/scope'; export {ivyEnabled as ɵivyEnabled} from './ivy_switch'; export {ComponentFactory as ɵComponentFactory} from './linker/component_factory'; export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver'; -export {resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading'; +export {clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading'; export {ReflectionCapabilities as ɵReflectionCapabilities} from './reflection/reflection_capabilities'; export {GetterFn as ɵGetterFn, MethodFn as ɵMethodFn, SetterFn as ɵSetterFn} from './reflection/types'; export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as ɵRenderDebugInfo} from './render/api'; export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer'; export {_sanitizeStyle as ɵ_sanitizeStyle} from './sanitization/style_sanitizer'; export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer'; -export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as ɵstringify} from './util'; +export {global as ɵglobal} from './util/global'; +export {looseIdentical as ɵlooseIdentical,} from './util/comparison'; +export {stringify as ɵstringify} from './util/stringify'; export {makeDecorator as ɵmakeDecorator} from './util/decorators'; export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang'; export {clearOverrides as ɵclearOverrides, initServicesIfNeeded as ɵinitServicesIfNeeded, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider} from './view/index'; diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index f384eba657..f13b2b91da 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -25,6 +25,7 @@ export { injectAttribute as ɵinjectAttribute, getFactoryOf as ɵgetFactoryOf, getInheritedFactory as ɵgetInheritedFactory, + setComponentScope as ɵsetComponentScope, templateRefExtractor as ɵtemplateRefExtractor, ProvidersFeature as ɵProvidersFeature, InheritDefinitionFeature as ɵInheritDefinitionFeature, @@ -46,8 +47,6 @@ export { listener as ɵlistener, text as ɵtext, embeddedViewStart as ɵembeddedViewStart, - query as ɵquery, - registerContentQuery as ɵregisterContentQuery, projection as ɵprojection, bind as ɵbind, interpolation1 as ɵinterpolation1, @@ -75,14 +74,20 @@ export { pureFunction8 as ɵpureFunction8, pureFunctionV as ɵpureFunctionV, getCurrentView as ɵgetCurrentView, + getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, restoreView as ɵrestoreView, containerRefreshStart as ɵcontainerRefreshStart, containerRefreshEnd as ɵcontainerRefreshEnd, queryRefresh as ɵqueryRefresh, - loadQueryList as ɵloadQueryList, + viewQuery as ɵviewQuery, + loadViewQuery as ɵloadViewQuery, + contentQuery as ɵcontentQuery, + loadContentQuery as ɵloadContentQuery, elementEnd as ɵelementEnd, elementProperty as ɵelementProperty, + componentHostSyntheticProperty as ɵcomponentHostSyntheticProperty, + componentHostSyntheticListener as ɵcomponentHostSyntheticListener, projectionDef as ɵprojectionDef, reference as ɵreference, enableBindings as ɵenableBindings, @@ -119,6 +124,9 @@ export { i18nApply as ɵi18nApply, i18nPostprocess as ɵi18nPostprocess, setClassMetadata as ɵsetClassMetadata, + resolveWindow as ɵresolveWindow, + resolveDocument as ɵresolveDocument, + resolveBody as ɵresolveBody, } from './render3/index'; @@ -131,6 +139,8 @@ export { compileNgModuleDefs as ɵcompileNgModuleDefs, patchComponentDefWithScope as ɵpatchComponentDefWithScope, resetCompiledComponents as ɵresetCompiledComponents, + flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, + transitiveScopesFor as ɵtransitiveScopesFor, } from './render3/jit/module'; export { compilePipe as ɵcompilePipe, @@ -145,8 +155,11 @@ export { export { sanitizeHtml as ɵsanitizeHtml, sanitizeStyle as ɵsanitizeStyle, + defaultStyleSanitizer as ɵdefaultStyleSanitizer, + sanitizeScript as ɵsanitizeScript, sanitizeUrl as ɵsanitizeUrl, sanitizeResourceUrl as ɵsanitizeResourceUrl, + sanitizeUrlOrResourceUrl as ɵsanitizeUrlOrResourceUrl, } from './sanitization/sanitization'; export { @@ -161,6 +174,20 @@ export { getLContext as ɵgetLContext } from './render3/context_discovery'; +export { + NG_ELEMENT_ID as ɵNG_ELEMENT_ID, + NG_COMPONENT_DEF as ɵNG_COMPONENT_DEF, + NG_DIRECTIVE_DEF as ɵNG_DIRECTIVE_DEF, + NG_PIPE_DEF as ɵNG_PIPE_DEF, + NG_MODULE_DEF as ɵNG_MODULE_DEF, + NG_BASE_DEF as ɵNG_BASE_DEF +} from './render3/fields'; + +export { + NG_INJECTABLE_DEF as ɵNG_INJECTABLE_DEF, + NG_INJECTOR_DEF as ɵNG_INJECTOR_DEF, +} from './di/interface/defs'; + export { Player as ɵPlayer, PlayerFactory as ɵPlayerFactory, @@ -186,7 +213,8 @@ export { // // no code actually imports these symbols from the @angular/core entry point export { - compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__ + compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__, + isBoundToModule__POST_R3__ as ɵisBoundToModule__POST_R3__ } from './application_ref'; export { SWITCH_COMPILE_COMPONENT__POST_R3__ as ɵSWITCH_COMPILE_COMPONENT__POST_R3__, @@ -233,8 +261,7 @@ export { publishGlobalUtil as ɵpublishGlobalUtil, publishDefaultGlobalUtils as ɵpublishDefaultGlobalUtils } from './render3/global_utils'; -export { - SWITCH_INJECTOR_FACTORY__POST_R3__ as ɵSWITCH_INJECTOR_FACTORY__POST_R3__, -} from './di/injector'; + +export {createInjector as ɵcreateInjector} from './di/r3_injector'; // clang-format on diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index 54c2c6cd70..b6c8396dd4 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -7,13 +7,14 @@ */ import {Injector} from '../di'; -import {assertDomNode} from '../render3/assert'; import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, isBrowserEvents, loadLContext, loadLContextFromNode} from '../render3/discovery_utils'; import {TNode} from '../render3/interfaces/node'; import {StylingIndex} from '../render3/interfaces/styling'; -import {TVIEW} from '../render3/interfaces/view'; +import {LView, TData, TVIEW} from '../render3/interfaces/view'; import {getProp, getValue, isClassBasedValue} from '../render3/styling/class_and_style_bindings'; import {getStylingContext} from '../render3/styling/util'; +import {INTERPOLATION_DELIMITER, isPropMetadataString, renderStringify} from '../render3/util'; +import {assertDomNode} from '../util/assert'; import {DebugContext} from '../view/index'; export class EventListener { @@ -195,11 +196,6 @@ function _queryNodeChildren( }); } } - -function notImplemented(): Error { - throw new Error('Missing proper ivy implementation.'); -} - class DebugNode__POST_R3__ implements DebugNode { readonly nativeNode: Node; @@ -239,15 +235,27 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme get name(): string { return this.nativeElement !.nodeName; } + /** + * Gets a map of property names to property values for an element. + * + * This map includes: + * - Regular property bindings (e.g. `[id]="id"`) + * - Host property bindings (e.g. `host: { '[id]': "id" }`) + * - Interpolated property bindings (e.g. `id="{{ value }}") + * + * It does not include: + * - input property bindings (e.g. `[myCustomInput]="value"`) + * - attribute bindings (e.g. `[attr.role]="menu"`) + */ get properties(): {[key: string]: any;} { const context = loadLContext(this.nativeNode) !; const lView = context.lView; - const tView = lView[TVIEW]; - const tNode = tView.data[context.nodeIndex] as TNode; - const properties = {}; - // TODO: https://angular-team.atlassian.net/browse/FW-681 - // Missing implementation here... - return properties; + const tData = lView[TVIEW].data; + const tNode = tData[context.nodeIndex] as TNode; + + const properties = collectPropertyBindings(tNode, lView, tData); + const hostProperties = collectHostPropertyBindings(tNode, lView, tData); + return {...properties, ...hostProperties}; } get attributes(): {[key: string]: string | null;} { @@ -268,14 +276,13 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme const element = this.nativeElement; if (element) { const lContext = loadLContextFromNode(element); - const lNode = lContext.lView[lContext.nodeIndex]; const stylingContext = getStylingContext(lContext.nodeIndex, lContext.lView); if (stylingContext) { - for (let i = StylingIndex.SingleStylesStartPosition; i < lNode.length; + for (let i = StylingIndex.SingleStylesStartPosition; i < stylingContext.length; i += StylingIndex.Size) { - if (isClassBasedValue(lNode, i)) { - const className = getProp(lNode, i); - const value = getValue(lNode, i); + if (isClassBasedValue(stylingContext, i)) { + const className = getProp(stylingContext, i); + const value = getValue(stylingContext, i); if (typeof value == 'boolean') { // we want to ignore `null` since those don't overwrite the values. classes[className] = value; @@ -298,14 +305,13 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme const element = this.nativeElement; if (element) { const lContext = loadLContextFromNode(element); - const lNode = lContext.lView[lContext.nodeIndex]; const stylingContext = getStylingContext(lContext.nodeIndex, lContext.lView); if (stylingContext) { - for (let i = StylingIndex.SingleStylesStartPosition; i < lNode.length; + for (let i = StylingIndex.SingleStylesStartPosition; i < stylingContext.length; i += StylingIndex.Size) { - if (!isClassBasedValue(lNode, i)) { - const styleName = getProp(lNode, i); - const value = getValue(lNode, i) as string | null; + if (!isClassBasedValue(stylingContext, i)) { + const styleName = getProp(stylingContext, i); + const value = getValue(stylingContext, i) as string | null; if (value !== null) { // we want to ignore `null` since those don't overwrite the values. styles[styleName] = value; @@ -389,6 +395,89 @@ function _queryNodeChildrenR3( } } +/** + * Iterates through the property bindings for a given node and generates + * a map of property names to values. This map only contains property bindings + * defined in templates, not in host bindings. + */ +function collectPropertyBindings( + tNode: TNode, lView: LView, tData: TData): {[key: string]: string} { + const properties: {[key: string]: string} = {}; + let bindingIndex = getFirstBindingIndex(tNode.propertyMetadataStartIndex, tData); + + while (bindingIndex < tNode.propertyMetadataEndIndex) { + let value = ''; + let propMetadata = tData[bindingIndex] as string; + while (!isPropMetadataString(propMetadata)) { + // This is the first value for an interpolation. We need to build up + // the full interpolation by combining runtime values in LView with + // the static interstitial values stored in TData. + value += renderStringify(lView[bindingIndex]) + tData[bindingIndex]; + propMetadata = tData[++bindingIndex] as string; + } + value += lView[bindingIndex]; + // Property metadata string has 3 parts: property name, prefix, and suffix + const metadataParts = propMetadata.split(INTERPOLATION_DELIMITER); + const propertyName = metadataParts[0]; + // Attr bindings don't have property names and should be skipped + if (propertyName) { + // Wrap value with prefix and suffix (will be '' for normal bindings) + properties[propertyName] = metadataParts[1] + value + metadataParts[2]; + } + bindingIndex++; + } + return properties; +} + +/** + * Retrieves the first binding index that holds values for this property + * binding. + * + * For normal bindings (e.g. `[id]="id"`), the binding index is the + * same as the metadata index. For interpolations (e.g. `id="{{id}}-{{name}}"`), + * there can be multiple binding values, so we might have to loop backwards + * from the metadata index until we find the first one. + * + * @param metadataIndex The index of the first property metadata string for + * this node. + * @param tData The data array for the current TView + * @returns The first binding index for this binding + */ +function getFirstBindingIndex(metadataIndex: number, tData: TData): number { + let currentBindingIndex = metadataIndex - 1; + + // If the slot before the metadata holds a string, we know that this + // metadata applies to an interpolation with at least 2 bindings, and + // we need to search further to access the first binding value. + let currentValue = tData[currentBindingIndex]; + + // We need to iterate until we hit either a: + // - TNode (it is an element slot marking the end of `consts` section), OR a + // - metadata string (slot is attribute metadata or a previous node's property metadata) + while (typeof currentValue === 'string' && !isPropMetadataString(currentValue)) { + currentValue = tData[--currentBindingIndex]; + } + return currentBindingIndex + 1; +} + +function collectHostPropertyBindings( + tNode: TNode, lView: LView, tData: TData): {[key: string]: string} { + const properties: {[key: string]: string} = {}; + + // Host binding values for a node are stored after directives on that node + let hostPropIndex = tNode.directiveEnd; + let propMetadata = tData[hostPropIndex] as any; + + // When we reach a value in TView.data that is not a string, we know we've + // hit the next node's providers and directives and should stop copying data. + while (typeof propMetadata === 'string') { + const propertyName = propMetadata.split(INTERPOLATION_DELIMITER)[0]; + properties[propertyName] = lView[hostPropIndex]; + propMetadata = tData[++hostPropIndex]; + } + return properties; +} + // Need to keep the nodes in a global Map so that multiple angular apps are supported. const _nativeNodeToDebugNode = new Map(); diff --git a/packages/core/src/di.ts b/packages/core/src/di.ts index c1f5989466..d9017e84b9 100644 --- a/packages/core/src/di.ts +++ b/packages/core/src/di.ts @@ -7,20 +7,20 @@ */ /** - * @module - * @description - * The `di` module provides dependency injection container services. + * This file should not be necessary because node resolution should just default to `./di/index`! + * + * However it does not seem to work and it breaks: + * - //packages/animations/browser/test:test_web_chromium-local + * - //packages/compiler-cli/test:extract_i18n + * - //packages/compiler-cli/test:ngc + * - //packages/compiler-cli/test:perform_watch + * - //packages/compiler-cli/test/diagnostics:check_types + * - //packages/compiler-cli/test/transformers:test + * - //packages/compiler/test:test + * - //tools/public_api_guard:core_api + * + * Remove this file once the above is solved or wait until `ngc` is deleted and then it should be + * safe to delete this file. */ -export * from './di/metadata'; -export {InjectableType, InjectorType, defineInjectable, defineInjector} from './di/defs'; -export {forwardRef, resolveForwardRef, ForwardRefFn} from './di/forward_ref'; -export {Injectable, InjectableDecorator, InjectableProvider} from './di/injectable'; -export {INJECTOR, Injector} from './di/injector'; -export {inject, InjectFlags} from './di/injector_compatibility'; -export {ReflectiveInjector} from './di/reflective_injector'; -export {StaticProvider, ValueProvider, ConstructorSansProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ClassProvider} from './di/provider'; -export {createInjector} from './di/r3_injector'; -export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './di/reflective_provider'; -export {ReflectiveKey} from './di/reflective_key'; -export {InjectionToken} from './di/injection_token'; +export * from './di/index'; diff --git a/packages/core/src/di/forward_ref.ts b/packages/core/src/di/forward_ref.ts index ad5b50908f..d1de311b54 100644 --- a/packages/core/src/di/forward_ref.ts +++ b/packages/core/src/di/forward_ref.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; -import {stringify} from '../util'; +import {Type} from '../interface/type'; import {getClosureSafeProperty} from '../util/property'; +import {stringify} from '../util/stringify'; diff --git a/packages/core/src/di/index.ts b/packages/core/src/di/index.ts new file mode 100644 index 0000000000..0b9df9f442 --- /dev/null +++ b/packages/core/src/di/index.ts @@ -0,0 +1,26 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * @module + * @description + * The `di` module provides dependency injection container services. + */ + +export * from './metadata'; +export {InjectFlags} from './interface/injector'; +export {defineInjectable, defineInjector, InjectableType, InjectorType} from './interface/defs'; +export {forwardRef, resolveForwardRef, ForwardRefFn} from './forward_ref'; +export {Injectable, InjectableDecorator, InjectableProvider} from './injectable'; +export {INJECTOR, Injector} from './injector'; +export {inject} from './injector_compatibility'; +export {ReflectiveInjector} from './reflective_injector'; +export {StaticProvider, ValueProvider, ConstructorSansProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ClassProvider} from './interface/provider'; +export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './reflective_provider'; +export {ReflectiveKey} from './reflective_key'; +export {InjectionToken} from './injection_token'; diff --git a/packages/core/src/di/injectable.ts b/packages/core/src/di/injectable.ts index 252dc48f0d..6832ed36f7 100644 --- a/packages/core/src/di/injectable.ts +++ b/packages/core/src/di/injectable.ts @@ -6,15 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {compileInjectable as render3CompileInjectable} from '../render3/jit/injectable'; -import {Type} from '../type'; +import {Type} from '../interface/type'; import {TypeDecorator, makeDecorator} from '../util/decorators'; - -import {InjectableDef, InjectableType, defineInjectable, getInjectableDef} from './defs'; -import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueSansProvider} from './provider'; +import {InjectableDef, InjectableType, defineInjectable, getInjectableDef} from './interface/defs'; +import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueSansProvider} from './interface/provider'; +import {compileInjectable as render3CompileInjectable} from './jit/injectable'; import {convertInjectableProviderToFactory} from './util'; + /** * Injectable providers used in `@Injectable` decorator. * @@ -34,23 +34,26 @@ export type InjectableProvider = ValueSansProvider | ExistingSansProvider | */ export interface InjectableDecorator { /** - * A marker metadata that marks a class as available to `Injector` for creation. + * Marks a class as available to `Injector` for creation. * * 标记性元数据,表示一个类可以由 `Injector` 进行创建。 * - * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). - * - * 欲知详情,参见["依赖注入"](guide/dependency-injection)。 + * @see [Introduction to Services and DI](guide/architecture-services) + * @see [Dependency Injection Guide](guide/dependency-injection) * * @usageNotes - * ### Example + * + * The following example shows how service classes are properly marked as + * injectable. + * + * 下面的例子展示了如何正确的把服务类标记为可注入的(Injectable)。 * * ### 范例 * * {@example core/di/ts/metadata_spec.ts region='Injectable'} * - * `Injector` will throw an error when trying to instantiate a class that - * does not have `@Injectable` marker, as shown in the example below. + * `Injector` throws an error if it tries to instantiate a class that + * is not decorated with `@Injectable`, as shown in the following example. * * `Injector`在试图实例化一个不带 `@Injectable` 标记的类时,就会抛出一个错误,如下面的例子所示。 * @@ -70,7 +73,15 @@ export interface InjectableDecorator { * * @publicApi */ -export interface Injectable { providedIn?: Type|'root'|null; } +export interface Injectable { + /** + * Determines which injectors will provide the injectable, + * by either associating it with an @NgModule or other `InjectorType`, + * or by specifying that this injectable should be provided in the + * 'root' injector, which will be the application-level injector in most apps. + */ + providedIn?: Type|'root'|null; +} /** * Injectable decorator and metadata. diff --git a/packages/core/src/di/injection_token.ts b/packages/core/src/di/injection_token.ts index 43ebde5302..4879bce567 100644 --- a/packages/core/src/di/injection_token.ts +++ b/packages/core/src/di/injection_token.ts @@ -6,16 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; +import {Type} from '../interface/type'; -import {defineInjectable} from './defs'; +import {defineInjectable} from './interface/defs'; /** * Creates a token that can be used in a DI Provider. * * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a * runtime representation) such as when injecting an interface, callable type, array or - * parametrized type. + * parameterized type. * * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by * the `Injector`. This provides additional level of type safety. @@ -60,13 +60,17 @@ export class InjectionToken { providedIn?: Type| 'root' | null, factory: () => T }) { - if (options !== undefined) { + this.ngInjectableDef = undefined; + if (typeof options == 'number') { + // This is a special hack to assign __NG_ELEMENT_ID__ to this instance. + // __NG_ELEMENT_ID__ is Used by Ivy to determine bloom filter id. + // We are using it to assign `-1` which is used to identify `Injector`. + (this as any).__NG_ELEMENT_ID__ = options; + } else if (options !== undefined) { this.ngInjectableDef = defineInjectable({ providedIn: options.providedIn || 'root', factory: options.factory, }); - } else { - this.ngInjectableDef = undefined; } } diff --git a/packages/core/src/di/injector.ts b/packages/core/src/di/injector.ts index 22a1b8161a..bc85842bb5 100644 --- a/packages/core/src/di/injector.ts +++ b/packages/core/src/di/injector.ts @@ -6,18 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {injectInjector} from '../render3/di'; -import {Type} from '../type'; -import {stringify} from '../util'; -import {noop} from '../util/noop'; +import {Type} from '../interface/type'; import {getClosureSafeProperty} from '../util/property'; - -import {defineInjectable} from './defs'; +import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {InjectFlags, inject} from './injector_compatibility'; +import {inject} from './injector_compatibility'; +import {defineInjectable} from './interface/defs'; +import {InjectFlags} from './interface/injector'; +import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; -import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './provider'; export const SOURCE = '__source'; const _THROW_IF_NOT_FOUND = new Object(); @@ -31,7 +29,10 @@ export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; * * @publicApi */ -export const INJECTOR = new InjectionToken('INJECTOR'); +export const INJECTOR = new InjectionToken( + 'INJECTOR', + -1 as any // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. + ); export class NullInjector implements Injector { get(token: any, notFoundValue: any = _THROW_IF_NOT_FOUND): any { @@ -40,7 +41,9 @@ export class NullInjector implements Injector { // reason why correctly written application should cause this exception. // TODO(misko): uncomment the next line once `ngDevMode` works with closure. // if(ngDevMode) debugger; - throw new Error(`NullInjectorError: No provider for ${stringify(token)}!`); + const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`); + error.name = 'NullInjectorError'; + throw error; } return notFoundValue; } @@ -109,15 +112,13 @@ export abstract class Injector { factory: () => inject(INJECTOR), }); - /** @internal */ - static __NG_ELEMENT_ID__: () => Injector = () => SWITCH_INJECTOR_FACTORY(); + /** + * @internal + * @nocollapse + */ + static __NG_ELEMENT_ID__ = -1; } -export const SWITCH_INJECTOR_FACTORY__POST_R3__ = function() { - return injectInjector(); -}; -const SWITCH_INJECTOR_FACTORY__PRE_R3__ = noop; -const SWITCH_INJECTOR_FACTORY: typeof injectInjector = SWITCH_INJECTOR_FACTORY__PRE_R3__; const IDENT = function(value: T): T { @@ -131,7 +132,7 @@ const MULTI_PROVIDER_FN = function(): any[] { export const USE_VALUE = getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); const NG_TOKEN_PATH = 'ngTokenPath'; -const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; +export const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; const enum OptionFlags { Optional = 1 << 0, CheckSelf = 1 << 1, @@ -167,14 +168,7 @@ export class StaticInjector implements Injector { try { return tryResolveToken(token, record, this._records, this.parent, notFoundValue, flags); } catch (e) { - const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; - if (token[SOURCE]) { - tokenPath.unshift(token[SOURCE]); - } - e.message = formatError('\n' + e.message, tokenPath, this.source); - e[NG_TOKEN_PATH] = tokenPath; - e[NG_TEMP_TOKEN_PATH] = null; - throw e; + return catchInjectorError(e, token, 'StaticInjectorError', this.source); } } @@ -200,8 +194,6 @@ interface DependencyRecord { options: number; } -type TokenPath = Array; - function resolveProvider(provider: SupportedProvider): Record { const deps = computeDeps(provider); let fn: Function = IDENT; @@ -385,7 +377,20 @@ function computeDeps(provider: StaticProvider): DependencyRecord[] { return deps; } -function formatError(text: string, obj: any, source: string | null = null): string { +export function catchInjectorError( + e: any, token: any, injectorErrorName: string, source: string | null): never { + const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; + if (token[SOURCE]) { + tokenPath.unshift(token[SOURCE]); + } + e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source); + e[NG_TOKEN_PATH] = tokenPath; + e[NG_TEMP_TOKEN_PATH] = null; + throw e; +} + +function formatError( + text: string, obj: any, injectorErrorName: string, source: string | null = null): string { text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text; let context = stringify(obj); if (obj instanceof Array) { @@ -401,9 +406,9 @@ function formatError(text: string, obj: any, source: string | null = null): stri } context = `{${parts.join(', ')}}`; } - return `StaticInjectorError${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; + return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; } function staticError(text: string, obj: any): Error { - return new Error(formatError(text, obj)); + return new Error(formatError(text, obj, 'StaticInjectorError')); } diff --git a/packages/core/src/di/injector_compatibility.ts b/packages/core/src/di/injector_compatibility.ts index 3eb5b47c3e..f314afce57 100644 --- a/packages/core/src/di/injector_compatibility.ts +++ b/packages/core/src/di/injector_compatibility.ts @@ -6,37 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; -import {stringify} from '../util'; +import {Type} from '../interface/type'; +import {stringify} from '../util/stringify'; -import {InjectableDef, getInjectableDef} from './defs'; import {InjectionToken} from './injection_token'; import {Injector} from './injector'; +import {InjectableDef, getInjectableDef} from './interface/defs'; +import {InjectFlags} from './interface/injector'; import {Inject, Optional, Self, SkipSelf} from './metadata'; -/** - * Injection flags for DI. - * - * @publicApi - */ -export enum InjectFlags { - // TODO(alxhub): make this 'const' when ngc no longer writes exports of it into ngfactory files. - - Default = 0b0000, - - /** - * Specifies that an injector should retrieve a dependency from any injector until reaching the - * host element of the current component. (Only used with Element Injector) - */ - Host = 0b0001, - /** Don't descend into ancestors of the node requesting injection. */ - Self = 0b0010, - /** Skip the node that is requesting injection. */ - SkipSelf = 0b0100, - /** Inject `defaultValue` instead if token not found. */ - Optional = 0b1000, -} - /** diff --git a/packages/core/src/di/interface/BUILD.bazel b/packages/core/src/di/interface/BUILD.bazel new file mode 100644 index 0000000000..e92fad0fae --- /dev/null +++ b/packages/core/src/di/interface/BUILD.bazel @@ -0,0 +1,21 @@ +package(default_visibility = [ + "//packages/core:__subpackages__", + "//tools/public_api_guard:__pkg__", +]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "interface", + srcs = glob( + [ + "**/*.ts", + ], + ), + deps = [ + "//packages/core/src/interface", + "//packages/core/src/util", + "@rxjs", + "@rxjs//operators", + ], +) diff --git a/packages/core/src/di/defs.ts b/packages/core/src/di/interface/defs.ts similarity index 93% rename from packages/core/src/di/defs.ts rename to packages/core/src/di/interface/defs.ts index ab82b2fcdd..5f5ba65187 100644 --- a/packages/core/src/di/defs.ts +++ b/packages/core/src/di/interface/defs.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {NG_INJECTABLE_DEF, NG_INJECTOR_DEF} from '../render3/fields'; -import {Type} from '../type'; +import {Type} from '../../interface/type'; +import {getClosureSafeProperty} from '../../util/property'; +import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, ValueProvider} from './provider'; + -import {ClassProvider, ClassSansProvider, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, StaticClassProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider'; /** * Information about how a type or `InjectionToken` interfaces with the DI system. @@ -178,4 +179,7 @@ export function getInjectableDef(type: any): InjectableDef|null { */ export function getInjectorDef(type: any): InjectorDef|null { return type && type.hasOwnProperty(NG_INJECTOR_DEF) ? (type as any)[NG_INJECTOR_DEF] : null; -} \ No newline at end of file +} + +export const NG_INJECTABLE_DEF = getClosureSafeProperty({ngInjectableDef: getClosureSafeProperty}); +export const NG_INJECTOR_DEF = getClosureSafeProperty({ngInjectorDef: getClosureSafeProperty}); diff --git a/packages/core/src/di/interface/injector.ts b/packages/core/src/di/interface/injector.ts new file mode 100644 index 0000000000..cf9b3c780b --- /dev/null +++ b/packages/core/src/di/interface/injector.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + + +/** + * Injection flags for DI. + * + * @publicApi + */ +export enum InjectFlags { + // TODO(alxhub): make this 'const' when ngc no longer writes exports of it into ngfactory files. + + /** Check self and check parent injector if needed */ + Default = 0b0000, + /** + * Specifies that an injector should retrieve a dependency from any injector until reaching the + * host element of the current component. (Only used with Element Injector) + */ + Host = 0b0001, + /** Don't ascend to ancestors of the node requesting injection. */ + Self = 0b0010, + /** Skip the node that is requesting injection. */ + SkipSelf = 0b0100, + /** Inject `defaultValue` instead if token not found. */ + Optional = 0b1000, +} diff --git a/packages/core/src/di/provider.ts b/packages/core/src/di/interface/provider.ts similarity index 99% rename from packages/core/src/di/provider.ts rename to packages/core/src/di/interface/provider.ts index 7263eebe13..d78314457f 100644 --- a/packages/core/src/di/provider.ts +++ b/packages/core/src/di/interface/provider.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; +import {Type} from '../../interface/type'; /** * Configures the `Injector` to return a value for a token. diff --git a/packages/core/src/di/jit/environment.ts b/packages/core/src/di/jit/environment.ts new file mode 100644 index 0000000000..5f3eb05beb --- /dev/null +++ b/packages/core/src/di/jit/environment.ts @@ -0,0 +1,33 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Type} from '../../interface/type'; +import {inject} from '../injector_compatibility'; +import {defineInjectable, defineInjector, getInjectableDef, getInjectorDef} from '../interface/defs'; + + +/** + * A mapping of the @angular/core API surface used in generated expressions to the actual symbols. + * + * This should be kept up to date with the public exports of @angular/core. + */ +export const angularCoreDiEnv: {[name: string]: Function} = { + 'defineInjectable': defineInjectable, + 'defineInjector': defineInjector, + 'inject': inject, + 'ɵgetFactoryOf': getFactoryOf, +}; + +function getFactoryOf(type: Type): ((type: Type| null) => T)|null { + const typeAny = type as any; + const def = getInjectableDef(typeAny) || getInjectorDef(typeAny); + if (!def || def.factory === undefined) { + return null; + } + return def.factory; +} diff --git a/packages/core/src/render3/jit/injectable.ts b/packages/core/src/di/jit/injectable.ts similarity index 88% rename from packages/core/src/render3/jit/injectable.ts rename to packages/core/src/di/jit/injectable.ts index 26f8b823e0..128985b578 100644 --- a/packages/core/src/render3/jit/injectable.ts +++ b/packages/core/src/di/jit/injectable.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injectable} from '../../di/injectable'; -import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, ValueProvider, ValueSansProvider} from '../../di/provider'; -import {Type} from '../../type'; +import {R3InjectableMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; +import {Type} from '../../interface/type'; import {getClosureSafeProperty} from '../../util/property'; -import {NG_INJECTABLE_DEF} from '../fields'; +import {Injectable} from '../injectable'; +import {NG_INJECTABLE_DEF} from '../interface/defs'; +import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, ValueProvider, ValueSansProvider} from '../interface/provider'; -import {R3InjectableMetadataFacade, getCompilerFacade} from './compiler_facade'; -import {angularCoreEnv} from './environment'; +import {angularCoreDiEnv} from './environment'; import {convertDependencies, reflectDependencies} from './util'; @@ -43,7 +43,7 @@ export function compileInjectable(type: Type, srcMeta?: Injectable): void { typeArgumentCount: 0, providedIn: meta.providedIn, ctorDeps: reflectDependencies(type), - userDeps: undefined + userDeps: undefined, }; if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) { compilerMeta.userDeps = convertDependencies(meta.deps); @@ -71,7 +71,7 @@ export function compileInjectable(type: Type, srcMeta?: Injectable): void { throw new Error(`Unreachable state.`); } def = getCompilerFacade().compileInjectable( - angularCoreEnv, `ng://${type.name}/ngInjectableDef.js`, compilerMeta); + angularCoreDiEnv, `ng://${type.name}/ngInjectableDef.js`, compilerMeta); } return def; }, diff --git a/packages/core/src/render3/jit/util.ts b/packages/core/src/di/jit/util.ts similarity index 93% rename from packages/core/src/render3/jit/util.ts rename to packages/core/src/di/jit/util.ts index 0bcc8da424..cc4805aa9d 100644 --- a/packages/core/src/render3/jit/util.ts +++ b/packages/core/src/di/jit/util.ts @@ -6,12 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Host, Inject, Optional, Self, SkipSelf} from '../../di/metadata'; -import {Attribute} from '../../metadata/di'; +import {CompilerFacade, R3DependencyMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; +import {Type} from '../../interface/type'; import {ReflectionCapabilities} from '../../reflection/reflection_capabilities'; -import {Type} from '../../type'; - -import {CompilerFacade, R3DependencyMetadataFacade, getCompilerFacade} from './compiler_facade'; +import {Attribute, Host, Inject, Optional, Self, SkipSelf} from '../metadata'; let _reflect: ReflectionCapabilities|null = null; diff --git a/packages/core/src/di/metadata.ts b/packages/core/src/di/metadata.ts index b3a0e72d8e..95c090bda3 100644 --- a/packages/core/src/di/metadata.ts +++ b/packages/core/src/di/metadata.ts @@ -6,11 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ClassSansProvider, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, StaticClassProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from '../di/provider'; -import {ReflectionCapabilities} from '../reflection/reflection_capabilities'; -import {Type} from '../type'; -import {makeDecorator, makeParamDecorator} from '../util/decorators'; -import {EMPTY_ARRAY} from '../view/util'; +import {makeParamDecorator} from '../util/decorators'; + /** @@ -20,10 +17,10 @@ import {EMPTY_ARRAY} from '../view/util'; */ export interface InjectDecorator { /** - * A constructor parameter decorator that specifies a - * custom provider of a dependency. + * A parameter decorator on a dependency parameter of a class constructor + * that specifies a custom provider of the dependency. * - * @see ["Dependency Injection Guide"](guide/dependency-injection). + * Learn more in the ["Dependency Injection Guide"](guide/dependency-injection). * * @usageNotes * The following example shows a class constructor that specifies a @@ -31,7 +28,7 @@ export interface InjectDecorator { * * {@example core/di/ts/metadata_spec.ts region='Inject'} * - * When `@Inject()` is not present, the `Injector` uses the type annotation of the + * When `@Inject()` is not present, the injector uses the type annotation of the * parameter as the provider. * * {@example core/di/ts/metadata_spec.ts region='InjectWithoutDecorator'} @@ -47,7 +44,7 @@ export interface InjectDecorator { */ export interface Inject { /** - * Injector token that maps to the dependency to be injected. + * A [DI token](guide/glossary#di-token) that maps to the dependency to be injected. */ token: any; } @@ -68,14 +65,21 @@ export const Inject: InjectDecorator = makeParamDecorator('Inject', (token: any) */ export interface OptionalDecorator { /** - * A constructor parameter decorator that marks a dependency as optional. - * + * A parameter decorator to be used on constructor parameters, + * which marks the parameter as being an optional dependency. * The DI framework provides null if the dependency is not found. - * For example, the following code allows the possibility of a null result: + * + * Can be used together with other parameter decorators + * that modify how dependency injection operates. + * + * Learn more in the ["Dependency Injection Guide"](guide/dependency-injection). + * + * @usageNotes + * + * The following code allows the possibility of a null result: * * {@example core/di/ts/metadata_spec.ts region='Optional'} * - * @see ["Dependency Injection Guide"](guide/dependency-injection). */ (): any; new (): Optional; @@ -103,8 +107,13 @@ export const Optional: OptionalDecorator = makeParamDecorator('Optional'); */ export interface SelfDecorator { /** - * A constructor parameter decorator that tells the DI framework - * to retrieve a dependency only from the local injector. + * A parameter decorator to be used on constructor parameters, + * which tells the DI framework to start dependency resolution from the local injector. + * + * Resolution works upward through the injector hierarchy, so the children + * of this class must configure their own providers or be prepared for a null result. + * + * @usageNotes * * In the following example, the dependency can be resolved * by the local injector when instantiating the class itself, but not @@ -112,8 +121,8 @@ export interface SelfDecorator { * * {@example core/di/ts/metadata_spec.ts region='Self'} * - * @see ["Dependency Injection Guide"](guide/dependency-injection). - * + * @see `SkipSelf` + * @see `Optional` * */ (): any; @@ -143,16 +152,23 @@ export const Self: SelfDecorator = makeParamDecorator('Self'); */ export interface SkipSelfDecorator { /** - * A constructor parameter decorator that tells the DI framework - * that dependency resolution should start from the parent injector. + * A parameter decorator to be used on constructor parameters, + * which tells the DI framework to start dependency resolution from the parent injector. + * Resolution works upward through the injector hierarchy, so the local injector + * is not checked for a provider. + * + * @usageNotes * * In the following example, the dependency can be resolved when * instantiating a child, but not when instantiating the class itself. * * {@example core/di/ts/metadata_spec.ts region='SkipSelf'} * - * @see ["Dependency Injection Guide"](guide/dependency-injection). + * Learn more in the + * [Dependency Injection guide](guide/dependency-injection-in-action#skip). * + * @see `Self` + * @see `Optional` * */ (): any; @@ -181,14 +197,17 @@ export const SkipSelf: SkipSelfDecorator = makeParamDecorator('SkipSelf'); */ export interface HostDecorator { /** - * A constructor parameter decorator that tells the DI framework - * to retrieve a dependency from any injector until - * reaching the host element of the current component. + * A parameter decorator on a view-provider parameter of a class constructor + * that tells the DI framework to resolve the view by checking injectors of child + * elements, and stop when reaching the host element of the current component. * - * @see ["Dependency Injection Guide"](guide/dependency-injection). + * For an extended example, see + * ["Dependency Injection Guide"](guide/dependency-injection-in-action#optional). * * @usageNotes * + * The following shows use with the `@Optional` decorator, and allows for a null result. + * * {@example core/di/ts/metadata_spec.ts region='Host'} */ (): any; @@ -209,3 +228,67 @@ export interface Host {} * @publicApi */ export const Host: HostDecorator = makeParamDecorator('Host'); + + +/** + * Type of the Attribute decorator / constructor function. + * + * @publicApi + */ +export interface AttributeDecorator { + /** + * Specifies that a constant attribute value should be injected. + * + * The directive can inject constant string literals of host element attributes. + * + * @usageNotes + * ### Example + * + * Suppose we have an `` element and want to know its `type`. + * + * ```html + * + * ``` + * + * A decorator can inject string literal `text` like so: + * + * {@example core/ts/metadata/metadata.ts region='attributeMetadata'} + * + * ### Example as TypeScript Decorator + * + * {@example core/ts/metadata/metadata.ts region='attributeFactory'} + * + * ### Example as ES5 annotation + * + * ``` + * var MyComponent = function(title) { + * ... + * }; + * + * MyComponent.annotations = [ + * new ng.Component({...}) + * ] + * MyComponent.parameters = [ + * [new ng.Attribute('title')] + * ] + * ``` + */ + (name: string): any; + new (name: string): Attribute; +} + +/** + * Type of the Attribute metadata. + * + * @publicApi + */ +export interface Attribute { attributeName?: string; } + +/** + * Attribute decorator and metadata. + * + * @Annotation + * @publicApi + */ +export const Attribute: AttributeDecorator = + makeParamDecorator('Attribute', (attributeName?: string) => ({attributeName})); diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index c80731ded4..b1415fd970 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -6,20 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ -import {OnDestroy} from '../metadata/lifecycle_hooks'; -import {Type} from '../type'; -import {stringify} from '../util'; - -import {InjectableDef, InjectableType, InjectorType, InjectorTypeWithProviders, getInjectableDef, getInjectorDef} from './defs'; +import {OnDestroy} from '../interface/lifecycle_hooks'; +import {Type} from '../interface/type'; +import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {INJECTOR, Injector, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE} from './injector'; -import {InjectFlags, inject, injectArgs, setCurrentInjector} from './injector_compatibility'; -import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, Provider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './provider'; +import {INJECTOR, Injector, NG_TEMP_TOKEN_PATH, NullInjector, USE_VALUE, catchInjectorError} from './injector'; +import {inject, injectArgs, setCurrentInjector} from './injector_compatibility'; +import {InjectableDef, InjectableType, InjectorType, InjectorTypeWithProviders, getInjectableDef, getInjectorDef} from './interface/defs'; +import {InjectFlags} from './interface/injector'; +import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './interface/provider'; import {APP_ROOT} from './scope'; - /** * Internal type for a single provider in a deep provider array. */ @@ -71,9 +70,9 @@ interface Record { */ export function createInjector( defType: /* InjectorType */ any, parent: Injector | null = null, - additionalProviders: StaticProvider[] | null = null): Injector { + additionalProviders: StaticProvider[] | null = null, name?: string): Injector { parent = parent || getNullInjector(); - return new R3Injector(defType, additionalProviders, parent); + return new R3Injector(defType, additionalProviders, parent, name); } export class R3Injector { @@ -98,14 +97,17 @@ export class R3Injector { */ private readonly isRootInjector: boolean; + readonly source: string|null; + /** * Flag indicating that this injector was previously destroyed. */ - private destroyed = false; + get destroyed(): boolean { return this._destroyed; } + private _destroyed = false; constructor( - def: InjectorType, additionalProviders: StaticProvider[]|null, - readonly parent: Injector) { + def: InjectorType, additionalProviders: StaticProvider[]|null, readonly parent: Injector, + source: string|null = null) { // Start off by creating Records for every provider declared in every InjectorType // included transitively in `def`. const dedupStack: InjectorType[] = []; @@ -125,6 +127,9 @@ export class R3Injector { // Eagerly instantiate the InjectorType classes themselves. this.injectorDefTypes.forEach(defType => this.get(defType)); + + // Source name, used for debugging + this.source = source || (def instanceof Array ? null : stringify(def)); } /** @@ -137,7 +142,7 @@ export class R3Injector { this.assertNotDestroyed(); // Set destroyed = true first, in case lifecycle hooks re-enter destroy(). - this.destroyed = true; + this._destroyed = true; try { // Call all the lifecycle hooks. this.onDestroy.forEach(service => service.ngOnDestroy()); @@ -150,7 +155,7 @@ export class R3Injector { } get( - token: Type|InjectionToken, notFoundValue: any = THROW_IF_NOT_FOUND, + token: Type|InjectionToken, notFoundValue: any = Injector.THROW_IF_NOT_FOUND, flags = InjectFlags.Default): T { this.assertNotDestroyed(); // Set the injection context. @@ -180,7 +185,21 @@ export class R3Injector { // Select the next injector based on the Self flag - if self is set, the next injector is // the NullInjector, otherwise it's the parent. const nextInjector = !(flags & InjectFlags.Self) ? this.parent : getNullInjector(); - return nextInjector.get(token, notFoundValue); + return nextInjector.get(token, flags & InjectFlags.Optional ? null : notFoundValue); + } catch (e) { + if (e.name === 'NullInjectorError') { + const path: any[] = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || []; + path.unshift(stringify(token)); + if (previousInjector) { + // We still have a parent injector, keep throwing + throw e; + } else { + // Format & throw the final error message when we don't have any previous injector + return catchInjectorError(e, token, 'R3InjectorError', this.source); + } + } else { + throw e; + } } finally { // Lastly, clean up the state by restoring the previous injector. setCurrentInjector(previousInjector); @@ -188,7 +207,7 @@ export class R3Injector { } private assertNotDestroyed(): void { - if (this.destroyed) { + if (this._destroyed) { throw new Error('Injector has already been destroyed.'); } } @@ -433,7 +452,7 @@ function deepForEach(input: (T | any[])[], fn: (value: T) => void): void { } function isValueProvider(value: SingleProvider): value is ValueProvider { - return value && typeof value == 'object' && USE_VALUE in value; + return value !== null && typeof value == 'object' && USE_VALUE in value; } function isExistingProvider(value: SingleProvider): value is ExistingProvider { @@ -454,7 +473,7 @@ function hasDeps(value: ClassProvider | ConstructorProvider | StaticClassProvide } function hasOnDestroy(value: any): value is OnDestroy { - return typeof value === 'object' && value != null && (value as OnDestroy).ngOnDestroy && + return value !== null && typeof value === 'object' && typeof(value as OnDestroy).ngOnDestroy === 'function'; } diff --git a/packages/core/src/di/reflective_errors.ts b/packages/core/src/di/reflective_errors.ts index c88ffa441d..584b863fed 100644 --- a/packages/core/src/di/reflective_errors.ts +++ b/packages/core/src/di/reflective_errors.ts @@ -6,10 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {wrappedError} from '../error_handler'; -import {ERROR_ORIGINAL_ERROR, getOriginalError} from '../errors'; -import {Type} from '../type'; -import {stringify} from '../util'; +import {Type} from '../interface/type'; +import {ERROR_ORIGINAL_ERROR, wrappedError} from '../util/errors'; +import {stringify} from '../util/stringify'; import {ReflectiveInjector} from './reflective_injector'; import {ReflectiveKey} from './reflective_key'; diff --git a/packages/core/src/di/reflective_injector.ts b/packages/core/src/di/reflective_injector.ts index aa30e76ed2..8ce87b226f 100644 --- a/packages/core/src/di/reflective_injector.ts +++ b/packages/core/src/di/reflective_injector.ts @@ -7,12 +7,13 @@ */ import {Injector, THROW_IF_NOT_FOUND} from './injector'; +import {Provider} from './interface/provider'; import {Self, SkipSelf} from './metadata'; -import {Provider} from './provider'; import {cyclicDependencyError, instantiationError, noProviderError, outOfBoundsError} from './reflective_errors'; import {ReflectiveKey} from './reflective_key'; import {ReflectiveDependency, ResolvedReflectiveFactory, ResolvedReflectiveProvider, resolveReflectiveProviders} from './reflective_provider'; + // Threshold for the dynamic version const UNDEFINED = new Object(); diff --git a/packages/core/src/di/reflective_key.ts b/packages/core/src/di/reflective_key.ts index 476f62906f..f7219f60f5 100644 --- a/packages/core/src/di/reflective_key.ts +++ b/packages/core/src/di/reflective_key.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {stringify} from '../util'; +import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; diff --git a/packages/core/src/di/reflective_provider.ts b/packages/core/src/di/reflective_provider.ts index 3d4666e82d..f9a8c26e7b 100644 --- a/packages/core/src/di/reflective_provider.ts +++ b/packages/core/src/di/reflective_provider.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import {Type} from '../interface/type'; import {reflector} from '../reflection/reflection'; -import {Type} from '../type'; import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; +import {ClassProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; -import {ClassProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ValueProvider} from './provider'; import {invalidProviderError, mixingMultiProvidersWithRegularProvidersError, noAnnotationError} from './reflective_errors'; import {ReflectiveKey} from './reflective_key'; diff --git a/packages/core/src/di/scope.ts b/packages/core/src/di/scope.ts index e4a3badc71..6c9c13bc6a 100644 --- a/packages/core/src/di/scope.ts +++ b/packages/core/src/di/scope.ts @@ -6,7 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; import {InjectionToken} from './injection_token'; diff --git a/packages/core/src/di/util.ts b/packages/core/src/di/util.ts index e8828521d7..de0294beb7 100644 --- a/packages/core/src/di/util.ts +++ b/packages/core/src/di/util.ts @@ -6,12 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import {Type} from '../interface/type'; import {ReflectionCapabilities} from '../reflection/reflection_capabilities'; -import {Type} from '../type'; import {getClosureSafeProperty} from '../util/property'; import {inject, injectArgs} from './injector_compatibility'; -import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './provider'; +import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './interface/provider'; const USE_VALUE = getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); diff --git a/packages/core/src/error_handler.ts b/packages/core/src/error_handler.ts index a85273ccac..fa3bb50d70 100644 --- a/packages/core/src/error_handler.ts +++ b/packages/core/src/error_handler.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ERROR_ORIGINAL_ERROR, getDebugContext, getErrorLogger, getOriginalError} from './errors'; +import {getDebugContext, getErrorLogger, getOriginalError} from './errors'; @@ -77,11 +77,3 @@ export class ErrorHandler { return e; } } - -export function wrappedError(message: string, originalError: any): Error { - const msg = - `${message} caused by: ${originalError instanceof Error ? originalError.message: originalError }`; - const error = Error(msg); - (error as any)[ERROR_ORIGINAL_ERROR] = originalError; - return error; -} diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index 002dbe903d..74712bc004 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -6,14 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {ERROR_DEBUG_CONTEXT, ERROR_LOGGER, ERROR_ORIGINAL_ERROR, ERROR_TYPE} from './util/errors'; import {DebugContext} from './view'; -export const ERROR_TYPE = 'ngType'; -export const ERROR_DEBUG_CONTEXT = 'ngDebugContext'; -export const ERROR_ORIGINAL_ERROR = 'ngOriginalError'; -export const ERROR_LOGGER = 'ngErrorLogger'; - - export function getType(error: Error): Function { return (error as any)[ERROR_TYPE]; } diff --git a/packages/core/src/event_emitter.ts b/packages/core/src/event_emitter.ts index 40482cd8df..c1a2bed99e 100644 --- a/packages/core/src/event_emitter.ts +++ b/packages/core/src/event_emitter.ts @@ -97,7 +97,7 @@ export class EventEmitter extends Subject { * @param complete When supplied, a custom handler for a completion * notification from this emitter. */ - subscribe(generatorOrNext?: any, error?: any, complete?: any): any { + subscribe(generatorOrNext?: any, error?: any, complete?: any): Subscription { let schedulerFn: (t: any) => any; let errorFn = (err: any): any => null; let completeFn = (): any => null; diff --git a/packages/core/src/interface/BUILD.bazel b/packages/core/src/interface/BUILD.bazel new file mode 100644 index 0000000000..57391b768e --- /dev/null +++ b/packages/core/src/interface/BUILD.bazel @@ -0,0 +1,15 @@ +package(default_visibility = [ + "//packages/core:__subpackages__", + "//tools/public_api_guard:__pkg__", +]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "interface", + srcs = glob( + [ + "*.ts", + ], + ), +) diff --git a/packages/core/src/metadata/lifecycle_hooks.ts b/packages/core/src/interface/lifecycle_hooks.ts similarity index 96% rename from packages/core/src/metadata/lifecycle_hooks.ts rename to packages/core/src/interface/lifecycle_hooks.ts index 8266863f6c..f5b1976d92 100644 --- a/packages/core/src/metadata/lifecycle_hooks.ts +++ b/packages/core/src/interface/lifecycle_hooks.ts @@ -5,21 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {SimpleChanges} from './simple_change'; -import {SimpleChange} from '../change_detection/change_detection_util'; - - -/** - * Defines an object that associates properties with - * instances of `SimpleChange`. - * - * 定义一个对象,它把属性与 `SimpleChange` 的实例关联起来。 - * - * @see `OnChanges` - * - * @publicApi - */ -export interface SimpleChanges { [propName: string]: SimpleChange; } /** * @description diff --git a/packages/core/src/interface/simple_change.ts b/packages/core/src/interface/simple_change.ts new file mode 100644 index 0000000000..6152cbd7ad --- /dev/null +++ b/packages/core/src/interface/simple_change.ts @@ -0,0 +1,35 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * Represents a basic change from a previous to a new value for a single + * property on a directive instance. Passed as a value in a + * {@link SimpleChanges} object to the `ngOnChanges` hook. + * + * @see `OnChanges` + * + * @publicApi + */ +export class SimpleChange { + constructor(public previousValue: any, public currentValue: any, public firstChange: boolean) {} + /** + * Check whether the new value is the first value assigned. + */ + isFirstChange(): boolean { return this.firstChange; } +} + +/** + * A hashtable of changes represented by {@link SimpleChange} objects stored + * at the declared property name they belong to on a Directive or Component. This is + * the type passed to the `ngOnChanges` hook. + * + * @see `OnChanges` + * + * @publicApi + */ +export interface SimpleChanges { [propName: string]: SimpleChange; } diff --git a/packages/core/src/type.ts b/packages/core/src/interface/type.ts similarity index 100% rename from packages/core/src/type.ts rename to packages/core/src/interface/type.ts diff --git a/packages/core/src/linker/compiler.ts b/packages/core/src/linker/compiler.ts index f5e8e4e1a8..25d572667c 100644 --- a/packages/core/src/linker/compiler.ts +++ b/packages/core/src/linker/compiler.ts @@ -8,11 +8,13 @@ import {Injectable} from '../di/injectable'; import {InjectionToken} from '../di/injection_token'; -import {StaticProvider} from '../di/provider'; +import {StaticProvider} from '../di/interface/provider'; import {MissingTranslationStrategy} from '../i18n/tokens'; +import {Type} from '../interface/type'; import {ViewEncapsulation} from '../metadata'; +import {ComponentFactory as ComponentFactoryR3} from '../render3/component_ref'; +import {getComponentDef, getNgModuleDef} from '../render3/definition'; import {NgModuleFactory as NgModuleFactoryR3} from '../render3/ng_module_ref'; -import {Type} from '../type'; import {ComponentFactory} from './component_factory'; import {NgModuleFactory} from './ng_module_factory'; @@ -56,7 +58,14 @@ const Compiler_compileModuleAndAllComponentsSync__PRE_R3__: (moduleType: Type export const Compiler_compileModuleAndAllComponentsSync__POST_R3__: (moduleType: Type) => ModuleWithComponentFactories = function(moduleType: Type): ModuleWithComponentFactories { - return new ModuleWithComponentFactories(Compiler_compileModuleSync__POST_R3__(moduleType), []); + const ngModuleFactory = Compiler_compileModuleSync__POST_R3__(moduleType); + const moduleDef = getNgModuleDef(moduleType) !; + const componentFactories = moduleDef.declarations.reduce((factories, declaration) => { + const componentDef = getComponentDef(declaration); + componentDef && factories.push(new ComponentFactoryR3(componentDef)); + return factories; + }, [] as ComponentFactory[]); + return new ModuleWithComponentFactories(ngModuleFactory, componentFactories); }; const Compiler_compileModuleAndAllComponentsSync = Compiler_compileModuleAndAllComponentsSync__PRE_R3__; diff --git a/packages/core/src/linker/component_factory.ts b/packages/core/src/linker/component_factory.ts index 660c45ea79..4ce743ca4a 100644 --- a/packages/core/src/linker/component_factory.ts +++ b/packages/core/src/linker/component_factory.ts @@ -8,7 +8,7 @@ import {ChangeDetectorRef} from '../change_detection/change_detection'; import {Injector} from '../di/injector'; -import {Type} from '../type'; +import {Type} from '../interface/type'; import {ElementRef} from './element_ref'; import {NgModuleRef} from './ng_module_factory'; diff --git a/packages/core/src/linker/component_factory_resolver.ts b/packages/core/src/linker/component_factory_resolver.ts index ac1f0abbe4..7d925672a5 100644 --- a/packages/core/src/linker/component_factory_resolver.ts +++ b/packages/core/src/linker/component_factory_resolver.ts @@ -7,8 +7,8 @@ */ import {Injector} from '../di/injector'; -import {Type} from '../type'; -import {stringify} from '../util'; +import {Type} from '../interface/type'; +import {stringify} from '../util/stringify'; import {ComponentFactory, ComponentRef} from './component_factory'; import {NgModuleRef} from './ng_module_factory'; diff --git a/packages/core/src/linker/element_ref.ts b/packages/core/src/linker/element_ref.ts index c723263a00..8759759ef6 100644 --- a/packages/core/src/linker/element_ref.ts +++ b/packages/core/src/linker/element_ref.ts @@ -66,7 +66,10 @@ export class ElementRef { constructor(nativeElement: T) { this.nativeElement = nativeElement; } - /** @internal */ + /** + * @internal + * @nocollapse + */ static __NG_ELEMENT_ID__: () => ElementRef = () => SWITCH_ELEMENT_REF_FACTORY(ElementRef); } diff --git a/packages/core/src/linker/ng_module_factory.ts b/packages/core/src/linker/ng_module_factory.ts index e307100003..043d450dac 100644 --- a/packages/core/src/linker/ng_module_factory.ts +++ b/packages/core/src/linker/ng_module_factory.ts @@ -7,7 +7,7 @@ */ import {Injector} from '../di/injector'; -import {Type} from '../type'; +import {Type} from '../interface/type'; import {ComponentFactoryResolver} from './component_factory_resolver'; diff --git a/packages/core/src/linker/ng_module_factory_loader.ts b/packages/core/src/linker/ng_module_factory_loader.ts index b6a678e6d6..c4660f71f8 100644 --- a/packages/core/src/linker/ng_module_factory_loader.ts +++ b/packages/core/src/linker/ng_module_factory_loader.ts @@ -6,11 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import {Type} from '../interface/type'; import {NgModuleFactory as R3NgModuleFactory, NgModuleType} from '../render3/ng_module_ref'; -import {Type} from '../type'; -import {stringify} from '../util'; +import {stringify} from '../util/stringify'; + import {NgModuleFactory} from './ng_module_factory'; + /** * Used to load ng module factories. * @@ -33,12 +35,12 @@ const modules = new Map|NgModuleType>(); */ export function registerModuleFactory(id: string, factory: NgModuleFactory) { const existing = modules.get(id) as NgModuleFactory; - assertNotExisting(id, existing && existing.moduleType); + assertSameOrNotExisting(id, existing && existing.moduleType, factory.moduleType); modules.set(id, factory); } -function assertNotExisting(id: string, type: Type| null): void { - if (type) { +function assertSameOrNotExisting(id: string, type: Type| null, incoming: Type): void { + if (type && type !== incoming) { throw new Error( `Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`); } @@ -46,7 +48,7 @@ function assertNotExisting(id: string, type: Type| null): void { export function registerNgModuleType(id: string, ngModuleType: NgModuleType) { const existing = modules.get(id) as NgModuleType | null; - assertNotExisting(id, existing); + assertSameOrNotExisting(id, existing, ngModuleType); modules.set(id, ngModuleType); } diff --git a/packages/core/src/linker/query_list.ts b/packages/core/src/linker/query_list.ts index 6f3c549c53..eaa1ce4534 100644 --- a/packages/core/src/linker/query_list.ts +++ b/packages/core/src/linker/query_list.ts @@ -9,7 +9,7 @@ import {Observable} from 'rxjs'; import {EventEmitter} from '../event_emitter'; -import {getSymbolIterator} from '../util'; +import {getSymbolIterator} from '../util/symbol'; /** diff --git a/packages/core/src/linker/template_ref.ts b/packages/core/src/linker/template_ref.ts index 9d797086b1..a5066c1e47 100644 --- a/packages/core/src/linker/template_ref.ts +++ b/packages/core/src/linker/template_ref.ts @@ -64,22 +64,27 @@ export abstract class TemplateRef { abstract get elementRef(): ElementRef; /** - * Creates a view object and attaches it to the view container of the parent view. + * Instantiates an embedded view based on this template, + * and attaches it to the view container. * * 创建一个视图对象,并把它附着到父视图的视图容器上。 * - * @param context The context for the new view, inherited from the anchor element. + * @param context The data-binding context of the embedded view, as declared + * in the `` usage. * * 这个新视图的上下文环境,继承自所附着的元素。 * - * @returns The new view object. + * @returns The new embedded view object. * * 这个新的视图对象。 * */ abstract createEmbeddedView(context: C): EmbeddedViewRef; - /** @internal */ + /** + * @internal + * @nocollapse + */ static __NG_ELEMENT_ID__: () => TemplateRef| null = () => SWITCH_TEMPLATE_REF_FACTORY(TemplateRef, ElementRef) } diff --git a/packages/core/src/linker/view_container_ref.ts b/packages/core/src/linker/view_container_ref.ts index 4d394d33bc..e3a657d68d 100644 --- a/packages/core/src/linker/view_container_ref.ts +++ b/packages/core/src/linker/view_container_ref.ts @@ -245,7 +245,10 @@ export abstract class ViewContainerRef { */ abstract detach(index?: number): ViewRef|null; - /** @internal */ + /** + * @internal + * @nocollapse + */ static __NG_ELEMENT_ID__: () => ViewContainerRef = () => SWITCH_VIEW_CONTAINER_REF_FACTORY(ViewContainerRef, ElementRef) } diff --git a/packages/core/src/metadata.ts b/packages/core/src/metadata.ts index d377b0afae..ca9b5feea3 100644 --- a/packages/core/src/metadata.ts +++ b/packages/core/src/metadata.ts @@ -11,13 +11,17 @@ * to be used by the decorator versions of these annotations. */ -import {Attribute, ContentChild, ContentChildren, Query, ViewChild, ViewChildren} from './metadata/di'; +import {Attribute} from './di'; +import {ContentChild, ContentChildren, Query, ViewChild, ViewChildren} from './metadata/di'; import {Component, Directive, HostBinding, HostListener, Input, Output, Pipe} from './metadata/directives'; -import {DoBootstrap, ModuleWithProviders, NgModule, SchemaMetadata} from './metadata/ng_module'; +import {DoBootstrap, ModuleWithProviders, NgModule} from './metadata/ng_module'; +import {SchemaMetadata} from './metadata/schema'; import {ViewEncapsulation} from './metadata/view'; -export {ANALYZE_FOR_ENTRY_COMPONENTS, Attribute, ContentChild, ContentChildDecorator, ContentChildren, ContentChildrenDecorator, Query, ViewChild, ViewChildDecorator, ViewChildren, ViewChildrenDecorator} from './metadata/di'; +export {Attribute} from './di'; +export {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, OnInit} from './interface/lifecycle_hooks'; +export {ANALYZE_FOR_ENTRY_COMPONENTS, ContentChild, ContentChildDecorator, ContentChildren, ContentChildrenDecorator, Query, ViewChild, ViewChildDecorator, ViewChildren, ViewChildrenDecorator} from './metadata/di'; export {Component, ComponentDecorator, Directive, DirectiveDecorator, HostBinding, HostListener, Input, Output, Pipe} from './metadata/directives'; -export {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, OnInit} from './metadata/lifecycle_hooks'; -export {CUSTOM_ELEMENTS_SCHEMA, DoBootstrap, ModuleWithProviders, NO_ERRORS_SCHEMA, NgModule, SchemaMetadata} from './metadata/ng_module'; +export {DoBootstrap, ModuleWithProviders, NgModule} from './metadata/ng_module'; +export {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from './metadata/schema'; export {ViewEncapsulation} from './metadata/view'; diff --git a/packages/core/src/metadata/di.ts b/packages/core/src/metadata/di.ts index 140637dc64..59fae60cb1 100644 --- a/packages/core/src/metadata/di.ts +++ b/packages/core/src/metadata/di.ts @@ -7,19 +7,20 @@ */ import {InjectionToken} from '../di/injection_token'; -import {Type} from '../type'; -import {makeParamDecorator, makePropDecorator} from '../util/decorators'; +import {Type} from '../interface/type'; +import {makePropDecorator} from '../util/decorators'; /** - * This token can be used to create a virtual provider that will populate the - * `entryComponents` fields of components and ng modules based on its `useValue`. + * A DI token that you can use to create a virtual [provider](guide/glossary#provider) + * that will populate the `entryComponents` field of components and NgModules + * based on its `useValue` property value. * All components that are referenced in the `useValue` value (either directly - * or in a nested array or map) will be added to the `entryComponents` property. + * or in a nested array or map) are added to the `entryComponents` property. * * @usageNotes - * ### Example + * * The following example shows how the router can populate the `entryComponents` - * field of an NgModule based on the router configuration which refers + * field of an NgModule based on a router configuration that refers * to components. * * ```typescript @@ -48,7 +49,7 @@ import {makeParamDecorator, makePropDecorator} from '../util/decorators'; export const ANALYZE_FOR_ENTRY_COMPONENTS = new InjectionToken('AnalyzeForEntryComponents'); /** - * Type of the Attribute decorator / constructor function. + * Type of the `Attribute` decorator / constructor function. * * @publicApi */ @@ -67,29 +68,10 @@ export interface AttributeDecorator { * * ``` * - * A decorator can inject string literal `text` like so: + * A decorator can inject string literal `text` as in the following example. * * {@example core/ts/metadata/metadata.ts region='attributeMetadata'} * - * ### Example as TypeScript Decorator - * - * {@example core/ts/metadata/metadata.ts region='attributeFactory'} - * - * ### Example as ES5 annotation - * - * ``` - * var MyComponent = function(title) { - * ... - * }; - * - * MyComponent.annotations = [ - * new ng.Component({...}) - * ] - * MyComponent.parameters = [ - * [new ng.Attribute('title')] - * ] - * ``` - * * @publicApi */ (name: string): any; @@ -102,16 +84,12 @@ export interface AttributeDecorator { * * @publicApi */ -export interface Attribute { attributeName?: string; } - -/** - * Attribute decorator and metadata. - * - * @Annotation - * @publicApi - */ -export const Attribute: AttributeDecorator = - makeParamDecorator('Attribute', (attributeName?: string) => ({attributeName})); +export interface Attribute { + /** + * The name of the attribute to be injected into the constructor. + */ + attributeName?: string; +} /** * Type of the Query metadata. @@ -240,8 +218,6 @@ export interface ContentChildDecorator { /** * Type of the ContentChild metadata. * - * @see `ContentChild`. - * * @publicApi */ export type ContentChild = Query; @@ -359,7 +335,7 @@ export interface ViewChildDecorator { * * 任何带有 `@Component` 或 `@Directive` 装饰器的类 * - * * a template reference variable as a string (e.g. query ` + * * a template reference variable as a string (e.g. query `` * with `@ViewChild('cmp')`) * * 字符串形式的模板引用变量(比如可以使用 `@ViewChild('cmp')` 来查询 `` diff --git a/packages/core/src/metadata/directives.ts b/packages/core/src/metadata/directives.ts index afdf8201f1..28ee9e1caa 100644 --- a/packages/core/src/metadata/directives.ts +++ b/packages/core/src/metadata/directives.ts @@ -8,10 +8,10 @@ import {ChangeDetectionStrategy} from '../change_detection/constants'; import {Provider} from '../di'; +import {Type} from '../interface/type'; import {NG_BASE_DEF} from '../render3/fields'; import {compileComponent as render3CompileComponent, compileDirective as render3CompileDirective} from '../render3/jit/directive'; import {compilePipe as render3CompilePipe} from '../render3/jit/pipe'; -import {Type} from '../type'; import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators'; import {noop} from '../util/noop'; import {fillProperties} from '../util/property'; @@ -641,8 +641,8 @@ export interface Component extends Directive { moduleId?: string; /** - * The URL of a template file for an Angular component. If provided, - * do not supply an inline template using `template`. + * The relative path or absolute URL of a template file for an Angular component. + * If provided, do not supply an inline template using `template`. * * Angular 组件模板文件的 URL。如果提供了它,就不要再用 `template` 来提供内联模板了。 */ @@ -657,7 +657,7 @@ export interface Component extends Directive { template?: string; /** - * One or more URLs for files containing CSS stylesheets to use + * One or more relative paths or absolute URLs for files containing CSS stylesheets to use * in this component. * * 一个或多个 URL,指向包含本组件 CSS 样式表的文件。 @@ -687,8 +687,7 @@ export interface Component extends Directive { * * 供模板和 CSS 样式使用的样式封装策略。取值为: * - * - `ViewEncapsulation.Native`: Use shadow roots. This works - * only if natively available on the platform. + * - `ViewEncapsulation.Native`: Deprecated. Use `ViewEncapsulation.ShadowDom` instead. * * `ViewEncapsulation.Native`:使用 Shadow DOM。它只在原生支持 Shadow DOM 的平台上才能工作。 * @@ -699,6 +698,7 @@ export interface Component extends Directive { * * - `ViewEncapsulation.None`: Use global CSS without any * encapsulation. + * - `ViewEncapsulation.ShadowDom`: Use Shadow DOM v1 to encapsulate styles. * * `ViewEncapsulation.None`:使用全局 CSS,不做任何封装。 * diff --git a/packages/core/src/metadata/ng_module.ts b/packages/core/src/metadata/ng_module.ts index ec97980f4a..6c015017ba 100644 --- a/packages/core/src/metadata/ng_module.ts +++ b/packages/core/src/metadata/ng_module.ts @@ -7,14 +7,16 @@ */ import {ApplicationRef} from '../application_ref'; -import {InjectorType, defineInjector} from '../di/defs'; -import {Provider} from '../di/provider'; +import {InjectorType, defineInjector} from '../di/interface/defs'; +import {Provider} from '../di/interface/provider'; import {convertInjectableProviderToFactory} from '../di/util'; +import {Type} from '../interface/type'; +import {SchemaMetadata} from '../metadata/schema'; import {NgModuleType} from '../render3'; import {compileNgModule as render3CompileNgModule} from '../render3/jit/module'; -import {Type} from '../type'; import {TypeDecorator, makeDecorator} from '../util/decorators'; + /** * Represents the expansion of an `NgModule` into its scopes. * @@ -33,6 +35,7 @@ import {TypeDecorator, makeDecorator} from '../util/decorators'; export interface NgModuleTransitiveScopes { compilation: {directives: Set; pipes: Set;}; exported: {directives: Set; pipes: Set;}; + schemas: SchemaMetadata[]|null; } export type NgModuleDefWithMeta = NgModuleDef; @@ -96,6 +99,9 @@ export interface NgModuleDef { * 永远不要直接使用它,而是通过 `transitiveScopesFor` 来访问。 */ transitiveCompileScopes: NgModuleTransitiveScopes|null; + + /** The set of schemas that declare elements to be allowed in the NgModule. */ + schemas: SchemaMetadata[]|null; } /** @@ -116,55 +122,6 @@ export interface ModuleWithProviders< providers?: Provider[]; } -/** - * A schema definition associated with an NgModule. - * - * 与 NgModule 相关的 schema(HTML架构)定义。 - * - * @see `@NgModule`, `CUSTOM_ELEMENTS_SCHEMA`, `NO_ERRORS_SCHEMA` - * - * @param name The name of a defined schema. - * - * 已定义的 schema 的名字。 - * - * @publicApi - */ -export interface SchemaMetadata { name: string; } - -/** - * Defines a schema that allows an NgModule to contain the following: - * - * 定义一个 schema,它允许 NgModule 包含下列内容: - * - * - Non-Angular elements named with dash case (`-`). - * - * 中线格式(`-`)的非 Angular 元素名。 - * - * - Element properties named with dash case (`-`). - * - * 中线格式(`-`)的元素属性名。 - * - * Dash case is the naming convention for custom elements. - * - * 中线格式是对自定义元素的命名约定。 - * - * @publicApi - */ -export const CUSTOM_ELEMENTS_SCHEMA: SchemaMetadata = { - name: 'custom-elements' -}; - -/** - * Defines a schema that allows any property on any element. - * - * 定义了一个允许任何元素上的任何属性的 schema。 - * - * @publicApi - */ -export const NO_ERRORS_SCHEMA: SchemaMetadata = { - name: 'no-errors-schema' -}; - /** * Type of the NgModule decorator / constructor function. diff --git a/packages/core/src/metadata/resource_loading.ts b/packages/core/src/metadata/resource_loading.ts index 1870d997c0..633e0ac871 100644 --- a/packages/core/src/metadata/resource_loading.ts +++ b/packages/core/src/metadata/resource_loading.ts @@ -18,18 +18,18 @@ import {Component} from './directives'; * selector: 'my-comp', * templateUrl: 'my-comp.html', // This requires asynchronous resolution * }) - * class MyComponnent{ + * class MyComponent{ * } * - * // Calling `renderComponent` will fail because `MyComponent`'s `@Compenent.templateUrl` - * // needs to be resolved because `renderComponent` is synchronous process. - * // renderComponent(MyComponent); + * // Calling `renderComponent` will fail because `renderComponent` is a synchronous process + * // and `MyComponent`'s `@Component.templateUrl` needs to be resolved asynchronously. * - * // Calling `resolveComponentResources` will resolve `@Compenent.templateUrl` into - * // `@Compenent.template`, which would allow `renderComponent` to proceed in synchronous manner. - * // Use browser's `fetch` function as the default resource resolution strategy. + * // Calling `resolveComponentResources()` will resolve `@Component.templateUrl` into + * // `@Component.template`, which allows `renderComponent` to proceed in a synchronous manner. + * + * // Use browser's `fetch()` function as the default resource resolution strategy. * resolveComponentResources(fetch).then(() => { - * // After resolution all URLs have been converted into strings. + * // After resolution all URLs have been converted into `template` strings. * renderComponent(MyComponent); * }); * @@ -38,8 +38,8 @@ import {Component} from './directives'; * NOTE: In AOT the resolution happens during compilation, and so there should be no need * to call this method outside JIT mode. * - * @param resourceResolver a function which is responsible to returning a `Promise` of the resolved - * URL. Browser's `fetch` method is a good default implementation. + * @param resourceResolver a function which is responsible for returning a `Promise` to the + * contents of the resolved URL. Browser's `fetch()` method is a good default implementation. */ export function resolveComponentResources( resourceResolver: (url: string) => (Promise}>)): Promise { @@ -62,7 +62,6 @@ export function resolveComponentResources( if (component.templateUrl) { cachedResourceResolve(component.templateUrl).then((template) => { component.template = template; - component.templateUrl = undefined; }); } const styleUrls = component.styleUrls; @@ -79,7 +78,7 @@ export function resolveComponentResources( }); }); }); - componentResourceResolutionQueue.clear(); + clearResolutionOfComponentResourcesQueue(); return Promise.all(urlFetches).then(() => null); } @@ -91,8 +90,10 @@ export function maybeQueueResolutionOfComponentResources(metadata: Component) { } } -export function componentNeedsResolution(component: Component) { - return component.templateUrl || component.styleUrls && component.styleUrls.length; +export function componentNeedsResolution(component: Component): boolean { + return !!( + (component.templateUrl && !component.template) || + component.styleUrls && component.styleUrls.length); } export function clearResolutionOfComponentResourcesQueue() { componentResourceResolutionQueue.clear(); @@ -100,4 +101,4 @@ export function clearResolutionOfComponentResourcesQueue() { function unwrapResponse(response: string | {text(): Promise}): string|Promise { return typeof response == 'string' ? response : response.text(); -} \ No newline at end of file +} diff --git a/packages/core/src/metadata/schema.ts b/packages/core/src/metadata/schema.ts new file mode 100644 index 0000000000..54c3d56dbe --- /dev/null +++ b/packages/core/src/metadata/schema.ts @@ -0,0 +1,40 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + + +/** + * A schema definition associated with an NgModule. + * + * @see `@NgModule`, `CUSTOM_ELEMENTS_SCHEMA`, `NO_ERRORS_SCHEMA` + * + * @param name The name of a defined schema. + * + * @publicApi + */ +export interface SchemaMetadata { name: string; } + +/** + * Defines a schema that allows an NgModule to contain the following: + * - Non-Angular elements named with dash case (`-`). + * - Element properties named with dash case (`-`). + * Dash case is the naming convention for custom elements. + * + * @publicApi + */ +export const CUSTOM_ELEMENTS_SCHEMA: SchemaMetadata = { + name: 'custom-elements' +}; + +/** + * Defines a schema that allows any property on any element. + * + * @publicApi + */ +export const NO_ERRORS_SCHEMA: SchemaMetadata = { + name: 'no-errors-schema' +}; diff --git a/packages/core/src/profile/wtf_impl.ts b/packages/core/src/profile/wtf_impl.ts index 5714aebb30..ca2972d13c 100644 --- a/packages/core/src/profile/wtf_impl.ts +++ b/packages/core/src/profile/wtf_impl.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {global} from '../util'; +import {global} from '../util/global'; /** * A scope function for the Web Tracing Framework (WTF). diff --git a/packages/core/src/r3_symbols.ts b/packages/core/src/r3_symbols.ts index 2bddd57e02..e040915411 100644 --- a/packages/core/src/r3_symbols.ts +++ b/packages/core/src/r3_symbols.ts @@ -14,20 +14,22 @@ * compiler writes imports to this file. * * Only a subset of such imports are supported - core is not allowed to declare components or pipes. - * A check in ngtsc's translator.ts validates this condition. The translator is responsible for - * translating an external name (prefixed with ɵ) to the internal symbol name as exported below. + * A check in ngtsc's `R3SymbolsImportRewriter` validates this condition. The rewriter is only used + * when compiling @angular/core and is responsible for translating an external name (prefixed with + * ɵ) to the internal symbol name as exported below. * * The below symbols are used for @Injectable and @NgModule compilation. */ -export {InjectableDef, InjectorDef, defineInjectable, defineInjector} from './di/defs'; export {inject} from './di/injector_compatibility'; +export {InjectableDef, InjectorDef, defineInjectable, defineInjector} from './di/interface/defs'; export {NgModuleDef, NgModuleDefWithMeta} from './metadata/ng_module'; export {defineNgModule} from './render3/definition'; export {setClassMetadata} from './render3/metadata'; export {NgModuleFactory} from './render3/ng_module_ref'; + /** * The existence of this constant (in this particular file) informs the Angular compiler that the * current program is actually @angular/core, which needs to be compiled specially. diff --git a/packages/core/src/reflection/BUILD.bazel b/packages/core/src/reflection/BUILD.bazel new file mode 100644 index 0000000000..73d9f570cd --- /dev/null +++ b/packages/core/src/reflection/BUILD.bazel @@ -0,0 +1,19 @@ +package(default_visibility = [ + "//packages/core:__subpackages__", + "//tools/public_api_guard:__pkg__", +]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "reflection", + srcs = glob( + [ + "**/*.ts", + ], + ), + deps = [ + "//packages/core/src/interface", + "//packages/core/src/util", + ], +) diff --git a/packages/core/src/reflection/platform_reflection_capabilities.ts b/packages/core/src/reflection/platform_reflection_capabilities.ts index 0fee368520..6d4ef3384c 100644 --- a/packages/core/src/reflection/platform_reflection_capabilities.ts +++ b/packages/core/src/reflection/platform_reflection_capabilities.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; +import {Type} from '../interface/type'; import {GetterFn, MethodFn, SetterFn} from './types'; export interface PlatformReflectionCapabilities { diff --git a/packages/core/src/reflection/reflection_capabilities.ts b/packages/core/src/reflection/reflection_capabilities.ts index ca3e397df9..c95112c140 100644 --- a/packages/core/src/reflection/reflection_capabilities.ts +++ b/packages/core/src/reflection/reflection_capabilities.ts @@ -6,14 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type, isType} from '../type'; -import {global, stringify} from '../util'; +import {Type, isType} from '../interface/type'; import {ANNOTATIONS, PARAMETERS, PROP_METADATA} from '../util/decorators'; +import {global} from '../util/global'; +import {stringify} from '../util/stringify'; import {PlatformReflectionCapabilities} from './platform_reflection_capabilities'; import {GetterFn, MethodFn, SetterFn} from './types'; + /** * Attention: These regex has to hold even if the code is minified! */ diff --git a/packages/core/src/reflection/reflector.ts b/packages/core/src/reflection/reflector.ts index 678941f442..6d7b8634f0 100644 --- a/packages/core/src/reflection/reflector.ts +++ b/packages/core/src/reflection/reflector.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; +import {Type} from '../interface/type'; import {PlatformReflectionCapabilities} from './platform_reflection_capabilities'; import {GetterFn, MethodFn, SetterFn} from './types'; diff --git a/packages/core/src/render/api.ts b/packages/core/src/render/api.ts index 3d2dd7dd2f..d8a56eabe1 100644 --- a/packages/core/src/render/api.ts +++ b/packages/core/src/render/api.ts @@ -13,6 +13,7 @@ import {injectRenderer2 as render3InjectRenderer2} from '../render3/view_engine_ import {noop} from '../util/noop'; + /** * @deprecated Use `RendererType2` (and `Renderer2`) instead. * @publicApi @@ -337,8 +338,14 @@ export abstract class Renderer2 { * @param oldChild The child node to remove. * * 要移除的子节点。 + * + * @param isHostElement Optionally signal to the renderer whether this element is a host element + * or not + * + * 可选值,用于告诉渲染器该元素是否宿主元素 + * */ - abstract removeChild(parent: any, oldChild: any): void; + abstract removeChild(parent: any, oldChild: any, isHostElement?: boolean): void; /** * Implement this callback to prepare an element to be bootstrapped * as a root element, and return the element instance. @@ -574,7 +581,10 @@ export abstract class Renderer2 { target: 'window'|'document'|'body'|any, eventName: string, callback: (event: any) => boolean | void): () => void; - /** @internal */ + /** + * @internal + * @nocollapse + */ static __NG_ELEMENT_ID__: () => Renderer2 = () => SWITCH_RENDERER2_FACTORY(); } diff --git a/packages/core/src/render3/assert.ts b/packages/core/src/render3/assert.ts index 3b7bc99403..a05546be2c 100644 --- a/packages/core/src/render3/assert.ts +++ b/packages/core/src/render3/assert.ts @@ -6,61 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import {assertDefined, assertEqual, throwError} from '../util/assert'; + import {getComponentDef, getNgModuleDef} from './definition'; import {TNode} from './interfaces/node'; import {LView} from './interfaces/view'; -// The functions in this file verify that the assumptions we are making -// about state in an instruction are correct before implementing any logic. -// They are meant only to be called in dev mode as sanity checks. - -export function assertNumber(actual: any, msg: string) { - if (typeof actual != 'number') { - throwError(msg); - } -} - -export function assertEqual(actual: T, expected: T, msg: string) { - if (actual != expected) { - throwError(msg); - } -} - -export function assertNotEqual(actual: T, expected: T, msg: string) { - if (actual == expected) { - throwError(msg); - } -} - -export function assertSame(actual: T, expected: T, msg: string) { - if (actual !== expected) { - throwError(msg); - } -} - -export function assertLessThan(actual: T, expected: T, msg: string) { - if (actual >= expected) { - throwError(msg); - } -} - -export function assertGreaterThan(actual: T, expected: T, msg: string) { - if (actual <= expected) { - throwError(msg); - } -} - -export function assertNotDefined(actual: T, msg: string) { - if (actual != null) { - throwError(msg); - } -} - -export function assertDefined(actual: T, msg: string) { - if (actual == null) { - throwError(msg); - } -} export function assertComponentType( actual: any, @@ -80,17 +31,6 @@ export function assertNgModuleType( } } -function throwError(msg: string): never { - // tslint:disable-next-line - debugger; // Left intentionally for better debugger experience. - throw new Error(`ASSERTION ERROR: ${msg}`); -} - -export function assertDomNode(node: any) { - assertEqual(node instanceof Node, true, 'The provided value must be an instance of a DOM Node'); -} - - export function assertPreviousIsParent(isParent: boolean) { assertEqual(isParent, true, 'previousOrParentTNode should be a parent'); } @@ -104,7 +44,3 @@ export function assertDataNext(lView: LView, index: number, arr?: any[]) { assertEqual( arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`); } - -export function assertDataInRange(arr: any[], index: number) { - assertLessThan(index, arr ? arr.length : 0, 'index expected to be a valid data index'); -} diff --git a/packages/core/src/render3/bindings.ts b/packages/core/src/render3/bindings.ts index 88f63a9bd2..f46d21ab2a 100644 --- a/packages/core/src/render3/bindings.ts +++ b/packages/core/src/render3/bindings.ts @@ -7,11 +7,10 @@ */ import {devModeEqual} from '../change_detection/change_detection_util'; - -import {assertDataInRange, assertLessThan, assertNotEqual} from './assert'; +import {assertDataInRange, assertLessThan, assertNotEqual} from '../util/assert'; import {throwErrorIfNoChangesMode} from './errors'; -import {BINDING_INDEX, LView} from './interfaces/view'; -import {getCheckNoChangesMode, isCreationMode} from './state'; +import {LView} from './interfaces/view'; +import {getCheckNoChangesMode} from './state'; import {NO_CHANGE} from './tokens'; import {isDifferent} from './util'; @@ -38,20 +37,21 @@ export function bindingUpdated(lView: LView, bindingIndex: number, value: any): ngDevMode && assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`); - if (lView[bindingIndex] === NO_CHANGE) { - // initial pass - lView[bindingIndex] = value; - } else if (isDifferent(lView[bindingIndex], value)) { + const oldValue = lView[bindingIndex]; + if (isDifferent(oldValue, value)) { if (ngDevMode && getCheckNoChangesMode()) { - if (!devModeEqual(lView[bindingIndex], value)) { - throwErrorIfNoChangesMode(isCreationMode(lView), lView[bindingIndex], value); + // View engine didn't report undefined values as changed on the first checkNoChanges pass + // (before the change detection was run). + const oldValueToCompare = oldValue !== NO_CHANGE ? oldValue : undefined; + if (!devModeEqual(oldValueToCompare, value)) { + throwErrorIfNoChangesMode(oldValue === NO_CHANGE, oldValueToCompare, value); } } lView[bindingIndex] = value; - } else { - return false; + return true; } - return true; + + return false; } /** Updates 2 bindings if changed, then returns whether either was updated. */ diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 30daba0a46..12f99a30c0 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -11,20 +11,21 @@ import {Type} from '../core'; import {Injector} from '../di/injector'; import {Sanitizer} from '../sanitization/security'; +import {assertDefined} from '../util/assert'; -import {assertComponentType, assertDefined} from './assert'; +import {assertComponentType} from './assert'; import {getComponentDef} from './definition'; import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di'; import {publishDefaultGlobalUtils} from './global_utils'; -import {queueInitHooks, queueLifecycleHooks} from './hooks'; -import {CLEAN_PROMISE, createLView, createNodeAtIndex, createTNode, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, locateHostElement, queueComponentIndexForCheck, refreshDescendantViews} from './instructions'; +import {registerPostOrderHooks, registerPreOrderHooks} from './hooks'; +import {CLEAN_PROMISE, addToViewTree, createLView, createNodeAtIndex, createTNode, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, invokeHostBindingsInCreationMode, locateHostElement, queueComponentIndexForCheck, refreshDescendantViews} from './instructions'; import {ComponentDef, ComponentType, RenderFlags} from './interfaces/definition'; import {TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node'; import {PlayerHandler} from './interfaces/player'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; -import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, LView, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view'; +import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, RootContext, RootContextFlags, TVIEW, T_HOST} from './interfaces/view'; import {enterView, getPreviousOrParentTNode, leaveView, resetComponentState, setCurrentDirectiveDef} from './state'; -import {defaultScheduler, getRootView, readPatchedLView, stringify} from './util'; +import {applyOnCreateInstructions, defaultScheduler, getRootView, readPatchedLView, renderStringify} from './util'; @@ -83,7 +84,7 @@ type HostFeature = ((component: T, componentDef: ComponentDef) => void); // TODO: A hack to not pull in the NullInjector from @angular/core. export const NULL_INJECTOR: Injector = { get: (token: any, notFoundValue?: any) => { - throw new Error('NullInjector: Not found: ' + stringify(token)); + throw new Error('NullInjector: Not found: ' + renderStringify(token)); } }; @@ -121,8 +122,8 @@ export function renderComponent( const renderer = rendererFactory.createRenderer(hostRNode, componentDef); const rootView: LView = createLView( - null, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags, rendererFactory, - renderer, undefined, opts.injector || null); + null, createTView(-1, null, 1, 0, null, null, null, null), rootContext, rootFlags, null, null, + rendererFactory, renderer, undefined, opts.injector || null); const oldView = enterView(rootView, null); let component: T; @@ -133,6 +134,8 @@ export function renderComponent( component = createRootComponent( componentView, componentDef, rootView, rootContext, opts.hostFeatures || null); + addToViewTree(rootView, HEADER_OFFSET, componentView); + refreshDescendantViews(rootView); // creation mode pass rootView[FLAGS] &= ~LViewFlags.CreationMode; refreshDescendantViews(rootView); // update mode pass @@ -160,13 +163,13 @@ export function createRootComponentView( rendererFactory: RendererFactory3, renderer: Renderer3, sanitizer?: Sanitizer | null): LView { resetComponentState(); const tView = rootView[TVIEW]; + const tNode: TElementNode = createNodeAtIndex(0, TNodeType.Element, rNode, null, null); const componentView = createLView( - rootView, - getOrCreateTView( - def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery), - null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rendererFactory, renderer, - sanitizer); - const tNode = createNodeAtIndex(0, TNodeType.Element, rNode, null, null); + rootView, getOrCreateTView( + def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, + def.viewQuery, def.schemas), + null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[HEADER_OFFSET], tNode, + rendererFactory, renderer, sanitizer); if (tView.firstTemplatePass) { diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), rootView, def.type); @@ -176,8 +179,6 @@ export function createRootComponentView( } // Store component view at node index, with node as the HOST - componentView[HOST] = rootView[HEADER_OFFSET]; - componentView[HOST_NODE] = tNode as TElementNode; return rootView[HEADER_OFFSET] = componentView; } @@ -199,9 +200,10 @@ export function createRootComponent( if (tView.firstTemplatePass && componentDef.hostBindings) { const rootTNode = getPreviousOrParentTNode(); - setCurrentDirectiveDef(componentDef); - componentDef.hostBindings(RenderFlags.Create, component, rootTNode.index - HEADER_OFFSET); - setCurrentDirectiveDef(null); + const expando = tView.expandoInstructions !; + invokeHostBindingsInCreationMode( + componentDef, expando, component, rootTNode, tView.firstTemplatePass); + rootTNode.onElementCreationFns && applyOnCreateInstructions(rootTNode); } return component; @@ -236,10 +238,11 @@ export function LifecycleHooksFeature(component: any, def: ComponentDef): v const rootTView = readPatchedLView(component) ![TVIEW]; const dirIndex = rootTView.data.length - 1; - queueInitHooks(dirIndex, def.onInit, def.doCheck, rootTView); + registerPreOrderHooks(dirIndex, def, rootTView); // TODO(misko): replace `as TNode` with createTNode call. (needs refactoring to lose dep on // LNode). - queueLifecycleHooks(rootTView, { directiveStart: dirIndex, directiveEnd: dirIndex + 1 } as TNode); + registerPostOrderHooks( + rootTView, { directiveStart: dirIndex, directiveEnd: dirIndex + 1 } as TNode); } /** diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index c35a624abb..4f3d56a386 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -10,22 +10,26 @@ import {ChangeDetectorRef as ViewEngine_ChangeDetectorRef} from '../change_detec import {InjectionToken} from '../di/injection_token'; import {Injector} from '../di/injector'; import {inject} from '../di/injector_compatibility'; +import {InjectFlags} from '../di/interface/injector'; +import {Type} from '../interface/type'; import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory'; import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver'; import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref'; import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory'; import {RendererFactory2} from '../render/api'; import {Sanitizer} from '../sanitization/security'; -import {Type} from '../type'; +import {assertDefined} from '../util/assert'; import {VERSION} from '../version'; -import {assertComponentType, assertDefined} from './assert'; +import {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from '../view/provider'; + +import {assertComponentType} from './assert'; import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component'; import {getComponentDef} from './definition'; import {NodeInjector} from './di'; -import {addToViewTree, createLView, createNodeAtIndex, createTView, createViewNode, elementCreate, locateHostElement, refreshDescendantViews} from './instructions'; -import {ComponentDef, RenderFlags} from './interfaces/definition'; -import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType} from './interfaces/node'; -import {RElement, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; +import {addToViewTree, assignTViewNodeToLView, createLView, createTView, elementCreate, locateHostElement, refreshDescendantViews} from './instructions'; +import {ComponentDef} from './interfaces/definition'; +import {TContainerNode, TElementContainerNode, TElementNode} from './interfaces/node'; +import {RNode, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; import {HEADER_OFFSET, LView, LViewFlags, RootContext, TVIEW} from './interfaces/view'; import {enterView, leaveView} from './state'; import {defaultScheduler, getTNode} from './util'; @@ -76,12 +80,10 @@ export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDUL factory: () => defaultScheduler, }); -const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {}; - function createChainedInjector(rootViewInjector: Injector, moduleInjector: Injector): Injector { return { - get: (token: Type| InjectionToken, notFoundValue?: T): T => { - const value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR); + get: (token: Type| InjectionToken, notFoundValue?: T, flags?: InjectFlags): T => { + const value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as T, flags); if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR || notFoundValue === NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) { @@ -93,7 +95,7 @@ function createChainedInjector(rootViewInjector: Injector, moduleInjector: Injec return value; } - return moduleInjector.get(token, notFoundValue); + return moduleInjector.get(token, notFoundValue, flags); } }; } @@ -107,6 +109,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { selector: string; componentType: Type; ngContentSelectors: string[]; + isBoundToModule: boolean; get inputs(): {propName: string; templateName: string;}[] { return toRefArray(this.componentDef.inputs); @@ -125,7 +128,11 @@ export class ComponentFactory extends viewEngine_ComponentFactory { super(); this.componentType = componentDef.type; this.selector = componentDef.selectors[0][0] as string; - this.ngContentSelectors = []; + // The component definition does not include the wildcard ('*') selector in its list. + // It is implicitly expected as the first item in the projectable nodes array. + this.ngContentSelectors = + componentDef.ngContentSelectors ? ['*', ...componentDef.ngContentSelectors] : []; + this.isBoundToModule = !!ngModule; } create( @@ -161,8 +168,8 @@ export class ComponentFactory extends viewEngine_ComponentFactory { // Create the root view. Uses empty TView and ContentTemplate. const rootLView = createLView( - null, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags, - rendererFactory, renderer, sanitizer, rootViewInjector); + null, createTView(-1, null, 1, 0, null, null, null, null), rootContext, rootFlags, null, + null, rendererFactory, renderer, sanitizer, rootViewInjector); // rootView is the parent when bootstrapping const oldLView = enterView(rootLView, null); @@ -170,41 +177,17 @@ export class ComponentFactory extends viewEngine_ComponentFactory { let component: T; let tElementNode: TElementNode; try { - if (rendererFactory.begin) rendererFactory.begin(); - const componentView = createRootComponentView( hostRNode, this.componentDef, rootLView, rendererFactory, renderer); tElementNode = getTNode(0, rootLView) as TElementNode; - // Transform the arrays of native nodes into a structure that can be consumed by the - // projection instruction. This is needed to support the reprojection of these nodes. if (projectableNodes) { - let index = 0; - const tView = rootLView[TVIEW]; - const projection: TNode[] = tElementNode.projection = []; - for (let i = 0; i < projectableNodes.length; i++) { - const nodeList = projectableNodes[i]; - let firstTNode: TNode|null = null; - let previousTNode: TNode|null = null; - for (let j = 0; j < nodeList.length; j++) { - if (tView.firstTemplatePass) { - // For dynamically created components such as ComponentRef, we create a new TView for - // each insert. This is not ideal since we should be sharing the TViews. - // Also the logic here should be shared with `component.ts`'s `renderComponent` - // method. - tView.expandoStartIndex++; - tView.blueprint.splice(++index + HEADER_OFFSET, 0, null); - tView.data.splice(index + HEADER_OFFSET, 0, null); - rootLView.splice(index + HEADER_OFFSET, 0, null); - } - const tNode = - createNodeAtIndex(index, TNodeType.Element, nodeList[j] as RElement, null, null); - previousTNode ? (previousTNode.next = tNode) : (firstTNode = tNode); - previousTNode = tNode; - } - projection.push(firstTNode !); - } + // projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade + // case). Here we do normalize passed data structure to be an array of arrays to avoid + // complex checks down the line. + tElementNode.projection = + projectableNodes.map((nodesforSlot: RNode[]) => { return Array.from(nodesforSlot); }); } // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and @@ -217,7 +200,6 @@ export class ComponentFactory extends viewEngine_ComponentFactory { refreshDescendantViews(rootLView); } finally { leaveView(oldLView); - if (rendererFactory.end) rendererFactory.end(); } const componentRef = new ComponentRef( @@ -271,7 +253,7 @@ export class ComponentRef extends viewEngine_ComponentRef { super(); this.instance = instance; this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView); - this.hostView._tViewNode = createViewNode(-1, _rootLView); + this.hostView._tViewNode = assignTViewNodeToLView(_rootLView[TVIEW], null, -1, _rootLView); this.componentType = componentType; } @@ -281,7 +263,7 @@ export class ComponentRef extends viewEngine_ComponentRef { ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); this.destroyCbs !.forEach(fn => fn()); this.destroyCbs = null; - this.hostView.destroy(); + !this.hostView.destroyed && this.hostView.destroy(); } onDestroy(callback: () => void): void { ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); diff --git a/packages/core/src/render3/context_discovery.ts b/packages/core/src/render3/context_discovery.ts index 651f37cf20..3a69d2f6a9 100644 --- a/packages/core/src/render3/context_discovery.ts +++ b/packages/core/src/render3/context_discovery.ts @@ -5,8 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import './ng_dev_mode'; -import {assertDomNode} from './assert'; +import '../util/ng_dev_mode'; +import {assertDomNode} from '../util/assert'; import {EMPTY_ARRAY} from './empty'; import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {TNode, TNodeFlags} from './interfaces/node'; @@ -298,11 +298,10 @@ export function discoverLocalRefs(lView: LView, nodeIndex: number): {[key: strin const tNode = lView[TVIEW].data[nodeIndex] as TNode; if (tNode && tNode.localNames) { const result: {[key: string]: any} = {}; + let localIndex = tNode.index + 1; for (let i = 0; i < tNode.localNames.length; i += 2) { - const localRefName = tNode.localNames[i]; - const directiveIndex = tNode.localNames[i + 1] as number; - result[localRefName] = - directiveIndex === -1 ? getNativeByTNode(tNode, lView) ! : lView[directiveIndex]; + result[tNode.localNames[i]] = lView[localIndex]; + localIndex++; } return result; } diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index 3d1d0d3aea..87d644ab6c 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -6,16 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ -import './ng_dev_mode'; +import '../util/ng_dev_mode'; import {ChangeDetectionStrategy} from '../change_detection/constants'; +import {Mutable, Type} from '../interface/type'; import {NgModuleDef} from '../metadata/ng_module'; +import {SchemaMetadata} from '../metadata/schema'; import {ViewEncapsulation} from '../metadata/view'; -import {Mutable, Type} from '../type'; -import {noSideEffects, stringify} from '../util'; +import {noSideEffects} from '../util/closure'; +import {stringify} from '../util/stringify'; + import {EMPTY_ARRAY, EMPTY_OBJ} from './empty'; import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields'; -import {BaseDef, ComponentDef, ComponentDefFeature, ComponentQuery, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFeature, DirectiveType, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory} from './interfaces/definition'; +import {BaseDef, ComponentDef, ComponentDefFeature, ComponentTemplate, ComponentType, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, DirectiveType, DirectiveTypesOrFactory, FactoryFn, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory, ViewQueriesFunction} from './interfaces/definition'; import {CssSelectorList} from './interfaces/projection'; let _renderCompCount = 0; @@ -47,7 +50,7 @@ export function defineComponent(componentDefinition: { /** * Factory method used to create an instance of directive. */ - factory: (t: Type| null) => T; + factory: FactoryFn; /** * The number of nodes, local refs, and pipes in this component template. @@ -66,14 +69,6 @@ export function defineComponent(componentDefinition: { */ vars: number; - /** - * Static attributes to set on host element. - * - * Even indices: attribute name - * Odd indices: attribute value - */ - attributes?: string[]; - /** * A map of input names. * @@ -139,17 +134,14 @@ export function defineComponent(componentDefinition: { /** * Function to create instances of content queries associated with a given directive. */ - contentQueries?: ((dirIndex: number) => void); - - /** Refreshes content queries associated with directives in a given view */ - contentQueriesRefresh?: ((directiveIndex: number, queryIndex: number) => void); + contentQueries?: ContentQueriesFunction; /** * Defines the name that can be used in the template to assign this directive to a variable. * * See: {@link Directive.exportAs} */ - exportAs?: string; + exportAs?: string[]; /** * Template function use for rendering DOM. @@ -182,6 +174,11 @@ export function defineComponent(componentDefinition: { */ template: ComponentTemplate; + /** + * An array of `ngContent[selector]` values that were found in the template. + */ + ngContentSelectors?: string[]; + /** * Additional set of instructions specific to view query processing. This could be seen as a * set of instruction to be inserted into the template function. @@ -190,7 +187,7 @@ export function defineComponent(componentDefinition: { * execution is different as compared to all other instructions (after change detection hooks but * before view hooks). */ - viewQuery?: ComponentQuery| null; + viewQuery?: ViewQueriesFunction| null; /** * A list of optional features to apply. @@ -238,6 +235,11 @@ export function defineComponent(componentDefinition: { * `PipeDefs`s. The function is necessary to be able to support forward declarations. */ pipes?: PipeTypesOrFactory | null; + + /** + * The set of schemas that declare elements to be allowed in the component's template. + */ + schemas?: SchemaMetadata[] | null; }): never { const type = componentDefinition.type; const typePrototype = type.prototype; @@ -249,14 +251,14 @@ export function defineComponent(componentDefinition: { vars: componentDefinition.vars, factory: componentDefinition.factory, template: componentDefinition.template || null !, + ngContentSelectors: componentDefinition.ngContentSelectors, hostBindings: componentDefinition.hostBindings || null, contentQueries: componentDefinition.contentQueries || null, - contentQueriesRefresh: componentDefinition.contentQueriesRefresh || null, - attributes: componentDefinition.attributes || null, declaredInputs: declaredInputs, inputs: null !, // assigned in noSideEffects outputs: null !, // assigned in noSideEffects exportAs: componentDefinition.exportAs || null, + onChanges: null, onInit: typePrototype.ngOnInit || null, doCheck: typePrototype.ngDoCheck || null, afterContentInit: typePrototype.ngAfterContentInit || null, @@ -277,6 +279,8 @@ export function defineComponent(componentDefinition: { id: 'c', styles: componentDefinition.styles || EMPTY_ARRAY, _: null as never, + setInput: null, + schemas: componentDefinition.schemas || null, }; def._ = noSideEffects(() => { const directiveTypes = componentDefinition.directives !; @@ -297,6 +301,13 @@ export function defineComponent(componentDefinition: { return def as never; } +export function setComponentScope( + type: ComponentType, directives: Type[], pipes: Type[]): void { + const def = (type.ngComponentDef as ComponentDef); + def.directiveDefs = () => directives.map(extractDirectiveDef); + def.pipeDefs = () => pipes.map(extractPipeDef); +} + export function extractDirectiveDef(type: DirectiveType& ComponentType): DirectiveDef|ComponentDef { const def = getComponentDef(type) || getDirectiveDef(type); @@ -322,6 +333,7 @@ export function defineNgModule(def: {type: T} & Partial>): nev imports: def.imports || EMPTY_ARRAY, exports: def.exports || EMPTY_ARRAY, transitiveCompileScopes: null, + schemas: def.schemas || null, }; return res as never; } @@ -381,12 +393,14 @@ export function defineNgModule(def: {type: T} & Partial>): nev * */ -function invertObject(obj: any, secondary?: any): any { - if (obj == null) return EMPTY_OBJ; +function invertObject( + obj?: {[P in keyof T]?: string | [string, string]}, + secondary?: {[key: string]: string}): {[P in keyof T]: string} { + if (obj == null) return EMPTY_OBJ as any; const newLookup: any = {}; for (const minifiedKey in obj) { if (obj.hasOwnProperty(minifiedKey)) { - let publicName: string = obj[minifiedKey]; + let publicName: string|[string, string] = obj[minifiedKey] !; let declaredName = publicName; if (Array.isArray(publicName)) { declaredName = publicName[1]; @@ -394,7 +408,7 @@ function invertObject(obj: any, secondary?: any): any { } newLookup[publicName] = minifiedKey; if (secondary) { - (secondary[publicName] = declaredName); + (secondary[publicName] = declaredName as string); } } } @@ -471,11 +485,11 @@ export function defineBase(baseDefinition: { */ outputs?: {[P in keyof T]?: string}; }): BaseDef { - const declaredInputs: {[P in keyof T]: P} = {} as any; + const declaredInputs: {[P in keyof T]: string} = {} as any; return { - inputs: invertObject(baseDefinition.inputs, declaredInputs), + inputs: invertObject(baseDefinition.inputs as any, declaredInputs), declaredInputs: declaredInputs, - outputs: invertObject(baseDefinition.outputs), + outputs: invertObject(baseDefinition.outputs as any), }; } @@ -505,15 +519,7 @@ export const defineDirective = defineComponent as any as(directiveDefinition: /** * Factory method used to create an instance of directive. */ - factory: (t: Type| null) => T; - - /** - * Static attributes to set on host element. - * - * Even indices: attribute name - * Odd indices: attribute value - */ - attributes?: string[]; + factory: FactoryFn; /** * A map of input names. @@ -587,17 +593,14 @@ export const defineDirective = defineComponent as any as(directiveDefinition: /** * Function to create instances of content queries associated with a given directive. */ - contentQueries?: ((directiveIndex: number) => void); - - /** Refreshes content queries associated with directives in a given view */ - contentQueriesRefresh?: ((directiveIndex: number, queryIndex: number) => void); + contentQueries?: ContentQueriesFunction; /** * Defines the name that can be used in the template to assign this directive to a variable. * * See: {@link Directive.exportAs} */ - exportAs?: string; + exportAs?: string[]; }) => never; /** @@ -622,7 +625,7 @@ export function definePipe(pipeDef: { type: Type, /** A factory for creating a pipe instance. */ - factory: (t: Type| null) => T, + factory: FactoryFn, /** Whether the pipe is pure. */ pure?: boolean diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 7bd723aa79..56accc32b5 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -6,22 +6,23 @@ * found in the LICENSE file at https://angular.io/license */ -import {getInjectableDef, getInjectorDef} from '../di/defs'; -import {InjectionToken} from '../di/injection_token'; +import {InjectFlags, InjectionToken} from '../di'; import {Injector} from '../di/injector'; -import {InjectFlags, injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility'; -import {Type} from '../type'; +import {injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility'; +import {getInjectableDef, getInjectorDef} from '../di/interface/defs'; +import {Type} from '../interface/type'; +import {assertDefined, assertEqual} from '../util/assert'; -import {assertDefined, assertEqual} from './assert'; import {getComponentDef, getDirectiveDef, getPipeDef} from './definition'; import {NG_ELEMENT_ID} from './fields'; import {DirectiveDef} from './interfaces/definition'; import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector'; import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType} from './interfaces/node'; -import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LView, TData, TVIEW, TView} from './interfaces/view'; +import {DECLARATION_VIEW, INJECTOR, LView, TData, TVIEW, TView, T_HOST} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; import {getLView, getPreviousOrParentTNode, setTNodeAndViewData} from './state'; -import {getHostTElementNode, getParentInjectorIndex, getParentInjectorView, hasParentInjector, isComponent, isComponentDef, stringify} from './util'; +import {findComponentView, getParentInjectorIndex, getParentInjectorView, hasParentInjector, isComponent, isComponentDef, renderStringify} from './util'; + /** @@ -60,7 +61,7 @@ import {getHostTElementNode, getParentInjectorIndex, getParentInjectorView, hasP * * ``` */ -let includeViewProviders = false; +let includeViewProviders = true; function setIncludeViewProviders(v: boolean): boolean { const oldValue = includeViewProviders; @@ -204,11 +205,11 @@ export function getParentInjectorLocation(tNode: TNode, view: LView): RelativeIn // For most cases, the parent injector index can be found on the host node (e.g. for component // or container), so this loop will be skipped, but we must keep the loop here to support // the rarer case of deeply nested tags or inline views. - let hostTNode = view[HOST_NODE]; + let hostTNode = view[T_HOST]; let viewOffset = 1; while (hostTNode && hostTNode.injectorIndex === -1) { view = view[DECLARATION_VIEW] !; - hostTNode = view[HOST_NODE] !; + hostTNode = view ? view[T_HOST] : null; viewOffset++; } @@ -284,6 +285,10 @@ export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): str * Look for the injector providing the token by walking up the node injector tree and then * the module injector tree. * + * This function patches `token` with `__NG_ELEMENT_ID__` which contains the id for the bloom + * filter. Negative values are reserved for special objects. + * - `-1` is reserved for injecting `Injector` (implemented by `NodeInjector`) + * * @param tNode The Node where the search for the injector should start * @param lView The `LView` that contains the `tNode` * @param token The token to look for @@ -292,81 +297,90 @@ export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): str * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided */ export function getOrCreateInjectable( - tNode: TElementNode | TContainerNode | TElementContainerNode, lView: LView, + tNode: TElementNode | TContainerNode | TElementContainerNode | null, lView: LView, token: Type| InjectionToken, flags: InjectFlags = InjectFlags.Default, notFoundValue?: any): T|null { - const bloomHash = bloomHashBitOrFactory(token); - // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef - // so just call the factory function to create it. - if (typeof bloomHash === 'function') { - const savePreviousOrParentTNode = getPreviousOrParentTNode(); - const saveLView = getLView(); - setTNodeAndViewData(tNode, lView); - try { - const value = bloomHash(); - if (value == null && !(flags & InjectFlags.Optional)) { - throw new Error(`No provider for ${stringify(token)}!`); - } else { - return value; + if (tNode) { + const bloomHash = bloomHashBitOrFactory(token); + // If the ID stored here is a function, this is a special object like ElementRef or TemplateRef + // so just call the factory function to create it. + if (typeof bloomHash === 'function') { + const savePreviousOrParentTNode = getPreviousOrParentTNode(); + const saveLView = getLView(); + setTNodeAndViewData(tNode, lView); + try { + const value = bloomHash(); + if (value == null && !(flags & InjectFlags.Optional)) { + throw new Error(`No provider for ${renderStringify(token)}!`); + } else { + return value; + } + } finally { + setTNodeAndViewData(savePreviousOrParentTNode, saveLView); } - } finally { - setTNodeAndViewData(savePreviousOrParentTNode, saveLView); - } - } else if (typeof bloomHash == 'number') { - // If the token has a bloom hash, then it is a token which could be in NodeInjector. - - // A reference to the previous injector TView that was found while climbing the element injector - // tree. This is used to know if viewProviders can be accessed on the current injector. - let previousTView: TView|null = null; - let injectorIndex = getInjectorIndex(tNode, lView); - let parentLocation: RelativeInjectorLocation = NO_PARENT_INJECTOR; - let hostTElementNode: TNode|null = flags & InjectFlags.Host ? getHostTElementNode(lView) : null; - - // If we should skip this injector, or if there is no injector on this node, start by searching - // the parent injector. - if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) { - parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) : - lView[injectorIndex + PARENT_INJECTOR]; - - if (!shouldSearchParent(flags, false)) { - injectorIndex = -1; - } else { - previousTView = lView[TVIEW]; - injectorIndex = getParentInjectorIndex(parentLocation); - lView = getParentInjectorView(parentLocation, lView); + } else if (typeof bloomHash == 'number') { + if (bloomHash === -1) { + // `-1` is a special value used to identify `Injector` types. + return new NodeInjector(tNode, lView) as any; } - } + // If the token has a bloom hash, then it is a token which could be in NodeInjector. - // Traverse up the injector tree until we find a potential match or until we know there - // *isn't* a match. - while (injectorIndex !== -1) { - parentLocation = lView[injectorIndex + PARENT_INJECTOR]; + // A reference to the previous injector TView that was found while climbing the element + // injector tree. This is used to know if viewProviders can be accessed on the current + // injector. + let previousTView: TView|null = null; + let injectorIndex = getInjectorIndex(tNode, lView); + let parentLocation: RelativeInjectorLocation = NO_PARENT_INJECTOR; + let hostTElementNode: TNode|null = + flags & InjectFlags.Host ? findComponentView(lView)[T_HOST] : null; - // Check the current injector. If it matches, see if it contains token. - const tView = lView[TVIEW]; - if (bloomHasToken(bloomHash, injectorIndex, tView.data)) { - // At this point, we have an injector which *may* contain the token, so we step through - // the providers and directives associated with the injector's corresponding node to get - // the instance. - const instance: T|null = searchTokensOnInjector( - injectorIndex, lView, token, previousTView, flags, hostTElementNode); - if (instance !== NOT_FOUND) { - return instance; + // If we should skip this injector, or if there is no injector on this node, start by + // searching + // the parent injector. + if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) { + parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) : + lView[injectorIndex + PARENT_INJECTOR]; + + if (!shouldSearchParent(flags, false)) { + injectorIndex = -1; + } else { + previousTView = lView[TVIEW]; + injectorIndex = getParentInjectorIndex(parentLocation); + lView = getParentInjectorView(parentLocation, lView); } } - if (shouldSearchParent( - flags, lView[TVIEW].data[injectorIndex + TNODE] === hostTElementNode) && - bloomHasToken(bloomHash, injectorIndex, lView)) { - // The def wasn't found anywhere on this node, so it was a false positive. - // Traverse up the tree and continue searching. - previousTView = tView; - injectorIndex = getParentInjectorIndex(parentLocation); - lView = getParentInjectorView(parentLocation, lView); - } else { - // If we should not search parent OR If the ancestor bloom filter value does not have the - // bit corresponding to the directive we can give up on traversing up to find the specific - // injector. - injectorIndex = -1; + + // Traverse up the injector tree until we find a potential match or until we know there + // *isn't* a match. + while (injectorIndex !== -1) { + parentLocation = lView[injectorIndex + PARENT_INJECTOR]; + + // Check the current injector. If it matches, see if it contains token. + const tView = lView[TVIEW]; + if (bloomHasToken(bloomHash, injectorIndex, tView.data)) { + // At this point, we have an injector which *may* contain the token, so we step through + // the providers and directives associated with the injector's corresponding node to get + // the instance. + const instance: T|null = searchTokensOnInjector( + injectorIndex, lView, token, previousTView, flags, hostTElementNode); + if (instance !== NOT_FOUND) { + return instance; + } + } + if (shouldSearchParent( + flags, lView[TVIEW].data[injectorIndex + TNODE] === hostTElementNode) && + bloomHasToken(bloomHash, injectorIndex, lView)) { + // The def wasn't found anywhere on this node, so it was a false positive. + // Traverse up the tree and continue searching. + previousTView = tView; + injectorIndex = getParentInjectorIndex(parentLocation); + lView = getParentInjectorView(parentLocation, lView); + } else { + // If we should not search parent OR If the ancestor bloom filter value does not have the + // bit corresponding to the directive we can give up on traversing up to find the specific + // injector. + injectorIndex = -1; + } } } } @@ -378,16 +392,24 @@ export function getOrCreateInjectable( if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) { const moduleInjector = lView[INJECTOR]; - if (moduleInjector) { - return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional); - } else { - return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional); + // switch to `injectInjectorOnly` implementation for module injector, since module injector + // should not have access to Component/Directive DI scope (that may happen through + // `directiveInject` implementation) + const previousInjectImplementation = setInjectImplementation(undefined); + try { + if (moduleInjector) { + return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional); + } else { + return injectRootLimpMode(token, notFoundValue, flags & InjectFlags.Optional); + } + } finally { + setInjectImplementation(previousInjectImplementation); } } if (flags & InjectFlags.Optional) { return notFoundValue; } else { - throw new Error(`NodeInjector: NOT_FOUND [${stringify(token)}]`); + throw new Error(`NodeInjector: NOT_FOUND [${renderStringify(token)}]`); } } @@ -485,7 +507,7 @@ export function getNodeInjectable( if (isFactory(value)) { const factory: NodeInjectorFactory = value; if (factory.resolving) { - throw new Error(`Circular dep for ${stringify(tData[index])}`); + throw new Error(`Circular dep for ${renderStringify(tData[index])}`); } const previousIncludeViewProviders = setIncludeViewProviders(factory.canSeeViewProviders); factory.resolving = true; @@ -498,6 +520,10 @@ export function getNodeInjectable( setTNodeAndViewData(tNode, lData); try { value = lData[index] = factory.factory(null, tData, lData, tNode); + const tView = lData[TVIEW]; + if (value && factory.isProvider && value.ngOnDestroy) { + (tView.destroyHooks || (tView.destroyHooks = [])).push(index, value.ngOnDestroy); + } } finally { if (factory.injectImpl) setInjectImplementation(previousInjectImplementation); setIncludeViewProviders(previousIncludeViewProviders); @@ -518,6 +544,7 @@ export function getNodeInjectable( * * @param token the injection token * @returns the matching bit to check in the bloom filter or `null` if the token is not known. + * When the returned value is negative then it represents special values such as `Injector`. */ export function bloomHashBitOrFactory(token: Type| InjectionToken| string): number| Function|undefined { @@ -526,7 +553,8 @@ export function bloomHashBitOrFactory(token: Type| InjectionToken| str return token.charCodeAt(0) || 0; } const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID]; - return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId; + // Negative token IDs are used for special objects such as `Injector` + return (typeof tokenId === 'number' && tokenId > 0) ? tokenId & BLOOM_MASK : tokenId; } export function bloomHasToken( @@ -562,14 +590,10 @@ function shouldSearchParent(flags: InjectFlags, isFirstHostTNode: boolean): bool return !(flags & InjectFlags.Self) && !(flags & InjectFlags.Host && isFirstHostTNode); } -export function injectInjector() { - const tNode = getPreviousOrParentTNode() as TElementNode | TContainerNode | TElementContainerNode; - return new NodeInjector(tNode, getLView()); -} - export class NodeInjector implements Injector { constructor( - private _tNode: TElementNode|TContainerNode|TElementContainerNode, private _lView: LView) {} + private _tNode: TElementNode|TContainerNode|TElementContainerNode|null, + private _lView: LView) {} get(token: any, notFoundValue?: any): any { return getOrCreateInjectable(this._tNode, this._lView, token, undefined, notFoundValue); diff --git a/packages/core/src/render3/di_setup.ts b/packages/core/src/render3/di_setup.ts index 58ad14c41a..9db9bcce86 100644 --- a/packages/core/src/render3/di_setup.ts +++ b/packages/core/src/render3/di_setup.ts @@ -8,7 +8,7 @@ import {resolveForwardRef} from '../di/forward_ref'; -import {Provider} from '../di/provider'; +import {Provider} from '../di/interface/provider'; import {isTypeProvider, providerToFactory} from '../di/r3_injector'; import {DirectiveDef} from '.'; @@ -83,7 +83,8 @@ function resolveProvider( if (isTypeProvider(provider) || !provider.multi) { // Single provider case: the factory is created and pushed immediately - const factory = new NodeInjectorFactory(providerFactory, isViewProvider, directiveInject); + const factory = + new NodeInjectorFactory(providerFactory, isViewProvider, true, directiveInject); const existingFactoryIndex = indexOf( token, tInjectables, isViewProvider ? beginIndex : beginIndex + cptViewProvidersCount, endIndex); @@ -245,7 +246,7 @@ function multiFactory( this: NodeInjectorFactory, _: null, tData: TData, lData: LView, tNode: TElementNode) => any, index: number, isViewProvider: boolean, isComponent: boolean, f: () => any): NodeInjectorFactory { - const factory = new NodeInjectorFactory(factoryFn, isViewProvider, directiveInject); + const factory = new NodeInjectorFactory(factoryFn, isViewProvider, true, directiveInject); factory.multi = []; factory.index = index; factory.componentProviders = 0; diff --git a/packages/core/src/render3/discovery_utils.ts b/packages/core/src/render3/discovery_utils.ts index 08ccd32fc4..31701cd30c 100644 --- a/packages/core/src/render3/discovery_utils.ts +++ b/packages/core/src/render3/discovery_utils.ts @@ -8,14 +8,14 @@ import {Injector} from '../di/injector'; -import {assertDefined} from './assert'; +import {assertDefined} from '../util/assert'; import {discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext} from './context_discovery'; import {NodeInjector} from './di'; import {LContext} from './interfaces/context'; import {DirectiveDef} from './interfaces/definition'; import {TElementNode, TNode, TNodeProviderIndexes} from './interfaces/node'; import {CLEANUP, CONTEXT, FLAGS, HOST, LView, LViewFlags, PARENT, RootContext, TVIEW} from './interfaces/view'; -import {readElementValue, readPatchedLView, stringify} from './util'; +import {readElementValue, readPatchedLView, renderStringify} from './util'; @@ -201,7 +201,7 @@ export function loadLContext(target: {}, throwOnNotFound: boolean = true): LCont const context = getLContext(target); if (!context && throwOnNotFound) { throw new Error( - ngDevMode ? `Unable to find context associated with ${stringify(target)}` : + ngDevMode ? `Unable to find context associated with ${renderStringify(target)}` : 'Invalid ng target'); } return context; diff --git a/packages/core/src/render3/empty.ts b/packages/core/src/render3/empty.ts index 46dc61bdf6..a3870a64cd 100644 --- a/packages/core/src/render3/empty.ts +++ b/packages/core/src/render3/empty.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import './ng_dev_mode'; +import '../util/ng_dev_mode'; /** * This file contains reuseable "empty" symbols that can be used as default return values diff --git a/packages/core/src/render3/features/inherit_definition_feature.ts b/packages/core/src/render3/features/inherit_definition_feature.ts index 5e2f7cc775..7305c619f2 100644 --- a/packages/core/src/render3/features/inherit_definition_feature.ts +++ b/packages/core/src/render3/features/inherit_definition_feature.ts @@ -6,11 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../../type'; +import {Type} from '../../interface/type'; +import {Component} from '../../metadata/directives'; import {fillProperties} from '../../util/property'; import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty'; import {ComponentDef, DirectiveDef, DirectiveDefFeature, RenderFlags} from '../interfaces/definition'; +import {NgOnChangesFeature} from './ng_onchanges_feature'; /** @@ -102,30 +104,15 @@ export function InheritDefinitionFeature(definition: DirectiveDef| Componen const superContentQueries = superDef.contentQueries; if (superContentQueries) { if (prevContentQueries) { - definition.contentQueries = (dirIndex: number) => { - superContentQueries(dirIndex); - prevContentQueries(dirIndex); + definition.contentQueries = (rf: RenderFlags, ctx: T, directiveIndex: number) => { + superContentQueries(rf, ctx, directiveIndex); + prevContentQueries(rf, ctx, directiveIndex); }; } else { definition.contentQueries = superContentQueries; } } - // Merge Content Queries Refresh - const prevContentQueriesRefresh = definition.contentQueriesRefresh; - const superContentQueriesRefresh = superDef.contentQueriesRefresh; - if (superContentQueriesRefresh) { - if (prevContentQueriesRefresh) { - definition.contentQueriesRefresh = (directiveIndex: number, queryIndex: number) => { - superContentQueriesRefresh(directiveIndex, queryIndex); - prevContentQueriesRefresh(directiveIndex, queryIndex); - }; - } else { - definition.contentQueriesRefresh = superContentQueriesRefresh; - } - } - - // Merge inputs and outputs fillProperties(definition.inputs, superDef.inputs); fillProperties(definition.declaredInputs, superDef.declaredInputs); @@ -156,18 +143,21 @@ export function InheritDefinitionFeature(definition: DirectiveDef| Componen } else { // Even if we don't have a definition, check the type for the hooks and use those if need be const superPrototype = superType.prototype; - if (superPrototype) { definition.afterContentChecked = - definition.afterContentChecked || superPrototype.afterContentChecked; + definition.afterContentChecked || superPrototype.ngAfterContentChecked; definition.afterContentInit = - definition.afterContentInit || superPrototype.afterContentInit; + definition.afterContentInit || superPrototype.ngAfterContentInit; definition.afterViewChecked = - definition.afterViewChecked || superPrototype.afterViewChecked; - definition.afterViewInit = definition.afterViewInit || superPrototype.afterViewInit; - definition.doCheck = definition.doCheck || superPrototype.doCheck; - definition.onDestroy = definition.onDestroy || superPrototype.onDestroy; - definition.onInit = definition.onInit || superPrototype.onInit; + definition.afterViewChecked || superPrototype.ngAfterViewChecked; + definition.afterViewInit = definition.afterViewInit || superPrototype.ngAfterViewInit; + definition.doCheck = definition.doCheck || superPrototype.ngDoCheck; + definition.onDestroy = definition.onDestroy || superPrototype.ngOnDestroy; + definition.onInit = definition.onInit || superPrototype.ngOnInit; + + if (superPrototype.ngOnChanges) { + NgOnChangesFeature()(definition); + } } } diff --git a/packages/core/src/render3/features/ng_onchanges_feature.ts b/packages/core/src/render3/features/ng_onchanges_feature.ts index 2b2d5468bc..660c12adf9 100644 --- a/packages/core/src/render3/features/ng_onchanges_feature.ts +++ b/packages/core/src/render3/features/ng_onchanges_feature.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {SimpleChange} from '../../change_detection/change_detection_util'; -import {OnChanges, SimpleChanges} from '../../metadata/lifecycle_hooks'; +import {OnChanges} from '../../interface/lifecycle_hooks'; +import {SimpleChange, SimpleChanges} from '../../interface/simple_change'; +import {EMPTY_OBJ} from '../empty'; import {DirectiveDef, DirectiveDefFeature} from '../interfaces/definition'; const PRIVATE_PREFIX = '__ngOnChanges_'; @@ -34,91 +35,72 @@ type OnChangesExpando = OnChanges & { * static ngComponentDef = defineComponent({ * ... * inputs: {name: 'publicName'}, - * features: [NgOnChangesFeature] + * features: [NgOnChangesFeature()] * }); * ``` */ -export function NgOnChangesFeature(definition: DirectiveDef): void { - const publicToDeclaredInputs = definition.declaredInputs; - const publicToMinifiedInputs = definition.inputs; - const proto = definition.type.prototype; - for (const publicName in publicToDeclaredInputs) { - if (publicToDeclaredInputs.hasOwnProperty(publicName)) { - const minifiedKey = publicToMinifiedInputs[publicName]; - const declaredKey = publicToDeclaredInputs[publicName]; - const privateMinKey = PRIVATE_PREFIX + minifiedKey; - - // Walk the prototype chain to see if we find a property descriptor - // That way we can honor setters and getters that were inherited. - let originalProperty: PropertyDescriptor|undefined = undefined; - let checkProto = proto; - while (!originalProperty && checkProto && - Object.getPrototypeOf(checkProto) !== Object.getPrototypeOf(Object.prototype)) { - originalProperty = Object.getOwnPropertyDescriptor(checkProto, minifiedKey); - checkProto = Object.getPrototypeOf(checkProto); - } - - const getter = originalProperty && originalProperty.get; - const setter = originalProperty && originalProperty.set; - - // create a getter and setter for property - Object.defineProperty(proto, minifiedKey, { - get: getter || - (setter ? undefined : function(this: OnChangesExpando) { return this[privateMinKey]; }), - set(this: OnChangesExpando, value: T) { - let simpleChanges = this[PRIVATE_PREFIX]; - if (!simpleChanges) { - simpleChanges = {}; - // Place where we will store SimpleChanges if there is a change - Object.defineProperty(this, PRIVATE_PREFIX, {value: simpleChanges, writable: true}); - } - - const isFirstChange = !this.hasOwnProperty(privateMinKey); - const currentChange = simpleChanges[declaredKey]; - - if (currentChange) { - currentChange.currentValue = value; - } else { - simpleChanges[declaredKey] = - new SimpleChange(this[privateMinKey], value, isFirstChange); - } - - if (isFirstChange) { - // Create a place where the actual value will be stored and make it non-enumerable - Object.defineProperty(this, privateMinKey, {value, writable: true}); - } else { - this[privateMinKey] = value; - } - - if (setter) setter.call(this, value); - }, - // Make the property configurable in dev mode to allow overriding in tests - configurable: !!ngDevMode - }); - } - } - - // If an onInit hook is defined, it will need to wrap the ngOnChanges call - // so the call order is changes-init-check in creation mode. In subsequent - // change detection runs, only the check wrapper will be called. - if (definition.onInit != null) { - definition.onInit = onChangesWrapper(definition.onInit); - } - - definition.doCheck = onChangesWrapper(definition.doCheck); +export function NgOnChangesFeature(): DirectiveDefFeature { + // This option ensures that the ngOnChanges lifecycle hook will be inherited + // from superclasses (in InheritDefinitionFeature). + (NgOnChangesFeatureImpl as DirectiveDefFeature).ngInherit = true; + return NgOnChangesFeatureImpl; } -// This option ensures that the ngOnChanges lifecycle hook will be inherited -// from superclasses (in InheritDefinitionFeature). -(NgOnChangesFeature as DirectiveDefFeature).ngInherit = true; +function NgOnChangesFeatureImpl(definition: DirectiveDef): void { + if (definition.type.prototype.ngOnChanges) { + definition.setInput = ngOnChangesSetInput; + definition.onChanges = wrapOnChanges(); + } +} -function onChangesWrapper(delegateHook: (() => void) | null) { - return function(this: OnChangesExpando) { - const simpleChanges = this[PRIVATE_PREFIX]; - if (simpleChanges != null) { - this.ngOnChanges(simpleChanges); - this[PRIVATE_PREFIX] = null; +function wrapOnChanges() { + return function(this: OnChanges) { + const simpleChangesStore = getSimpleChangesStore(this); + const current = simpleChangesStore && simpleChangesStore.current; + + if (current) { + const previous = simpleChangesStore !.previous; + if (previous === EMPTY_OBJ) { + simpleChangesStore !.previous = current; + } else { + // New changes are copied to the previous store, so that we don't lose history for inputs + // which were not changed this time + for (let key in current) { + previous[key] = current[key]; + } + } + simpleChangesStore !.current = null; + this.ngOnChanges(current); } - if (delegateHook) delegateHook.apply(this); }; } + +function ngOnChangesSetInput( + this: DirectiveDef, instance: T, value: any, publicName: string, privateName: string): void { + const simpleChangesStore = getSimpleChangesStore(instance) || + setSimpleChangesStore(instance, {previous: EMPTY_OBJ, current: null}); + const current = simpleChangesStore.current || (simpleChangesStore.current = {}); + const previous = simpleChangesStore.previous; + + const declaredName = (this.declaredInputs as{[key: string]: string})[publicName]; + const previousChange = previous[declaredName]; + current[declaredName] = new SimpleChange( + previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ); + + (instance as any)[privateName] = value; +} + +const SIMPLE_CHANGES_STORE = '__ngSimpleChanges__'; + +function getSimpleChangesStore(instance: any): null|NgSimpleChangesStore { + return instance[SIMPLE_CHANGES_STORE] || null; +} + +function setSimpleChangesStore(instance: any, store: NgSimpleChangesStore): NgSimpleChangesStore { + return instance[SIMPLE_CHANGES_STORE] = store; +} + +interface NgSimpleChangesStore { + previous: SimpleChanges; + current: SimpleChanges|null; +} diff --git a/packages/core/src/render3/features/providers_feature.ts b/packages/core/src/render3/features/providers_feature.ts index 7ecca8807f..e95d389c5a 100644 --- a/packages/core/src/render3/features/providers_feature.ts +++ b/packages/core/src/render3/features/providers_feature.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {Provider} from '../../di/provider'; +import {Provider} from '../../di/interface/provider'; import {providersResolver} from '../di_setup'; import {DirectiveDef} from '../interfaces/definition'; diff --git a/packages/core/src/render3/fields.ts b/packages/core/src/render3/fields.ts index 3a187f0856..26b29af9da 100644 --- a/packages/core/src/render3/fields.ts +++ b/packages/core/src/render3/fields.ts @@ -10,8 +10,6 @@ import {getClosureSafeProperty} from '../util/property'; export const NG_COMPONENT_DEF = getClosureSafeProperty({ngComponentDef: getClosureSafeProperty}); export const NG_DIRECTIVE_DEF = getClosureSafeProperty({ngDirectiveDef: getClosureSafeProperty}); -export const NG_INJECTABLE_DEF = getClosureSafeProperty({ngInjectableDef: getClosureSafeProperty}); -export const NG_INJECTOR_DEF = getClosureSafeProperty({ngInjectorDef: getClosureSafeProperty}); export const NG_PIPE_DEF = getClosureSafeProperty({ngPipeDef: getClosureSafeProperty}); export const NG_MODULE_DEF = getClosureSafeProperty({ngModuleDef: getClosureSafeProperty}); export const NG_BASE_DEF = getClosureSafeProperty({ngBaseDef: getClosureSafeProperty}); @@ -21,4 +19,5 @@ export const NG_BASE_DEF = getClosureSafeProperty({ngBaseDef: getClosureSafeProp * the key and the directive's unique ID as the value. This allows us to map directives to their * bloom filter bit for DI. */ +// TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified. export const NG_ELEMENT_ID = getClosureSafeProperty({__NG_ELEMENT_ID__: getClosureSafeProperty}); diff --git a/packages/core/src/render3/global_utils.ts b/packages/core/src/render3/global_utils.ts index 7abd6f9189..d2ff76ccba 100644 --- a/packages/core/src/render3/global_utils.ts +++ b/packages/core/src/render3/global_utils.ts @@ -5,9 +5,9 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {global} from '../util'; +import {assertDefined} from '../util/assert'; +import {global} from '../util/global'; -import {assertDefined} from './assert'; import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getPlayers, getRootComponents, getViewComponent, markDirty} from './global_utils_api'; @@ -30,13 +30,13 @@ import {getComponent, getContext, getDirectives, getHostElement, getInjector, ge * */ export const GLOBAL_PUBLISH_EXPANDO_KEY = 'ng'; -/* - * Publishes a collection of default debug tools onto `window._ng_`. +let _published = false; +/** + * Publishes a collection of default debug tools onto`window.ng`. * * These functions are available globally when Angular is in development * mode and are automatically stripped away from prod mode is on. */ -let _published = false; export function publishDefaultGlobalUtils() { if (!_published) { _published = true; @@ -58,7 +58,7 @@ export declare type GlobalDevModeContainer = { }; /** - * Publishes the given function to `window.ngDevMode` so that it can be + * Publishes the given function to `window.ng` so that it can be * used from the browser console when an application is not in production. */ export function publishGlobalUtil(name: string, fn: Function): void { diff --git a/packages/core/src/render3/hooks.ts b/packages/core/src/render3/hooks.ts index c00146b3e9..f901adf7de 100644 --- a/packages/core/src/render3/hooks.ts +++ b/packages/core/src/render3/hooks.ts @@ -6,126 +6,177 @@ * found in the LICENSE file at https://angular.io/license */ -import {assertEqual} from './assert'; +import {assertEqual} from '../util/assert'; + import {DirectiveDef} from './interfaces/definition'; import {TNode} from './interfaces/node'; -import {FLAGS, HookData, LView, LViewFlags, TView} from './interfaces/view'; +import {FLAGS, HookData, InitPhaseState, LView, LViewFlags, TView} from './interfaces/view'; /** - * If this is the first template pass, any ngOnInit or ngDoCheck hooks will be queued into - * TView.initHooks during directiveCreate. + * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`. * - * The directive index and hook type are encoded into one number (1st bit: type, remaining bits: - * directive index), then saved in the even indices of the initHooks array. The odd indices - * hold the hook functions themselves. + * Must be run *only* on the first template pass. * - * @param index The index of the directive in LView - * @param hooks The static hooks map on the directive def + * The TView's hooks arrays are arranged in alternating pairs of directiveIndex and hookFunction, + * i.e.: `[directiveIndexA, hookFunctionA, directiveIndexB, hookFunctionB, ...]`. For `OnChanges` + * hooks, the `directiveIndex` will be *negative*, signaling {@link callHooks} that the + * `hookFunction` must be passed the the appropriate {@link SimpleChanges} object. + * + * @param directiveIndex The index of the directive in LView + * @param directiveDef The definition containing the hooks to setup in tView * @param tView The current TView */ -export function queueInitHooks( - index: number, onInit: (() => void) | null, doCheck: (() => void) | null, tView: TView): void { +export function registerPreOrderHooks( + directiveIndex: number, directiveDef: DirectiveDef, tView: TView): void { ngDevMode && assertEqual(tView.firstTemplatePass, true, 'Should only be called on first template pass'); + + const {onChanges, onInit, doCheck} = directiveDef; + + if (onChanges) { + (tView.initHooks || (tView.initHooks = [])).push(directiveIndex, onChanges); + (tView.checkHooks || (tView.checkHooks = [])).push(directiveIndex, onChanges); + } + if (onInit) { - (tView.initHooks || (tView.initHooks = [])).push(index, onInit); + (tView.initHooks || (tView.initHooks = [])).push(-directiveIndex, onInit); } if (doCheck) { - (tView.initHooks || (tView.initHooks = [])).push(index, doCheck); - (tView.checkHooks || (tView.checkHooks = [])).push(index, doCheck); + (tView.initHooks || (tView.initHooks = [])).push(directiveIndex, doCheck); + (tView.checkHooks || (tView.checkHooks = [])).push(directiveIndex, doCheck); } } /** - * Loops through the directives on a node and queues all their hooks except ngOnInit - * and ngDoCheck, which are queued separately in directiveCreate. + * + * Loops through the directives on the provided `tNode` and queues hooks to be + * run that are not initialization hooks. + * + * Should be executed during `elementEnd()` and similar to + * preserve hook execution order. Content, view, and destroy hooks for projected + * components and directives must be called *before* their hosts. + * + * Sets up the content, view, and destroy hooks on the provided `tView` such that + * they're added in alternating pairs of directiveIndex and hookFunction, + * i.e.: `[directiveIndexA, hookFunctionA, directiveIndexB, hookFunctionB, ...]` + * + * NOTE: This does not set up `onChanges`, `onInit` or `doCheck`, those are set up + * separately at `elementStart`. + * + * @param tView The current TView + * @param tNode The TNode whose directives are to be searched for hooks to queue */ -export function queueLifecycleHooks(tView: TView, tNode: TNode): void { +export function registerPostOrderHooks(tView: TView, tNode: TNode): void { if (tView.firstTemplatePass) { // It's necessary to loop through the directives at elementEnd() (rather than processing in // directiveCreate) so we can preserve the current hook order. Content, view, and destroy // hooks for projected components and directives must be called *before* their hosts. for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) { - const def = tView.data[i] as DirectiveDef; - queueContentHooks(def, tView, i); - queueViewHooks(def, tView, i); - queueDestroyHooks(def, tView, i); + const directiveDef = tView.data[i] as DirectiveDef; + if (directiveDef.afterContentInit) { + (tView.contentHooks || (tView.contentHooks = [])).push(-i, directiveDef.afterContentInit); + } + + if (directiveDef.afterContentChecked) { + (tView.contentHooks || (tView.contentHooks = [])).push(i, directiveDef.afterContentChecked); + (tView.contentCheckHooks || (tView.contentCheckHooks = [ + ])).push(i, directiveDef.afterContentChecked); + } + + if (directiveDef.afterViewInit) { + (tView.viewHooks || (tView.viewHooks = [])).push(-i, directiveDef.afterViewInit); + } + + if (directiveDef.afterViewChecked) { + (tView.viewHooks || (tView.viewHooks = [])).push(i, directiveDef.afterViewChecked); + (tView.viewCheckHooks || (tView.viewCheckHooks = [ + ])).push(i, directiveDef.afterViewChecked); + } + + if (directiveDef.onDestroy != null) { + (tView.destroyHooks || (tView.destroyHooks = [])).push(i, directiveDef.onDestroy); + } } } } -/** Queues afterContentInit and afterContentChecked hooks on TView */ -function queueContentHooks(def: DirectiveDef, tView: TView, i: number): void { - if (def.afterContentInit) { - (tView.contentHooks || (tView.contentHooks = [])).push(i, def.afterContentInit); - } - - if (def.afterContentChecked) { - (tView.contentHooks || (tView.contentHooks = [])).push(i, def.afterContentChecked); - (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, def.afterContentChecked); - } -} - -/** Queues afterViewInit and afterViewChecked hooks on TView */ -function queueViewHooks(def: DirectiveDef, tView: TView, i: number): void { - if (def.afterViewInit) { - (tView.viewHooks || (tView.viewHooks = [])).push(i, def.afterViewInit); - } - - if (def.afterViewChecked) { - (tView.viewHooks || (tView.viewHooks = [])).push(i, def.afterViewChecked); - (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, def.afterViewChecked); - } -} - -/** Queues onDestroy hooks on TView */ -function queueDestroyHooks(def: DirectiveDef, tView: TView, i: number): void { - if (def.onDestroy != null) { - (tView.destroyHooks || (tView.destroyHooks = [])).push(i, def.onDestroy); - } -} - /** - * Calls onInit and doCheck calls if they haven't already been called. + * Executes necessary hooks at the start of executing a template. * - * @param currentView The current view + * Executes hooks that are to be run during the initialization of a directive such + * as `onChanges`, `onInit`, and `doCheck`. + * + * Has the side effect of updating the RunInit flag in `lView` to be `0`, so that + * this isn't run a second time. + * + * @param lView The current view + * @param tView Static data for the view containing the hooks to be executed + * @param checkNoChangesMode Whether or not we're in checkNoChanges mode. */ export function executeInitHooks( currentView: LView, tView: TView, checkNoChangesMode: boolean): void { - if (!checkNoChangesMode && currentView[FLAGS] & LViewFlags.RunInit) { - executeHooks(currentView, tView.initHooks, tView.checkHooks, checkNoChangesMode); - currentView[FLAGS] &= ~LViewFlags.RunInit; + if (!checkNoChangesMode) { + executeHooks( + currentView, tView.initHooks, tView.checkHooks, checkNoChangesMode, + InitPhaseState.OnInitHooksToBeRun); } } /** - * Iterates over afterViewInit and afterViewChecked functions and calls them. + * Executes hooks against the given `LView` based off of whether or not + * This is the first pass. * - * @param currentView The current view + * @param lView The view instance data to run the hooks against + * @param firstPassHooks An array of hooks to run if we're in the first view pass + * @param checkHooks An Array of hooks to run if we're not in the first view pass. + * @param checkNoChangesMode Whether or not we're in no changes mode. */ export function executeHooks( - currentView: LView, allHooks: HookData | null, checkHooks: HookData | null, - checkNoChangesMode: boolean): void { + currentView: LView, firstPassHooks: HookData | null, checkHooks: HookData | null, + checkNoChangesMode: boolean, initPhase: number): void { if (checkNoChangesMode) return; - - const hooksToCall = currentView[FLAGS] & LViewFlags.FirstLViewPass ? allHooks : checkHooks; + const hooksToCall = (currentView[FLAGS] & LViewFlags.InitPhaseStateMask) === initPhase ? + firstPassHooks : + checkHooks; if (hooksToCall) { - callHooks(currentView, hooksToCall); + callHooks(currentView, hooksToCall, initPhase); + } + // The init phase state must be always checked here as it may have been recursively updated + if ((currentView[FLAGS] & LViewFlags.InitPhaseStateMask) === initPhase && + initPhase !== InitPhaseState.InitPhaseCompleted) { + currentView[FLAGS] &= LViewFlags.IndexWithinInitPhaseReset; + currentView[FLAGS] += LViewFlags.InitPhaseStateIncrementer; } } /** * Calls lifecycle hooks with their contexts, skipping init hooks if it's not - * the first LView pass. + * the first LView pass * * @param currentView The current view * @param arr The array in which the hooks are found */ -export function callHooks(currentView: any[], arr: HookData): void { +export function callHooks(currentView: LView, arr: HookData, initPhase?: number): void { + let initHooksCount = 0; for (let i = 0; i < arr.length; i += 2) { - (arr[i + 1] as() => void).call(currentView[arr[i] as number]); + const isInitHook = arr[i] < 0; + const directiveIndex = isInitHook ? -arr[i] : arr[i] as number; + const directive = currentView[directiveIndex]; + const hook = arr[i + 1] as() => void; + if (isInitHook) { + initHooksCount++; + const indexWithintInitPhase = currentView[FLAGS] >> LViewFlags.IndexWithinInitPhaseShift; + // The init phase state must be always checked here as it may have been recursively updated + if (indexWithintInitPhase < initHooksCount && + (currentView[FLAGS] & LViewFlags.InitPhaseStateMask) === initPhase) { + currentView[FLAGS] += LViewFlags.IndexWithinInitPhaseIncrementer; + hook.call(directive); + } + } else { + hook.call(directive); + } } } diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 754586036b..00cb81fc6e 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -9,32 +9,41 @@ import {SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS, getTemplateContent} from '../sanitization/html_sanitizer'; import {InertBodyHelper} from '../sanitization/inert_body'; import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer'; -import {assertDefined, assertEqual, assertGreaterThan} from './assert'; +import {assertDefined, assertEqual, assertGreaterThan} from '../util/assert'; + import {attachPatchData} from './context_discovery'; import {allocExpando, createNodeAtIndex, elementAttribute, load, textBinding} from './instructions'; -import {LContainer, NATIVE, RENDER_PARENT} from './interfaces/container'; +import {LContainer, NATIVE} from './interfaces/container'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, IcuType, TI18n, TIcu} from './interfaces/i18n'; import {TElementNode, TIcuContainerNode, TNode, TNodeType} from './interfaces/node'; import {RComment, RElement} from './interfaces/renderer'; import {SanitizerFn} from './interfaces/sanitization'; import {StylingContext} from './interfaces/styling'; -import {BINDING_INDEX, HEADER_OFFSET, HOST_NODE, LView, RENDERER, TVIEW, TView} from './interfaces/view'; -import {appendChild, createTextNode, removeChild} from './node_manipulation'; +import {BINDING_INDEX, HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from './interfaces/view'; +import {appendChild, createTextNode, nativeRemoveNode} from './node_manipulation'; import {getIsParent, getLView, getPreviousOrParentTNode, setIsParent, setPreviousOrParentTNode} from './state'; import {NO_CHANGE} from './tokens'; -import {addAllToArray, getNativeByIndex, getNativeByTNode, getTNode, isLContainer, stringify} from './util'; +import {addAllToArray, getNativeByIndex, getNativeByTNode, getTNode, isLContainer, renderStringify} from './util'; const MARKER = `�`; -const ICU_BLOCK_REGEX = /^\s*(�\d+�)\s*,\s*(select|plural)\s*,/; +const ICU_BLOCK_REGEXP = /^\s*(�\d+:?\d*�)\s*,\s*(select|plural)\s*,/; const SUBTEMPLATE_REGEXP = /�\/?\*(\d+:\d+)�/gi; const PH_REGEXP = /�(\/?[#*]\d+):?\d*�/gi; const BINDING_REGEXP = /�(\d+):?\d*�/gi; -const ICU_REGEXP = /({\s*�\d+�\s*,\s*\S{6}\s*,[\s\S]*})/gi; +const ICU_REGEXP = /({\s*�\d+:?\d*�\s*,\s*\S{6}\s*,[\s\S]*})/gi; -// i18nPostproocess regexps -const PP_PLACEHOLDERS = /\[(�.+?�?)\]/g; -const PP_ICU_VARS = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g; -const PP_ICUS = /�I18N_EXP_(ICU(_\d+)?)�/g; +// i18nPostprocess consts +const ROOT_TEMPLATE_ID = 0; +const PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/; +const PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g; +const PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g; +const PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g; +const PP_CLOSE_TEMPLATE_REGEXP = /\/\*/; +const PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/; + +// Parsed placeholder structure used in postprocessing (within `i18nPostprocess` function) +// Contains the following fields: [templateId, isCloseTemplateTag, placeholder] +type PostprocessPlaceholder = [number, boolean, string]; interface IcuExpression { type: IcuType; @@ -104,7 +113,7 @@ function extractParts(pattern: string): (string | IcuExpression)[] { if (braceStack.length == 0) { // End of the block. const block = pattern.substring(prevPos, pos); - if (ICU_BLOCK_REGEX.test(block)) { + if (ICU_BLOCK_REGEXP.test(block)) { results.push(parseICUBlock(block)); } else if (block) { // Don't push empty strings results.push(block); @@ -142,7 +151,7 @@ function parseICUBlock(pattern: string): IcuExpression { const values: (string | IcuExpression)[][] = []; let icuType = IcuType.plural; let mainBinding = 0; - pattern = pattern.replace(ICU_BLOCK_REGEX, function(str: string, binding: string, type: string) { + pattern = pattern.replace(ICU_BLOCK_REGEXP, function(str: string, binding: string, type: string) { if (type === 'select') { icuType = IcuType.select; } else { @@ -343,19 +352,24 @@ export function i18nStart(index: number, message: string, subTemplateIndex?: num } } +// Count for the number of vars that will be allocated for each i18n block. +// It is global because this is used in multiple functions that include loops and recursive calls. +// This is reset to 0 when `i18nStartFirstPass` is called. +let i18nVarsCount: number; + /** * See `i18nStart` above. */ function i18nStartFirstPass( tView: TView, index: number, message: string, subTemplateIndex?: number) { const viewData = getLView(); - const expandoStartIndex = tView.blueprint.length - HEADER_OFFSET; + const startIndex = tView.blueprint.length - HEADER_OFFSET; + i18nVarsCount = 0; const previousOrParentTNode = getPreviousOrParentTNode(); const parentTNode = getIsParent() ? getPreviousOrParentTNode() : previousOrParentTNode && previousOrParentTNode.parent; - let parentIndex = parentTNode && parentTNode !== viewData[HOST_NODE] ? - parentTNode.index - HEADER_OFFSET : - index; + let parentIndex = + parentTNode && parentTNode !== viewData[T_HOST] ? parentTNode.index - HEADER_OFFSET : index; let parentIndexPointer = 0; parentIndexStack[parentIndexPointer] = parentIndex; const createOpCodes: I18nMutateOpCodes = []; @@ -395,21 +409,18 @@ function i18nStartFirstPass( } } else { // Even indexes are text (including bindings & ICU expressions) - const parts = value.split(ICU_REGEXP); + const parts = extractParts(value); for (let j = 0; j < parts.length; j++) { - value = parts[j]; - if (j & 1) { // Odd indexes are ICU expressions // Create the comment node that will anchor the ICU expression - allocExpando(viewData); - const icuNodeIndex = tView.blueprint.length - 1 - HEADER_OFFSET; + const icuNodeIndex = startIndex + i18nVarsCount++; createOpCodes.push( - COMMENT_MARKER, ngDevMode ? `ICU ${icuNodeIndex}` : '', + COMMENT_MARKER, ngDevMode ? `ICU ${icuNodeIndex}` : '', icuNodeIndex, parentIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild); // Update codes for the ICU expression - const icuExpression = parseICUBlock(value.substr(1, value.length - 2)); + const icuExpression = parts[j] as IcuExpression; const mask = getBindingMask(icuExpression); icuStart(icuExpressions, icuExpression, icuNodeIndex, icuNodeIndex); // Since this is recursive, the last TIcu that was pushed is the one we want @@ -422,30 +433,30 @@ function i18nStartFirstPass( mask, // mask of all the bindings of this ICU expression 2, // skip 2 opCodes if not changed icuNodeIndex << I18nUpdateOpCode.SHIFT_REF | I18nUpdateOpCode.IcuUpdate, tIcuIndex); - } else if (value !== '') { + } else if (parts[j] !== '') { + const text = parts[j] as string; // Even indexes are text (including bindings) - const hasBinding = value.match(BINDING_REGEXP); + const hasBinding = text.match(BINDING_REGEXP); // Create text nodes - allocExpando(viewData); + const textNodeIndex = startIndex + i18nVarsCount++; createOpCodes.push( // If there is a binding, the value will be set during update - hasBinding ? '' : value, + hasBinding ? '' : text, textNodeIndex, parentIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild); if (hasBinding) { - addAllToArray( - generateBindingUpdateOpCodes(value, tView.blueprint.length - 1 - HEADER_OFFSET), - updateOpCodes); + addAllToArray(generateBindingUpdateOpCodes(text, textNodeIndex), updateOpCodes); } } } } } + allocExpando(viewData, i18nVarsCount); + // NOTE: local var needed to properly assert the type of `TI18n`. const tI18n: TI18n = { - vars: tView.blueprint.length - HEADER_OFFSET - expandoStartIndex, - expandoStartIndex, + vars: i18nVarsCount, create: createOpCodes, update: updateOpCodes, icus: icuExpressions.length ? icuExpressions : null, @@ -470,7 +481,7 @@ function appendI18nNode(tNode: TNode, parentTNode: TNode, previousTNode: TNode | tNode.next = null; } - if (parentTNode !== viewData[HOST_NODE]) { + if (parentTNode !== viewData[T_HOST]) { tNode.parent = parentTNode as TElementNode; } @@ -504,25 +515,63 @@ function appendI18nNode(tNode: TNode, parentTNode: TNode, previousTNode: TNode | * @publicAPI */ export function i18nPostprocess( - message: string, replacements: {[key: string]: (string | string[])}): string { - // - // Step 1: resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�]) - // - const matches: {[key: string]: string[]} = {}; - let result = message.replace(PP_PLACEHOLDERS, (_match, content: string): string => { - if (!matches[content]) { - matches[content] = content.split('|'); - } - if (!matches[content].length) { - throw new Error(`i18n postprocess: unmatched placeholder - ${content}`); - } - return matches[content].shift() !; - }); + message: string, replacements: {[key: string]: (string | string[])} = {}): string { + /** + * Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�] + * + * Note: due to the way we process nested templates (BFS), multi-value placeholders are typically + * grouped by templates, for example: [�#5�|�#6�|�#1:1�|�#3:2�] where �#5� and �#6� belong to root + * template, �#1:1� belong to nested template with index 1 and �#1:2� - nested template with index + * 3. However in real templates the order might be different: i.e. �#1:1� and/or �#3:2� may go in + * front of �#6�. The post processing step restores the right order by keeping track of the + * template id stack and looks for placeholders that belong to the currently active template. + */ + let result: string = message; + if (PP_MULTI_VALUE_PLACEHOLDERS_REGEXP.test(message)) { + const matches: {[key: string]: PostprocessPlaceholder[]} = {}; + const templateIdsStack: number[] = [ROOT_TEMPLATE_ID]; + result = result.replace(PP_PLACEHOLDERS_REGEXP, (m: any, phs: string, tmpl: string): string => { + const content = phs || tmpl; + if (!matches[content]) { + const placeholders: PostprocessPlaceholder[] = []; + content.split('|').forEach((placeholder: string) => { + const match = placeholder.match(PP_TEMPLATE_ID_REGEXP); + const templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID; + const isCloseTemplateTag = PP_CLOSE_TEMPLATE_REGEXP.test(placeholder); + placeholders.push([templateId, isCloseTemplateTag, placeholder]); + }); + matches[content] = placeholders; + } + if (!matches[content].length) { + throw new Error(`i18n postprocess: unmatched placeholder - ${content}`); + } + const currentTemplateId = templateIdsStack[templateIdsStack.length - 1]; + const placeholders = matches[content]; + let idx = 0; + // find placeholder index that matches current template id + for (let i = 0; i < placeholders.length; i++) { + if (placeholders[i][0] === currentTemplateId) { + idx = i; + break; + } + } + // update template id stack based on the current tag extracted + const [templateId, isCloseTemplateTag, placeholder] = placeholders[idx]; + if (isCloseTemplateTag) { + templateIdsStack.pop(); + } else if (currentTemplateId !== templateId) { + templateIdsStack.push(templateId); + } + // remove processed tag from the list + placeholders.splice(idx, 1); + return placeholder; + }); - // verify that we injected all values - const hasUnmatchedValues = Object.keys(matches).some(key => !!matches[key].length); - if (hasUnmatchedValues) { - throw new Error(`i18n postprocess: unmatched values - ${JSON.stringify(matches)}`); + // verify that we injected all values + const hasUnmatchedValues = Object.keys(matches).some(key => !!matches[key].length); + if (hasUnmatchedValues) { + throw new Error(`i18n postprocess: unmatched values - ${JSON.stringify(matches)}`); + } } // return current result if no replacements specified @@ -530,18 +579,18 @@ export function i18nPostprocess( return result; } - // - // Step 2: replace all ICU vars (like "VAR_PLURAL") - // - result = result.replace(PP_ICU_VARS, (match, start, key, _type, _idx, end): string => { + /** + * Step 2: replace all ICU vars (like "VAR_PLURAL") + */ + result = result.replace(PP_ICU_VARS_REGEXP, (match, start, key, _type, _idx, end): string => { return replacements.hasOwnProperty(key) ? `${start}${replacements[key]}${end}` : match; }); - // - // Step 3: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) - // in case multiple ICUs have the same placeholder name - // - result = result.replace(PP_ICUS, (match, key): string => { + /** + * Step 3: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case + * multiple ICUs have the same placeholder name + */ + result = result.replace(PP_ICUS_REGEXP, (match, key): string => { if (replacements.hasOwnProperty(key)) { const list = replacements[key] as string[]; if (!list.length) { @@ -565,6 +614,16 @@ export function i18nEnd(): void { i18nEndFirstPass(tView); } +function findLastNode(node: TNode): TNode { + while (node.next) { + node = node.next; + } + if (node.child) { + return findLastNode(node.child); + } + return node; +} + /** * See `i18nEnd` above. */ @@ -580,33 +639,38 @@ function i18nEndFirstPass(tView: TView) { // The last placeholder that was added before `i18nEnd` const previousOrParentTNode = getPreviousOrParentTNode(); - const visitedPlaceholders = - readCreateOpCodes(rootIndex, tI18n.create, tI18n.expandoStartIndex, viewData); + const visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, tI18n.icus, viewData); - // Remove deleted placeholders - // The last placeholder that was added before `i18nEnd` is `previousOrParentTNode` - for (let i = rootIndex + 1; i <= previousOrParentTNode.index - HEADER_OFFSET; i++) { - if (visitedPlaceholders.indexOf(i) === -1) { + // Find the last node that was added before `i18nEnd` + let lastCreatedNode = previousOrParentTNode; + if (lastCreatedNode.child) { + lastCreatedNode = findLastNode(lastCreatedNode.child); + } + + // Remove deleted nodes + for (let i = rootIndex + 1; i <= lastCreatedNode.index - HEADER_OFFSET; i++) { + if (visitedNodes.indexOf(i) === -1) { removeNode(i, viewData); } } } function readCreateOpCodes( - index: number, createOpCodes: I18nMutateOpCodes, expandoStartIndex: number, + index: number, createOpCodes: I18nMutateOpCodes, icus: TIcu[] | null, viewData: LView): number[] { const renderer = getLView()[RENDERER]; let currentTNode: TNode|null = null; let previousTNode: TNode|null = null; - const visitedPlaceholders: number[] = []; + const visitedNodes: number[] = []; for (let i = 0; i < createOpCodes.length; i++) { const opCode = createOpCodes[i]; if (typeof opCode == 'string') { const textRNode = createTextNode(opCode, renderer); + const textNodeIndex = createOpCodes[++i] as number; ngDevMode && ngDevMode.rendererCreateTextNode++; previousTNode = currentTNode; - currentTNode = - createNodeAtIndex(expandoStartIndex++, TNodeType.Element, textRNode, null, null); + currentTNode = createNodeAtIndex(textNodeIndex, TNodeType.Element, textRNode, null, null); + visitedNodes.push(textNodeIndex); setIsParent(false); } else if (typeof opCode == 'number') { switch (opCode & I18nMutateOpCode.MASK_OPCODE) { @@ -616,7 +680,7 @@ function readCreateOpCodes( if (destinationNodeIndex === index) { // If the destination node is `i18nStart`, we don't have a // top-level node and we should use the host node instead - destinationTNode = viewData[HOST_NODE] !; + destinationTNode = viewData[T_HOST] !; } else { destinationTNode = getTNode(destinationNodeIndex, viewData); } @@ -629,7 +693,7 @@ function readCreateOpCodes( break; case I18nMutateOpCode.Select: const nodeIndex = opCode >>> I18nMutateOpCode.SHIFT_REF; - visitedPlaceholders.push(nodeIndex); + visitedNodes.push(nodeIndex); previousTNode = currentTNode; currentTNode = getTNode(nodeIndex, viewData); if (currentTNode) { @@ -658,14 +722,16 @@ function readCreateOpCodes( switch (opCode) { case COMMENT_MARKER: const commentValue = createOpCodes[++i] as string; + const commentNodeIndex = createOpCodes[++i] as number; ngDevMode && assertEqual( typeof commentValue, 'string', `Expected "${commentValue}" to be a comment node value`); const commentRNode = renderer.createComment(commentValue); ngDevMode && ngDevMode.rendererCreateComment++; previousTNode = currentTNode; - currentTNode = createNodeAtIndex( - expandoStartIndex++, TNodeType.IcuContainer, commentRNode, null, null); + currentTNode = + createNodeAtIndex(commentNodeIndex, TNodeType.IcuContainer, commentRNode, null, null); + visitedNodes.push(commentNodeIndex); attachPatchData(commentRNode, viewData); (currentTNode as TIcuContainerNode).activeCaseIndex = null; // We will add the case nodes later, during the update phase @@ -673,6 +739,7 @@ function readCreateOpCodes( break; case ELEMENT_MARKER: const tagNameValue = createOpCodes[++i] as string; + const elementNodeIndex = createOpCodes[++i] as number; ngDevMode && assertEqual( typeof tagNameValue, 'string', `Expected "${tagNameValue}" to be an element node tag name`); @@ -680,7 +747,8 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateElement++; previousTNode = currentTNode; currentTNode = createNodeAtIndex( - expandoStartIndex++, TNodeType.Element, elementRNode, tagNameValue, null); + elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue, null); + visitedNodes.push(elementNodeIndex); break; default: throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`); @@ -690,7 +758,7 @@ function readCreateOpCodes( setIsParent(false); - return visitedPlaceholders; + return visitedNodes; } function readUpdateOpCodes( @@ -712,7 +780,7 @@ function readUpdateOpCodes( } else if (typeof opCode == 'number') { if (opCode < 0) { // It's a binding index whose value is negative - value += stringify(viewData[bindingsStartIndex - opCode]); + value += renderStringify(viewData[bindingsStartIndex - opCode]); } else { const nodeIndex = opCode >>> I18nUpdateOpCode.SHIFT_REF; switch (opCode & I18nUpdateOpCode.MASK_OPCODE) { @@ -759,7 +827,7 @@ function readUpdateOpCodes( icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null; // Add the nodes for the new case - readCreateOpCodes(-1, tIcu.create[caseIndex], tIcu.expandoStartIndex, viewData); + readCreateOpCodes(-1, tIcu.create[caseIndex], icus, viewData); caseCreated = true; break; case I18nUpdateOpCode.IcuUpdate: @@ -782,18 +850,19 @@ function readUpdateOpCodes( function removeNode(index: number, viewData: LView) { const removedPhTNode = getTNode(index, viewData); const removedPhRNode = getNativeByIndex(index, viewData); - removeChild(removedPhTNode, removedPhRNode || null, viewData); - removedPhTNode.detached = true; - ngDevMode && ngDevMode.rendererRemoveNode++; + if (removedPhRNode) { + nativeRemoveNode(viewData[RENDERER], removedPhRNode); + } const slotValue = load(index) as RElement | RComment | LContainer | StylingContext; if (isLContainer(slotValue)) { const lContainer = slotValue as LContainer; if (removedPhTNode.type !== TNodeType.Container) { - removeChild(removedPhTNode, lContainer[NATIVE] || null, viewData); + nativeRemoveNode(viewData[RENDERER], lContainer[NATIVE]); } - lContainer[RENDER_PARENT] = null; } + + ngDevMode && ngDevMode.rendererRemoveNode++; } /** @@ -834,9 +903,6 @@ export function i18n(index: number, message: string, subTemplateIndex?: number): export function i18nAttributes(index: number, values: string[]): void { const tView = getLView()[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); - ngDevMode && - assertEqual( - tView.firstTemplatePass, true, `You should only call i18nEnd on first template pass`); if (tView.firstTemplatePass && tView.data[index + HEADER_OFFSET] === null) { i18nAttributesFirstPass(tView, index, values); } @@ -1334,18 +1400,15 @@ function icuStart( const tIcu: TIcu = { type: icuExpression.type, vars, - expandoStartIndex: expandoStartIndex + 1, childIcus, + childIcus, cases: icuExpression.cases, create: createCodes, remove: removeCodes, update: updateCodes }; tIcus.push(tIcu); - const lView = getLView(); - const worstCaseSize = Math.max(...vars); - for (let i = 0; i < worstCaseSize; i++) { - allocExpando(lView); - } + // Adding the maximum possible of vars needed (based on the cases with the most vars) + i18nVarsCount += Math.max(...vars); } /** @@ -1401,7 +1464,7 @@ function parseNodes( icuCase.vars--; } else { icuCase.create.push( - ELEMENT_MARKER, tagName, + ELEMENT_MARKER, tagName, newIndex, parentIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild); const elAttrs = element.attributes; for (let i = 0; i < elAttrs.length; i++) { @@ -1447,7 +1510,7 @@ function parseNodes( const value = currentNode.textContent || ''; const hasBinding = value.match(BINDING_REGEXP); icuCase.create.push( - hasBinding ? '' : value, + hasBinding ? '' : value, newIndex, parentIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild); icuCase.remove.push(newIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove); if (hasBinding) { @@ -1462,7 +1525,7 @@ function parseNodes( const newLocal = ngDevMode ? `nested ICU ${nestedIcuIndex}` : ''; // Create the comment node that will anchor the ICU expression icuCase.create.push( - COMMENT_MARKER, newLocal, + COMMENT_MARKER, newLocal, newIndex, parentIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild); const nestedIcu = nestedIcus[nestedIcuIndex]; nestedIcusToCreate.push([nestedIcu, newIndex]); diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index f1971992b5..447538a3b3 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ import {LifecycleHooksFeature, renderComponent, whenRendered} from './component'; -import {defineBase, defineComponent, defineDirective, defineNgModule, definePipe} from './definition'; -import {getComponent, getHostElement, getRenderedText} from './discovery_utils'; +import {defineBase, defineComponent, defineDirective, defineNgModule, definePipe, setComponentScope} from './definition'; +import {getComponent, getDirectives, getHostElement, getRenderedText} from './discovery_utils'; import {InheritDefinitionFeature} from './features/inherit_definition_feature'; import {NgOnChangesFeature} from './features/ng_onchanges_feature'; import {ProvidersFeature} from './features/providers_feature'; @@ -44,6 +44,8 @@ export { elementClassProp, elementEnd, elementProperty, + componentHostSyntheticProperty, + componentHostSyntheticListener, elementStart, elementContainerStart, @@ -120,14 +122,12 @@ export { } from './pipe'; export { - QueryList, - query, queryRefresh, + viewQuery, + loadViewQuery, + contentQuery, + loadContentQuery, } from './query'; -export { - registerContentQuery, - loadQueryList, -} from './instructions'; export { pureFunction0, @@ -144,6 +144,7 @@ export { export {templateRefExtractor} from './view_engine_compatibility_prebound'; +export {resolveWindow, resolveDocument, resolveBody} from './util'; // clang-format on @@ -170,8 +171,10 @@ export { definePipe, getHostElement, getComponent, + getDirectives, getRenderedText, renderComponent, + setComponentScope, whenRendered, }; diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 6ed84dd888..2cede59d00 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -6,41 +6,43 @@ * found in the LICENSE file at https://angular.io/license */ +import {InjectFlags, InjectionToken, Injector} from '../di'; import {resolveForwardRef} from '../di/forward_ref'; -import {InjectionToken} from '../di/injection_token'; -import {Injector} from '../di/injector'; -import {InjectFlags} from '../di/injector_compatibility'; -import {QueryList} from '../linker'; +import {ErrorHandler} from '../error_handler'; +import {Type} from '../interface/type'; +import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../metadata/schema'; +import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../sanitization/sanitization'; import {Sanitizer} from '../sanitization/security'; import {StyleSanitizeFn} from '../sanitization/style_sanitizer'; -import {Type} from '../type'; +import {assertDataInRange, assertDefined, assertEqual, assertLessThan, assertNotEqual} from '../util/assert'; +import {isObservable} from '../util/lang'; import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect'; -import {assertDataInRange, assertDefined, assertEqual, assertHasParent, assertLessThan, assertNotEqual, assertPreviousIsParent} from './assert'; +import {assertHasParent, assertPreviousIsParent} from './assert'; import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from './bindings'; import {attachPatchData, getComponentViewByInstance} from './context_discovery'; import {diPublicInInjector, getNodeInjectable, getOrCreateInjectable, getOrCreateNodeInjectorForNode, injectAttributeImpl} from './di'; import {throwMultipleComponentError} from './errors'; -import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks'; +import {executeHooks, executeInitHooks, registerPostOrderHooks, registerPreOrderHooks} from './hooks'; import {ACTIVE_INDEX, LContainer, VIEWS} from './interfaces/container'; -import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags} from './interfaces/definition'; +import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from './interfaces/definition'; import {INJECTOR_BLOOM_PARENT_SIZE, NodeInjectorFactory} from './interfaces/injector'; import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from './interfaces/node'; import {PlayerFactory} from './interfaces/player'; import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection'; import {LQueries} from './interfaces/query'; -import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer'; +import {GlobalTargetResolver, ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer'; import {SanitizerFn} from './interfaces/sanitization'; -import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LView, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view'; +import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, INJECTOR, InitPhaseState, LView, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TAIL, TData, TVIEW, TView, T_HOST} from './interfaces/view'; import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; -import {appendChild, appendProjectedNode, createTextNode, getLViewChild, getRenderParent, insertView, removeView} from './node_manipulation'; +import {appendChild, appendProjectedNode, createTextNode, getLViewChild, insertView, removeView} from './node_manipulation'; import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher'; -import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getElementDepthCount, getFirstTemplatePass, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state'; -import {getInitialClassNameValue, initializeStaticContext as initializeStaticStylingContext, patchContextWithStaticAttrs, renderInitialStylesAndClasses, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings'; +import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getElementDepthCount, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode} from './state'; +import {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticContext as initializeStaticStylingContext, patchContextWithStaticAttrs, renderInitialClasses, renderInitialStyles, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings'; import {BoundPlayerFactory} from './styling/player_factory'; -import {createEmptyStylingContext, getStylingContext, hasClassInput, hasStyling, isAnimationProp} from './styling/util'; +import {ANIMATION_PROP_PREFIX, allocateDirectiveIntoContext, createEmptyStylingContext, forceClassesAsString, forceStylesAsString, getStylingContext, hasClassInput, hasStyleInput, hasStyling, isAnimationProp} from './styling/util'; import {NO_CHANGE} from './tokens'; -import {findComponentView, getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, loadInternal, readElementValue, readPatchedLView, stringify} from './util'; +import {INTERPOLATION_DELIMITER, applyOnCreateInstructions, findComponentView, getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, loadInternal, readElementValue, readPatchedLView, renderStringify} from './util'; @@ -65,7 +67,9 @@ export function refreshDescendantViews(lView: LView) { const tView = lView[TVIEW]; // This needs to be set before children are processed to support recursive components tView.firstTemplatePass = false; - setFirstTemplatePass(false); + + // Resetting the bindingIndex of the current LView as the next steps may trigger change detection. + lView[BINDING_INDEX] = tView.bindingStartIndex; // If this is a creation pass, we should not call lifecycle hooks or evaluate bindings. // This will be done in the update pass. @@ -77,9 +81,11 @@ export function refreshDescendantViews(lView: LView) { refreshDynamicEmbeddedViews(lView); // Content query results must be refreshed before content hooks are called. - refreshContentQueries(tView); + refreshContentQueries(tView, lView); - executeHooks(lView, tView.contentHooks, tView.contentCheckHooks, checkNoChangesMode); + executeHooks( + lView, tView.contentHooks, tView.contentCheckHooks, checkNoChangesMode, + InitPhaseState.AfterContentInitHooksToBeRun); setHostBindings(tView, lView); } @@ -129,14 +135,15 @@ export function setHostBindings(tView: TView, viewData: LView): void { } /** Refreshes content queries for all directives in the given view. */ -function refreshContentQueries(tView: TView): void { +function refreshContentQueries(tView: TView, lView: LView): void { if (tView.contentQueries != null) { - for (let i = 0; i < tView.contentQueries.length; i += 2) { + setCurrentQueryIndex(0); + for (let i = 0; i < tView.contentQueries.length; i++) { const directiveDefIdx = tView.contentQueries[i]; const directiveDef = tView.data[directiveDefIdx] as DirectiveDef; - - directiveDef.contentQueriesRefresh !( - directiveDefIdx - HEADER_OFFSET, tView.contentQueries[i + 1]); + ngDevMode && + assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined'); + directiveDef.contentQueries !(RenderFlags.Update, lView[directiveDefIdx], directiveDefIdx); } } } @@ -152,11 +159,11 @@ function refreshChildComponents(components: number[] | null): void { export function createLView( parentLView: LView | null, tView: TView, context: T | null, flags: LViewFlags, + host: RElement | null, tHostNode: TViewNode | TElementNode | null, rendererFactory?: RendererFactory3 | null, renderer?: Renderer3 | null, sanitizer?: Sanitizer | null, injector?: Injector | null): LView { const lView = tView.blueprint.slice() as LView; - lView[FLAGS] = flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit | - LViewFlags.FirstLViewPass; + lView[FLAGS] = flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.FirstLViewPass; lView[PARENT] = lView[DECLARATION_VIEW] = parentLView; lView[CONTEXT] = context; lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]) !; @@ -165,6 +172,8 @@ export function createLView( ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required'); lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null !; lView[INJECTOR as any] = injector || parentLView && parentLView[INJECTOR] || null; + lView[HOST] = host; + lView[T_HOST] = tHostNode; return lView; } @@ -204,17 +213,24 @@ export function createNodeAtIndex( assertLessThan(adjustedIndex, lView.length, `Slot should have been initialized with null`); lView[adjustedIndex] = native; + const previousOrParentTNode = getPreviousOrParentTNode(); + const isParent = getIsParent(); let tNode = tView.data[adjustedIndex] as TNode; if (tNode == null) { - // TODO(misko): Refactor createTNode so that it does not depend on LView. - tNode = tView.data[adjustedIndex] = createTNode(lView, type, adjustedIndex, name, attrs, null); + const parent = + isParent ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; + + // Parents cannot cross component boundaries because components will be used in multiple places, + // so it's only set if the view is the same. + const parentInSameView = parent && parent !== lView[T_HOST]; + const tParentNode = parentInSameView ? parent as TElementNode | TContainerNode : null; + + tNode = tView.data[adjustedIndex] = createTNode(tParentNode, type, adjustedIndex, name, attrs); } // Now link ourselves into the tree. // We need this even if tNode exists, otherwise we might end up pointing to unexisting tNodes when // we use i18n (especially with ICU expressions that update the DOM during the update phase). - const previousOrParentTNode = getPreviousOrParentTNode(); - const isParent = getIsParent(); if (previousOrParentTNode) { if (isParent && previousOrParentTNode.child == null && (tNode.parent !== null || previousOrParentTNode.type === TNodeType.View)) { @@ -235,14 +251,20 @@ export function createNodeAtIndex( TProjectionNode & TIcuContainerNode; } -export function createViewNode(index: number, view: LView) { +export function assignTViewNodeToLView( + tView: TView, tParentNode: TNode | null, index: number, lView: LView): TViewNode { // View nodes are not stored in data because they can be added / removed at runtime (which // would cause indices to change). Their TNodes are instead stored in tView.node. - if (view[TVIEW].node == null) { - view[TVIEW].node = createTNode(view, TNodeType.View, index, null, null, null) as TViewNode; + let tNode = tView.node; + if (tNode == null) { + ngDevMode && tParentNode && + assertNodeOfPossibleTypes(tParentNode, TNodeType.Element, TNodeType.Container); + tView.node = tNode = createTNode( + tParentNode as TElementNode | TContainerNode | null, // + TNodeType.View, index, null, null) as TViewNode; } - return view[HOST_NODE] = view[TVIEW].node as TViewNode; + return lView[T_HOST] = tNode as TViewNode; } @@ -251,13 +273,24 @@ export function createViewNode(index: number, view: LView) { * i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future * template passes. */ -export function allocExpando(view: LView) { +export function allocExpando(view: LView, numSlotsToAlloc: number) { const tView = view[TVIEW]; if (tView.firstTemplatePass) { - tView.expandoStartIndex++; - tView.blueprint.push(null); - tView.data.push(null); - view.push(null); + for (let i = 0; i < numSlotsToAlloc; i++) { + tView.blueprint.push(null); + tView.data.push(null); + view.push(null); + } + + // We should only increment the expando start index if there aren't already directives + // and injectors saved in the "expando" section + if (!tView.expandoInstructions) { + tView.expandoStartIndex += numSlotsToAlloc; + } else { + // Since we're adding the dynamic nodes into the expando section, we need to let the host + // bindings know that they should skip x slots + tView.expandoInstructions.push(numSlotsToAlloc); + } } } @@ -279,28 +312,28 @@ export function allocExpando(view: LView) { */ export function renderTemplate( hostNode: RElement, templateFn: ComponentTemplate, consts: number, vars: number, context: T, - providedRendererFactory: RendererFactory3, hostView: LView | null, + providedRendererFactory: RendererFactory3, componentView: LView | null, directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null, sanitizer?: Sanitizer | null): LView { - if (hostView == null) { + if (componentView === null) { resetComponentState(); const renderer = providedRendererFactory.createRenderer(null, null); // We need to create a root view so it's possible to look up the host element through its index const hostLView = createLView( - null, createTView(-1, null, 1, 0, null, null, null), {}, - LViewFlags.CheckAlways | LViewFlags.IsRoot, providedRendererFactory, renderer); + null, createTView(-1, null, 1, 0, null, null, null, null), {}, + LViewFlags.CheckAlways | LViewFlags.IsRoot, null, null, providedRendererFactory, renderer); enterView(hostLView, null); // SUSPECT! why do we need to enter the View? const componentTView = - getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null); - hostView = createLView( - hostLView, componentTView, context, LViewFlags.CheckAlways, providedRendererFactory, - renderer, sanitizer); - hostView[HOST_NODE] = createNodeAtIndex(0, TNodeType.Element, hostNode, null, null); + getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null, null); + const hostTNode = createNodeAtIndex(0, TNodeType.Element, hostNode, null, null); + componentView = createLView( + hostLView, componentTView, context, LViewFlags.CheckAlways, hostNode, hostTNode, + providedRendererFactory, renderer, sanitizer); } - renderComponentOrTemplate(hostView, context, templateFn); - return hostView; + renderComponentOrTemplate(componentView, context, templateFn); + return componentView; } /** @@ -309,20 +342,20 @@ export function renderTemplate( * Such lViewNode will then be renderer with renderEmbeddedTemplate() (see below). */ export function createEmbeddedViewAndNode( - tView: TView, context: T, declarationView: LView, renderer: Renderer3, queries: LQueries | null, + tView: TView, context: T, declarationView: LView, queries: LQueries | null, injectorIndex: number): LView { const _isParent = getIsParent(); const _previousOrParentTNode = getPreviousOrParentTNode(); setIsParent(true); setPreviousOrParentTNode(null !); - const lView = createLView(declarationView, tView, context, LViewFlags.CheckAlways); + const lView = createLView(declarationView, tView, context, LViewFlags.CheckAlways, null, null); lView[DECLARATION_VIEW] = declarationView; if (queries) { lView[QUERIES] = queries.createView(); } - createViewNode(-1, lView); + assignTViewNodeToLView(tView, null, -1, lView); if (tView.firstTemplatePass) { tView.node !.injectorIndex = injectorIndex; @@ -346,8 +379,6 @@ export function createEmbeddedViewAndNode( export function renderEmbeddedTemplate(viewToRender: LView, tView: TView, context: T) { const _isParent = getIsParent(); const _previousOrParentTNode = getPreviousOrParentTNode(); - setIsParent(true); - setPreviousOrParentTNode(null !); let oldView: LView; if (viewToRender[FLAGS] & LViewFlags.IsRoot) { // This is a root view inside the view tree @@ -357,7 +388,7 @@ export function renderEmbeddedTemplate(viewToRender: LView, tView: TView, con setIsParent(true); setPreviousOrParentTNode(null !); - oldView = enterView(viewToRender, viewToRender[HOST_NODE]); + oldView = enterView(viewToRender, viewToRender[T_HOST]); namespaceHTML(); tView.template !(getRenderFlags(viewToRender), context); // This must be set to false immediately after the first creation run because in an @@ -365,7 +396,6 @@ export function renderEmbeddedTemplate(viewToRender: LView, tView: TView, con // off firstTemplatePass. If we don't set it here, instances will perform directive // matching, etc again and again. viewToRender[TVIEW].firstTemplatePass = false; - setFirstTemplatePass(false); refreshDescendantViews(viewToRender); } finally { @@ -393,17 +423,19 @@ export function nextContext(level: number = 1): T { function renderComponentOrTemplate( hostView: LView, context: T, templateFn?: ComponentTemplate) { const rendererFactory = hostView[RENDERER_FACTORY]; - const oldView = enterView(hostView, hostView[HOST_NODE]); + const oldView = enterView(hostView, hostView[T_HOST]); + const normalExecutionPath = !getCheckNoChangesMode(); + const creationModeIsActive = isCreationMode(hostView); try { - if (rendererFactory.begin) { + if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) { rendererFactory.begin(); } - if (isCreationMode(hostView)) { + if (creationModeIsActive) { // creation mode pass if (templateFn) { namespaceHTML(); - templateFn(RenderFlags.Create, context !); + templateFn(RenderFlags.Create, context); } refreshDescendantViews(hostView); @@ -411,10 +443,10 @@ function renderComponentOrTemplate( } // update mode pass - templateFn && templateFn(RenderFlags.Update, context !); + templateFn && templateFn(RenderFlags.Update, context); refreshDescendantViews(hostView); } finally { - if (rendererFactory.end) { + if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) { rendererFactory.end(); } leaveView(oldView); @@ -499,6 +531,26 @@ export function elementContainerStart( appendChild(native, tNode, lView); createDirectivesAndLocals(tView, lView, localRefs); attachPatchData(native, lView); + + const currentQueries = lView[QUERIES]; + if (currentQueries) { + currentQueries.addNode(tNode); + lView[QUERIES] = currentQueries.clone(); + } + executeContentQueries(tView, tNode, lView); +} + +function executeContentQueries(tView: TView, tNode: TNode, lView: LView) { + if (isContentQueryHost(tNode)) { + const start = tNode.directiveStart; + const end = tNode.directiveEnd; + for (let directiveIndex = start; directiveIndex < end; directiveIndex++) { + const def = tView.data[directiveIndex] as DirectiveDef; + if (def.contentQueries) { + def.contentQueries(RenderFlags.Create, lView[directiveIndex], directiveIndex); + } + } + } } /** Mark the end of the . */ @@ -509,7 +561,7 @@ export function elementContainerEnd(): void { if (getIsParent()) { setIsParent(false); } else { - ngDevMode && assertHasParent(getPreviousOrParentTNode()); + ngDevMode && assertHasParent(previousOrParentTNode); previousOrParentTNode = previousOrParentTNode.parent !; setPreviousOrParentTNode(previousOrParentTNode); } @@ -517,10 +569,10 @@ export function elementContainerEnd(): void { ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.ElementContainer); const currentQueries = lView[QUERIES]; if (currentQueries) { - lView[QUERIES] = currentQueries.addNode(previousOrParentTNode as TElementContainerNode); + lView[QUERIES] = currentQueries.parent; } - queueLifecycleHooks(tView, previousOrParentTNode); + registerPostOrderHooks(tView, previousOrParentTNode); } /** @@ -584,13 +636,24 @@ export function elementStart( if (inputData && inputData.hasOwnProperty('class')) { tNode.flags |= TNodeFlags.hasClassInput; } + if (inputData && inputData.hasOwnProperty('style')) { + tNode.flags |= TNodeFlags.hasStyleInput; + } } // There is no point in rendering styles when a class directive is present since // it will take that over for us (this will be removed once #FW-882 is in). - if (tNode.stylingTemplate && (tNode.flags & TNodeFlags.hasClassInput) === 0) { - renderInitialStylesAndClasses(native, tNode.stylingTemplate, lView[RENDERER]); + if (tNode.stylingTemplate) { + renderInitialClasses(native, tNode.stylingTemplate, lView[RENDERER]); + renderInitialStyles(native, tNode.stylingTemplate, lView[RENDERER]); } + + const currentQueries = lView[QUERIES]; + if (currentQueries) { + currentQueries.addNode(tNode); + lView[QUERIES] = currentQueries.clone(); + } + executeContentQueries(tView, tNode, lView); } /** @@ -622,20 +685,19 @@ export function elementCreate(name: string, overriddenRenderer?: Renderer3): REl * @param localRefExtractor mapping function that extracts local ref value from TNode */ function createDirectivesAndLocals( - tView: TView, viewData: LView, localRefs: string[] | null | undefined, + tView: TView, lView: LView, localRefs: string[] | null | undefined, localRefExtractor: LocalRefExtractor = getNativeByTNode) { if (!getBindingsEnabled()) return; const previousOrParentTNode = getPreviousOrParentTNode(); - if (getFirstTemplatePass()) { + if (tView.firstTemplatePass) { ngDevMode && ngDevMode.firstTemplatePass++; - resolveDirectives( - tView, viewData, findDirectiveMatches(tView, viewData, previousOrParentTNode), + tView, lView, findDirectiveMatches(tView, lView, previousOrParentTNode), previousOrParentTNode, localRefs || null); } - instantiateAllDirectives(tView, viewData, previousOrParentTNode); - invokeDirectivesHostBindings(tView, viewData, previousOrParentTNode); - saveResolvedLocalsInData(viewData, previousOrParentTNode, localRefExtractor); + instantiateAllDirectives(tView, lView, previousOrParentTNode); + invokeDirectivesHostBindings(tView, lView, previousOrParentTNode); + saveResolvedLocalsInData(lView, previousOrParentTNode, localRefExtractor); } /** @@ -667,12 +729,14 @@ function saveResolvedLocalsInData( * @param vars The number of bindings and pure function bindings in this view * @param directives Directive defs that should be saved on TView * @param pipes Pipe defs that should be saved on TView + * @param viewQuery View query that should be saved on TView + * @param schemas Schemas that should be saved on TView * @returns TView */ export function getOrCreateTView( templateFn: ComponentTemplate, consts: number, vars: number, directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null, - viewQuery: ComponentQuery| null): TView { + viewQuery: ViewQueriesFunction| null, schemas: SchemaMetadata[] | null): TView { // TODO(misko): reading `ngPrivateData` here is problematic for two reasons // 1. It is a megamorphic call on each invocation. // 2. For nested embedded views (ngFor inside ngFor) the template instance is per @@ -681,8 +745,8 @@ export function getOrCreateTView( // and not on embedded templates. return templateFn.ngPrivateData || - (templateFn.ngPrivateData = - createTView(-1, templateFn, consts, vars, directives, pipes, viewQuery) as never); + (templateFn.ngPrivateData = createTView( + -1, templateFn, consts, vars, directives, pipes, viewQuery, schemas) as never); } /** @@ -693,11 +757,13 @@ export function getOrCreateTView( * @param consts The number of nodes, local refs, and pipes in this template * @param directives Registry of directives for this view * @param pipes Registry of pipes for this view + * @param viewQuery View queries for this view + * @param schemas Schemas for this view */ export function createTView( viewIndex: number, templateFn: ComponentTemplate| null, consts: number, vars: number, directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null, - viewQuery: ComponentQuery| null): TView { + viewQuery: ViewQueriesFunction| null, schemas: SchemaMetadata[] | null): TView { ngDevMode && ngDevMode.tView++; const bindingStartIndex = HEADER_OFFSET + consts; // This length does not yet contain host bindings from child directives because at this point, @@ -711,9 +777,10 @@ export function createTView( template: templateFn, viewQuery: viewQuery, node: null !, - data: blueprint.slice(), // Fill in to match HEADER_OFFSET in LView - childIndex: -1, // Children set in addToViewTree(), if any + data: blueprint.slice().fill(null, bindingStartIndex), + childIndex: -1, // Children set in addToViewTree(), if any bindingStartIndex: bindingStartIndex, + viewQueryStartIndex: initialViewLength, expandoStartIndex: initialViewLength, expandoInstructions: null, firstTemplatePass: true, @@ -724,13 +791,13 @@ export function createTView( viewHooks: null, viewCheckHooks: null, destroyHooks: null, - pipeDestroyHooks: null, cleanup: null, contentQueries: null, components: null, directiveRegistry: typeof directives === 'function' ? directives() : directives, pipeRegistry: typeof pipes === 'function' ? pipes() : pipes, firstChild: null, + schemas: schemas, }; } @@ -743,31 +810,62 @@ function createViewBlueprint(bindingStartIndex: number, initialViewLength: numbe return blueprint; } -function setUpAttributes(native: RElement, attrs: TAttributes): void { +/** + * Assigns all attribute values to the provided element via the inferred renderer. + * + * This function accepts two forms of attribute entries: + * + * default: (key, value): + * attrs = [key1, value1, key2, value2] + * + * namespaced: (NAMESPACE_MARKER, uri, name, value) + * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value] + * + * The `attrs` array can contain a mix of both the default and namespaced entries. + * The "default" values are set without a marker, but if the function comes across + * a marker value then it will attempt to set a namespaced value. If the marker is + * not of a namespaced value then the function will quit and return the index value + * where it stopped during the iteration of the attrs array. + * + * See [AttributeMarker] to understand what the namespace marker value is. + * + * Note that this instruction does not support assigning style and class values to + * an element. See `elementStart` and `elementHostAttrs` to learn how styling values + * are applied to an element. + * + * @param native The element that the attributes will be assigned to + * @param attrs The attribute array of values that will be assigned to the element + * @returns the index value that was last accessed in the attributes array + */ +function setUpAttributes(native: RElement, attrs: TAttributes): number { const renderer = getLView()[RENDERER]; const isProc = isProceduralRenderer(renderer); - let i = 0; + let i = 0; while (i < attrs.length) { - const attrName = attrs[i++]; - if (typeof attrName == 'number') { - if (attrName === AttributeMarker.NamespaceURI) { - // Namespaced attributes - const namespaceURI = attrs[i++] as string; - const attrName = attrs[i++] as string; - const attrVal = attrs[i++] as string; - ngDevMode && ngDevMode.rendererSetAttribute++; - isProc ? - (renderer as ProceduralRenderer3) - .setAttribute(native, attrName, attrVal, namespaceURI) : - native.setAttributeNS(namespaceURI, attrName, attrVal); - } else { - // All other `AttributeMarker`s are ignored here. + const value = attrs[i]; + if (typeof value === 'number') { + // only namespaces are supported. Other value types (such as style/class + // entries) are not supported in this function. + if (value !== AttributeMarker.NamespaceURI) { break; } + + // we just landed on the marker value ... therefore + // we should skip to the next entry + i++; + + const namespaceURI = attrs[i++] as string; + const attrName = attrs[i++] as string; + const attrVal = attrs[i++] as string; + ngDevMode && ngDevMode.rendererSetAttribute++; + isProc ? + (renderer as ProceduralRenderer3).setAttribute(native, attrName, attrVal, namespaceURI) : + native.setAttributeNS(namespaceURI, attrName, attrVal); } else { /// attrName is string; - const attrVal = attrs[i++]; + const attrName = value as string; + const attrVal = attrs[++i]; if (attrName !== NG_PROJECT_AS_ATTR_NAME) { // Standard attributes ngDevMode && ngDevMode.rendererSetAttribute++; @@ -782,12 +880,19 @@ function setUpAttributes(native: RElement, attrs: TAttributes): void { native.setAttribute(attrName as string, attrVal as string); } } + i++; } } + + // another piece of code may iterate over the same attributes array. Therefore + // it may be helpful to return the exact spot where the attributes array exited + // whether by running into an unsupported marker or if all the static values were + // iterated over. + return i; } export function createError(text: string, token: any) { - return new Error(`Renderer: ${text} [${stringify(token)}]`); + return new Error(`Renderer: ${text} [${renderStringify(token)}]`); } @@ -822,23 +927,61 @@ export function locateHostElement( * * @param eventName Name of the event * @param listenerFn The function to be called when event emits - * @param useCapture Whether or not to use capture in event listener. + * @param useCapture Whether or not to use capture in event listener + * @param eventTargetResolver Function that returns global target information in case this listener + * should be attached to a global object like window, document or body */ export function listener( - eventName: string, listenerFn: (e?: any) => any, useCapture = false): void { + eventName: string, listenerFn: (e?: any) => any, useCapture = false, + eventTargetResolver?: GlobalTargetResolver): void { + listenerInternal(eventName, listenerFn, useCapture, eventTargetResolver); +} + +/** + * Registers a synthetic host listener (e.g. `(@foo.start)`) on a component. + * + * This instruction is for compatibility purposes and is designed to ensure that a + * synthetic host listener (e.g. `@HostListener('@foo.start')`) properly gets rendered + * in the component's renderer. Normally all host listeners are evaluated with the + * parent component's renderer, but, in the case of animation @triggers, they need + * to be evaluated with the sub component's renderer (because that's where the + * animation triggers are defined). + * + * Do not use this instruction as a replacement for `listener`. This instruction + * only exists to ensure compatibility with the ViewEngine's host binding behavior. + * + * @param eventName Name of the event + * @param listenerFn The function to be called when event emits + * @param useCapture Whether or not to use capture in event listener + * @param eventTargetResolver Function that returns global target information in case this listener + * should be attached to a global object like window, document or body + */ +export function componentHostSyntheticListener( + eventName: string, listenerFn: (e?: any) => any, useCapture = false, + eventTargetResolver?: GlobalTargetResolver): void { + listenerInternal(eventName, listenerFn, useCapture, eventTargetResolver, loadComponentRenderer); +} + +function listenerInternal( + eventName: string, listenerFn: (e?: any) => any, useCapture = false, + eventTargetResolver?: GlobalTargetResolver, + loadRendererFn?: ((tNode: TNode, lView: LView) => Renderer3) | null): void { const lView = getLView(); const tNode = getPreviousOrParentTNode(); const tView = lView[TVIEW]; const firstTemplatePass = tView.firstTemplatePass; const tCleanup: false|any[] = firstTemplatePass && (tView.cleanup || (tView.cleanup = [])); + ngDevMode && assertNodeOfPossibleTypes( tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); // add native event listener - applicable to elements only if (tNode.type === TNodeType.Element) { const native = getNativeByTNode(tNode, lView) as RElement; + const resolved = eventTargetResolver ? eventTargetResolver(native) : {} as any; + const target = resolved.target || native; ngDevMode && ngDevMode.rendererAddEventListener++; - const renderer = lView[RENDERER]; + const renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER]; const lCleanup = getCleanup(lView); const lCleanupIndex = lCleanup.length; let useCaptureOrSubIdx: boolean|number = useCapture; @@ -846,15 +989,23 @@ export function listener( // In order to match current behavior, native DOM event listeners must be added for all // events (including outputs). if (isProceduralRenderer(renderer)) { - const cleanupFn = renderer.listen(native, eventName, listenerFn); + // 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) + // - or element reference (in all other cases) + listenerFn = wrapListener(tNode, lView, listenerFn, false /** preventDefault */); + const cleanupFn = renderer.listen(resolved.name || target, eventName, listenerFn); lCleanup.push(listenerFn, cleanupFn); useCaptureOrSubIdx = lCleanupIndex + 1; } else { - const wrappedListener = wrapListenerWithPreventDefault(listenerFn); - native.addEventListener(eventName, wrappedListener, useCapture); - lCleanup.push(wrappedListener); + listenerFn = wrapListener(tNode, lView, listenerFn, true /** preventDefault */); + target.addEventListener(eventName, listenerFn, useCapture); + lCleanup.push(listenerFn); } - tCleanup && tCleanup.push(eventName, tNode.index, lCleanupIndex, useCaptureOrSubIdx); + + const idxOrTargetGetter = eventTargetResolver ? + (_lView: LView) => eventTargetResolver(readElementValue(_lView[tNode.index])).target : + tNode.index; + tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCaptureOrSubIdx); } // subscribe to directive outputs @@ -870,9 +1021,19 @@ export function listener( const propsLength = props.length; if (propsLength) { const lCleanup = getCleanup(lView); - for (let i = 0; i < propsLength; i += 2) { - ngDevMode && assertDataInRange(lView, props[i] as number); - const subscription = lView[props[i] as number][props[i + 1]].subscribe(listenerFn); + for (let i = 0; i < propsLength; i += 3) { + const index = props[i] as number; + ngDevMode && assertDataInRange(lView, index); + const minifiedName = props[i + 2]; + const directiveInstance = lView[index]; + const output = directiveInstance[minifiedName]; + + if (ngDevMode && !isObservable(output)) { + throw new Error( + `@Output ${minifiedName} not initialized in '${directiveInstance.constructor.name}'.`); + } + + const subscription = output.subscribe(listenerFn); const idx = lCleanup.length; lCleanup.push(listenerFn, subscription); tCleanup && tCleanup.push(eventName, tNode.index, idx, -(idx + 1)); @@ -923,14 +1084,19 @@ export function elementEnd(): void { previousOrParentTNode = previousOrParentTNode.parent !; setPreviousOrParentTNode(previousOrParentTNode); } + + // this is required for all host-level styling-related instructions to run + // in the correct order + previousOrParentTNode.onElementCreationFns && applyOnCreateInstructions(previousOrParentTNode); + ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Element); const lView = getLView(); const currentQueries = lView[QUERIES]; if (currentQueries) { - lView[QUERIES] = currentQueries.addNode(previousOrParentTNode as TElementNode); + lView[QUERIES] = currentQueries.parent; } - queueLifecycleHooks(getLView()[TVIEW], previousOrParentTNode); + registerPostOrderHooks(getLView()[TVIEW], previousOrParentTNode); decreaseElementDepthCount(); // this is fired at the end of elementEnd because ALL of the stylingBindings code @@ -941,6 +1107,12 @@ export function elementEnd(): void { setInputsForProperty( lView, previousOrParentTNode.inputs !['class'] !, getInitialClassNameValue(stylingContext)); } + if (hasStyleInput(previousOrParentTNode)) { + const stylingContext = getStylingContext(previousOrParentTNode.index, lView); + setInputsForProperty( + lView, previousOrParentTNode.inputs !['style'] !, + getInitialStyleStringValue(stylingContext)); + } } /** @@ -951,22 +1123,33 @@ export function elementEnd(): void { * @param value value The attribute is removed when value is `null` or `undefined`. * Otherwise the attribute value is set to the stringified value. * @param sanitizer An optional function used to sanitize the value. + * @param namespace Optional namespace to use when setting the attribute. */ export function elementAttribute( - index: number, name: string, value: any, sanitizer?: SanitizerFn | null): void { + index: number, name: string, value: any, sanitizer?: SanitizerFn | null, + namespace?: string): void { if (value !== NO_CHANGE) { + ngDevMode && validateAgainstEventAttributes(name); const lView = getLView(); const renderer = lView[RENDERER]; const element = getNativeByIndex(index, lView); if (value == null) { ngDevMode && ngDevMode.rendererRemoveAttribute++; - isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name) : + isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) : element.removeAttribute(name); } else { ngDevMode && ngDevMode.rendererSetAttribute++; - const strValue = sanitizer == null ? stringify(value) : sanitizer(value); - isProceduralRenderer(renderer) ? renderer.setAttribute(element, name, strValue) : - element.setAttribute(name, strValue); + const tNode = getTNode(index, lView); + const strValue = + sanitizer == null ? renderStringify(value) : sanitizer(value, tNode.tagName || '', name); + + + if (isProceduralRenderer(renderer)) { + renderer.setAttribute(element, name, strValue, namespace); + } else { + namespace ? element.setAttributeNS(namespace, name, strValue) : + element.setAttribute(name, strValue); + } } } } @@ -986,10 +1169,43 @@ export function elementAttribute( * @param nativeOnly Whether or not we should only set native properties and skip input check * (this is necessary for host property bindings) */ - export function elementProperty( index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null, nativeOnly?: boolean): void { + elementPropertyInternal(index, propName, value, sanitizer, nativeOnly); +} + +/** + * Updates a synthetic host binding (e.g. `[@foo]`) on a component. + * + * This instruction is for compatibility purposes and is designed to ensure that a + * synthetic host binding (e.g. `@HostBinding('@foo')`) properly gets rendered in + * the component's renderer. Normally all host bindings are evaluated with the parent + * component's renderer, but, in the case of animation @triggers, they need to be + * evaluated with the sub component's renderer (because that's where the animation + * triggers are defined). + * + * Do not use this instruction as a replacement for `elementProperty`. This instruction + * only exists to ensure compatibility with the ViewEngine's host binding behavior. + * + * @param index The index of the element to update in the data array + * @param propName Name of property. Because it is going to DOM, this is not subject to + * renaming as part of minification. + * @param value New value to write. + * @param sanitizer An optional function used to sanitize the value. + * @param nativeOnly Whether or not we should only set native properties and skip input check + * (this is necessary for host property bindings) + */ +export function componentHostSyntheticProperty( + index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null, + nativeOnly?: boolean) { + elementPropertyInternal(index, propName, value, sanitizer, nativeOnly, loadComponentRenderer); +} + +function elementPropertyInternal( + index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null, + nativeOnly?: boolean, + loadRendererFn?: ((tNode: TNode, lView: LView) => Renderer3) | null): void { if (value === NO_CHANGE) return; const lView = getLView(); const element = getNativeByIndex(index, lView) as RElement | RComment; @@ -1006,11 +1222,18 @@ export function elementProperty( } } } else if (tNode.type === TNodeType.Element) { - const renderer = lView[RENDERER]; + if (ngDevMode) { + validateAgainstEventProperties(propName); + validateAgainstUnknownProperties(lView, element, propName, tNode); + ngDevMode.rendererSetProperty++; + } + + savePropertyDebugData(tNode, lView, propName, lView[TVIEW].data, nativeOnly); + + const renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER]; // It is assumed that the sanitizer is only added when the compiler determines that the property // is risky, so sanitization can be done without further checks. - value = sanitizer != null ? (sanitizer(value) as any) : value; - ngDevMode && ngDevMode.rendererSetProperty++; + value = sanitizer != null ? (sanitizer(value, tNode.tagName || '', propName) as any) : value; if (isProceduralRenderer(renderer)) { renderer.setProperty(element as RElement, propName, value); } else if (!isAnimationProp(propName)) { @@ -1020,6 +1243,69 @@ export function elementProperty( } } +function validateAgainstUnknownProperties( + hostView: LView, element: RElement | RComment, propName: string, tNode: TNode) { + // If the tag matches any of the schemas we shouldn't throw. + if (matchingSchemas(hostView, tNode.tagName)) { + return; + } + + // If prop is not a known property of the HTML element... + if (!(propName in element) && + // and we are in a browser context... (web worker nodes should be skipped) + typeof Node === 'function' && element instanceof Node && + // and isn't a synthetic animation property... + propName[0] !== ANIMATION_PROP_PREFIX) { + // ... it is probably a user error and we should throw. + throw new Error( + `Template error: Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`); + } +} + +function matchingSchemas(hostView: LView, tagName: string | null): boolean { + const schemas = hostView[TVIEW].schemas; + + if (schemas !== null) { + for (let i = 0; i < schemas.length; i++) { + const schema = schemas[i]; + if (schema === NO_ERRORS_SCHEMA || + schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) { + return true; + } + } + } + + return false; +} + +/** + * Stores debugging data for this property binding on first template pass. + * This enables features like DebugElement.properties. + */ +function savePropertyDebugData( + tNode: TNode, lView: LView, propName: string, tData: TData, + nativeOnly: boolean | undefined): void { + const lastBindingIndex = lView[BINDING_INDEX] - 1; + + // Bind/interpolation functions save binding metadata in the last binding index, + // but leave the property name blank. If the interpolation delimiter is at the 0 + // index, we know that this is our first pass and the property name still needs to + // be set. + const bindingMetadata = tData[lastBindingIndex] as string; + if (bindingMetadata[0] == INTERPOLATION_DELIMITER) { + tData[lastBindingIndex] = propName + bindingMetadata; + + // We don't want to store indices for host bindings because they are stored in a + // different part of LView (the expando section). + if (!nativeOnly) { + if (tNode.propertyMetadataStartIndex == -1) { + tNode.propertyMetadataStartIndex = lastBindingIndex; + } + tNode.propertyMetadataEndIndex = lastBindingIndex + 1; + } + } +} + /** * Constructs a TNode object from the arguments. * @@ -1031,24 +1317,17 @@ export function elementProperty( * @returns the TNode object */ export function createTNode( - lView: LView, type: TNodeType, adjustedIndex: number, tagName: string | null, - attrs: TAttributes | null, tViews: TView[] | null): TNode { - const previousOrParentTNode = getPreviousOrParentTNode(); + tParent: TElementNode | TContainerNode | null, type: TNodeType, adjustedIndex: number, + tagName: string | null, attrs: TAttributes | null): TNode { ngDevMode && ngDevMode.tNode++; - const parent = - getIsParent() ? previousOrParentTNode : previousOrParentTNode && previousOrParentTNode.parent; - - // Parents cannot cross component boundaries because components will be used in multiple places, - // so it's only set if the view is the same. - const parentInSameView = parent && lView && parent !== lView[HOST_NODE]; - const tParent = parentInSameView ? parent as TElementNode | TContainerNode : null; - return { type: type, index: adjustedIndex, injectorIndex: tParent ? tParent.injectorIndex : -1, directiveStart: -1, directiveEnd: -1, + propertyMetadataStartIndex: -1, + propertyMetadataEndIndex: -1, flags: 0, providerIndexes: 0, tagName: tagName, @@ -1057,33 +1336,48 @@ export function createTNode( initialInputs: undefined, inputs: undefined, outputs: undefined, - tViews: tViews, + tViews: null, next: null, child: null, parent: tParent, - detached: null, stylingTemplate: null, - projection: null + projection: null, + onElementCreationFns: null, }; } /** - * Given a list of directive indices and minified input names, sets the - * input properties on the corresponding directives. + * Set the inputs of directives at the current node to corresponding value. + * + * @param lView the `LView` which contains the directives. + * @param inputAliases mapping between the public "input" name and privately-known, + * possibly minified, property names to write to. + * @param value Value to set. */ function setInputsForProperty(lView: LView, inputs: PropertyAliasValue, value: any): void { - for (let i = 0; i < inputs.length; i += 2) { - ngDevMode && assertDataInRange(lView, inputs[i] as number); - lView[inputs[i] as number][inputs[i + 1]] = value; + const tView = lView[TVIEW]; + for (let i = 0; i < inputs.length;) { + const index = inputs[i++] as number; + const publicName = inputs[i++] as string; + const privateName = inputs[i++] as string; + const instance = lView[index]; + ngDevMode && assertDataInRange(lView, index); + const def = tView.data[index] as DirectiveDef; + const setInput = def.setInput; + if (setInput) { + def.setInput !(instance, value, publicName, privateName); + } else { + instance[privateName] = value; + } } } function setNgReflectProperties( lView: LView, element: RElement | RComment, type: TNodeType, inputs: PropertyAliasValue, value: any) { - for (let i = 0; i < inputs.length; i += 2) { + for (let i = 0; i < inputs.length; i += 3) { const renderer = lView[RENDERER]; - const attrName = normalizeDebugBindingName(inputs[i + 1] as string); + const attrName = normalizeDebugBindingName(inputs[i + 2] as string); const debugValue = normalizeDebugBindingValue(value); if (type === TNodeType.Element) { isProceduralRenderer(renderer) ? @@ -1126,8 +1420,8 @@ function generatePropertyAliases(tNode: TNode, direction: BindingDirection): Pro propStore = propStore || {}; const internalName = propertyAliasMap[publicName]; const hasProperty = propStore.hasOwnProperty(publicName); - hasProperty ? propStore[publicName].push(i, internalName) : - (propStore[publicName] = [i, internalName]); + hasProperty ? propStore[publicName].push(i, publicName, internalName) : + (propStore[publicName] = [i, publicName, internalName]); } } } @@ -1163,25 +1457,71 @@ export function elementStyling( if (!tNode.stylingTemplate) { tNode.stylingTemplate = createEmptyStylingContext(); } + + if (directive) { + // this will ALWAYS happen first before the bindings are applied so that the ordering + // of directives is correct (otherwise if a follow-up directive contains static styling, + // which is applied through elementHostAttrs, then it may end up being listed in the + // context directive array before a former one (because the former one didn't contain + // any static styling values)) + allocateDirectiveIntoContext(tNode.stylingTemplate, directive); + + const fns = tNode.onElementCreationFns = tNode.onElementCreationFns || []; + fns.push( + () => initElementStyling( + tNode, classBindingNames, styleBindingNames, styleSanitizer, directive)); + } else { + // this will make sure that the root directive (the template) will always be + // run FIRST before all the other styling properties are populated into the + // context... + initElementStyling(tNode, classBindingNames, styleBindingNames, styleSanitizer, directive); + } +} + +function initElementStyling( + tNode: TNode, classBindingNames?: string[] | null, styleBindingNames?: string[] | null, + styleSanitizer?: StyleSanitizeFn | null, directive?: {}): void { updateContextWithBindings( tNode.stylingTemplate !, directive || null, classBindingNames, styleBindingNames, - styleSanitizer, hasClassInput(tNode)); + styleSanitizer); } /** - * Assign static styling values to a host element. + * Assign static attribute values to a host element. + * + * This instruction will assign static attribute values as well as class and style + * values to an element within the host bindings function. Since attribute values + * can consist of different types of values, the `attrs` array must include the values in + * the following format: + * + * attrs = [ + * // static attributes (like `title`, `name`, `id`...) + * attr1, value1, attr2, value, + * + * // a single namespace value (like `x:id`) + * NAMESPACE_MARKER, namespaceUri1, name1, value1, + * + * // another single namespace value (like `x:name`) + * NAMESPACE_MARKER, namespaceUri2, name2, value2, + * + * // a series of CSS classes that will be applied to the element (no spaces) + * CLASSES_MARKER, class1, class2, class3, + * + * // a series of CSS styles (property + value) that will be applied to the element + * STYLES_MARKER, prop1, value1, prop2, value2 + * ] + * + * All non-class and non-style attributes must be defined at the start of the list + * first before all class and style values are set. When there is a change in value + * type (like when classes and styles are introduced) a marker must be used to separate + * the entries. The marker values themselves are set via entries found in the + * [AttributeMarker] enum. * * NOTE: This instruction is meant to used from `hostBindings` function only. * * @param directive A directive instance the styling is associated with. - * @param attrs An array containing class and styling information. The values must be marked with - * `AttributeMarker`. - * - * ``` - * var attrs = [AttributeMarker.Classes, 'foo', 'bar', - * AttributeMarker.Styles, 'width', '100px', 'height, '200px'] - * elementHostAttrs(directive, attrs); - * ``` + * @param attrs An array of static values (attributes, classes and styles) with the correct marker + * values. * * @publicApi */ @@ -1190,7 +1530,10 @@ export function elementHostAttrs(directive: any, attrs: TAttributes) { if (!tNode.stylingTemplate) { tNode.stylingTemplate = initializeStaticStylingContext(attrs); } - patchContextWithStaticAttrs(tNode.stylingTemplate, attrs, directive); + const lView = getLView(); + const native = getNativeByTNode(tNode, lView) as RElement; + const i = setUpAttributes(native, attrs); + patchContextWithStaticAttrs(tNode.stylingTemplate, attrs, i, directive); } /** @@ -1247,13 +1590,13 @@ components */ export function elementStyleProp( index: number, styleIndex: number, value: string | number | String | PlayerFactory | null, - suffix?: string | null, directive?: {}): void { + suffix?: string | null, directive?: {}, forceOverride?: boolean): void { let valueToAdd: string|null = null; if (value !== null) { if (suffix) { // when a suffix is applied then it will bypass // sanitization entirely (b/c a new string is created) - valueToAdd = stringify(value) + suffix; + valueToAdd = renderStringify(value) + suffix; } else { // sanitization happens by dealing with a String value // this means that the string value will be passed through @@ -1263,7 +1606,8 @@ export function elementStyleProp( } } updateElementStyleProp( - getStylingContext(index + HEADER_OFFSET, getLView()), styleIndex, valueToAdd, directive); + getStylingContext(index + HEADER_OFFSET, getLView()), styleIndex, valueToAdd, directive, + forceOverride); } /** @@ -1281,26 +1625,36 @@ export function elementStyleProp( * @param value A true/false value which will turn the class on or off. * @param directive Directive instance that is attempting to change styling. (Defaults to the * component of the current view). -components + * @param forceOverride Whether or not this value will be applied regardless of where it is being + * set within the directive priority structure. * * @publicApi */ export function elementClassProp( - index: number, classIndex: number, value: boolean | PlayerFactory, directive?: {}): void { - const onOrOffClassValue = - (value instanceof BoundPlayerFactory) ? (value as BoundPlayerFactory) : (!!value); + index: number, classIndex: number, value: boolean | PlayerFactory, directive?: {}, + forceOverride?: boolean): void { + const input = (value instanceof BoundPlayerFactory) ? + (value as BoundPlayerFactory) : + booleanOrNull(value); updateElementClassProp( - getStylingContext(index + HEADER_OFFSET, getLView()), classIndex, onOrOffClassValue, - directive); + getStylingContext(index + HEADER_OFFSET, getLView()), classIndex, input, directive, + forceOverride); +} + +function booleanOrNull(value: any): boolean|null { + if (typeof value === 'boolean') return value; + return value ? true : null; } /** * Update style and/or class bindings using object literal. * * This instruction is meant apply styling via the `[style]="exp"` and `[class]="exp"` template - * bindings. When styles are applied to the Element they will then be placed with respect to + * bindings. When styles are applied to the element they will then be placed with respect to * any styles set with `elementStyleProp`. If any styles are set to `null` then they will be - * removed from the element. + * removed from the element. This instruction is also called for host bindings that write to + * `[style]` and `[class]` (the directive param helps the instruction code determine where the + * binding values come from). * * (Note that the styling instruction will not be applied until `elementStylingApply` is called.) * @@ -1319,29 +1673,33 @@ export function elementClassProp( export function elementStylingMap( index: number, classes: {[key: string]: any} | string | NO_CHANGE | null, styles?: {[styleName: string]: any} | NO_CHANGE | null, directive?: {}): void { - if (directive != undefined) - return hackImplementationOfElementStylingMap( - index, classes, styles, directive); // supported in next PR const lView = getLView(); const tNode = getTNode(index, lView); const stylingContext = getStylingContext(index + HEADER_OFFSET, lView); - if (hasClassInput(tNode) && classes !== NO_CHANGE) { - const initialClasses = getInitialClassNameValue(stylingContext); - const classInputVal = - (initialClasses.length ? (initialClasses + ' ') : '') + (classes as string); - setInputsForProperty(lView, tNode.inputs !['class'] !, classInputVal); - } else { - updateStylingMap(stylingContext, classes, styles); - } -} -/* START OF HACK BLOCK */ -function hackImplementationOfElementStylingMap( - index: number, classes: {[key: string]: any} | string | NO_CHANGE | null, - styles?: {[styleName: string]: any} | NO_CHANGE | null, directive?: {}): void { - throw new Error('unimplemented. Should not be needed by ViewEngine compatibility'); + // inputs are only evaluated from a template binding into a directive, therefore, + // there should not be a situation where a directive host bindings function + // evaluates the inputs (this should only happen in the template function) + if (!directive) { + if (hasClassInput(tNode) && classes !== NO_CHANGE) { + const initialClasses = getInitialClassNameValue(stylingContext); + const classInputVal = + (initialClasses.length ? (initialClasses + ' ') : '') + forceClassesAsString(classes); + setInputsForProperty(lView, tNode.inputs !['class'] !, classInputVal); + classes = NO_CHANGE; + } + + if (hasStyleInput(tNode) && styles !== NO_CHANGE) { + const initialStyles = getInitialClassNameValue(stylingContext); + const styleInputVal = + (initialStyles.length ? (initialStyles + ' ') : '') + forceStylesAsString(styles); + setInputsForProperty(lView, tNode.inputs !['style'] !, styleInputVal); + styles = NO_CHANGE; + } + } + + updateStylingMap(stylingContext, classes, styles, directive); } -/* END OF HACK BLOCK */ ////////////////////////// //// Text @@ -1382,8 +1740,8 @@ export function textBinding(index: number, value: T | NO_CHANGE): void { ngDevMode && assertDefined(element, 'native element should exist'); ngDevMode && ngDevMode.rendererSetText++; const renderer = lView[RENDERER]; - isProceduralRenderer(renderer) ? renderer.setValue(element, stringify(value)) : - element.textContent = stringify(value); + isProceduralRenderer(renderer) ? renderer.setValue(element, renderStringify(value)) : + element.textContent = renderStringify(value); } } @@ -1404,7 +1762,7 @@ export function instantiateRootComponent( } const directive = getNodeInjectable(tView.data, viewData, viewData.length - 1, rootTNode as TElementNode); - postProcessBaseDirective(viewData, rootTNode, directive, def as DirectiveDef); + postProcessBaseDirective(viewData, rootTNode, directive); return directive; } @@ -1415,7 +1773,7 @@ function resolveDirectives( tView: TView, viewData: LView, directives: DirectiveDef[] | null, tNode: TNode, localRefs: string[] | null): void { // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in tsickle. - ngDevMode && assertEqual(getFirstTemplatePass(), true, 'should run on first template pass only'); + ngDevMode && assertEqual(tView.firstTemplatePass, true, 'should run on first template pass only'); const exportsMap: ({[key: string]: number} | null) = localRefs ? {'': -1} : null; if (directives) { initNodeFlags(tNode, tView.data.length, directives.length); @@ -1440,7 +1798,7 @@ function resolveDirectives( // Init hooks are queued now so ngOnInit is called in host components before // any projected components. - queueInitHooks(directiveDefIdx, def.onInit, def.doCheck, tView); + registerPreOrderHooks(directiveDefIdx, def, tView); } } if (exportsMap) cacheMatchingLocalNames(tNode, localRefs, exportsMap); @@ -1452,7 +1810,7 @@ function resolveDirectives( function instantiateAllDirectives(tView: TView, lView: LView, tNode: TNode) { const start = tNode.directiveStart; const end = tNode.directiveEnd; - if (!getFirstTemplatePass() && start < end) { + if (!tView.firstTemplatePass && start < end) { getOrCreateNodeInjectorForNode( tNode as TElementNode | TContainerNode | TElementContainerNode, lView); } @@ -1470,28 +1828,34 @@ function invokeDirectivesHostBindings(tView: TView, viewData: LView, tNode: TNod const start = tNode.directiveStart; const end = tNode.directiveEnd; const expando = tView.expandoInstructions !; - const firstTemplatePass = getFirstTemplatePass(); + const firstTemplatePass = tView.firstTemplatePass; for (let i = start; i < end; i++) { const def = tView.data[i] as DirectiveDef; const directive = viewData[i]; if (def.hostBindings) { - const previousExpandoLength = expando.length; - setCurrentDirectiveDef(def); - def.hostBindings !(RenderFlags.Create, directive, tNode.index - HEADER_OFFSET); - setCurrentDirectiveDef(null); - // `hostBindings` function may or may not contain `allocHostVars` call - // (e.g. it may not if it only contains host listeners), so we need to check whether - // `expandoInstructions` has changed and if not - we still push `hostBindings` to - // expando block, to make sure we execute it for DI cycle - if (previousExpandoLength === expando.length && firstTemplatePass) { - expando.push(def.hostBindings); - } + invokeHostBindingsInCreationMode(def, expando, directive, tNode, firstTemplatePass); } else if (firstTemplatePass) { expando.push(null); } } } +export function invokeHostBindingsInCreationMode( + def: DirectiveDef, expando: ExpandoInstructions, directive: any, tNode: TNode, + firstTemplatePass: boolean) { + const previousExpandoLength = expando.length; + setCurrentDirectiveDef(def); + def.hostBindings !(RenderFlags.Create, directive, tNode.index - HEADER_OFFSET); + setCurrentDirectiveDef(null); + // `hostBindings` function may or may not contain `allocHostVars` call + // (e.g. it may not if it only contains host listeners), so we need to check whether + // `expandoInstructions` has changed and if not - we still push `hostBindings` to + // expando block, to make sure we execute it for DI cycle + if (previousExpandoLength === expando.length && firstTemplatePass) { + expando.push(def.hostBindings); + } +} + /** * Generates a new block in TView.expandoInstructions for this node. * @@ -1518,7 +1882,7 @@ export function generateExpandoInstructionBlock( */ function prefillHostVars(tView: TView, lView: LView, totalHostVars: number): void { ngDevMode && - assertEqual(getFirstTemplatePass(), true, 'Should only be called in first template pass.'); + assertEqual(tView.firstTemplatePass, true, 'Should only be called in first template pass.'); for (let i = 0; i < totalHostVars; i++) { lView.push(NO_CHANGE); tView.blueprint.push(NO_CHANGE); @@ -1532,14 +1896,14 @@ function prefillHostVars(tView: TView, lView: LView, totalHostVars: number): voi function postProcessDirective( viewData: LView, directive: T, def: DirectiveDef, directiveDefIdx: number): void { const previousOrParentTNode = getPreviousOrParentTNode(); - postProcessBaseDirective(viewData, previousOrParentTNode, directive, def); + postProcessBaseDirective(viewData, previousOrParentTNode, directive); ngDevMode && assertDefined(previousOrParentTNode, 'previousOrParentTNode'); if (previousOrParentTNode && previousOrParentTNode.attrs) { - setInputsFromAttrs(directiveDefIdx, directive, def.inputs, previousOrParentTNode); + setInputsFromAttrs(directiveDefIdx, directive, def, previousOrParentTNode); } - if (def.contentQueries) { - def.contentQueries(directiveDefIdx); + if (viewData[TVIEW].firstTemplatePass && def.contentQueries) { + previousOrParentTNode.flags |= TNodeFlags.hasContentQuery; } if (isComponentDef(def)) { @@ -1552,7 +1916,7 @@ function postProcessDirective( * A lighter version of postProcessDirective() that is used for the root component. */ function postProcessBaseDirective( - lView: LView, previousOrParentTNode: TNode, directive: T, def: DirectiveDef): void { + lView: LView, previousOrParentTNode: TNode, directive: T): void { const native = getNativeByTNode(previousOrParentTNode, lView); ngDevMode && assertEqual( @@ -1564,11 +1928,6 @@ function postProcessBaseDirective( if (native) { attachPatchData(native, lView); } - - // TODO(misko): setUpAttributes should be a feature for better treeshakability. - if (def.attributes != null && previousOrParentTNode.type == TNodeType.Element) { - setUpAttributes(native as RElement, def.attributes as string[]); - } } @@ -1579,7 +1938,7 @@ function postProcessBaseDirective( */ function findDirectiveMatches(tView: TView, viewData: LView, tNode: TNode): DirectiveDef[]| null { - ngDevMode && assertEqual(getFirstTemplatePass(), true, 'should run on first template pass only'); + ngDevMode && assertEqual(tView.firstTemplatePass, true, 'should run on first template pass only'); const registry = tView.directiveRegistry; let matches: any[]|null = null; if (registry) { @@ -1610,9 +1969,9 @@ function findDirectiveMatches(tView: TView, viewData: LView, tNode: TNode): Dire /** Stores index of component's host element so it will be queued for view refresh during CD. */ export function queueComponentIndexForCheck(previousOrParentTNode: TNode): void { - ngDevMode && - assertEqual(getFirstTemplatePass(), true, 'Should only be called in first template pass.'); const tView = getLView()[TVIEW]; + ngDevMode && + assertEqual(tView.firstTemplatePass, true, 'Should only be called in first template pass.'); (tView.components || (tView.components = [])).push(previousOrParentTNode.index); } @@ -1623,7 +1982,7 @@ export function queueComponentIndexForCheck(previousOrParentTNode: TNode): void function queueHostBindingForCheck( tView: TView, def: DirectiveDef| ComponentDef, hostVars: number): void { ngDevMode && - assertEqual(getFirstTemplatePass(), true, 'Should only be called in first template pass.'); + assertEqual(tView.firstTemplatePass, true, 'Should only be called in first template pass.'); const expando = tView.expandoInstructions !; const length = expando.length; // Check whether a given `hostBindings` function already exists in expandoInstructions, @@ -1663,7 +2022,11 @@ function saveNameToExportMap( index: number, def: DirectiveDef| ComponentDef, exportsMap: {[key: string]: number} | null) { if (exportsMap) { - if (def.exportAs) exportsMap[def.exportAs] = index; + if (def.exportAs) { + for (let i = 0; i < def.exportAs.length; i++) { + exportsMap[def.exportAs[i]] = index; + } + } if ((def as ComponentDef).template) exportsMap[''] = index; } } @@ -1674,7 +2037,6 @@ function saveNameToExportMap( * @param index the initial index */ export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: number) { - ngDevMode && assertEqual(getFirstTemplatePass(), true, 'expected firstTemplatePass to be true'); const flags = tNode.flags; ngDevMode && assertEqual( flags === 0 || flags === TNodeFlags.isComponent, true, @@ -1694,7 +2056,8 @@ function baseResolveDirective( tView: TView, viewData: LView, def: DirectiveDef, directiveFactory: (t: Type| null) => any) { tView.data.push(def); - const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null); + const nodeInjectorFactory = + new NodeInjectorFactory(directiveFactory, isComponentDef(def), false, null); tView.blueprint.push(nodeInjectorFactory); viewData.push(nodeInjectorFactory); } @@ -1704,7 +2067,8 @@ function addComponentLogic( const native = getNativeByTNode(previousOrParentTNode, lView); const tView = getOrCreateTView( - def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery); + def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, + def.schemas); // Only component views should be added to the view tree directly. Embedded views are // accessed through their containers because they may be removed / re-added later. @@ -1713,16 +2077,16 @@ function addComponentLogic( lView, previousOrParentTNode.index as number, createLView( lView, tView, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, + lView[previousOrParentTNode.index], previousOrParentTNode as TElementNode, rendererFactory, lView[RENDERER_FACTORY].createRenderer(native as RElement, def))); - componentView[HOST_NODE] = previousOrParentTNode as TElementNode; + componentView[T_HOST] = previousOrParentTNode as TElementNode; // Component view will always be created before any injected LContainers, // so this is a regular element, wrap it with the component view - componentView[HOST] = lView[previousOrParentTNode.index]; lView[previousOrParentTNode.index] = componentView; - if (getFirstTemplatePass()) { + if (lView[TVIEW].firstTemplatePass) { queueComponentIndexForCheck(previousOrParentTNode); } } @@ -1736,16 +2100,24 @@ function addComponentLogic( * @param tNode The static data for this node */ function setInputsFromAttrs( - directiveIndex: number, instance: T, inputs: {[P in keyof T]: string;}, tNode: TNode): void { + directiveIndex: number, instance: T, def: DirectiveDef, tNode: TNode): void { let initialInputData = tNode.initialInputs as InitialInputData | undefined; if (initialInputData === undefined || directiveIndex >= initialInputData.length) { - initialInputData = generateInitialInputs(directiveIndex, inputs, tNode); + initialInputData = generateInitialInputs(directiveIndex, def.inputs, tNode); } const initialInputs: InitialInputs|null = initialInputData[directiveIndex]; if (initialInputs) { - for (let i = 0; i < initialInputs.length; i += 2) { - (instance as any)[initialInputs[i]] = initialInputs[i + 1]; + const setInput = def.setInput; + for (let i = 0; i < initialInputs.length;) { + const publicName = initialInputs[i++]; + const privateName = initialInputs[i++]; + const value = initialInputs[i++]; + if (setInput) { + def.setInput !(instance, value, publicName, privateName); + } else { + (instance as any)[privateName] = value; + } } } } @@ -1774,7 +2146,10 @@ function generateInitialInputs( let i = 0; while (i < attrs.length) { const attrName = attrs[i]; - if (attrName === AttributeMarker.SelectOnly) break; + // If we hit Select-Only, Classes or Styles, we're done anyway. None of those are valid inputs. + if (attrName === AttributeMarker.SelectOnly || attrName === AttributeMarker.Classes || + attrName === AttributeMarker.Styles) + break; if (attrName === AttributeMarker.NamespaceURI) { // We do not allow inputs on namespaced attributes. i += 4; @@ -1786,7 +2161,7 @@ function generateInitialInputs( if (minifiedInputName !== undefined) { const inputsToStore: InitialInputs = initialInputData[directiveIndex] || (initialInputData[directiveIndex] = []); - inputsToStore.push(minifiedInputName, attrValue as string); + inputsToStore.push(attrName, minifiedInputName, attrValue as string); } i += 2; @@ -1809,18 +2184,16 @@ function generateInitialInputs( * @returns LContainer */ export function createLContainer( - hostNative: RElement | RComment, - hostTNode: TElementNode | TContainerNode | TElementContainerNode, currentView: LView, - native: RComment, isForViewContainerRef?: boolean): LContainer { + hostNative: RElement | RComment, currentView: LView, native: RComment, + isForViewContainerRef?: boolean): LContainer { return [ - isForViewContainerRef ? -1 : 0, // active index - [], // views - currentView, // parent - null, // next - null, // queries - hostNative, // host native - native, // native - getRenderParent(hostTNode, currentView) // renderParent + isForViewContainerRef ? -1 : 0, // active index + [], // views + currentView, // parent + null, // next + null, // queries + hostNative, // host native + native, // native ]; } @@ -1847,23 +2220,18 @@ export function template( localRefExtractor?: LocalRefExtractor) { const lView = getLView(); const tView = lView[TVIEW]; - // TODO: consider a separate node type for templates - const tNode = containerInternal(index, tagName || null, attrs || null); - if (getFirstTemplatePass()) { - tNode.tViews = createTView( - -1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null); + // TODO: consider a separate node type for templates + const tContainerNode = containerInternal(index, tagName || null, attrs || null); + if (tView.firstTemplatePass) { + tContainerNode.tViews = createTView( + -1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null, null); } createDirectivesAndLocals(tView, lView, localRefs, localRefExtractor); - const currentQueries = lView[QUERIES]; - const previousOrParentTNode = getPreviousOrParentTNode(); - const native = getNativeByTNode(previousOrParentTNode, lView); - attachPatchData(native, lView); - if (currentQueries) { - lView[QUERIES] = currentQueries.addNode(previousOrParentTNode as TContainerNode); - } - queueLifecycleHooks(tView, tNode); + addTContainerToQueries(lView, tContainerNode); + attachPatchData(getNativeByTNode(tContainerNode, lView), lView); + registerPostOrderHooks(tView, tContainerNode); setIsParent(false); } @@ -1878,12 +2246,16 @@ export function template( */ export function container(index: number): void { const tNode = containerInternal(index, null, null); - getFirstTemplatePass() && (tNode.tViews = []); + const lView = getLView(); + if (lView[TVIEW].firstTemplatePass) { + tNode.tViews = []; + } + addTContainerToQueries(lView, tNode); setIsParent(false); } function containerInternal( - index: number, tagName: string | null, attrs: TAttributes | null): TNode { + index: number, tagName: string | null, attrs: TAttributes | null): TContainerNode { const lView = getLView(); ngDevMode && assertEqual( lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, @@ -1893,8 +2265,7 @@ function containerInternal( const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : ''); ngDevMode && ngDevMode.rendererCreateComment++; const tNode = createNodeAtIndex(index, TNodeType.Container, comment, tagName, attrs); - const lContainer = lView[adjustedIndex] = - createLContainer(lView[adjustedIndex], tNode, lView, comment); + const lContainer = lView[adjustedIndex] = createLContainer(lView[adjustedIndex], lView, comment); appendChild(comment, tNode, lView); @@ -1902,16 +2273,28 @@ function containerInternal( // because views can be removed and re-inserted. addToViewTree(lView, index + HEADER_OFFSET, lContainer); - const currentQueries = lView[QUERIES]; - if (currentQueries) { - // prepare place for matching nodes from views inserted into a given container - lContainer[QUERIES] = currentQueries.container(); - } - ngDevMode && assertNodeType(getPreviousOrParentTNode(), TNodeType.Container); return tNode; } +/** + * Reporting a TContainer node queries is a 2-step process as we need to: + * - check if the container node itself is matching (query might match a node); + * - prepare room for nodes from views that might be created based on the TemplateRef linked to this + * container. + * + * Those 2 operations need to happen in the specific order (match the container node itself, then + * prepare space for nodes from views). + */ +function addTContainerToQueries(lView: LView, tContainerNode: TContainerNode): void { + const queries = lView[QUERIES]; + if (queries) { + queries.addNode(tContainerNode); + const lContainer = lView[tContainerNode.index]; + lContainer[QUERIES] = queries.container(); + } +} + /** * Sets a container up to receive views. * @@ -1956,7 +2339,7 @@ export function containerRefreshEnd(): void { // remove extra views at the end of the container while (nextIndex < lContainer[VIEWS].length) { - removeView(lContainer, previousOrParentTNode as TContainerNode, nextIndex); + removeView(lContainer, nextIndex); } } @@ -1987,14 +2370,11 @@ function refreshDynamicEmbeddedViews(lView: LView) { * Removes views that need to be deleted in the process. * * @param lContainer to search for views - * @param tContainerNode to search for views * @param startIdx starting index in the views array to search from * @param viewBlockId exact view block id to look for * @returns index of a found view or -1 if not found */ -function scanForView( - lContainer: LContainer, tContainerNode: TContainerNode, startIdx: number, - viewBlockId: number): LView|null { +function scanForView(lContainer: LContainer, startIdx: number, viewBlockId: number): LView|null { const views = lContainer[VIEWS]; for (let i = startIdx; i < views.length; i++) { const viewAtPositionId = views[i][TVIEW].id; @@ -2002,7 +2382,7 @@ function scanForView( return views[i]; } else if (viewAtPositionId < viewBlockId) { // found a view that should not be at this position - remove - removeView(lContainer, tContainerNode, i); + removeView(lContainer, i); } else { // found a view with id greater than the one we are searching for // which means that required view doesn't exist and can't be found at @@ -2029,8 +2409,7 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num const lContainer = lView[containerTNode.index] as LContainer; ngDevMode && assertNodeType(containerTNode, TNodeType.Container); - let viewToRender = scanForView( - lContainer, containerTNode as TContainerNode, lContainer[ACTIVE_INDEX] !, viewBlockId); + let viewToRender = scanForView(lContainer, lContainer[ACTIVE_INDEX] !, viewBlockId); if (viewToRender) { setIsParent(true); @@ -2040,13 +2419,15 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num viewToRender = createLView( lView, getOrCreateEmbeddedTView(viewBlockId, consts, vars, containerTNode as TContainerNode), null, - LViewFlags.CheckAlways); + LViewFlags.CheckAlways, null, null); if (lContainer[QUERIES]) { viewToRender[QUERIES] = lContainer[QUERIES] !.createView(); } - createViewNode(viewBlockId, viewToRender); + const tParentNode = getIsParent() ? previousOrParentTNode : + previousOrParentTNode && previousOrParentTNode.parent; + assignTViewNodeToLView(viewToRender[TVIEW], tParentNode, viewBlockId, viewToRender); enterView(viewToRender, viewToRender[TVIEW].node); } if (lContainer) { @@ -2082,7 +2463,7 @@ function getOrCreateEmbeddedTView( ngDevMode && assertEqual(Array.isArray(containerTViews), true, 'TViews should be in an array'); if (viewIndex >= containerTViews.length || containerTViews[viewIndex] == null) { containerTViews[viewIndex] = createTView( - viewIndex, null, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null); + viewIndex, null, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null, null); } return containerTViews[viewIndex]; } @@ -2090,7 +2471,7 @@ function getOrCreateEmbeddedTView( /** Marks the end of an embedded view. */ export function embeddedViewEnd(): void { const lView = getLView(); - const viewHost = lView[HOST_NODE]; + const viewHost = lView[T_HOST]; if (isCreationMode(lView)) { refreshDescendantViews(lView); // creation mode pass @@ -2182,7 +2563,7 @@ export function viewAttached(view: LView): boolean { * @param rawSelectors A collection of CSS selectors in the raw, un-parsed form */ export function projectionDef(selectors?: CssSelectorList[], textSelectors?: string[]): void { - const componentNode = findComponentView(getLView())[HOST_NODE] as TElementNode; + const componentNode = findComponentView(getLView())[T_HOST] as TElementNode; if (!componentNode.projection) { const noOfNodeBuckets = selectors ? selectors.length + 1 : 1; @@ -2201,8 +2582,8 @@ export function projectionDef(selectors?: CssSelectorList[], textSelectors?: str tails[bucketIndex] !.next = componentChild; } else { pData[bucketIndex] = componentChild; - componentChild.next = null; } + componentChild.next = null; tails[bucketIndex] = componentChild; componentChild = nextNode; @@ -2241,41 +2622,49 @@ export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: // re-distribution of projectable nodes is stored on a component's view level const componentView = findComponentView(lView); - const componentNode = componentView[HOST_NODE] as TElementNode; + const componentNode = componentView[T_HOST] as TElementNode; let nodeToProject = (componentNode.projection as(TNode | null)[])[selectorIndex]; let projectedView = componentView[PARENT] !; let projectionNodeIndex = -1; - while (nodeToProject) { - if (nodeToProject.type === TNodeType.Projection) { - // This node is re-projected, so we must go up the tree to get its projected nodes. - const currentComponentView = findComponentView(projectedView); - const currentComponentHost = currentComponentView[HOST_NODE] as TElementNode; - const firstProjectedNode = - (currentComponentHost.projection as(TNode | null)[])[nodeToProject.projection as number]; + if (Array.isArray(nodeToProject)) { + appendChild(nodeToProject, tProjectionNode, lView); + } else { + while (nodeToProject) { + if (nodeToProject.type === TNodeType.Projection) { + // This node is re-projected, so we must go up the tree to get its projected nodes. + const currentComponentView = findComponentView(projectedView); + const currentComponentHost = currentComponentView[T_HOST] as TElementNode; + const firstProjectedNode = (currentComponentHost.projection as( + TNode | null)[])[nodeToProject.projection as number]; - if (firstProjectedNode) { - projectionNodeStack[++projectionNodeIndex] = nodeToProject; - projectionNodeStack[++projectionNodeIndex] = projectedView; + if (firstProjectedNode) { + if (Array.isArray(firstProjectedNode)) { + appendChild(firstProjectedNode, tProjectionNode, lView); + } else { + projectionNodeStack[++projectionNodeIndex] = nodeToProject; + projectionNodeStack[++projectionNodeIndex] = projectedView; - nodeToProject = firstProjectedNode; - projectedView = currentComponentView[PARENT] !; - continue; + nodeToProject = firstProjectedNode; + projectedView = currentComponentView[PARENT] !; + continue; + } + } + } else { + // This flag must be set now or we won't know that this node is projected + // if the nodes are inserted into a container later. + nodeToProject.flags |= TNodeFlags.isProjected; + appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView); } - } else { - // This flag must be set now or we won't know that this node is projected - // if the nodes are inserted into a container later. - nodeToProject.flags |= TNodeFlags.isProjected; - appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView); - } - // If we are finished with a list of re-projected nodes, we need to get - // back to the root projection node that was re-projected. - if (nodeToProject.next === null && projectedView !== componentView[PARENT] !) { - projectedView = projectionNodeStack[projectionNodeIndex--] as LView; - nodeToProject = projectionNodeStack[projectionNodeIndex--] as TNode; + // If we are finished with a list of re-projected nodes, we need to get + // back to the root projection node that was re-projected. + if (nodeToProject.next === null && projectedView !== componentView[PARENT] !) { + projectedView = projectionNodeStack[projectionNodeIndex--] as LView; + nodeToProject = projectionNodeStack[projectionNodeIndex--] as TNode; + } + nodeToProject = nodeToProject.next; } - nodeToProject = nodeToProject.next; } } @@ -2293,10 +2682,9 @@ export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: export function addToViewTree( lView: LView, adjustedHostIndex: number, state: T): T { const tView = lView[TVIEW]; - const firstTemplatePass = getFirstTemplatePass(); if (lView[TAIL]) { lView[TAIL] ![NEXT] = state; - } else if (firstTemplatePass) { + } else if (tView.firstTemplatePass) { tView.childIndex = adjustedHostIndex; } lView[TAIL] = state; @@ -2315,28 +2703,67 @@ function markDirtyIfOnPush(lView: LView, viewIndex: number): void { } } -/** Wraps an event listener with preventDefault behavior. */ -function wrapListenerWithPreventDefault(listenerFn: (e?: any) => any): EventListener { - return function wrapListenerIn_preventDefault(e: Event) { - if (listenerFn(e) === false) { - e.preventDefault(); - // Necessary for legacy browsers that don't support preventDefault (e.g. IE) - e.returnValue = false; +/** + * Wraps an event listener with a function that marks ancestors dirty and prevents default behavior, + * if applicable. + * + * @param tNode The TNode associated with this listener + * @param lView The LView that contains this listener + * @param listenerFn The listener function to call + * @param wrapWithPreventDefault Whether or not to prevent default behavior + * (the procedural renderer does this already, so in those cases, we should skip) + */ +function wrapListener( + tNode: TNode, lView: LView, listenerFn: (e?: any) => any, + wrapWithPreventDefault: boolean): EventListener { + // Note: we are performing most of the work in the listener function itself + // to optimize listener registration. + return function wrapListenerIn_markDirtyAndPreventDefault(e: Event) { + // In order to be backwards compatible with View Engine, events on component host nodes + // must also mark the component view itself dirty (i.e. the view that it owns). + const startView = + tNode.flags & TNodeFlags.isComponent ? getComponentViewByIndex(tNode.index, lView) : lView; + + // See interfaces/view.ts for more on LViewFlags.ManualOnPush + if ((lView[FLAGS] & LViewFlags.ManualOnPush) === 0) { + markViewDirty(startView); + } + + try { + const result = listenerFn(e); + if (wrapWithPreventDefault && result === false) { + e.preventDefault(); + // Necessary for legacy browsers that don't support preventDefault (e.g. IE) + e.returnValue = false; + } + return result; + } catch (error) { + handleError(lView, error); } }; } - -/** Marks current view and all ancestors dirty */ -export function markViewDirty(lView: LView): void { - while (lView && !(lView[FLAGS] & LViewFlags.IsRoot)) { +/** + * Marks current view and all ancestors dirty. + * + * Returns the root view because it is found as a byproduct of marking the view tree + * dirty, and can be used by methods that consume markViewDirty() to easily schedule + * change detection. Otherwise, such methods would need to traverse up the view tree + * an additional time to get the root view and schedule a tick on it. + * + * @param lView The starting LView to mark dirty + * @returns the root LView + */ +export function markViewDirty(lView: LView): LView|null { + while (lView) { lView[FLAGS] |= LViewFlags.Dirty; + // Stop traversing up as soon as you find a root view that wasn't attached to any container + if (isRootView(lView) && lView[CONTAINER_INDEX] === -1) { + return lView; + } + // continue otherwise lView = lView[PARENT] !; } - lView[FLAGS] |= LViewFlags.Dirty; - ngDevMode && assertDefined(lView[CONTEXT], 'rootContext should be defined'); - - const rootContext = lView[CONTEXT] as RootContext; - scheduleTick(rootContext, RootContextFlags.DetectChanges); + return null; } /** @@ -2416,7 +2843,7 @@ function tickRootContext(rootContext: RootContext) { * @param component The component which the change detection should be performed on. */ export function detectChanges(component: T): void { - const view = getComponentViewByInstance(component) !; + const view = getComponentViewByInstance(component); detectChangesInternal(view, component); } @@ -2425,12 +2852,17 @@ export function detectChangesInternal(view: LView, context: T) { if (rendererFactory.begin) rendererFactory.begin(); - if (isCreationMode(view)) { - checkView(view, context); // creation mode pass + try { + if (isCreationMode(view)) { + checkView(view, context); // creation mode pass + } + checkView(view, context); // update mode pass + } catch (error) { + handleError(view, error); + throw error; + } finally { + if (rendererFactory.end) rendererFactory.end(); } - checkView(view, context); // update mode pass - - if (rendererFactory.end) rendererFactory.end(); } /** @@ -2450,9 +2882,14 @@ export function detectChangesInRootView(lView: LView): void { * introduce other changes. */ export function checkNoChanges(component: T): void { + const view = getComponentViewByInstance(component); + checkNoChangesInternal(view, component); +} + +export function checkNoChangesInternal(view: LView, context: T) { setCheckNoChangesMode(true); try { - detectChanges(component); + detectChangesInternal(view, context); } finally { setCheckNoChangesMode(false); } @@ -2479,30 +2916,26 @@ export function checkNoChangesInRootView(lView: LView): void { /** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */ export function checkView(hostView: LView, component: T) { const hostTView = hostView[TVIEW]; - const oldView = enterView(hostView, hostView[HOST_NODE]); + const oldView = enterView(hostView, hostView[T_HOST]); const templateFn = hostTView.template !; - const viewQuery = hostTView.viewQuery; + const creationMode = isCreationMode(hostView); try { namespaceHTML(); - createViewQuery(viewQuery, hostView, component); + creationMode && executeViewQueryFn(hostView, hostTView, component); templateFn(getRenderFlags(hostView), component); refreshDescendantViews(hostView); - updateViewQuery(viewQuery, hostView, component); + !creationMode && executeViewQueryFn(hostView, hostTView, component); } finally { leaveView(oldView); } } -function createViewQuery(viewQuery: ComponentQuery<{}>| null, view: LView, component: T): void { - if (viewQuery && isCreationMode(view)) { - viewQuery(RenderFlags.Create, component); - } -} - -function updateViewQuery(viewQuery: ComponentQuery<{}>| null, view: LView, component: T): void { - if (viewQuery && !isCreationMode(view)) { - viewQuery(RenderFlags.Update, component); +function executeViewQueryFn(lView: LView, tView: TView, component: T): void { + const viewQuery = tView.viewQuery; + if (viewQuery) { + setCurrentQueryIndex(tView.viewQueryStartIndex); + viewQuery(getRenderFlags(lView), component); } } @@ -2525,7 +2958,10 @@ function updateViewQuery(viewQuery: ComponentQuery<{}>| null, view: LView, co */ export function markDirty(component: T) { ngDevMode && assertDefined(component, 'component'); - markViewDirty(getComponentViewByInstance(component)); + const rootView = markViewDirty(getComponentViewByInstance(component)) !; + + ngDevMode && assertDefined(rootView[CONTEXT], 'rootContext should be defined'); + scheduleTick(rootView[CONTEXT] as RootContext, RootContextFlags.DetectChanges); } /////////////////////////////// @@ -2539,7 +2975,9 @@ export function markDirty(component: T) { */ export function bind(value: T): T|NO_CHANGE { const lView = getLView(); - return bindingUpdated(lView, lView[BINDING_INDEX]++, value) ? value : NO_CHANGE; + const bindingIndex = lView[BINDING_INDEX]++; + storeBindingMetadata(lView); + return bindingUpdated(lView, bindingIndex, value) ? value : NO_CHANGE; } /** @@ -2548,9 +2986,9 @@ export function bind(value: T): T|NO_CHANGE { * @param count Amount of vars to be allocated */ export function allocHostVars(count: number): void { - if (!getFirstTemplatePass()) return; const lView = getLView(); const tView = lView[TVIEW]; + if (!tView.firstTemplatePass) return; queueHostBindingForCheck(tView, getCurrentDirectiveDef() !, count); prefillHostVars(tView, lView, count); } @@ -2572,13 +3010,23 @@ export function interpolationV(values: any[]): string|NO_CHANGE { ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values'); let different = false; const lView = getLView(); - + const tData = lView[TVIEW].data; let bindingIndex = lView[BINDING_INDEX]; + + if (tData[bindingIndex] == null) { + // 2 is the index of the first static interstitial value (ie. not prefix) + for (let i = 2; i < values.length; i += 2) { + tData[bindingIndex++] = values[i]; + } + bindingIndex = lView[BINDING_INDEX]; + } + for (let i = 1; i < values.length; i += 2) { // Check if bindings (odd indexes) have changed bindingUpdated(lView, bindingIndex++, values[i]) && (different = true); } lView[BINDING_INDEX] = bindingIndex; + storeBindingMetadata(lView, values[0], values[values.length - 1]); if (!different) { return NO_CHANGE; @@ -2587,7 +3035,7 @@ export function interpolationV(values: any[]): string|NO_CHANGE { // Build the updated content let content = values[0]; for (let i = 1; i < values.length; i += 2) { - content += stringify(values[i]) + values[i + 1]; + content += renderStringify(values[i]) + values[i + 1]; } return content; @@ -2602,19 +3050,26 @@ export function interpolationV(values: any[]): string|NO_CHANGE { */ export function interpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE { const lView = getLView(); - const different = bindingUpdated(lView, lView[BINDING_INDEX], v0); - lView[BINDING_INDEX] += 1; - return different ? prefix + stringify(v0) + suffix : NO_CHANGE; + const different = bindingUpdated(lView, lView[BINDING_INDEX]++, v0); + storeBindingMetadata(lView, prefix, suffix); + return different ? prefix + renderStringify(v0) + suffix : NO_CHANGE; } /** Creates an interpolation binding with 2 expressions. */ export function interpolation2( prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE { const lView = getLView(); - const different = bindingUpdated2(lView, lView[BINDING_INDEX], v0, v1); + const bindingIndex = lView[BINDING_INDEX]; + const different = bindingUpdated2(lView, bindingIndex, v0, v1); lView[BINDING_INDEX] += 2; - return different ? prefix + stringify(v0) + i0 + stringify(v1) + suffix : NO_CHANGE; + // Only set static strings the first time (data will be null subsequent runs). + const data = storeBindingMetadata(lView, prefix, suffix); + if (data) { + lView[TVIEW].data[bindingIndex] = i0; + } + + return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + suffix : NO_CHANGE; } /** Creates an interpolation binding with 3 expressions. */ @@ -2622,11 +3077,21 @@ export function interpolation3( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string| NO_CHANGE { const lView = getLView(); - const different = bindingUpdated3(lView, lView[BINDING_INDEX], v0, v1, v2); + const bindingIndex = lView[BINDING_INDEX]; + const different = bindingUpdated3(lView, bindingIndex, v0, v1, v2); lView[BINDING_INDEX] += 3; - return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + suffix : - NO_CHANGE; + // Only set static strings the first time (data will be null subsequent runs). + const data = storeBindingMetadata(lView, prefix, suffix); + if (data) { + const tData = lView[TVIEW].data; + tData[bindingIndex] = i0; + tData[bindingIndex + 1] = i1; + } + + return different ? + prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + suffix : + NO_CHANGE; } /** Create an interpolation binding with 4 expressions. */ @@ -2634,12 +3099,22 @@ export function interpolation4( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): string|NO_CHANGE { const lView = getLView(); - const different = bindingUpdated4(lView, lView[BINDING_INDEX], v0, v1, v2, v3); + const bindingIndex = lView[BINDING_INDEX]; + const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); lView[BINDING_INDEX] += 4; + // Only set static strings the first time (data will be null subsequent runs). + const data = storeBindingMetadata(lView, prefix, suffix); + if (data) { + const tData = lView[TVIEW].data; + tData[bindingIndex] = i0; + tData[bindingIndex + 1] = i1; + tData[bindingIndex + 2] = i2; + } + return different ? - prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + - suffix : + prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + + renderStringify(v3) + suffix : NO_CHANGE; } @@ -2653,9 +3128,19 @@ export function interpolation5( different = bindingUpdated(lView, bindingIndex + 4, v4) || different; lView[BINDING_INDEX] += 5; + // Only set static strings the first time (data will be null subsequent runs). + const data = storeBindingMetadata(lView, prefix, suffix); + if (data) { + const tData = lView[TVIEW].data; + tData[bindingIndex] = i0; + tData[bindingIndex + 1] = i1; + tData[bindingIndex + 2] = i2; + tData[bindingIndex + 3] = i3; + } + return different ? - prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + - stringify(v4) + suffix : + prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + + renderStringify(v3) + i3 + renderStringify(v4) + suffix : NO_CHANGE; } @@ -2669,9 +3154,20 @@ export function interpolation6( different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different; lView[BINDING_INDEX] += 6; + // Only set static strings the first time (data will be null subsequent runs). + const data = storeBindingMetadata(lView, prefix, suffix); + if (data) { + const tData = lView[TVIEW].data; + tData[bindingIndex] = i0; + tData[bindingIndex + 1] = i1; + tData[bindingIndex + 2] = i2; + tData[bindingIndex + 3] = i3; + tData[bindingIndex + 4] = i4; + } + return different ? - prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + - stringify(v4) + i4 + stringify(v5) + suffix : + prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + + renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + suffix : NO_CHANGE; } @@ -2686,9 +3182,22 @@ export function interpolation7( different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different; lView[BINDING_INDEX] += 7; + // Only set static strings the first time (data will be null subsequent runs). + const data = storeBindingMetadata(lView, prefix, suffix); + if (data) { + const tData = lView[TVIEW].data; + tData[bindingIndex] = i0; + tData[bindingIndex + 1] = i1; + tData[bindingIndex + 2] = i2; + tData[bindingIndex + 3] = i3; + tData[bindingIndex + 4] = i4; + tData[bindingIndex + 5] = i5; + } + return different ? - prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + - stringify(v4) + i4 + stringify(v5) + i5 + stringify(v6) + suffix : + prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + + renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 + + renderStringify(v6) + suffix : NO_CHANGE; } @@ -2703,12 +3212,50 @@ export function interpolation8( different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different; lView[BINDING_INDEX] += 8; + // Only set static strings the first time (data will be null subsequent runs). + const data = storeBindingMetadata(lView, prefix, suffix); + if (data) { + const tData = lView[TVIEW].data; + tData[bindingIndex] = i0; + tData[bindingIndex + 1] = i1; + tData[bindingIndex + 2] = i2; + tData[bindingIndex + 3] = i3; + tData[bindingIndex + 4] = i4; + tData[bindingIndex + 5] = i5; + tData[bindingIndex + 6] = i6; + } + return different ? - prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + - stringify(v4) + i4 + stringify(v5) + i5 + stringify(v6) + i6 + stringify(v7) + suffix : + prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + + renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 + + renderStringify(v6) + i6 + renderStringify(v7) + suffix : NO_CHANGE; } +/** + * Creates binding metadata for a particular binding and stores it in + * TView.data. These are generated in order to support DebugElement.properties. + * + * Each binding / interpolation will have one (including attribute bindings) + * because at the time of binding, we don't know to which instruction the binding + * belongs. It is always stored in TView.data at the index of the last binding + * value in LView (e.g. for interpolation8, it would be stored at the index of + * the 8th value). + * + * @param lView The LView that contains the current binding index. + * @param prefix The static prefix string + * @param suffix The static suffix string + * + * @returns Newly created binding metadata string for this binding or null + */ +function storeBindingMetadata(lView: LView, prefix = '', suffix = ''): string|null { + const tData = lView[TVIEW].data; + const lastBindingIndex = lView[BINDING_INDEX] - 1; + const value = INTERPOLATION_DELIMITER + prefix + INTERPOLATION_DELIMITER + suffix; + + return tData[lastBindingIndex] == null ? (tData[lastBindingIndex] = value) : null; +} + /** Store a value in the `data` at a given `index`. */ export function store(index: number, value: T): void { const lView = getLView(); @@ -2718,6 +3265,7 @@ export function store(index: number, value: T): void { const adjustedIndex = index + HEADER_OFFSET; if (adjustedIndex >= tView.data.length) { tView.data[adjustedIndex] = null; + tView.blueprint[adjustedIndex] = null; } lView[adjustedIndex] = value; } @@ -2735,16 +3283,6 @@ export function reference(index: number) { return loadInternal(contextLView, index); } -export function loadQueryList(queryListIdx: number): QueryList { - const lView = getLView(); - ngDevMode && - assertDefined( - lView[CONTENT_QUERIES], 'Content QueryList array should be defined if reading a query.'); - ngDevMode && assertDataInRange(lView[CONTENT_QUERIES] !, queryListIdx); - - return lView[CONTENT_QUERIES] ![queryListIdx]; -} - /** Retrieves a value from current `viewData`. */ export function load(index: number): T { return loadInternal(getLView(), index); @@ -2794,29 +3332,9 @@ export function injectAttribute(attrNameToInject: string): string|null { return injectAttributeImpl(getPreviousOrParentTNode(), attrNameToInject); } -/** - * Registers a QueryList, associated with a content query, for later refresh (part of a view - * refresh). - */ -export function registerContentQuery( - queryList: QueryList, currentDirectiveIndex: number): void { - const viewData = getLView(); - const tView = viewData[TVIEW]; - const savedContentQueriesLength = - (viewData[CONTENT_QUERIES] || (viewData[CONTENT_QUERIES] = [])).push(queryList); - if (getFirstTemplatePass()) { - const tViewContentQueries = tView.contentQueries || (tView.contentQueries = []); - const lastSavedDirectiveIndex = - tView.contentQueries.length ? tView.contentQueries[tView.contentQueries.length - 2] : -1; - if (currentDirectiveIndex !== lastSavedDirectiveIndex) { - tViewContentQueries.push(currentDirectiveIndex, savedContentQueriesLength - 1); - } - } -} - export const CLEAN_PROMISE = _CLEAN_PROMISE; -function initializeTNodeInputs(tNode: TNode | null) { +function initializeTNodeInputs(tNode: TNode | null): PropertyAliases|null { // If tNode.inputs is undefined, a listener has created outputs, but inputs haven't // yet been checked. if (tNode) { @@ -2849,3 +3367,19 @@ function getCleanup(view: LView): any[] { function getTViewCleanup(view: LView): any[] { return view[TVIEW].cleanup || (view[TVIEW].cleanup = []); } + +/** + * There are cases where the sub component's renderer needs to be included + * instead of the current renderer (see the componentSyntheticHost* instructions). + */ +function loadComponentRenderer(tNode: TNode, lView: LView): Renderer3 { + const componentLView = lView[tNode.index] as LView; + return componentLView[RENDERER]; +} + +/** Handles an error thrown in an LView. */ +function handleError(lView: LView, error: any): void { + const injector = lView[INJECTOR]; + const errorHandler = injector ? injector.get(ErrorHandler, null) : null; + errorHandler && errorHandler.handleError(error); +} diff --git a/packages/core/src/render3/interfaces/container.ts b/packages/core/src/render3/interfaces/container.ts index a8378c2c9c..5978bb6e69 100644 --- a/packages/core/src/render3/interfaces/container.ts +++ b/packages/core/src/render3/interfaces/container.ts @@ -22,7 +22,6 @@ export const VIEWS = 1; // PARENT, NEXT, QUERIES, and HOST are indices 2, 3, 4, and 5. // As we already have these constants in LView, we don't need to re-create them. export const NATIVE = 6; -export const RENDER_PARENT = 7; // Because interfaces in TS/JS cannot be instanceof-checked this means that we // need to rely on predictable characteristics of data-structures to check if they // are what we expect for them to be. The `LContainer` interface code below has a @@ -30,7 +29,7 @@ export const RENDER_PARENT = 7; // below we can predictably gaurantee that we are dealing with an `LContainer` array. // This value MUST be kept up to date with the length of the `LContainer` array // interface below so that runtime type checking can work. -export const LCONTAINER_LENGTH = 8; +export const LCONTAINER_LENGTH = 7; /** * The state associated with a container. @@ -90,28 +89,6 @@ export interface LContainer extends Array { /** The comment element that serves as an anchor for this LContainer. */ [NATIVE]: RComment; - - /** - * Parent Element which will contain the location where all of the views will be - * inserted into to. - * - * If `renderParent` is `null` it is headless. This means that it is contained - * in another view which in turn is contained in another container and - * therefore it does not yet have its own parent. - * - * If `renderParent` is not `null` then it may be: - * - same as `tContainerNode.parent` in which case it is just a normal container. - * - different from `tContainerNode.parent` in which case it has been re-projected. - * In other words `tContainerNode.parent` is logical parent where as - * `tContainerNode.projectedParent` is render parent. - * - * When views are inserted into `LContainer` then `renderParent` is: - * - `null`, we are in a view, keep going up a hierarchy until actual - * `renderParent` is found. - * - not `null`, then use the `projectedParent.native` as the `RElement` to insert - * views into. - */ - [RENDER_PARENT]: RElement|null; } // Note: This hack is necessary so we don't erroneously get a circular dependency diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index f530b5cea2..f60da2940b 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ViewEncapsulation} from '../../core'; -import {Type} from '../../type'; +import {SchemaMetadata, ViewEncapsulation} from '../../core'; +import {Type} from '../../interface/type'; import {CssSelectorList} from './projection'; @@ -15,13 +15,38 @@ import {CssSelectorList} from './projection'; * Definition of what a template rendering function should look like for a component. */ export type ComponentTemplate = { - (rf: RenderFlags, ctx: T): void; ngPrivateData?: never; + // Note: the ctx parameter is typed as T|U, as using only U would prevent a template with + // e.g. ctx: {} from being assigned to ComponentTemplate as TypeScript won't infer U = any + // in that scenario. By including T this incompatibility is resolved. + (rf: RenderFlags, ctx: T | U): void; ngPrivateData?: never; }; /** - * Definition of what a query function should look like. + * Definition of what a view queries function should look like. */ -export type ComponentQuery = ComponentTemplate; +export type ViewQueriesFunction = (rf: RenderFlags, ctx: U) => void; + +/** + * Definition of what a content queries function should look like. + */ +export type ContentQueriesFunction = + (rf: RenderFlags, ctx: U, directiveIndex: number) => void; + +/** + * Definition of what a factory function should look like. + */ +export type FactoryFn = { + /** + * Subclasses without an explicit constructor call through to the factory of their base + * definition, providing it with their own constructor to instantiate. + */ + (t: Type): U; + + /** + * If no constructor to instantiate is provided, an instance of type T itself is created. + */ + (t: null): T; +}; /** * Flags passed into template functions to determine which blocks (i.e. creation, update) @@ -60,7 +85,7 @@ export const enum DirectiveDefFlags {ContentQuery = 0b10} export interface PipeType extends Type { ngPipeDef: never; } export type DirectiveDefWithMeta< - T, Selector extends string, ExportAs extends string, InputMap extends{[key: string]: string}, + T, Selector extends string, ExportAs extends string[], InputMap extends{[key: string]: string}, OutputMap extends{[key: string]: string}, QueryFields extends string[]> = DirectiveDef; /** @@ -84,14 +109,14 @@ export interface BaseDef { * @deprecated This is only here because `NgOnChanges` incorrectly uses declared name instead of * public or minified name. */ - readonly declaredInputs: {[P in keyof T]: P}; + readonly declaredInputs: {[P in keyof T]: string}; /** * A dictionary mapping the outputs' minified property names to their public API names, which * are their aliases if any, or their original unminified property names * (as in `@Output('alias') propertyName: any;`). */ - readonly outputs: {[P in keyof T]: P}; + readonly outputs: {[P in keyof T]: string}; } /** @@ -113,7 +138,7 @@ export interface DirectiveDef extends BaseDef { type: Type; /** Function that resolves providers and publishes them into the DI system. */ - providersResolver: ((def: DirectiveDef) => void)|null; + providersResolver: ((def: DirectiveDef) => void)|null; /** The selectors that will be used to match nodes to this directive. */ readonly selectors: CssSelectorList; @@ -121,33 +146,25 @@ export interface DirectiveDef extends BaseDef { /** * Name under which the directive is exported (for use with local references in template) */ - readonly exportAs: string|null; + readonly exportAs: string[]|null; /** * Factory function used to create a new directive instance. */ - factory: (t: Type|null) => T; + factory: FactoryFn; /** - * Function to create instances of content queries associated with a given directive. + * Function to create and refresh content queries associated with a given directive. */ - contentQueries: ((directiveIndex: number) => void)|null; + contentQueries: ContentQueriesFunction|null; - /** Refreshes content queries associated with directives in a given view */ - contentQueriesRefresh: ((directiveIndex: number, queryIndex: number) => void)|null; - - /** Refreshes host bindings on the associated directive. */ + /** + * Refreshes host bindings on the associated directive. + */ hostBindings: HostBindingsFunction|null; - /** - * Static attributes to set on host element. - * - * Even indices: attribute name - * Odd indices: attribute value - */ - readonly attributes: string[]|null; - /* The following are lifecycle hooks for this component */ + onChanges: (() => void)|null; onInit: (() => void)|null; doCheck: (() => void)|null; afterContentInit: (() => void)|null; @@ -160,10 +177,15 @@ export interface DirectiveDef extends BaseDef { * The features applied to this directive */ readonly features: DirectiveDefFeature[]|null; + + setInput: + (( + this: DirectiveDef, instance: U, value: any, publicName: string, + privateName: string) => void)|null; } export type ComponentDefWithMeta< - T, Selector extends String, ExportAs extends string, InputMap extends{[key: string]: string}, + T, Selector extends String, ExportAs extends string[], InputMap extends{[key: string]: string}, OutputMap extends{[key: string]: string}, QueryFields extends string[]> = ComponentDef; /** @@ -189,6 +211,11 @@ export interface ComponentDef extends DirectiveDef { */ readonly template: ComponentTemplate; + /** + * An array of `ngContent[selector]` values that were found in the template. + */ + readonly ngContentSelectors?: string[]; + /** * A set of styles that the component needs to be present for component to render correctly. */ @@ -214,7 +241,7 @@ export interface ComponentDef extends DirectiveDef { /** * Query-related instructions for a component. */ - viewQuery: ComponentQuery|null; + viewQuery: ViewQueriesFunction|null; /** * The view encapsulation type, which determines how styles are applied to @@ -237,7 +264,6 @@ export interface ComponentDef extends DirectiveDef { readonly onPush: boolean; /** - * Registry of directives and components that may be found in this view. * * The property is either an array of `DirectiveDef`s or a function which returns the array of @@ -253,6 +279,11 @@ export interface ComponentDef extends DirectiveDef { */ pipeDefs: PipeDefListOrFactory|null; + /** + * The set of schemas that declare elements to be allowed in the component's template. + */ + schemas: SchemaMetadata[]|null; + /** * Used to store the result of `noSideEffects` function so that it is not removed by closure * compiler. The property should never be read. @@ -283,7 +314,7 @@ export interface PipeDef { /** * Factory function used to create a new pipe instance. */ - factory: (t: Type|null) => T; + factory: FactoryFn; /** * Whether or not the pipe is pure. @@ -301,11 +332,27 @@ export type PipeDefWithMeta = PipeDef; export interface DirectiveDefFeature { (directiveDef: DirectiveDef): void; + /** + * Marks a feature as something that {@link InheritDefinitionFeature} will execute + * during inheritance. + * + * NOTE: DO NOT SET IN ROOT OF MODULE! Doing so will result in tree-shakers/bundlers + * identifying the change as a side effect, and the feature will be included in + * every bundle. + */ ngInherit?: true; } export interface ComponentDefFeature { (componentDef: ComponentDef): void; + /** + * Marks a feature as something that {@link InheritDefinitionFeature} will execute + * during inheritance. + * + * NOTE: DO NOT SET IN ROOT OF MODULE! Doing so will result in tree-shakers/bundlers + * identifying the change as a side effect, and the feature will be included in + * every bundle. + */ ngInherit?: true; } @@ -325,7 +372,8 @@ export type DirectiveTypeList = (DirectiveDef| ComponentDef| Type/* Type as workaround for: Microsoft/TypeScript/issues/4881 */)[]; -export type HostBindingsFunction = (rf: RenderFlags, ctx: T, elementIndex: number) => void; +export type HostBindingsFunction = + (rf: RenderFlags, ctx: U, elementIndex: number) => void; /** * Type used for PipeDefs on component definition. @@ -344,4 +392,4 @@ export type PipeTypeList = // Note: This hack is necessary so we don't erroneously get a circular dependency // failure based on types. -export const unusedValueExportToPlacateAjd = 1; \ No newline at end of file +export const unusedValueExportToPlacateAjd = 1; diff --git a/packages/core/src/render3/interfaces/i18n.ts b/packages/core/src/render3/interfaces/i18n.ts index 02da87ebc9..5fc0a7cf91 100644 --- a/packages/core/src/render3/interfaces/i18n.ts +++ b/packages/core/src/render3/interfaces/i18n.ts @@ -245,14 +245,6 @@ export interface TI18n { */ vars: number; - /** - * Index in EXPANDO where the i18n stores its DOM nodes. - * - * When the bindings are processed by the `i18nEnd` instruction it is necessary to know where the - * newly created DOM nodes will be inserted. - */ - expandoStartIndex: number; - /** * A set of OpCodes which will create the Text Nodes and ICU anchors for the translation blocks. * @@ -332,14 +324,6 @@ export interface TIcu { */ childIcus: number[][]; - /** - * Index in EXPANDO where the i18n stores its DOM nodes. - * - * When the bindings are processed by the `i18nEnd` instruction it is necessary to know where the - * newly created DOM nodes will be inserted. - */ - expandoStartIndex: number; - /** * A list of case values which the current ICU will try to match. * diff --git a/packages/core/src/render3/interfaces/injector.ts b/packages/core/src/render3/interfaces/injector.ts index 199b90b0de..9b8a6695e8 100644 --- a/packages/core/src/render3/interfaces/injector.ts +++ b/packages/core/src/render3/interfaces/injector.ts @@ -7,8 +7,9 @@ */ import {InjectionToken} from '../../di/injection_token'; -import {InjectFlags} from '../../di/injector_compatibility'; -import {Type} from '../../type'; +import {InjectFlags} from '../../di/interface/injector'; +import {Type} from '../../interface/type'; + import {TElementNode} from './node'; import {LView, TData} from './view'; @@ -234,6 +235,10 @@ export class NodeInjectorFactory { * Set to `true` if the token is declared in `viewProviders` (or if it is component). */ isViewProvider: boolean, + /** + * Set to `true` if the token is a provider, and not a directive. + */ + public isProvider: boolean, injectImplementation: null|((token: Type|InjectionToken, flags: InjectFlags) => T)) { this.canSeeViewProviders = isViewProvider; this.injectImpl = injectImplementation; @@ -243,7 +248,7 @@ export class NodeInjectorFactory { const FactoryPrototype = NodeInjectorFactory.prototype; export function isFactory(obj: any): obj is NodeInjectorFactory { // See: https://jsperf.com/instanceof-vs-getprototypeof - return obj != null && typeof obj == 'object' && Object.getPrototypeOf(obj) == FactoryPrototype; + return obj !== null && typeof obj == 'object' && Object.getPrototypeOf(obj) == FactoryPrototype; } // Note: This hack is necessary so we don't erroneously get a circular dependency diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index dcf5468846..4f8ac12766 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {RNode} from './renderer'; import {StylingContext} from './styling'; import {LView, TView} from './view'; @@ -29,16 +30,19 @@ export const enum TNodeType { */ export const enum TNodeFlags { /** This bit is set if the node is a component */ - isComponent = 0b0001, + isComponent = 0b00001, /** This bit is set if the node has been projected */ - isProjected = 0b0010, + isProjected = 0b00010, - /** This bit is set if the node has any content queries */ - hasContentQuery = 0b0100, + /** This bit is set if any directive on this node has content queries */ + hasContentQuery = 0b00100, - /** This bit is set if the node has any directives that contain [class properties */ - hasClassInput = 0b1000, + /** This bit is set if the node has any "class" inputs */ + hasClassInput = 0b01000, + + /** This bit is set if the node has any "style" inputs */ + hasStyleInput = 0b10000, } /** @@ -169,7 +173,19 @@ export interface TNode { directiveEnd: number; /** - * Stores if Node isComponent, isProjected, hasContentQuery and hasClassInput + * Stores the first index where property binding metadata is stored for + * this node. + */ + propertyMetadataStartIndex: number; + + /** + * Stores the exclusive final index where property binding metadata is + * stored for this node. + */ + propertyMetadataEndIndex: number; + + /** + * Stores if Node isComponent, isProjected, hasContentQuery, hasClassInput and hasStyleInput */ flags: TNodeFlags; @@ -291,12 +307,6 @@ export interface TNode { */ parent: TElementNode|TContainerNode|null; - /** - * If this node is part of an i18n block, it indicates whether this node is part of the DOM. - * If this node is not part of an i18n block, this field is null. - */ - detached: boolean|null; - stylingTemplate: StylingContext|null; /** * List of projected TNodes for a given component host element OR index into the said nodes. @@ -333,8 +343,24 @@ export interface TNode { * `getHost(currentTNode).projection[currentTNode.projection]`. * - When projecting nodes the parent node retrieved may be a `` node, in which case * the process is recursive in nature (not implementation). + * + * If `projection` is of type `RNode[][]` than we have a collection of native nodes passed as + * projectable nodes during dynamic component creation. */ - projection: (TNode|null)[]|number|null; + projection: (TNode|RNode[])[]|number|null; + + /** + * A buffer of functions that will be called once `elementEnd` (or `element`) completes. + * + * Due to the nature of how directives work in Angular, some directive code may + * need to fire after any template-level code runs. If present, this array will + * be flushed (each function will be invoked) once the associated element is + * created. + * + * If an element is created multiple times then this function will be populated + * with functions each time the creation block is called. + */ + onElementCreationFns: Function[]|null; } /** Static data for an element */ @@ -352,10 +378,10 @@ export interface TElementNode extends TNode { /** * If this is a component TNode with projection, this will be an array of projected - * TNodes (see TNode.projection for more info). If it's a regular element node or a - * component without projection, it will be null. + * TNodes or native nodes (see TNode.projection for more info). If it's a regular element node or + * a component without projection, it will be null. */ - projection: (TNode|null)[]|null; + projection: (TNode|RNode[])[]|null; } /** Static data for a text node */ @@ -464,14 +490,14 @@ export type PropertyAliases = { /** * Store the runtime input or output names for all the directives. * - * - Even indices: directive index - * - Odd indices: minified / internal name + * i+0: directive instance index + * i+1: publicName + * i+2: privateName * - * e.g. [0, 'change-minified'] + * e.g. [0, 'change', 'change-minified'] */ export type PropertyAliasValue = (number | string)[]; - /** * This array contains information about input properties that * need to be set once from attribute data. It's ordered by @@ -480,14 +506,15 @@ export type PropertyAliasValue = (number | string)[]; * * Within each sub-array: * - * Even indices: minified/internal input name - * Odd indices: initial value + * i+0: attribute name + * i+1: minified/internal input name + * i+2: initial value * * If a directive on a node does not have any input properties * that should be set from attributes, its index is set to null * to avoid a sparse array. * - * e.g. [null, ['role-min', 'button']] + * e.g. [null, ['role-min', 'minified-input', 'button']] */ export type InitialInputData = (InitialInputs | null)[]; @@ -495,10 +522,11 @@ export type InitialInputData = (InitialInputs | null)[]; * Used by InitialInputData to store input properties * that should be set once from attributes. * - * Even indices: minified/internal input name - * Odd indices: initial value + * i+0: attribute name + * i+1: minified/internal input name + * i+2: initial value * - * e.g. ['role-min', 'button'] + * e.g. ['role-min', 'minified-input', 'button'] */ export type InitialInputs = string[]; diff --git a/packages/core/src/render3/interfaces/query.ts b/packages/core/src/render3/interfaces/query.ts index c69542a7de..b13c448b51 100644 --- a/packages/core/src/render3/interfaces/query.ts +++ b/packages/core/src/render3/interfaces/query.ts @@ -6,10 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import {Type} from '../../interface/type'; import {QueryList} from '../../linker'; -import {Type} from '../../type'; + import {TContainerNode, TElementContainerNode, TElementNode, TNode} from './node'; + /** Used for tracking queries (e.g. ViewChild, ContentChild). */ export interface LQueries { /** @@ -33,7 +35,7 @@ export interface LQueries { * Notify `LQueries` that a new `TNode` has been created and needs to be added to query results * if matching query predicate. */ - addNode(tNode: TElementNode|TContainerNode|TElementContainerNode): LQueries|null; + addNode(tNode: TElementNode|TContainerNode|TElementContainerNode): void; /** * Notify `LQueries` that a new LContainer was added to ivy data structures. As a result we need diff --git a/packages/core/src/render3/interfaces/renderer.ts b/packages/core/src/render3/interfaces/renderer.ts index c54ee5326b..a247204bc6 100644 --- a/packages/core/src/render3/interfaces/renderer.ts +++ b/packages/core/src/render3/interfaces/renderer.ts @@ -26,6 +26,12 @@ export enum RendererStyleFlags3 { export type Renderer3 = ObjectOrientedRenderer3 | ProceduralRenderer3; +export type GlobalTargetName = 'document' | 'window' | 'body'; + +export type GlobalTargetResolver = (element: any) => { + name: GlobalTargetName, target: EventTarget +}; + /** * Object Oriented style of API needed to create elements and text nodes. * @@ -68,7 +74,7 @@ export interface ProceduralRenderer3 { destroyNode?: ((node: RNode) => void)|null; appendChild(parent: RElement, newChild: RNode): void; insertBefore(parent: RNode, newChild: RNode, refChild: RNode|null): void; - removeChild(parent: RElement, oldChild: RNode): void; + removeChild(parent: RElement, oldChild: RNode, isHostElement?: boolean): void; selectRootElement(selectorOrNode: string|any): RElement; parentNode(node: RNode): RElement|null; @@ -86,7 +92,9 @@ export interface ProceduralRenderer3 { setValue(node: RText|RComment, value: string): void; // TODO(misko): Deprecate in favor of addEventListener/removeEventListener - listen(target: RNode, eventName: string, callback: (event: any) => boolean | void): () => void; + listen( + target: GlobalTargetName|RNode, eventName: string, + callback: (event: any) => boolean | void): () => void; } export interface RendererFactory3 { diff --git a/packages/core/src/render3/interfaces/sanitization.ts b/packages/core/src/render3/interfaces/sanitization.ts index 24970f93c9..e329c03024 100644 --- a/packages/core/src/render3/interfaces/sanitization.ts +++ b/packages/core/src/render3/interfaces/sanitization.ts @@ -9,4 +9,4 @@ /** * Function used to sanitize the value before writing it into the renderer. */ -export type SanitizerFn = (value: any) => string; +export type SanitizerFn = (value: any, tagName?: string, propName?: string) => string; diff --git a/packages/core/src/render3/interfaces/styling.ts b/packages/core/src/render3/interfaces/styling.ts index fa2091b342..c8d90677da 100644 --- a/packages/core/src/render3/interfaces/styling.ts +++ b/packages/core/src/render3/interfaces/styling.ts @@ -30,7 +30,7 @@ import {PlayerContext} from './player'; * * Say for example we have this: * ``` - * *
    * ``` @@ -44,9 +44,9 @@ import {PlayerContext} from './player'; * 1. elementStart or element (within the template function of a component) * 2. elementHostAttrs (for directive host bindings) * - * In either case, a styling context will be created and stored within an element's LViewData. Once - * the styling context is created then single and multi properties can stored within it. For this to - * happen, the following function needs to be called: + * In either case, a styling context will be created and stored within an element's `LViewData`. + * Once the styling context is created then single and multi properties can be stored within it. + * For this to happen, the following function needs to be called: * * `elementStyling` (called with style properties, class properties and a sanitizer + a directive * instance). @@ -73,8 +73,8 @@ import {PlayerContext} from './player'; * * The context generated from these values will look like this (note that * for each binding name (the class and style bindings) the values will - * be inserted twice into the array (once for single property entries) and - * another for multi property entries). + * be inserted twice into the array (once for single property entries and + * again for multi property entries). * * context = [ * // 0-8: header values (about 8 entries of configuration data) @@ -147,9 +147,10 @@ import {PlayerContext} from './player'; * have changed. * * ## Directives - * Directives style values (which are provided through host bindings) are also supported and - * housed within the same styling context as are template-level style/class properties/bindings. - * Both directive-level and template-level styling bindings share the same context. + * Directive style/class values (which are provided through host bindings) are also supported and + * housed within the same styling context as are template-level style/class properties/bindings + * So long as they are all assigned to the same element, both directive-level and template-level + * styling bindings share the same context. * * Each of the following instructions supports accepting a directive instance as an input parameter: * @@ -160,22 +161,40 @@ import {PlayerContext} from './player'; * - `elementStylingMap` * - `elementStylingApply` * - * Each time a directiveRef is passed in, it will be converted into an index by examining the + * Each time a directive value is passed in, it will be converted into an index by examining the * directive registry (which lives in the context configuration area). The index is then used * to help single style properties figure out where a value is located in the context. * + * + * ## Single-level styling bindings (`[style.prop]` and `[class.name]`) + * + * Both `[style.prop]` and `[class.name]` bindings are run through the `updateStyleProp` + * and `updateClassProp` functions respectively. They work by examining the provided + * `offset` value and are able to locate the exact spot in the context where the + * matching style is located. + * + * Both `[style.prop]` and `[class.name]` bindings are able to process these values + * from directive host bindings. When evaluated (from the host binding function) the + * `directiveRef` value is then passed in. + * * If two directives or a directive + a template binding both write to the same style/class * binding then the styling context code will decide which one wins based on the following * rule: * * 1. If the template binding has a value then it always wins - * 2. If not then whichever first-registered directive that has that value first will win + * 2. Otherwise whichever first-registered directive that has that value first will win * * The code example helps make this clear: * * ``` - *
    - * @Directive({ selector: '[my-width-directive' ]}) + * + * + * @Directive({ + * selector: '[my-width-directive'] + * }) * class MyWidthDirective { * @Input('my-width-directive') * @HostBinding('style.width') @@ -187,7 +206,8 @@ import {PlayerContext} from './player'; * it will always win over the width binding that is present as a host binding within * the `MyWidthDirective`. However, if `[style.width]` renders as `null` (so `myWidth=null`) * then the `MyWidthDirective` will be able to write to the `width` style within the context. - * Simply put, whichever directive writes to a value ends up having ownership of it. + * Simply put, whichever directive writes to a value first ends up having ownership of it as + * long as the template didn't set anything. * * The way in which the ownership is facilitated is through index value. The earliest directives * get the smallest index values (with 0 being reserved for the template element bindings). Each @@ -195,10 +215,48 @@ import {PlayerContext} from './player'; * assigned the directive index value in its data. If another directive writes a value again then * its directive index gets compared against the directive index that exists on the element. Only * when the new value's directive index is less than the existing directive index then the new - * value will be written to the context. + * value will be written to the context. But, if the existing value is null then the new value is + * written by the less important directive. * * Each directive also has its own sanitizer and dirty flags. These values are consumed within the * rendering function. + * + * + * ## Multi-level styling bindings (`[style]` and `[class]`) + * + * Multi-level styling bindings are treated as less important (less specific) as single-level + * bindings (things like `[style.prop]` and `[class.name]`). + * + * Multi-level bindings are still applied to the context in a similar way as are single level + * bindings, but this process works by diffing the new multi-level values (which are key/value + * maps) against the existing set of styles that live in the context. Each time a new map value + * is detected (via identity check) then it will loop through the values and figure out what + * has changed and reorder the context array to match the ordering of the keys. This reordering + * of the context makes sure that follow-up traversals of the context when updated against the + * key/value map are as close as possible to o(n) (where "n" is the size of the key/value map). + * + * If a `directiveRef` value is passed in then the styling algorithm code will take the directive's + * prioritization index into account and update the values with respect to more important + * directives. This means that if a value such as `width` is updated in two different `[style]` + * bindings (say one on the template and another within a directive that sits on the same element) + * then the algorithm will decide how to update the value based on the following heuristic: + * + * 1. If the template binding has a value then it always wins + * 2. If not then whichever first-registered directive that has that value first will win + * + * It will also update the value if it was set to `null` by a previous directive (or the template). + * + * Each time a value is updated (or removed) then the context will change shape to better match + * the ordering of the styling data as well as the ordering of each directive that contains styling + * data. (See `patchStylingMapIntoContext` inside of class_and_style_bindings.ts to better + * understand how this works.) + * + * ## Rendering + * The rendering mechanism (when the styling data is applied on screen) occurs via the + * `elementStylingApply` function and is designed to run after **all** styling functions have been + * evaluated. The rendering algorithm will loop over the context and only apply the styles that are + * flagged as dirty (either because they are new, updated or have been removed via multi or + * single bindings). */ export interface StylingContext extends Array<{[key: string]: any}|number|string|boolean|RElement|StyleSanitizeFn|PlayerContext|null> { @@ -240,13 +298,13 @@ export interface StylingContext extends * The last class value that was interpreted by elementStylingMap. This is cached * So that the algorithm can exit early incase the value has not changed. */ - [StylingIndex.CachedClassValueOrInitialClassString]: {[key: string]: any}|string|(string)[]|null; + [StylingIndex.CachedMultiClasses]: any|MapBasedOffsetValues; /** * The last style value that was interpreted by elementStylingMap. This is cached * So that the algorithm can exit early incase the value has not changed. */ - [StylingIndex.CachedStyleValue]: {[key: string]: any}|(string)[]|null; + [StylingIndex.CachedMultiStyles]: any|MapBasedOffsetValues; /** * Location of animation context (which contains the active players) for this element styling @@ -262,7 +320,10 @@ export interface StylingContext extends * * See [InitialStylingValuesIndex] for a breakdown of how all this works. */ -export interface InitialStylingValues extends Array { [0]: null; } +export interface InitialStylingValues extends Array { + [InitialStylingValuesIndex.DefaultNullValuePosition]: null; + [InitialStylingValuesIndex.InitialClassesStringPosition]: string|null; +} /** * Used as an offset/position index to figure out where initial styling @@ -270,13 +331,16 @@ export interface InitialStylingValues extends Array { [0]: * * Used as a reference point to provide markers to all static styling * values (the initial style and class values on an element) within an - * array within the StylingContext. This array contains key/value pairs + * array within the `StylingContext`. This array contains key/value pairs * where the key is the style property name or className and the value is * the style value or whether or not a class is present on the elment. * - * The first value is also always null so that a initial index value of + * The first value is always null so that a initial index value of * `0` will always point to a null value. * + * The second value is also always null unless a string-based representation + * of the styling data was constructed (it gets cached in this slot). + * * If a
    elements contains a list of static styling values like so: * *
    @@ -284,14 +348,18 @@ export interface InitialStylingValues extends Array { [0]: * Then the initial styles for that will look like so: * * Styles: + * ``` * StylingContext[InitialStylesIndex] = [ - * null, 'width', '100px', height, '200px' + * null, null, 'width', '100px', height, '200px' * ] + * ``` * * Classes: - * StylingContext[InitialStylesIndex] = [ - * null, 'foo', true, 'bar', true, 'baz', true + * ``` + * StylingContext[InitialClassesIndex] = [ + * null, null, 'foo', true, 'bar', true, 'baz', true * ] + * ``` * * Initial style and class entries have their own arrays. This is because * it's easier to add to the end of one array and not then have to update @@ -300,26 +368,32 @@ export interface InitialStylingValues extends Array { [0]: * When property bindinds are added to a context then initial style/class * values will also be inserted into the array. This is to create a space * in the situation when a follow-up directive inserts static styling into - * the array. By default style values are `null` and class values are + * the array. By default, style values are `null` and class values are * `false` when inserted by property bindings. * * For example: + * ``` *
    + * ``` * * Will construct initial styling values that look like: * * Styles: + * ``` * StylingContext[InitialStylesIndex] = [ - * null, 'width', '100px', height, '200px', 'opacity', null + * null, null, 'width', '100px', height, '200px', 'opacity', null * ] + * ``` * * Classes: - * StylingContext[InitialStylesIndex] = [ - * null, 'foo', true, 'bar', true, 'baz', true, 'car', false + * ``` + * StylingContext[InitialClassesIndex] = [ + * null, null, 'foo', true, 'bar', true, 'baz', true, 'car', false * ] + * ``` * * Now if a directive comes along and introduces `car` as a static * class value or `opacity` then those values will be filled into @@ -327,6 +401,7 @@ export interface InitialStylingValues extends Array { [0]: * * For example: * + * ``` * @Directive({ * selector: 'opacity-car-directive', * host: { @@ -335,21 +410,28 @@ export interface InitialStylingValues extends Array { [0]: * } * }) * class OpacityCarDirective {} + * ``` * * This will render itself as: * * Styles: + * ``` * StylingContext[InitialStylesIndex] = [ - * null, 'width', '100px', height, '200px', 'opacity', null + * null, null, 'width', '100px', height, '200px', 'opacity', '0.5' * ] + * ``` * * Classes: - * StylingContext[InitialStylesIndex] = [ - * null, 'foo', true, 'bar', true, 'baz', true, 'car', false + * ``` + * StylingContext[InitialClassesIndex] = [ + * null, null, 'foo', true, 'bar', true, 'baz', true, 'car', true * ] + * ``` */ export const enum InitialStylingValuesIndex { - KeyValueStartPosition = 1, + DefaultNullValuePosition = 0, + InitialClassesStringPosition = 1, + KeyValueStartPosition = 2, PropOffset = 0, ValueOffset = 1, Size = 2 @@ -361,28 +443,27 @@ export const enum InitialStylingValuesIndex { * * Each entry in this array represents a source of where style/class binding values could * come from. By default, there is always at least one directive here with a null value and - * that represents bindings that live directly on an element (not host bindings). + * that represents bindings that live directly on an element in the template (not host bindings). * - * Each successive entry in the array is an actual instance of an array as well as some - * additional info. + * Each successive entry in the array is an actual instance of a directive as well as some + * additional info about that entry. * * An entry within this array has the following values: - * [0] = The instance of the directive (or null when it is not a directive, but a template binding - * source) + * [0] = The instance of the directive (the first entry is null because its reserved for the + * template) * [1] = The pointer that tells where the single styling (stuff like [class.foo] and [style.prop]) * offset values are located. This value will allow for a binding instruction to find exactly * where a style is located. * [2] = Whether or not the directive has any styling values that are dirty. This is used as - * reference within the renderClassAndStyleBindings function to decide whether to skip - * iterating through the context when rendering is executed. + * reference within the `renderStyling` function to decide whether to skip iterating + * through the context when rendering is executed. * [3] = The styleSanitizer instance that is assigned to the directive. Although it's unlikely, * a directive could introduce its own special style sanitizer and for this reach each * directive will get its own space for it (if null then the very first sanitizer is used). * * Each time a new directive is added it will insert these four values at the end of the array. - * When this array is examined (using indexOf) then the resulting directiveIndex will be resolved - * by dividing the index value by the size of the array entries (so if DirA is at spot 8 then its - * index will be 2). + * When this array is examined then the resulting directiveIndex will be resolved by dividing the + * index value by the size of the array entries (so if DirA is at spot 8 then its index will be 2). */ export interface DirectiveRegistryValues extends Array { [DirectiveRegistryValuesIndex.DirectiveValueOffset]: null; @@ -441,29 +522,94 @@ export const enum SinglePropOffsetValuesIndex { ValueStartPosition = 2 } +/** + * Used a reference for all multi styling values (values that are assigned via the + * `[style]` and `[class]` bindings). + * + * Single-styling properties (things set via `[style.prop]` and `[class.name]` bindings) + * are not handled using the same approach as multi-styling bindings (such as `[style]` + * `[class]` bindings). + * + * Multi-styling bindings rely on a diffing algorithm to figure out what properties have been added, + * removed and modified. Multi-styling properties are also evaluated across directives--which means + * that Angular supports having multiple directives all write to the same `[style]` and `[class]` + * bindings (using host bindings) even if the `[style]` and/or `[class]` bindings are being written + * to on the template element. + * + * All multi-styling values that are written to an element (whether it be from the template or any + * directives attached to the element) are all written into the `MapBasedOffsetValues` array. (Note + * that there are two arrays: one for styles and another for classes.) + * + * This array is shaped in the following way: + * + * [0] = The total amount of unique multi-style or multi-class entries that exist currently in the + * context. + * [1+] = Contains an entry of four values ... Each entry is a value assigned by a + * `[style]`/`[class]` + * binding (we call this a **source**). + * + * An example entry looks like so (at a given `i` index): + * [i + 0] = Whether or not the value is dirty + * + * [i + 1] = The index of where the map-based values + * (for this **source**) start within the context + * + * [i + 2] = The untouched, last set value of the binding + * + * [i + 3] = The total amount of unqiue binding values that were + * extracted and set into the context. (Note that this value does + * not reflect the total amount of values within the binding + * value (since it's a map), but instead reflects the total values + * that were not used by another directive). + * + * Each time a directive (or template) writes a value to a `[class]`/`[style]` binding then the + * styling diffing algorithm code will decide whether or not to update the value based on the + * following rules: + * + * 1. If a more important directive (either the template or a directive that was registered + * beforehand) has written a specific styling value into the context then any follow-up styling + * values (set by another directive via its `[style]` and/or `[class]` host binding) will not be + * able to set it. This is because the former directive has priorty. + * 2. Only if a former directive has set a specific styling value to null (whether by actually + * setting it to null or not including it in is map value) then a less imporatant directive can + * set its own value. + * + * ## How the map-based styling algorithm updates itself + */ +export interface MapBasedOffsetValues extends Array { + [MapBasedOffsetValuesIndex.EntriesCountPosition]: number; +} + +export const enum MapBasedOffsetValuesIndex { + EntriesCountPosition = 0, + ValuesStartPosition = 1, + DirtyFlagOffset = 0, + PositionStartOffset = 1, + ValueOffset = 2, + ValueCountOffset = 3, + Size = 4 +} + /** * Used to set the context to be dirty or not both on the master flag (position 1) * or for each single/multi property that exists in the context. */ export const enum StylingFlags { // Implies no configurations - None = 0b000000, + None = 0b00000, // Whether or not the entry or context itself is dirty - Dirty = 0b000001, + Dirty = 0b00001, // Whether or not this is a class-based assignment - Class = 0b000010, + Class = 0b00010, // Whether or not a sanitizer was applied to this property - Sanitize = 0b000100, + Sanitize = 0b00100, // Whether or not any player builders within need to produce new players - PlayerBuildersDirty = 0b001000, - // If NgClass is present (or some other class handler) then it will handle the map expressions and - // initial classes - OnlyProcessSingleClasses = 0b010000, + PlayerBuildersDirty = 0b01000, // The max amount of bits used to represent these configuration values - BindingAllocationLocked = 0b100000, - BitCountSize = 6, - // There are only six bits here - BitMask = 0b111111 + BindingAllocationLocked = 0b10000, + BitCountSize = 5, + // There are only five bits here + BitMask = 0b11111 } /** Used as numeric pointer values to determine what cells to update in the `StylingContext` */ @@ -482,9 +628,9 @@ export const enum StylingIndex { ElementPosition = 5, // Position of where the last string-based CSS class value was stored (or a cached version of the // initial styles when a [class] directive is present) - CachedClassValueOrInitialClassString = 6, + CachedMultiClasses = 6, // Position of where the last string-based CSS class value was stored - CachedStyleValue = 7, + CachedMultiStyles = 7, // Multi and single entries are stored in `StylingContext` as: Flag; PropertyName; PropertyValue // Position of where the initial styles are stored in the styling context PlayerContext = 8, diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 996415a284..500984ab4d 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -8,11 +8,13 @@ import {InjectionToken} from '../../di/injection_token'; import {Injector} from '../../di/injector'; +import {Type} from '../../interface/type'; import {QueryList} from '../../linker'; +import {SchemaMetadata} from '../../metadata'; import {Sanitizer} from '../../sanitization/security'; -import {Type} from '../../type'; + import {LContainer} from './container'; -import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList} from './definition'; +import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList, ViewQueriesFunction} from './definition'; import {I18nUpdateOpCodes, TI18n} from './i18n'; import {TElementNode, TNode, TViewNode} from './node'; import {PlayerHandler} from './player'; @@ -21,6 +23,7 @@ import {RElement, Renderer3, RendererFactory3} from './renderer'; import {StylingContext} from './styling'; + // Below are constants for LView indices to help us look up LView members // without having to remember the specific indices. // Uglify will inline these when minifying so there shouldn't be a cost. @@ -30,7 +33,7 @@ export const PARENT = 2; export const NEXT = 3; export const QUERIES = 4; export const HOST = 5; -export const HOST_NODE = 6; // Rename to `T_HOST`? +export const T_HOST = 6; export const BINDING_INDEX = 7; export const CLEANUP = 8; export const CONTEXT = 9; @@ -116,7 +119,7 @@ export interface LView extends Array { * * If null, this is the root view of an application (root component is in this view). */ - [HOST_NODE]: TViewNode|TElementNode|null; + [T_HOST]: TViewNode|TElementNode|null; /** * The binding index we should access next. @@ -213,6 +216,10 @@ export interface LView extends Array { /** Flags associated with an LView (saved in LView[FLAGS]) */ export const enum LViewFlags { + /** The state of the init phase on the first 2 bits */ + InitPhaseStateIncrementer = 0b00000000001, + InitPhaseStateMask = 0b00000000011, + /** * Whether or not the view is in creationMode. * @@ -221,7 +228,7 @@ export const enum LViewFlags { * back into the parent view, `data` will be defined and `creationMode` will be * improperly reported as false. */ - CreationMode = 0b000000001, + CreationMode = 0b00000000100, /** * Whether or not this LView instance is on its first processing pass. @@ -230,33 +237,69 @@ export const enum LViewFlags { * has completed one creation mode run and one update mode run. At this * time, the flag is turned off. */ - FirstLViewPass = 0b000000010, + FirstLViewPass = 0b00000001000, /** Whether this view has default change detection strategy (checks always) or onPush */ - CheckAlways = 0b000000100, - - /** Whether or not this view is currently dirty (needing check) */ - Dirty = 0b000001000, - - /** Whether or not this view is currently attached to change detection tree. */ - Attached = 0b000010000, + CheckAlways = 0b00000010000, /** - * Whether or not the init hooks have run. + * Whether or not manual change detection is turned on for onPush components. * - * If on, the init hooks haven't yet been run and should be executed by the first component that - * runs OR the first cR() instruction that runs (so inits are run for the top level view before - * any embedded views). + * This is a special mode that only marks components dirty in two cases: + * 1) There has been a change to an @Input property + * 2) `markDirty()` has been called manually by the user + * + * Note that in this mode, the firing of events does NOT mark components + * dirty automatically. + * + * Manual mode is turned off by default for backwards compatibility, as events + * automatically mark OnPush components dirty in View Engine. + * + * TODO: Add a public API to ChangeDetectionStrategy to turn this mode on */ - RunInit = 0b000100000, + ManualOnPush = 0b00000100000, + + /** Whether or not this view is currently dirty (needing check) */ + Dirty = 0b000001000000, + + /** Whether or not this view is currently attached to change detection tree. */ + Attached = 0b000010000000, /** Whether or not this view is destroyed. */ - Destroyed = 0b001000000, + Destroyed = 0b000100000000, /** Whether or not this view is the root view */ - IsRoot = 0b010000000, + IsRoot = 0b001000000000, + + /** + * Index of the current init phase on last 22 bits + */ + IndexWithinInitPhaseIncrementer = 0b010000000000, + IndexWithinInitPhaseShift = 10, + IndexWithinInitPhaseReset = 0b001111111111, } +/** + * Possible states of the init phase: + * - 00: OnInit hooks to be run. + * - 01: AfterContentInit hooks to be run + * - 10: AfterViewInit hooks to be run + * - 11: All init hooks have been run + */ +export const enum InitPhaseState { + OnInitHooksToBeRun = 0b00, + AfterContentInitHooksToBeRun = 0b01, + AfterViewInitHooksToBeRun = 0b10, + InitPhaseCompleted = 0b11, +} + +/** + * Set of instructions used to process host bindings efficiently. + * + * See VIEW_DATA.md for more information. + */ +export interface ExpandoInstructions extends Array|null> {} + /** * The static data for an LView (shared between all templates of a * given type). @@ -288,7 +331,7 @@ export interface TView { /** * A function containing query-related instructions. */ - viewQuery: ComponentQuery<{}>|null; + viewQuery: ViewQueriesFunction<{}>|null; /** * Pointer to the `TNode` that represents the root of the view. @@ -333,6 +376,17 @@ export interface TView { */ expandoStartIndex: number; + /** + * The index where the viewQueries section of `LView` begins. This section contains + * view queries defined for a component/directive. + * + * We store this start index so we know where the list of view queries starts. + * This is required when we invoke view queries at runtime. We invoke queries one by one and + * increment query index after each iteration. This information helps us to reset index back to + * the beginning of view query list before we invoke view queries again. + */ + viewQueryStartIndex: number; + /** * Index of the host node of the first LView or LContainer beneath this LView in * the hierarchy. @@ -355,7 +409,7 @@ export interface TView { * * See VIEW_DATA.md for more information. */ - expandoInstructions: (number|HostBindingsFunction|null)[]|null; + expandoInstructions: ExpandoInstructions|null; /** * Full registry of directives and components that may be found in this view. @@ -437,17 +491,6 @@ export interface TView { */ destroyHooks: HookData|null; - /** - * Array of pipe ngOnDestroy hooks that should be executed when this view is destroyed. - * - * Even indices: Index of pipe in data - * Odd indices: Hook function - * - * These must be stored separately from directive destroy hooks because their contexts - * are stored in data. - */ - pipeDestroyHooks: HookData|null; - /** * When a view is destroyed, listeners need to be released and outputs need to be * unsubscribed. This cleanup array stores both listener data (in chunks of 4) @@ -457,7 +500,11 @@ export interface TView { * * If it's a native DOM listener or output subscription being stored: * 1st index is: event name `name = tView.cleanup[i+0]` - * 2nd index is: index of native element `element = lView[tView.cleanup[i+1]]` + * 2nd index is: index of native element or a function that retrieves global target (window, + * document or body) reference based on the native element: + * `typeof idxOrTargetGetter === 'function'`: global target getter function + * `typeof idxOrTargetGetter === 'number'`: index of native element + * * 3rd index is: index of listener function `listener = lView[CLEANUP][tView.cleanup[i+2]]` * 4th index is: `useCaptureOrIndx = tView.cleanup[i+3]` * `typeof useCaptureOrIndx == 'boolean' : useCapture boolean @@ -487,11 +534,13 @@ export interface TView { /** * A list of indices for child directives that have content queries. - * - * Even indices: Directive indices - * Odd indices: Starting index of content queries (stored in CONTENT_QUERIES) for this directive */ contentQueries: number[]|null; + + /** + * Set of schemas that declare elements to be allowed inside the view. + */ + schemas: SchemaMetadata[]|null; } export const enum RootContextFlags {Empty = 0b00, DetectChanges = 0b01, FlushPlayers = 0b10} @@ -550,11 +599,26 @@ export type HookData = (number | (() => void))[]; * Each pipe's definition is stored here at the same index as its pipe instance in * the data array. * + * Each host property's name is stored here at the same index as its value in the + * data array. + * + * Each property binding name is stored here at the same index as its value in + * the data array. If the binding is an interpolation, the static string values + * are stored parallel to the dynamic values. Example: + * + * id="prefix {{ v0 }} a {{ v1 }} b {{ v2 }} suffix" + * + * LView | TView.data + *------------------------ + * v0 value | 'a' + * v1 value | 'b' + * v2 value | id � prefix � suffix + * * Injector bloom filters are also stored here. */ export type TData = (TNode | PipeDef| DirectiveDef| ComponentDef| number | Type| - InjectionToken| TI18n | I18nUpdateOpCodes | null)[]; + InjectionToken| TI18n | I18nUpdateOpCodes | null | string)[]; // Note: This hack is necessary so we don't erroneously get a circular dependency // failure based on types. diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 89e2696718..81c785c328 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -7,20 +7,21 @@ */ import {ComponentType} from '..'; +import {R3DirectiveMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; +import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface'; +import {resolveForwardRef} from '../../di/forward_ref'; +import {getReflect, reflectDependencies} from '../../di/jit/util'; +import {Type} from '../../interface/type'; import {Query} from '../../metadata/di'; -import {Component, Directive} from '../../metadata/directives'; +import {Component, Directive, Input} from '../../metadata/directives'; import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading'; import {ViewEncapsulation} from '../../metadata/view'; -import {Type} from '../../type'; import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty'; import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from '../fields'; -import {stringify} from '../util'; +import {renderStringify} from '../util'; -import {R3DirectiveMetadataFacade, getCompilerFacade} from './compiler_facade'; -import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from './compiler_facade_interface'; import {angularCoreEnv} from './environment'; import {flushModuleScopingQueueAsMuchAsPossible, patchComponentDefWithScope, transitiveScopesFor} from './module'; -import {getReflect, reflectDependencies} from './util'; @@ -42,9 +43,9 @@ export function compileComponent(type: Type, metadata: Component): void { const compiler = getCompilerFacade(); if (ngComponentDef === null) { if (componentNeedsResolution(metadata)) { - const error = [`Component '${stringify(type)}' is not resolved:`]; + const error = [`Component '${renderStringify(type)}' is not resolved:`]; if (metadata.templateUrl) { - error.push(` - templateUrl: ${stringify(metadata.templateUrl)}`); + error.push(` - templateUrl: ${renderStringify(metadata.templateUrl)}`); } if (metadata.styleUrls && metadata.styleUrls.length) { error.push(` - styleUrls: ${JSON.stringify(metadata.styleUrls)}`); @@ -53,8 +54,11 @@ export function compileComponent(type: Type, metadata: Component): void { throw new Error(error.join('\n')); } + const templateUrl = metadata.templateUrl || `ng:///${renderStringify(type)}/template.html`; const meta: R3ComponentMetadataFacade = { ...directiveMetadata(type, metadata), + typeSourceSpan: + compiler.createParseSourceSpan('Component', renderStringify(type), templateUrl), template: metadata.template || '', preserveWhitespaces: metadata.preserveWhitespaces || false, styles: metadata.styles || EMPTY_ARRAY, @@ -67,8 +71,7 @@ export function compileComponent(type: Type, metadata: Component): void { interpolation: metadata.interpolation, viewProviders: metadata.viewProviders || null, }; - ngComponentDef = compiler.compileComponent( - angularCoreEnv, `ng://${stringify(type)}/template.html`, meta); + ngComponentDef = compiler.compileComponent(angularCoreEnv, templateUrl, meta); // When NgModule decorator executed, we enqueued the module definition such that // it would only dequeue and add itself as module scope to all of its declarations, @@ -110,9 +113,13 @@ export function compileDirective(type: Type, directive: Directive): void { Object.defineProperty(type, NG_DIRECTIVE_DEF, { get: () => { if (ngDirectiveDef === null) { + const name = type && type.name; + const sourceMapUrl = `ng://${name}/ngDirectiveDef.js`; + const compiler = getCompilerFacade(); const facade = directiveMetadata(type as ComponentType, directive); - ngDirectiveDef = getCompilerFacade().compileDirective( - angularCoreEnv, `ng://${type && type.name}/ngDirectiveDef.js`, facade); + facade.typeSourceSpan = + compiler.createParseSourceSpan('Directive', renderStringify(type), sourceMapUrl); + ngDirectiveDef = compiler.compileDirective(angularCoreEnv, sourceMapUrl, facade); } return ngDirectiveDef; }, @@ -144,18 +151,16 @@ function directiveMetadata(type: Type, metadata: Directive): R3DirectiveMet inputs: metadata.inputs || EMPTY_ARRAY, outputs: metadata.outputs || EMPTY_ARRAY, queries: extractQueriesMetadata(type, propMetadata, isContentQuery), - lifecycle: { - usesOnChanges: type.prototype.ngOnChanges !== undefined, - }, + lifecycle: {usesOnChanges: type.prototype.hasOwnProperty('ngOnChanges')}, typeSourceSpan: null !, usesInheritance: !extendsDirectlyFromObject(type), - exportAs: metadata.exportAs || null, + exportAs: extractExportAs(metadata.exportAs), providers: metadata.providers || null, }; } function convertToR3QueryPredicate(selector: any): any|string[] { - return typeof selector === 'string' ? splitByComma(selector) : selector; + return typeof selector === 'string' ? splitByComma(selector) : resolveForwardRef(selector); } export function convertToR3QueryMetadata(propertyName: string, ann: Query): R3QueryMetadataFacade { @@ -173,12 +178,16 @@ function extractQueriesMetadata( const queriesMeta: R3QueryMetadataFacade[] = []; for (const field in propMetadata) { if (propMetadata.hasOwnProperty(field)) { - propMetadata[field].forEach(ann => { + const annotations = propMetadata[field]; + annotations.forEach(ann => { if (isQueryAnn(ann)) { if (!ann.selector) { throw new Error( `Can't construct a query for the property "${field}" of ` + - `"${stringify(type)}" since the query selector wasn't defined.`); + `"${renderStringify(type)}" since the query selector wasn't defined.`); + } + if (annotations.some(isInputAnn)) { + throw new Error(`Cannot combine @Input decorators with query decorators`); } queriesMeta.push(convertToR3QueryMetadata(field, ann)); } @@ -188,6 +197,14 @@ function extractQueriesMetadata( return queriesMeta; } +function extractExportAs(exportAs: string | undefined): string[]|null { + if (exportAs === undefined) { + return null; + } + + return exportAs.split(',').map(part => part.trim()); +} + function isContentQuery(value: any): value is Query { const name = value.ngMetadataName; return name === 'ContentChild' || name === 'ContentChildren'; @@ -198,6 +215,10 @@ function isViewQuery(value: any): value is Query { return name === 'ViewChild' || name === 'ViewChildren'; } +function isInputAnn(value: any): value is Input { + return value.ngMetadataName === 'Input'; +} + function splitByComma(value: string): string[] { return value.split(',').map(piece => piece.trim()); } diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index 1a30e41a4c..81b440d3c2 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {defineInjectable, defineInjector,} from '../../di/defs'; +import {defineInjectable, defineInjector,} from '../../di/interface/defs'; import {inject} from '../../di/injector_compatibility'; import * as r3 from '../index'; import * as sanitization from '../../sanitization/sanitization'; @@ -40,7 +40,6 @@ export const angularCoreEnv: {[name: string]: Function} = { 'ɵnextContext': r3.nextContext, 'ɵcontainerRefreshStart': r3.containerRefreshStart, 'ɵcontainerRefreshEnd': r3.containerRefreshEnd, - 'ɵloadQueryList': r3.loadQueryList, 'ɵnamespaceHTML': r3.namespaceHTML, 'ɵnamespaceMathML': r3.namespaceMathML, 'ɵnamespaceSVG': r3.namespaceSVG, @@ -78,6 +77,8 @@ export const angularCoreEnv: {[name: string]: Function} = { 'ɵload': r3.load, 'ɵprojection': r3.projection, 'ɵelementProperty': r3.elementProperty, + 'ɵcomponentHostSyntheticProperty': r3.componentHostSyntheticProperty, + 'ɵcomponentHostSyntheticListener': r3.componentHostSyntheticListener, 'ɵpipeBind1': r3.pipeBind1, 'ɵpipeBind2': r3.pipeBind2, 'ɵpipeBind3': r3.pipeBind3, @@ -85,9 +86,11 @@ export const angularCoreEnv: {[name: string]: Function} = { 'ɵpipeBindV': r3.pipeBindV, 'ɵprojectionDef': r3.projectionDef, 'ɵpipe': r3.pipe, - 'ɵquery': r3.query, 'ɵqueryRefresh': r3.queryRefresh, - 'ɵregisterContentQuery': r3.registerContentQuery, + 'ɵviewQuery': r3.viewQuery, + 'ɵloadViewQuery': r3.loadViewQuery, + 'ɵcontentQuery': r3.contentQuery, + 'ɵloadContentQuery': r3.loadContentQuery, 'ɵreference': r3.reference, 'ɵelementStyling': r3.elementStyling, 'ɵelementHostAttrs': r3.elementHostAttrs, @@ -106,11 +109,16 @@ export const angularCoreEnv: {[name: string]: Function} = { 'ɵi18nEnd': r3.i18nEnd, 'ɵi18nApply': r3.i18nApply, 'ɵi18nPostprocess': r3.i18nPostprocess, + 'ɵresolveWindow': r3.resolveWindow, + 'ɵresolveDocument': r3.resolveDocument, + 'ɵresolveBody': r3.resolveBody, + 'ɵsetComponentScope': r3.setComponentScope, 'ɵsanitizeHtml': sanitization.sanitizeHtml, 'ɵsanitizeStyle': sanitization.sanitizeStyle, 'ɵdefaultStyleSanitizer': sanitization.defaultStyleSanitizer, 'ɵsanitizeResourceUrl': sanitization.sanitizeResourceUrl, 'ɵsanitizeScript': sanitization.sanitizeScript, - 'ɵsanitizeUrl': sanitization.sanitizeUrl + 'ɵsanitizeUrl': sanitization.sanitizeUrl, + 'ɵsanitizeUrlOrResourceUrl': sanitization.sanitizeUrlOrResourceUrl }; diff --git a/packages/core/src/render3/jit/module.ts b/packages/core/src/render3/jit/module.ts index dd87c0f867..0ef0cc7298 100644 --- a/packages/core/src/render3/jit/module.ts +++ b/packages/core/src/render3/jit/module.ts @@ -6,21 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ +import {R3InjectorMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; import {resolveForwardRef} from '../../di/forward_ref'; +import {NG_INJECTOR_DEF} from '../../di/interface/defs'; +import {reflectDependencies} from '../../di/jit/util'; +import {Type} from '../../interface/type'; import {registerNgModuleType} from '../../linker/ng_module_factory_loader'; import {Component} from '../../metadata'; import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module'; -import {Type} from '../../type'; -import {assertDefined} from '../assert'; +import {assertDefined} from '../../util/assert'; import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition'; -import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_INJECTOR_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields'; +import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields'; import {ComponentDef} from '../interfaces/definition'; import {NgModuleType} from '../ng_module_ref'; -import {stringify} from '../util'; +import {renderStringify} from '../util'; -import {R3InjectorMetadataFacade, getCompilerFacade} from './compiler_facade'; import {angularCoreEnv} from './environment'; -import {reflectDependencies} from './util'; const EMPTY_ARRAY: Type[] = []; @@ -107,11 +108,14 @@ export function compileNgModuleDefs(moduleType: NgModuleType, ngModule: NgModule ngModuleDef = getCompilerFacade().compileNgModule( angularCoreEnv, `ng://${moduleType.name}/ngModuleDef.js`, { type: moduleType, - bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY), - declarations: declarations, - imports: flatten(ngModule.imports || EMPTY_ARRAY).map(expandModuleWithProviders), - exports: flatten(ngModule.exports || EMPTY_ARRAY).map(expandModuleWithProviders), + bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY, resolveForwardRef), + declarations: declarations.map(resolveForwardRef), + imports: flatten(ngModule.imports || EMPTY_ARRAY, resolveForwardRef) + .map(expandModuleWithProviders), + exports: flatten(ngModule.exports || EMPTY_ARRAY, resolveForwardRef) + .map(expandModuleWithProviders), emitInline: true, + schemas: ngModule.schemas ? flatten(ngModule.schemas) : null, }); } return ngModuleDef; @@ -132,8 +136,8 @@ export function compileNgModuleDefs(moduleType: NgModuleType, ngModule: NgModule deps: reflectDependencies(moduleType), providers: ngModule.providers || EMPTY_ARRAY, imports: [ - ngModule.imports || EMPTY_ARRAY, - ngModule.exports || EMPTY_ARRAY, + (ngModule.imports || EMPTY_ARRAY).map(resolveForwardRef), + (ngModule.exports || EMPTY_ARRAY).map(resolveForwardRef), ], }; ngInjectorDef = getCompilerFacade().compileInjector( @@ -154,8 +158,8 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { const errors: string[] = []; ngModuleDef.declarations.forEach(verifyDeclarationsHaveDefinitions); const combinedDeclarations: Type[] = [ - ...ngModuleDef.declarations, // - ...flatten(ngModuleDef.imports.map(computeCombinedExports)), + ...ngModuleDef.declarations.map(resolveForwardRef), // + ...flatten(ngModuleDef.imports.map(computeCombinedExports), resolveForwardRef), ]; ngModuleDef.exports.forEach(verifyExportsAreDeclaredOrReExported); ngModuleDef.declarations.forEach(verifyDeclarationIsUnique); @@ -166,6 +170,7 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { ngModule.imports && flatten(ngModule.imports, unwrapModuleWithProvidersImports) .forEach(verifySemanticsOfNgModuleDef); + ngModule.bootstrap && ngModule.bootstrap.forEach(verifyCorrectBootstrapType); ngModule.bootstrap && ngModule.bootstrap.forEach(verifyComponentIsPartOfNgModule); ngModule.entryComponents && ngModule.entryComponents.forEach(verifyComponentIsPartOfNgModule); } @@ -180,7 +185,7 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef(type); if (!def) { errors.push( - `Unexpected value '${stringify(type)}' declared by the module '${stringify(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`); + `Unexpected value '${renderStringify(type)}' declared by the module '${renderStringify(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`); } } @@ -194,7 +199,7 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { if (combinedDeclarations.lastIndexOf(type) === -1) { // We are exporting something which we don't explicitly declare or import. errors.push( - `Can't export ${kind} ${stringify(type)} from ${stringify(moduleType)} as it was neither declared nor imported!`); + `Can't export ${kind} ${renderStringify(type)} from ${renderStringify(moduleType)} as it was neither declared nor imported!`); } } } @@ -203,11 +208,11 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { type = resolveForwardRef(type); const existingModule = ownerNgModule.get(type); if (existingModule && existingModule !== moduleType) { - const modules = [existingModule, moduleType].map(stringify).sort(); + const modules = [existingModule, moduleType].map(renderStringify).sort(); errors.push( - `Type ${stringify(type)} is part of the declarations of 2 modules: ${modules[0]} and ${modules[1]}! ` + - `Please consider moving ${stringify(type)} to a higher module that imports ${modules[0]} and ${modules[1]}. ` + - `You can also create a new NgModule that exports and includes ${stringify(type)} then import that NgModule in ${modules[0]} and ${modules[1]}.`); + `Type ${renderStringify(type)} is part of the declarations of 2 modules: ${modules[0]} and ${modules[1]}! ` + + `Please consider moving ${renderStringify(type)} to a higher module that imports ${modules[0]} and ${modules[1]}. ` + + `You can also create a new NgModule that exports and includes ${renderStringify(type)} then import that NgModule in ${modules[0]} and ${modules[1]}.`); } else { // Mark type as having owner. ownerNgModule.set(type, moduleType); @@ -219,7 +224,14 @@ function verifySemanticsOfNgModuleDef(moduleType: NgModuleType): void { const existingModule = ownerNgModule.get(type); if (!existingModule) { errors.push( - `Component ${stringify(type)} is not part of any NgModule or the module has not been imported into your module.`); + `Component ${renderStringify(type)} is not part of any NgModule or the module has not been imported into your module.`); + } + } + + function verifyCorrectBootstrapType(type: Type) { + type = resolveForwardRef(type); + if (!getComponentDef(type)) { + errors.push(`${renderStringify(type)} cannot be used as an entry component.`); } } @@ -334,11 +346,15 @@ function setScopeOnDeclaredComponents(moduleType: Type, ngModule: NgModule) */ export function patchComponentDefWithScope( componentDef: ComponentDef, transitiveScopes: NgModuleTransitiveScopes) { - componentDef.directiveDefs = () => Array.from(transitiveScopes.compilation.directives) - .map(dir => getDirectiveDef(dir) || getComponentDef(dir) !) - .filter(def => !!def); + componentDef.directiveDefs = () => + Array.from(transitiveScopes.compilation.directives) + .map( + dir => dir.hasOwnProperty(NG_COMPONENT_DEF) ? getComponentDef(dir) ! : + getDirectiveDef(dir) !) + .filter(def => !!def); componentDef.pipeDefs = () => Array.from(transitiveScopes.compilation.pipes).map(pipe => getPipeDef(pipe) !); + componentDef.schemas = transitiveScopes.schemas; } /** @@ -348,7 +364,9 @@ export function patchComponentDefWithScope( * on modules with components that have not fully compiled yet, but the result should not be used * until they have. */ -export function transitiveScopesFor(moduleType: Type): NgModuleTransitiveScopes { +export function transitiveScopesFor( + moduleType: Type, + processNgModuleFn?: (ngModule: NgModuleType) => void): NgModuleTransitiveScopes { if (!isNgModule(moduleType)) { throw new Error(`${moduleType.name} does not have an ngModuleDef`); } @@ -359,6 +377,7 @@ export function transitiveScopesFor(moduleType: Type): NgModuleTransitiveS } const scopes: NgModuleTransitiveScopes = { + schemas: def.schemas || null, compilation: { directives: new Set(), pipes: new Set(), @@ -383,24 +402,28 @@ export function transitiveScopesFor(moduleType: Type): NgModuleTransitiveS }); def.imports.forEach((imported: Type) => { - const importedTyped = imported as Type& { + const importedType = imported as Type& { // If imported is an @NgModule: ngModuleDef?: NgModuleDef; }; - if (!isNgModule(importedTyped)) { - throw new Error(`Importing ${importedTyped.name} which does not have an ngModuleDef`); + if (!isNgModule(importedType)) { + throw new Error(`Importing ${importedType.name} which does not have an ngModuleDef`); + } + + if (processNgModuleFn) { + processNgModuleFn(importedType as NgModuleType); } // When this module imports another, the imported module's exported directives and pipes are // added to the compilation scope of this module. - const importedScope = transitiveScopesFor(importedTyped); + const importedScope = transitiveScopesFor(importedType, processNgModuleFn); importedScope.exported.directives.forEach(entry => scopes.compilation.directives.add(entry)); importedScope.exported.pipes.forEach(entry => scopes.compilation.pipes.add(entry)); }); def.exports.forEach((exported: Type) => { - const exportedTyped = exported as Type& { + const exportedType = exported as Type& { // Components, Directives, NgModules, and Pipes can all be exported. ngComponentDef?: any; ngDirectiveDef?: any; @@ -410,10 +433,10 @@ export function transitiveScopesFor(moduleType: Type): NgModuleTransitiveS // Either the type is a module, a pipe, or a component/directive (which may not have an // ngComponentDef as it might be compiled asynchronously). - if (isNgModule(exportedTyped)) { + if (isNgModule(exportedType)) { // When this module exports another, the exported module's exported directives and pipes are // added to both the compilation and exported scopes of this module. - const exportedScope = transitiveScopesFor(exportedTyped); + const exportedScope = transitiveScopesFor(exportedType, processNgModuleFn); exportedScope.exported.directives.forEach(entry => { scopes.compilation.directives.add(entry); scopes.exported.directives.add(entry); @@ -422,10 +445,10 @@ export function transitiveScopesFor(moduleType: Type): NgModuleTransitiveS scopes.compilation.pipes.add(entry); scopes.exported.pipes.add(entry); }); - } else if (getPipeDef(exportedTyped)) { - scopes.exported.pipes.add(exportedTyped); + } else if (getPipeDef(exportedType)) { + scopes.exported.pipes.add(exportedType); } else { - scopes.exported.directives.add(exportedTyped); + scopes.exported.directives.add(exportedType); } }); diff --git a/packages/core/src/render3/jit/pipe.ts b/packages/core/src/render3/jit/pipe.ts index 01ef332667..4319e4a330 100644 --- a/packages/core/src/render3/jit/pipe.ts +++ b/packages/core/src/render3/jit/pipe.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ +import {getCompilerFacade} from '../../compiler/compiler_facade'; +import {reflectDependencies} from '../../di/jit/util'; +import {Type} from '../../interface/type'; import {Pipe} from '../../metadata/directives'; -import {Type} from '../../type'; import {NG_PIPE_DEF} from '../fields'; -import {stringify} from '../util'; +import {renderStringify} from '../util'; -import {getCompilerFacade} from './compiler_facade'; import {angularCoreEnv} from './environment'; -import {reflectDependencies} from './util'; export function compilePipe(type: Type, meta: Pipe): void { let ngPipeDef: any = null; @@ -21,7 +21,7 @@ export function compilePipe(type: Type, meta: Pipe): void { get: () => { if (ngPipeDef === null) { ngPipeDef = getCompilerFacade().compilePipe( - angularCoreEnv, `ng://${stringify(type)}/ngPipeDef.js`, { + angularCoreEnv, `ng://${renderStringify(type)}/ngPipeDef.js`, { type: type, name: type.name, deps: reflectDependencies(type), diff --git a/packages/core/src/render3/metadata.ts b/packages/core/src/render3/metadata.ts index 19988e1d2f..053d742845 100644 --- a/packages/core/src/render3/metadata.ts +++ b/packages/core/src/render3/metadata.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; +import {Type} from '../interface/type'; interface TypeWithMetadata extends Type { decorators?: any[]; @@ -28,7 +28,7 @@ export function setClassMetadata( propDecorators: {[field: string]: any} | null): void { const clazz = type as TypeWithMetadata; if (decorators !== null) { - if (clazz.decorators !== undefined) { + if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) { clazz.decorators.push(...decorators); } else { clazz.decorators = decorators; diff --git a/packages/core/src/render3/ng_module_ref.ts b/packages/core/src/render3/ng_module_ref.ts index ed82ed08bc..f13faac4d2 100644 --- a/packages/core/src/render3/ng_module_ref.ts +++ b/packages/core/src/render3/ng_module_ref.ts @@ -7,16 +7,15 @@ */ import {INJECTOR, Injector} from '../di/injector'; -import {InjectFlags} from '../di/injector_compatibility'; -import {StaticProvider} from '../di/provider'; -import {createInjector} from '../di/r3_injector'; +import {InjectFlags} from '../di/interface/injector'; +import {StaticProvider} from '../di/interface/provider'; +import {R3Injector, createInjector} from '../di/r3_injector'; +import {Type} from '../interface/type'; import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver'; import {InternalNgModuleRef, NgModuleFactory as viewEngine_NgModuleFactory, NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory'; import {NgModuleDef} from '../metadata/ng_module'; -import {Type} from '../type'; -import {stringify} from '../util'; - -import {assertDefined} from './assert'; +import {assertDefined} from '../util/assert'; +import {stringify} from '../util/stringify'; import {ComponentFactoryResolver} from './component_ref'; import {getNgModuleDef} from './definition'; @@ -32,7 +31,7 @@ export class NgModuleRef extends viewEngine_NgModuleRef implements Interna // tslint:disable-next-line:require-internal-with-underscore _bootstrapComponents: Type[] = []; // tslint:disable-next-line:require-internal-with-underscore - _r3Injector: Injector; + _r3Injector: R3Injector; injector: Injector = this; instance: T; destroyCbs: (() => void)[]|null = []; @@ -52,7 +51,8 @@ export class NgModuleRef extends viewEngine_NgModuleRef implements Interna }, COMPONENT_FACTORY_RESOLVER ]; - this._r3Injector = createInjector(ngModuleType, _parent, additionalProviders); + this._r3Injector = createInjector( + ngModuleType, _parent, additionalProviders, stringify(ngModuleType)) as R3Injector; this.instance = this.get(ngModuleType); } @@ -70,6 +70,8 @@ export class NgModuleRef extends viewEngine_NgModuleRef implements Interna destroy(): void { ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); + const injector = this._r3Injector; + !injector.destroyed && injector.destroy(); this.destroyCbs !.forEach(fn => fn()); this.destroyCbs = null; } diff --git a/packages/core/src/render3/node_assert.ts b/packages/core/src/render3/node_assert.ts index a6c6229e3e..dc3e6198f3 100644 --- a/packages/core/src/render3/node_assert.ts +++ b/packages/core/src/render3/node_assert.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {assertDefined, assertEqual} from './assert'; +import {assertDefined, assertEqual} from '../util/assert'; import {TNode, TNodeType} from './interfaces/node'; export function assertNodeType(tNode: TNode, type: TNodeType) { diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index efa5f1d50f..8c02f94fa8 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -6,51 +6,21 @@ * found in the LICENSE file at https://angular.io/license */ -import {assertDefined} from './assert'; +import {ViewEncapsulation} from '../metadata/view'; + import {attachPatchData} from './context_discovery'; import {callHooks} from './hooks'; -import {LContainer, NATIVE, RENDER_PARENT, VIEWS, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; +import {LContainer, NATIVE, VIEWS, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; +import {ComponentDef} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; -import {CLEANUP, CONTAINER_INDEX, FLAGS, HEADER_OFFSET, HOST_NODE, HookData, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; +import {CLEANUP, CONTAINER_INDEX, FLAGS, HEADER_OFFSET, HookData, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, T_HOST, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {assertNodeType} from './node_assert'; -import {findComponentView, getNativeByTNode, isLContainer, isRootView, readElementValue, stringify} from './util'; +import {findComponentView, getNativeByTNode, isComponent, isLContainer, isRootView, readElementValue, renderStringify} from './util'; const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5; -/** Retrieves the parent element of a given node. */ -export function getParentNative(tNode: TNode, currentView: LView): RElement|RComment|null { - if (tNode.parent == null) { - return getHostNative(currentView); - } else { - const parentTNode = getFirstParentNative(tNode); - return getNativeByTNode(parentTNode, currentView); - } -} - -/** - * Get the first parent of a node that isn't an IcuContainer TNode - */ -function getFirstParentNative(tNode: TNode): TNode { - let parent = tNode.parent; - while (parent && parent.type === TNodeType.IcuContainer) { - parent = parent.parent; - } - return parent !; -} - -/** - * Gets the host element given a view. Will return null if the current view is an embedded view, - * which does not have a host element. - */ -export function getHostNative(currentView: LView): RElement|null { - const hostTNode = currentView[HOST_NODE] as TElementNode; - return hostTNode && hostTNode.type !== TNodeType.View ? - (getNativeByTNode(hostTNode, currentView[PARENT] !) as RElement) : - null; -} - export function getLContainer(tNode: TViewNode, embeddedView: LView): LContainer|null { if (tNode.index === -1) { // This is a dynamically created view inside a dynamic container. @@ -68,9 +38,9 @@ export function getLContainer(tNode: TViewNode, embeddedView: LView): LContainer * Retrieves render parent for a given view. * Might be null if a view is not yet attached to any container. */ -export function getContainerRenderParent(tViewNode: TViewNode, view: LView): RElement|null { +function getContainerRenderParent(tViewNode: TViewNode, view: LView): RElement|null { const container = getLContainer(tViewNode, view); - return container ? container[RENDER_PARENT] : null; + return container ? nativeParentNode(view[RENDERER], container[NATIVE]) : null; } const enum WalkTNodeTreeAction { @@ -117,17 +87,16 @@ function walkTNodeTree( let nextTNode: TNode|null = null; if (tNode.type === TNodeType.Element) { executeNodeAction( - action, renderer, renderParent, getNativeByTNode(tNode, currentView), beforeNode); + action, renderer, renderParent, getNativeByTNode(tNode, currentView), tNode, beforeNode); const nodeOrContainer = currentView[tNode.index]; if (isLContainer(nodeOrContainer)) { // This element has an LContainer, and its comment needs to be handled - executeNodeAction(action, renderer, renderParent, nodeOrContainer[NATIVE], beforeNode); + executeNodeAction( + action, renderer, renderParent, nodeOrContainer[NATIVE], tNode, beforeNode); } } else if (tNode.type === TNodeType.Container) { const lContainer = currentView ![tNode.index] as LContainer; - executeNodeAction(action, renderer, renderParent, lContainer[NATIVE], beforeNode); - - if (renderParent) lContainer[RENDER_PARENT] = renderParent; + executeNodeAction(action, renderer, renderParent, lContainer[NATIVE], tNode, beforeNode); if (lContainer[VIEWS].length) { currentView = lContainer[VIEWS][0]; @@ -139,18 +108,26 @@ function walkTNodeTree( } } else if (tNode.type === TNodeType.Projection) { const componentView = findComponentView(currentView !); - const componentHost = componentView[HOST_NODE] as TElementNode; + const componentHost = componentView[T_HOST] as TElementNode; const head: TNode|null = (componentHost.projection as(TNode | null)[])[tNode.projection as number]; - // Must store both the TNode and the view because this projection node could be nested - // deeply inside embedded views, and we need to get back down to this particular nested view. - projectionNodeStack[++projectionNodeIndex] = tNode; - projectionNodeStack[++projectionNodeIndex] = currentView !; - if (head) { - currentView = componentView[PARENT] !; - nextTNode = currentView[TVIEW].data[head.index] as TNode; + if (Array.isArray(head)) { + for (let nativeNode of head) { + executeNodeAction(action, renderer, renderParent, nativeNode, tNode, beforeNode); + } + } else { + // Must store both the TNode and the view because this projection node could be nested + // deeply inside embedded views, and we need to get back down to this particular nested + // view. + projectionNodeStack[++projectionNodeIndex] = tNode; + projectionNodeStack[++projectionNodeIndex] = currentView !; + if (head) { + currentView = componentView[PARENT] !; + nextTNode = currentView[TVIEW].data[head.index] as TNode; + } } + } else { // Otherwise, this is a View or an ElementContainer nextTNode = tNode.child; @@ -173,7 +150,7 @@ function walkTNodeTree( */ while (!nextTNode) { // If parent is null, we're crossing the view boundary, so we should get the host TNode. - tNode = tNode.parent || currentView[TVIEW].node; + tNode = tNode.parent || currentView[T_HOST]; if (tNode === null || tNode === rootTNode) return null; @@ -183,9 +160,26 @@ function walkTNodeTree( beforeNode = currentView[tNode.index][NATIVE]; } - if (tNode.type === TNodeType.View && currentView[NEXT]) { - currentView = currentView[NEXT] as LView; - nextTNode = currentView[TVIEW].node; + if (tNode.type === TNodeType.View) { + /** + * If current lView doesn't have next pointer, we try to find it by going up parents + * chain until: + * - we find an lView with a next pointer + * - or find a tNode with a parent that has a next pointer + * - or reach root TNode (in which case we exit, since we traversed all nodes) + */ + while (!currentView[NEXT] && currentView[PARENT] && + !(tNode.parent && tNode.parent.next)) { + if (tNode === rootTNode) return null; + currentView = currentView[PARENT] as LView; + tNode = currentView[T_HOST] !; + } + if (currentView[NEXT]) { + currentView = currentView[NEXT] as LView; + nextTNode = currentView[T_HOST]; + } else { + nextTNode = tNode.next; + } } else { nextTNode = tNode.next; } @@ -201,15 +195,11 @@ function walkTNodeTree( */ function executeNodeAction( action: WalkTNodeTreeAction, renderer: Renderer3, parent: RElement | null, - node: RComment | RElement | RText, beforeNode?: RNode | null) { + node: RComment | RElement | RText, tNode: TNode, beforeNode?: RNode | null) { if (action === WalkTNodeTreeAction.Insert) { - isProceduralRenderer(renderer !) ? - (renderer as ProceduralRenderer3).insertBefore(parent !, node, beforeNode as RNode | null) : - parent !.insertBefore(node, beforeNode as RNode | null, true); + nativeInsertBefore(renderer, parent !, node, beforeNode || null); } else if (action === WalkTNodeTreeAction.Detach) { - isProceduralRenderer(renderer !) ? - (renderer as ProceduralRenderer3).removeChild(parent !, node) : - parent !.removeChild(node); + nativeRemoveNode(renderer, node, isComponent(tNode)); } else if (action === WalkTNodeTreeAction.Destroy) { ngDevMode && ngDevMode.rendererDestroyNode++; (renderer as ProceduralRenderer3).destroyNode !(node); @@ -217,8 +207,8 @@ function executeNodeAction( } export function createTextNode(value: any, renderer: Renderer3): RText { - return isProceduralRenderer(renderer) ? renderer.createText(stringify(value)) : - renderer.createTextNode(stringify(value)); + return isProceduralRenderer(renderer) ? renderer.createText(renderStringify(value)) : + renderer.createTextNode(renderStringify(value)); } /** @@ -350,19 +340,16 @@ export function insertView( * * @param lContainer The container from which to detach a view * @param removeIndex The index of the view to detach - * @param detached Whether or not this view is already detached. * @returns Detached LView instance. */ -export function detachView(lContainer: LContainer, removeIndex: number, detached: boolean): LView { +export function detachView(lContainer: LContainer, removeIndex: number): LView { const views = lContainer[VIEWS]; const viewToDetach = views[removeIndex]; if (removeIndex > 0) { views[removeIndex - 1][NEXT] = viewToDetach[NEXT] as LView; } views.splice(removeIndex, 1); - if (!detached) { - addRemoveViewFromContainer(viewToDetach, false); - } + addRemoveViewFromContainer(viewToDetach, false); if (viewToDetach[QUERIES]) { viewToDetach[QUERIES] !.removeView(); @@ -378,14 +365,11 @@ export function detachView(lContainer: LContainer, removeIndex: number, detached * Removes a view from a container, i.e. detaches it and then destroys the underlying LView. * * @param lContainer The container from which to remove a view - * @param tContainer The TContainer node associated with the LContainer * @param removeIndex The index of the view to remove */ -export function removeView( - lContainer: LContainer, containerHost: TElementNode | TContainerNode | TElementContainerNode, - removeIndex: number) { +export function removeView(lContainer: LContainer, removeIndex: number) { const view = lContainer[VIEWS][removeIndex]; - detachView(lContainer, removeIndex, !!containerHost.detached); + detachView(lContainer, removeIndex); destroyLView(view); } @@ -402,13 +386,14 @@ export function getLViewChild(lView: LView): LView|LContainer|null { * @param view The view to be destroyed. */ export function destroyLView(view: LView) { - const renderer = view[RENDERER]; - if (isProceduralRenderer(renderer) && renderer.destroyNode) { - walkTNodeTree(view, WalkTNodeTreeAction.Destroy, renderer, null); + if (!(view[FLAGS] & LViewFlags.Destroyed)) { + const renderer = view[RENDERER]; + if (isProceduralRenderer(renderer) && renderer.destroyNode) { + walkTNodeTree(view, WalkTNodeTreeAction.Destroy, renderer, null); + } + + destroyViewTree(view); } - destroyViewTree(view); - // Sets the destroyed flag - view[FLAGS] |= LViewFlags.Destroyed; } /** @@ -425,7 +410,7 @@ export function destroyLView(view: LView) { */ export function getParentState(state: LView | LContainer, rootView: LView): LView|LContainer|null { let tNode; - if (state.length >= HEADER_OFFSET && (tNode = (state as LView) ![HOST_NODE]) && + if (state.length >= HEADER_OFFSET && (tNode = (state as LView) ![T_HOST]) && tNode.type === TNodeType.View) { // if it's an embedded view, the state needs to go up to the container, in case the // container has a next @@ -446,10 +431,17 @@ export function getParentState(state: LView | LContainer, rootView: LView): LVie function cleanUpView(viewOrContainer: LView | LContainer): void { if ((viewOrContainer as LView).length >= HEADER_OFFSET) { const view = viewOrContainer as LView; + + // Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook + // runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If + // We don't flag the view as destroyed before the hooks, this could lead to an infinite loop. + // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is + // really more of an "afterDestroy" hook if you think about it. + view[FLAGS] |= LViewFlags.Destroyed; + executeOnDestroys(view); - executePipeOnDestroys(view); removeListeners(view); - const hostTNode = view[HOST_NODE]; + const hostTNode = view[T_HOST]; // For component views only, the local renderer is destroyed as clean up time. if (hostTNode && hostTNode.type === TNodeType.Element && isProceduralRenderer(view[RENDERER])) { ngDevMode && ngDevMode.rendererDestroy++; @@ -466,13 +458,15 @@ function removeListeners(lView: LView): void { for (let i = 0; i < tCleanup.length - 1; i += 2) { if (typeof tCleanup[i] === 'string') { // This is a listener with the native renderer - const idx = tCleanup[i + 1]; + const idxOrTargetGetter = tCleanup[i + 1]; + const target = typeof idxOrTargetGetter === 'function' ? + idxOrTargetGetter(lView) : + readElementValue(lView[idxOrTargetGetter]); const listener = lCleanup[tCleanup[i + 2]]; - const native = readElementValue(lView[idx]); const useCaptureOrSubIdx = tCleanup[i + 3]; if (typeof useCaptureOrSubIdx === 'boolean') { // DOM listener - native.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx); + target.removeEventListener(tCleanup[i], listener, useCaptureOrSubIdx); } else { if (useCaptureOrSubIdx >= 0) { // unregister @@ -506,81 +500,8 @@ function executeOnDestroys(view: LView): void { } } -/** Calls pipe destroy hooks for this view */ -function executePipeOnDestroys(lView: LView): void { - const pipeDestroyHooks = lView[TVIEW] && lView[TVIEW].pipeDestroyHooks; - if (pipeDestroyHooks) { - callHooks(lView !, pipeDestroyHooks); - } -} - -export function getRenderParent(tNode: TNode, currentView: LView): RElement|null { - if (canInsertNativeNode(tNode, currentView)) { - // If we are asked for a render parent of the root component we need to do low-level DOM - // operation as LTree doesn't exist above the topmost host node. We might need to find a render - // parent of the topmost host node if the root component injects ViewContainerRef. - if (isRootView(currentView)) { - return nativeParentNode(currentView[RENDERER], getNativeByTNode(tNode, currentView)); - } - - const hostTNode = currentView[HOST_NODE]; - - const tNodeParent = tNode.parent; - if (tNodeParent != null && tNodeParent.type === TNodeType.ElementContainer) { - tNode = getHighestElementContainer(tNodeParent); - } - - return tNode.parent == null && hostTNode !.type === TNodeType.View ? - getContainerRenderParent(hostTNode as TViewNode, currentView) : - getParentNative(tNode, currentView) as RElement; - } - return null; -} - -function canInsertNativeChildOfElement(tNode: TNode): boolean { - // If the parent is null, then we are inserting across views. This happens when we - // insert a root element of the component view into the component host element and it - // should always be eager. - if (tNode.parent == null || - // We should also eagerly insert if the parent is a regular, non-component element - // since we know that this relationship will never be broken. - tNode.parent.type === TNodeType.Element && !(tNode.parent.flags & TNodeFlags.isComponent)) { - return true; - } - - // Parent is a Component. Component's content nodes are not inserted immediately - // because they will be projected, and so doing insert at this point would be wasteful. - // Since the projection would than move it to its final destination. - return false; -} - /** - * We might delay insertion of children for a given view if it is disconnected. - * This might happen for 2 main reasons: - * - view is not inserted into any container (view was created but not inserted yet) - * - view is inserted into a container but the container itself is not inserted into the DOM - * (container might be part of projection or child of a view that is not inserted yet). - * - * In other words we can insert children of a given view if this view was inserted into a container - * and - * the container itself has its render parent determined. - */ -function canInsertNativeChildOfView(viewTNode: TViewNode, view: LView): boolean { - // Because we are inserting into a `View` the `View` may be disconnected. - const container = getLContainer(viewTNode, view) !; - if (container == null || container[RENDER_PARENT] == null) { - // The `View` is not inserted into a `Container` or the parent `Container` - // itself is disconnected. So we have to delay. - return false; - } - - // The parent `Container` is in inserted state, so we can eagerly insert into - // this location. - return true; -} - -/** - * Returns whether a native element can be inserted into the given parent. + * Returns a native element if a node can be inserted into the given parent. * * There are two reasons why we may not be able to insert a element immediately. * - Projection: When creating a child content element of a component, we have to skip the @@ -588,38 +509,71 @@ function canInsertNativeChildOfView(viewTNode: TViewNode, view: LView): boolean * `delayed due to projection` * - Parent container is disconnected: This can happen when we are inserting a view into * parent container, which itself is disconnected. For example the parent container is part - * of a View which has not be inserted or is mare for projection but has not been inserted + * of a View which has not be inserted or is made for projection but has not been inserted * into destination. - * - - * - * @param tNode The tNode of the node that we want to insert. - * @param currentView Current LView being processed. - * @return boolean Whether the node should be inserted now (or delayed until later). */ -export function canInsertNativeNode(tNode: TNode, currentView: LView): boolean { - let currentNode = tNode; - let parent: TNode|null = tNode.parent; +function getRenderParent(tNode: TNode, currentView: LView): RElement|null { + // Nodes of the top-most view can be inserted eagerly. + if (isRootView(currentView)) { + return nativeParentNode(currentView[RENDERER], getNativeByTNode(tNode, currentView)); + } - if (tNode.parent) { - if (tNode.parent.type === TNodeType.ElementContainer) { - currentNode = getHighestElementContainer(tNode); - parent = currentNode.parent; - } else if (tNode.parent.type === TNodeType.IcuContainer) { - currentNode = getFirstParentNative(currentNode); - parent = currentNode.parent; + // Skip over element and ICU containers as those are represented by a comment node and + // can't be used as a render parent. + const parent = getHighestElementOrICUContainer(tNode).parent; + + // If the parent is null, then we are inserting across views: either into an embedded view or a + // component view. + if (parent == null) { + const hostTNode = currentView[T_HOST] !; + if (hostTNode.type === TNodeType.View) { + // We are inserting a root element of an embedded view We might delay insertion of children + // for a given view if it is disconnected. This might happen for 2 main reasons: + // - view is not inserted into any container(view was created but not inserted yet) + // - view is inserted into a container but the container itself is not inserted into the DOM + // (container might be part of projection or child of a view that is not inserted yet). + // In other words we can insert children of a given view if this view was inserted into a + // container and the container itself has its render parent determined. + return getContainerRenderParent(hostTNode as TViewNode, currentView); + } else { + // We are inserting a root element of the component view into the component host element and + // it should always be eager. + return getHostNative(currentView); } - } - if (parent === null) parent = currentView[HOST_NODE]; - - if (parent && parent.type === TNodeType.View) { - return canInsertNativeChildOfView(parent as TViewNode, currentView); } else { - // Parent is a regular element or a component - return canInsertNativeChildOfElement(currentNode); + ngDevMode && assertNodeType(parent, TNodeType.Element); + if (parent.flags & TNodeFlags.isComponent) { + const tData = currentView[TVIEW].data; + const tNode = tData[parent.index] as TNode; + const encapsulation = (tData[tNode.directiveStart] as ComponentDef).encapsulation; + + // We've got a parent which is an element in the current view. We just need to verify if the + // parent element is not a component. Component's content nodes are not inserted immediately + // because they will be projected, and so doing insert at this point would be wasteful. + // Since the projection would then move it to its final destination. Note that we can't + // make this assumption when using the Shadow DOM, because the native projection placeholders + // ( or ) have to be in place as elements are being inserted. + if (encapsulation !== ViewEncapsulation.ShadowDom && + encapsulation !== ViewEncapsulation.Native) { + return null; + } + } + + return getNativeByTNode(parent, currentView) as RElement; } } +/** + * Gets the native host element for a given view. Will return null if the current view does not have + * a host element. + */ +function getHostNative(currentView: LView): RElement|null { + const hostTNode = currentView[T_HOST]; + return hostTNode && hostTNode.type === TNodeType.Element ? + (getNativeByTNode(hostTNode, currentView[PARENT] !) as RElement) : + null; +} + /** * Inserts a native node before another native node for a given parent using {@link Renderer3}. * This is a utility function that can be used when native nodes were determined - it abstracts an @@ -634,6 +588,33 @@ export function nativeInsertBefore( } } +function nativeAppendChild(renderer: Renderer3, parent: RElement, child: RNode): void { + if (isProceduralRenderer(renderer)) { + renderer.appendChild(parent, child); + } else { + parent.appendChild(child); + } +} + +function nativeAppendOrInsertBefore( + renderer: Renderer3, parent: RElement, child: RNode, beforeNode: RNode | null) { + if (beforeNode) { + nativeInsertBefore(renderer, parent, child, beforeNode); + } else { + nativeAppendChild(renderer, parent, child); + } +} + +/** Removes a node from the DOM given its native parent. */ +function nativeRemoveChild( + renderer: Renderer3, parent: RElement, child: RNode, isHostElement?: boolean): void { + if (isProceduralRenderer(renderer)) { + renderer.removeChild(parent, child, isHostElement); + } else { + parent.removeChild(child); + } +} + /** * Returns a native parent of a given native node. */ @@ -649,61 +630,69 @@ export function nativeNextSibling(renderer: Renderer3, node: RNode): RNode|null } /** - * Appends the `child` element to the `parent`. + * Finds a native "anchor" node for cases where we can't append a native child directly + * (`appendChild`) and need to use a reference (anchor) node for the `insertBefore` operation. + * @param parentTNode + * @param lView + */ +function getNativeAnchorNode(parentTNode: TNode, lView: LView): RNode|null { + if (parentTNode.type === TNodeType.View) { + const lContainer = getLContainer(parentTNode as TViewNode, lView) !; + const views = lContainer[VIEWS]; + const index = views.indexOf(lView); + return getBeforeNodeForView(index, views, lContainer[NATIVE]); + } else if ( + parentTNode.type === TNodeType.ElementContainer || + parentTNode.type === TNodeType.IcuContainer) { + return getNativeByTNode(parentTNode, lView); + } + return null; +} + +/** + * Appends the `child` native node (or a collection of nodes) to the `parent`. * * The element insertion might be delayed {@link canInsertNativeNode}. * - * @param childEl The child that should be appended + * @param childEl The native child (or children) that should be appended * @param childTNode The TNode of the child element * @param currentView The current LView * @returns Whether or not the child was appended */ -export function appendChild( - childEl: RNode | null = null, childTNode: TNode, currentView: LView): boolean { - if (childEl !== null && canInsertNativeNode(childTNode, currentView)) { +export function appendChild(childEl: RNode | RNode[], childTNode: TNode, currentView: LView): void { + const renderParent = getRenderParent(childTNode, currentView); + if (renderParent != null) { const renderer = currentView[RENDERER]; - const parentEl = getParentNative(childTNode, currentView); - const parentTNode: TNode = childTNode.parent || currentView[HOST_NODE] !; - - if (parentTNode.type === TNodeType.View) { - const lContainer = getLContainer(parentTNode as TViewNode, currentView) as LContainer; - const views = lContainer[VIEWS]; - const index = views.indexOf(currentView); - nativeInsertBefore( - renderer, lContainer[RENDER_PARENT] !, childEl, - getBeforeNodeForView(index, views, lContainer[NATIVE])); - } else if (parentTNode.type === TNodeType.ElementContainer) { - const renderParent = getRenderParent(childTNode, currentView) !; - nativeInsertBefore(renderer, renderParent, childEl, parentEl); - } else if (parentTNode.type === TNodeType.IcuContainer) { - const icuAnchorNode = getNativeByTNode(childTNode.parent !, currentView) !as RElement; - nativeInsertBefore(renderer, parentEl as RElement, childEl, icuAnchorNode); + const parentTNode: TNode = childTNode.parent || currentView[T_HOST] !; + const anchorNode = getNativeAnchorNode(parentTNode, currentView); + if (Array.isArray(childEl)) { + for (let nativeNode of childEl) { + nativeAppendOrInsertBefore(renderer, renderParent, nativeNode, anchorNode); + } } else { - isProceduralRenderer(renderer) ? renderer.appendChild(parentEl !as RElement, childEl) : - parentEl !.appendChild(childEl); + nativeAppendOrInsertBefore(renderer, renderParent, childEl, anchorNode); } - return true; } - return false; } /** - * Gets the top-level ng-container if ng-containers are nested. + * Gets the top-level element or an ICU container if those containers are nested. * - * @param ngContainer The TNode of the starting ng-container - * @returns tNode The TNode of the highest level ng-container + * @param tNode The starting TNode for which we should skip element and ICU containers + * @returns The TNode of the highest level ICU container or element container */ -function getHighestElementContainer(ngContainer: TNode): TNode { - while (ngContainer.parent != null && ngContainer.parent.type === TNodeType.ElementContainer) { - ngContainer = ngContainer.parent; +function getHighestElementOrICUContainer(tNode: TNode): TNode { + while (tNode.parent != null && (tNode.parent.type === TNodeType.ElementContainer || + tNode.parent.type === TNodeType.IcuContainer)) { + tNode = tNode.parent; } - return ngContainer; + return tNode; } export function getBeforeNodeForView(index: number, views: LView[], containerNative: RComment) { if (index + 1 < views.length) { const view = views[index + 1] as LView; - const viewTNode = view[HOST_NODE] as TViewNode; + const viewTNode = view[T_HOST] as TViewNode; return viewTNode.child ? getNativeByTNode(viewTNode.child, view) : containerNative; } else { return containerNative; @@ -711,23 +700,19 @@ export function getBeforeNodeForView(index: number, views: LView[], containerNat } /** - * Removes the `child` element from the DOM if not in view and not projected. + * Removes a native node itself using a given renderer. To remove the node we are looking up its + * parent from the native tree as not all platforms / browsers support the equivalent of + * node.remove(). * - * @param childTNode The TNode of the child to remove - * @param childEl The child that should be removed - * @param currentView The current LView - * @returns Whether or not the child was removed + * @param renderer A renderer to be used + * @param rNode The native node that should be removed + * @param isHostElement A flag indicating if a node to be removed is a host of a component. */ -export function removeChild(childTNode: TNode, childEl: RNode | null, currentView: LView): boolean { - // We only remove the element if not in View or not projected. - if (childEl !== null && canInsertNativeNode(childTNode, currentView)) { - const parentNative = getParentNative(childTNode, currentView) !as RElement; - const renderer = currentView[RENDERER]; - isProceduralRenderer(renderer) ? renderer.removeChild(parentNative as RElement, childEl) : - parentNative !.removeChild(childEl); - return true; +export function nativeRemoveNode(renderer: Renderer3, rNode: RNode, isHostElement?: boolean): void { + const nativeParent = nativeParentNode(renderer, rNode); + if (nativeParent) { + nativeRemoveChild(renderer, nativeParent, rNode, isHostElement); } - return false; } /** @@ -750,8 +735,6 @@ export function appendProjectedNode( // logical container of the content projected views attachPatchData(native, projectionView); - const renderParent = getRenderParent(tProjectionNode, currentView); - const nodeOrContainer = projectionView[projectedTNode.index]; if (projectedTNode.type === TNodeType.Container) { // The node we are adding is a container and we are adding it to an element which @@ -759,7 +742,6 @@ export function appendProjectedNode( // Alternatively a container is projected at the root of a component's template // and can't be re-projected (as not content of any component). // Assign the final projection location in those cases. - nodeOrContainer[RENDER_PARENT] = renderParent; const views = nodeOrContainer[VIEWS]; for (let i = 0; i < views.length; i++) { addRemoveViewFromContainer(views[i], true, nodeOrContainer[NATIVE]); @@ -774,7 +756,6 @@ export function appendProjectedNode( } if (isLContainer(nodeOrContainer)) { - nodeOrContainer[RENDER_PARENT] = renderParent; appendChild(nodeOrContainer[NATIVE], tProjectionNode, currentView); } } diff --git a/packages/core/src/render3/node_selector_matcher.ts b/packages/core/src/render3/node_selector_matcher.ts index ed56726ec4..9fcc32cfa7 100644 --- a/packages/core/src/render3/node_selector_matcher.ts +++ b/packages/core/src/render3/node_selector_matcher.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import './ng_dev_mode'; +import '../util/ng_dev_mode'; -import {assertDefined, assertNotEqual} from './assert'; +import {assertDefined, assertNotEqual} from '../util/assert'; import {AttributeMarker, TAttributes, TNode, TNodeType, unusedValueExportToPlacateAjd as unused1} from './interfaces/node'; import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection'; +import {getInitialClassNameValue} from './styling/class_and_style_bindings'; const unusedValueToPlacateAjd = unused1 + unused2; @@ -58,7 +59,6 @@ function hasTagAndTypeMatch( export function isNodeMatchingSelector( tNode: TNode, selector: CssSelector, isProjectionMode: boolean): boolean { ngDevMode && assertDefined(selector[0], 'Selector should have a tag name'); - let mode: SelectorFlags = SelectorFlags.ELEMENT; const nodeAttrs = tNode.attrs !; const selectOnlyMarkerIdx = nodeAttrs ? nodeAttrs.indexOf(AttributeMarker.SelectOnly) : -1; @@ -92,7 +92,19 @@ export function isNodeMatchingSelector( skipToNextSelector = true; } } else { - const attrName = mode & SelectorFlags.CLASS ? 'class' : current; + const selectorAttrValue = mode & SelectorFlags.CLASS ? current : selector[++i]; + + // special case for matching against classes when a tNode has been instantiated with + // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo']) + if ((mode & SelectorFlags.CLASS) && tNode.stylingTemplate) { + if (!isCssClassMatching(readClassValueFromTNode(tNode), selectorAttrValue as string)) { + if (isPositive(mode)) return false; + skipToNextSelector = true; + } + continue; + } + + const attrName = (mode & SelectorFlags.CLASS) ? 'class' : current; const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs); if (attrIndexInNode === -1) { @@ -101,7 +113,6 @@ export function isNodeMatchingSelector( continue; } - const selectorAttrValue = mode & SelectorFlags.CLASS ? current : selector[++i]; if (selectorAttrValue !== '') { let nodeAttrValue: string; const maybeAttrName = nodeAttrs[attrIndexInNode]; @@ -113,8 +124,10 @@ export function isNodeMatchingSelector( 'We do not match directives on namespaced attributes'); nodeAttrValue = nodeAttrs[attrIndexInNode + 1] as string; } - if (mode & SelectorFlags.CLASS && - !isCssClassMatching(nodeAttrValue as string, selectorAttrValue as string) || + + const compareAgainstClassName = mode & SelectorFlags.CLASS ? nodeAttrValue : null; + if (compareAgainstClassName && + !isCssClassMatching(compareAgainstClassName, selectorAttrValue as string) || mode & SelectorFlags.ATTRIBUTE && selectorAttrValue !== nodeAttrValue) { if (isPositive(mode)) return false; skipToNextSelector = true; @@ -130,6 +143,16 @@ function isPositive(mode: SelectorFlags): boolean { return (mode & SelectorFlags.NOT) === 0; } +function readClassValueFromTNode(tNode: TNode): string { + // comparing against CSS class values is complex because the compiler doesn't place them as + // regular attributes when an element is created. Instead, the classes (and styles for + // that matter) are placed in a special styling context that is used for resolving all + // class/style values across static attributes, [style]/[class] and [style.prop]/[class.name] + // bindings. Therefore if and when the styling context exists then the class values are to be + // extracted by the context helper code below... + return tNode.stylingTemplate ? getInitialClassNameValue(tNode.stylingTemplate) : ''; +} + /** * Examines an attributes definition array from a node to find the index of the * attribute with the specified name. diff --git a/packages/core/src/render3/pipe.ts b/packages/core/src/render3/pipe.ts index 435cd012d6..f06dc839ce 100644 --- a/packages/core/src/render3/pipe.ts +++ b/packages/core/src/render3/pipe.ts @@ -11,9 +11,9 @@ import {PipeTransform} from '../change_detection/pipe_transform'; import {load, store} from './instructions'; import {PipeDef, PipeDefList} from './interfaces/definition'; -import {HEADER_OFFSET, TVIEW} from './interfaces/view'; +import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view'; import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunctionV} from './pure_function'; -import {getBindingRoot, getLView} from './state'; +import {getLView} from './state'; import {NO_CHANGE} from './tokens'; @@ -33,8 +33,7 @@ export function pipe(index: number, pipeName: string): any { pipeDef = getPipeDef(pipeName, tView.pipeRegistry); tView.data[adjustedIndex] = pipeDef; if (pipeDef.onDestroy) { - (tView.pipeDestroyHooks || (tView.pipeDestroyHooks = [ - ])).push(adjustedIndex, pipeDef.onDestroy); + (tView.destroyHooks || (tView.destroyHooks = [])).push(adjustedIndex, pipeDef.onDestroy); } } else { pipeDef = tView.data[adjustedIndex] as PipeDef; @@ -55,7 +54,7 @@ export function pipe(index: number, pipeName: string): any { */ function getPipeDef(name: string, registry: PipeDefList | null): PipeDef { if (registry) { - for (let i = 0; i < registry.length; i++) { + for (let i = registry.length - 1; i >= 0; i--) { const pipeDef = registry[i]; if (name === pipeDef.name) { return pipeDef; @@ -172,7 +171,11 @@ function isPure(index: number): boolean { function unwrapValue(newValue: any): any { if (WrappedValue.isWrapped(newValue)) { newValue = WrappedValue.unwrap(newValue); - getLView()[getBindingRoot()] = NO_CHANGE; + const lView = getLView(); + // The NO_CHANGE value needs to be written at the index where the impacted binding value is + // stored + const bindingToInvalidateIdx = lView[BINDING_INDEX]; + lView[bindingToInvalidateIdx] = NO_CHANGE; } return newValue; } diff --git a/packages/core/src/render3/players.ts b/packages/core/src/render3/players.ts index b703ac1baa..438b24cb5e 100644 --- a/packages/core/src/render3/players.ts +++ b/packages/core/src/render3/players.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import './ng_dev_mode'; +import '../util/ng_dev_mode'; import {getLContext} from './context_discovery'; import {getRootContext} from './discovery_utils'; diff --git a/packages/core/src/render3/query.ts b/packages/core/src/render3/query.ts index 4066f151a2..59e305e41c 100644 --- a/packages/core/src/render3/query.ts +++ b/packages/core/src/render3/query.ts @@ -8,26 +8,23 @@ // We are temporarily importing the existing viewEngine_from core so we can be sure we are // correctly implementing its interfaces for backwards compatibility. -import {Observable} from 'rxjs'; -import {EventEmitter} from '../event_emitter'; +import {Type} from '../interface/type'; import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref'; -import {QueryList as viewEngine_QueryList} from '../linker/query_list'; +import {QueryList} from '../linker/query_list'; import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref'; -import {Type} from '../type'; -import {getSymbolIterator} from '../util'; +import {assertDataInRange, assertDefined, assertEqual} from '../util/assert'; -import {assertDefined, assertEqual, assertPreviousIsParent} from './assert'; +import {assertPreviousIsParent} from './assert'; import {getNodeInjectable, locateDirectiveOrProvider} from './di'; import {NG_ELEMENT_ID} from './fields'; -import {store, storeCleanupWithContext} from './instructions'; +import {load, store, storeCleanupWithContext} from './instructions'; import {unusedValueExportToPlacateAjd as unused1} from './interfaces/definition'; import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector'; import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node'; import {LQueries, unusedValueExportToPlacateAjd as unused4} from './interfaces/query'; -import {LView, TVIEW} from './interfaces/view'; -import {getIsParent, getLView, getOrCreateCurrentQueries} from './state'; -import {flatten, isContentQueryHost} from './util'; +import {CONTENT_QUERIES, HEADER_OFFSET, LView, QUERIES, TVIEW} from './interfaces/view'; +import {getCurrentQueryIndex, getIsParent, getLView, setCurrentQueryIndex} from './state'; import {createElementRef, createTemplateRef} from './view_engine_compatibility'; const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4; @@ -95,9 +92,8 @@ export class LQueries_ implements LQueries { public parent: LQueries_|null, private shallow: LQuery|null, private deep: LQuery|null) {} - track( - queryList: viewEngine_QueryList, predicate: Type|string[], descend?: boolean, - read?: Type): void { + track(queryList: QueryList, predicate: Type|string[], descend?: boolean, read?: Type): + void { if (descend) { this.deep = createQuery(this.deep, queryList, predicate, read != null ? read : null); } else { @@ -110,7 +106,6 @@ export class LQueries_ implements LQueries { container(): LQueries|null { const shallowResults = copyQueriesToContainer(this.shallow); const deepResults = copyQueriesToContainer(this.deep); - return shallowResults || deepResults ? new LQueries_(this, shallowResults, deepResults) : null; } @@ -126,22 +121,9 @@ export class LQueries_ implements LQueries { insertView(index, this.deep); } - addNode(tNode: TElementNode|TContainerNode|TElementContainerNode): LQueries|null { + addNode(tNode: TElementNode|TContainerNode|TElementContainerNode): void { add(this.deep, tNode); - - if (isContentQueryHost(tNode)) { - add(this.shallow, tNode); - - if (tNode.parent && isContentQueryHost(tNode.parent)) { - // if node has a content query and parent also has a content query - // both queries need to check this node for shallow matches - add(this.parent !.shallow, tNode); - } - return this.parent; - } - - isRootNodeOfQuery(tNode) && add(this.shallow, tNode); - return this; + add(this.shallow, tNode); } removeView(): void { @@ -150,10 +132,6 @@ export class LQueries_ implements LQueries { } } -function isRootNodeOfQuery(tNode: TNode) { - return tNode.parent === null || isContentQueryHost(tNode.parent); -} - function copyQueriesToContainer(query: LQuery| null): LQuery|null { let result: LQuery|null = null; @@ -194,19 +172,21 @@ function copyQueriesToView(query: LQuery| null): LQuery|null { function insertView(index: number, query: LQuery| null) { while (query) { - ngDevMode && - assertDefined( - query.containerValues, 'View queries need to have a pointer to container values.'); + ngDevMode && assertViewQueryhasPointerToDeclarationContainer(query); query.containerValues !.splice(index, 0, query.values); + + // mark a query as dirty only when inserted view had matching modes + if (query.values.length) { + query.list.setDirty(); + } + query = query.next; } } function removeView(query: LQuery| null) { while (query) { - ngDevMode && - assertDefined( - query.containerValues, 'View queries need to have a pointer to container values.'); + ngDevMode && assertViewQueryhasPointerToDeclarationContainer(query); const containerValues = query.containerValues !; const viewValuesIdx = containerValues.indexOf(query.values); @@ -222,6 +202,9 @@ function removeView(query: LQuery| null) { } } +function assertViewQueryhasPointerToDeclarationContainer(query: LQuery) { + assertDefined(query.containerValues, 'View queries need to have a pointer to container values.'); +} /** * Iterates over local names for a given node and returns directive index @@ -355,115 +338,26 @@ function createQuery( }; } -class QueryList_/* implements viewEngine_QueryList */ { - readonly dirty = true; - readonly changes: Observable = new EventEmitter(); - private _values: T[] = []; - /** @internal */ - _valuesTree: any[] = []; - - get length(): number { return this._values.length; } - - get first(): T|null { - let values = this._values; - return values.length ? values[0] : null; - } - - get last(): T|null { - let values = this._values; - return values.length ? values[values.length - 1] : null; - } - - /** - * See - * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) - */ - map(fn: (item: T, index: number, array: T[]) => U): U[] { return this._values.map(fn); } - - /** - * See - * [Array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) - */ - filter(fn: (item: T, index: number, array: T[]) => boolean): T[] { - return this._values.filter(fn); - } - - /** - * See - * [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) - */ - find(fn: (item: T, index: number, array: T[]) => boolean): T|undefined { - return this._values.find(fn); - } - - /** - * See - * [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) - */ - reduce(fn: (prevValue: U, curValue: T, curIndex: number, array: T[]) => U, init: U): U { - return this._values.reduce(fn, init); - } - - /** - * See - * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) - */ - forEach(fn: (item: T, index: number, array: T[]) => void): void { this._values.forEach(fn); } - - /** - * See - * [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) - */ - some(fn: (value: T, index: number, array: T[]) => boolean): boolean { - return this._values.some(fn); - } - - toArray(): T[] { return this._values.slice(0); } - - [getSymbolIterator()](): Iterator { return (this._values as any)[getSymbolIterator()](); } - - toString(): string { return this._values.toString(); } - - reset(res: (any[]|T)[]): void { - this._values = flatten(res); - (this as{dirty: boolean}).dirty = false; - } - - notifyOnChanges(): void { (this.changes as EventEmitter).emit(this); } - setDirty(): void { (this as{dirty: boolean}).dirty = true; } - destroy(): void { - (this.changes as EventEmitter).complete(); - (this.changes as EventEmitter).unsubscribe(); - } -} - -// NOTE: this hack is here because IQueryList has private members and therefore -// it can't be implemented only extended. -export type QueryList = viewEngine_QueryList; -export const QueryList: typeof viewEngine_QueryList = QueryList_ as any; +type QueryList_ = QueryList& {_valuesTree: any[]}; /** * Creates and returns a QueryList. * - * @param memoryIndex The index in memory where the QueryList should be saved. If null, - * this is is a content query and the QueryList will be saved later through directiveCreate. * @param predicate The type for which the query will search * @param descend Whether or not to descend into children * @param read What to save in the query * @returns QueryList */ export function query( - memoryIndex: number | null, predicate: Type| string[], descend?: boolean, // TODO: "read" should be an AbstractType (FW-486) - read?: any): QueryList { + predicate: Type| string[], descend?: boolean, read?: any): QueryList { ngDevMode && assertPreviousIsParent(getIsParent()); + const lView = getLView(); const queryList = new QueryList(); - const queries = getOrCreateCurrentQueries(LQueries_); + const queries = lView[QUERIES] || (lView[QUERIES] = new LQueries_(null, null, null)); + (queryList as QueryList_)._valuesTree = []; queries.track(queryList, predicate, descend, read); - storeCleanupWithContext(getLView(), queryList, queryList.destroy); - if (memoryIndex != null) { - store(memoryIndex, queryList); - } + storeCleanupWithContext(lView, queryList, queryList.destroy); return queryList; } @@ -475,9 +369,83 @@ export function query( export function queryRefresh(queryList: QueryList): boolean { const queryListImpl = (queryList as any as QueryList_); if (queryList.dirty) { - queryList.reset(queryListImpl._valuesTree); + queryList.reset(queryListImpl._valuesTree || []); queryList.notifyOnChanges(); return true; } return false; } + +/** + * Creates new QueryList, stores the reference in LView and returns QueryList. + * + * @param predicate The type for which the query will search + * @param descend Whether or not to descend into children + * @param read What to save in the query + * @returns QueryList + */ +export function viewQuery( + // TODO: "read" should be an AbstractType (FW-486) + predicate: Type| string[], descend?: boolean, read?: any): QueryList { + const lView = getLView(); + const tView = lView[TVIEW]; + if (tView.firstTemplatePass) { + tView.expandoStartIndex++; + } + const index = getCurrentQueryIndex(); + const viewQuery: QueryList = query(predicate, descend, read); + store(index - HEADER_OFFSET, viewQuery); + setCurrentQueryIndex(index + 1); + return viewQuery; +} + +/** +* Loads current View Query and moves the pointer/index to the next View Query in LView. +*/ +export function loadViewQuery(): T { + const index = getCurrentQueryIndex(); + setCurrentQueryIndex(index + 1); + return load(index - HEADER_OFFSET); +} + +/** + * Registers a QueryList, associated with a content query, for later refresh (part of a view + * refresh). + * + * @param directiveIndex Current directive index + * @param predicate The type for which the query will search + * @param descend Whether or not to descend into children + * @param read What to save in the query + * @returns QueryList + */ +export function contentQuery( + directiveIndex: number, predicate: Type| string[], descend?: boolean, + // TODO: "read" should be an AbstractType (FW-486) + read?: any): QueryList { + const lView = getLView(); + const tView = lView[TVIEW]; + const contentQuery: QueryList = query(predicate, descend, read); + (lView[CONTENT_QUERIES] || (lView[CONTENT_QUERIES] = [])).push(contentQuery); + if (tView.firstTemplatePass) { + const tViewContentQueries = tView.contentQueries || (tView.contentQueries = []); + const lastSavedDirectiveIndex = + tView.contentQueries.length ? tView.contentQueries[tView.contentQueries.length - 1] : -1; + if (directiveIndex !== lastSavedDirectiveIndex) { + tViewContentQueries.push(directiveIndex); + } + } + return contentQuery; +} + +export function loadContentQuery(): QueryList { + const lView = getLView(); + ngDevMode && + assertDefined( + lView[CONTENT_QUERIES], 'Content QueryList array should be defined if reading a query.'); + + const index = getCurrentQueryIndex(); + ngDevMode && assertDataInRange(lView[CONTENT_QUERIES] !, index); + + setCurrentQueryIndex(index + 1); + return lView[CONTENT_QUERIES] ![index]; +} \ No newline at end of file diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index 69185a2340..8e4b292b1a 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -6,14 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {assertDefined} from './assert'; +import {assertDefined} from '../util/assert'; + import {executeHooks} from './hooks'; import {ComponentDef, DirectiveDef} from './interfaces/definition'; -import {TElementNode, TNode, TNodeFlags, TViewNode} from './interfaces/node'; -import {LQueries} from './interfaces/query'; -import {BINDING_INDEX, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LView, LViewFlags, OpaqueViewState, QUERIES, TVIEW} from './interfaces/view'; -import {isContentQueryHost} from './util'; - +import {TElementNode, TNode, TViewNode} from './interfaces/node'; +import {BINDING_INDEX, CONTEXT, DECLARATION_VIEW, FLAGS, InitPhaseState, LView, LViewFlags, OpaqueViewState, TVIEW} from './interfaces/view'; /** @@ -164,27 +162,6 @@ export function setIsParent(value: boolean): void { isParent = value; } -/** - * Query instructions can ask for "current queries" in 2 different cases: - * - when creating view queries (at the root of a component view, before any node is created - in - * this case currentQueries points to view queries) - * - when creating content queries (i.e. this previousOrParentTNode points to a node on which we - * create content queries). - */ -export function getOrCreateCurrentQueries( - QueryType: {new (parent: null, shallow: null, deep: null): LQueries}): LQueries { - const lView = getLView(); - let currentQueries = lView[QUERIES]; - // if this is the first content query on a node, any existing LQueries needs to be cloned - // in subsequent template passes, the cloning occurs before directive instantiation. - if (previousOrParentTNode && previousOrParentTNode !== lView[HOST_NODE] && - !isContentQueryHost(previousOrParentTNode)) { - currentQueries && (currentQueries = lView[QUERIES] = currentQueries.clone()); - previousOrParentTNode.flags |= TNodeFlags.hasContentQuery; - } - - return currentQueries || (lView[QUERIES] = new QueryType(null, null, null)); -} /** Checks whether a given view is in creation mode */ export function isCreationMode(view: LView = lView): boolean { @@ -228,17 +205,6 @@ export function setCheckNoChangesMode(mode: boolean): void { checkNoChangesMode = mode; } -/** Whether or not this is the first time the current view has been processed. */ -let firstTemplatePass = true; - -export function getFirstTemplatePass(): boolean { - return firstTemplatePass; -} - -export function setFirstTemplatePass(value: boolean): void { - firstTemplatePass = value; -} - /** * The root index from which pure function instructions should calculate their binding * indices. In component views, this is TView.bindingStartIndex. In a host binding @@ -255,6 +221,21 @@ export function setBindingRoot(value: number) { bindingRootIndex = value; } +/** + * Current index of a View or Content Query which needs to be processed next. + * We iterate over the list of Queries and increment current query index at every step. + */ +let currentQueryIndex: number = 0; + +export function getCurrentQueryIndex(): number { + // top level variables should not be exported for performance reasons (PERF_NOTES.md) + return currentQueryIndex; +} + +export function setCurrentQueryIndex(value: number): void { + currentQueryIndex = value; +} + /** * Swap the current state with a new state. * @@ -271,7 +252,6 @@ export function enterView(newView: LView, hostTNode: TElementNode | TViewNode | const oldView = lView; if (newView) { const tView = newView[TVIEW]; - firstTemplatePass = tView.firstTemplatePass; bindingRootIndex = tView.bindingStartIndex; } @@ -319,11 +299,15 @@ export function leaveView(newView: LView): void { if (isCreationMode(lView)) { lView[FLAGS] &= ~LViewFlags.CreationMode; } else { - executeHooks(lView, tView.viewHooks, tView.viewCheckHooks, checkNoChangesMode); - // Views are clean and in update mode after being checked, so these bits are cleared - lView[FLAGS] &= ~(LViewFlags.Dirty | LViewFlags.FirstLViewPass); - lView[FLAGS] |= LViewFlags.RunInit; - lView[BINDING_INDEX] = tView.bindingStartIndex; + try { + executeHooks( + lView, tView.viewHooks, tView.viewCheckHooks, checkNoChangesMode, + InitPhaseState.AfterViewInitHooksToBeRun); + } finally { + // Views are clean and in update mode after being checked, so these bits are cleared + lView[FLAGS] &= ~(LViewFlags.Dirty | LViewFlags.FirstLViewPass); + lView[BINDING_INDEX] = tView.bindingStartIndex; + } } enterView(newView, null); } diff --git a/packages/core/src/render3/styling/class_and_style_bindings.ts b/packages/core/src/render3/styling/class_and_style_bindings.ts index a84d3b7041..3123eceec4 100644 --- a/packages/core/src/render3/styling/class_and_style_bindings.ts +++ b/packages/core/src/render3/styling/class_and_style_bindings.ts @@ -6,18 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ import {StyleSanitizeFn} from '../../sanitization/style_sanitizer'; -import {assertNotEqual} from '../assert'; +import {assertNotEqual} from '../../util/assert'; import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty'; import {AttributeMarker, TAttributes} from '../interfaces/node'; import {BindingStore, BindingType, Player, PlayerBuilder, PlayerFactory, PlayerIndex} from '../interfaces/player'; import {RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer'; -import {DirectiveOwnerAndPlayerBuilderIndex, DirectiveRegistryValues, DirectiveRegistryValuesIndex, InitialStylingValues, InitialStylingValuesIndex, SinglePropOffsetValues, SinglePropOffsetValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; +import {DirectiveOwnerAndPlayerBuilderIndex, DirectiveRegistryValues, DirectiveRegistryValuesIndex, InitialStylingValues, InitialStylingValuesIndex, MapBasedOffsetValues, MapBasedOffsetValuesIndex, SinglePropOffsetValues, SinglePropOffsetValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; import {LView, RootContext} from '../interfaces/view'; import {NO_CHANGE} from '../tokens'; import {getRootContext} from '../util'; import {BoundPlayerFactory} from './player_factory'; -import {addPlayerInternal, allocPlayerContext, createEmptyStylingContext, getPlayerContext} from './util'; +import {addPlayerInternal, allocPlayerContext, allocateDirectiveIntoContext, createEmptyStylingContext, getPlayerContext} from './util'; + /** @@ -29,8 +30,11 @@ import {addPlayerInternal, allocPlayerContext, createEmptyStylingContext, getPla * [style.prop]="myPropValue" * [class.name]="myClassValue" * + * It also includes code that will allow style binding code to operate within host + * bindings for components/directives. + * * There are many different ways in which these functions below are called. Please see - * `interfaces/styles.ts` to get a better idea of how the styling algorithm works. + * `render3/interfaces/styling.ts` to get a better idea of how the styling algorithm works. */ @@ -38,12 +42,12 @@ import {addPlayerInternal, allocPlayerContext, createEmptyStylingContext, getPla /** * Creates a new StylingContext an fills it with the provided static styling attribute values. */ -export function initializeStaticContext(attrs: TAttributes) { +export function initializeStaticContext(attrs: TAttributes): StylingContext { const context = createEmptyStylingContext(); const initialClasses: InitialStylingValues = context[StylingIndex.InitialClassValuesPosition] = - [null]; + [null, null]; const initialStyles: InitialStylingValues = context[StylingIndex.InitialStyleValuesPosition] = - [null]; + [null, null]; // The attributes array has marker values (numbers) indicating what the subsequent // values represent. When we encounter a number, we set the mode to that type of attribute. @@ -71,24 +75,24 @@ export function initializeStaticContext(attrs: TAttributes) { * @param context the existing styling context * @param attrs an array of new static styling attributes that will be * assigned to the context - * @param directive the directive instance with which static data is associated with. + * @param directiveRef the directive instance with which static data is associated with. */ export function patchContextWithStaticAttrs( - context: StylingContext, attrs: TAttributes, directive: any): void { + context: StylingContext, attrs: TAttributes, startingIndex: number, directiveRef: any): void { // If the styling context has already been patched with the given directive's bindings, // then there is no point in doing it again. The reason why this may happen (the directive // styling being patched twice) is because the `stylingBinding` function is called each time // an element is created (both within a template function and within directive host bindings). const directives = context[StylingIndex.DirectiveRegistryPosition]; - if (getDirectiveRegistryValuesIndexOf(directives, directive) == -1) { + if (getDirectiveRegistryValuesIndexOf(directives, directiveRef) == -1) { // this is a new directive which we have not seen yet. - directives.push(directive, -1, false, null); + allocateDirectiveIntoContext(context, directiveRef); let initialClasses: InitialStylingValues|null = null; let initialStyles: InitialStylingValues|null = null; let mode = -1; - for (let i = 0; i < attrs.length; i++) { + for (let i = startingIndex; i < attrs.length; i++) { const attr = attrs[i]; if (typeof attr == 'number') { mode = attr; @@ -133,16 +137,23 @@ function patchInitialStylingValue( } /** - * Runs through the initial styling data present in the context and renders + * Runs through the initial style data present in the context and renders * them via the renderer on the element. */ -export function renderInitialStylesAndClasses( +export function renderInitialStyles( + element: RElement, context: StylingContext, renderer: Renderer3) { + const initialStyles = context[StylingIndex.InitialStyleValuesPosition]; + renderInitialStylingValues(element, renderer, initialStyles, false); +} + +/** + * Runs through the initial class data present in the context and renders + * them via the renderer on the element. + */ +export function renderInitialClasses( element: RElement, context: StylingContext, renderer: Renderer3) { const initialClasses = context[StylingIndex.InitialClassValuesPosition]; renderInitialStylingValues(element, renderer, initialClasses, true); - - const initialStyles = context[StylingIndex.InitialStyleValuesPosition]; - renderInitialStylingValues(element, renderer, initialStyles, false); } /** @@ -189,8 +200,7 @@ export function allowNewBindingsForStylingContext(context: StylingContext): bool */ export function updateContextWithBindings( context: StylingContext, directiveRef: any | null, classBindingNames?: string[] | null, - styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null, - onlyProcessSingleClasses?: boolean) { + styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null) { if (context[StylingIndex.MasterFlagPosition] & StylingFlags.BindingAllocationLocked) return; // this means the context has already been patched with the directive's bindings @@ -200,6 +210,10 @@ export function updateContextWithBindings( return; } + if (styleBindingNames) { + styleBindingNames = hyphenateEntries(styleBindingNames); + } + // there are alot of variables being used below to track where in the context the new // binding values will be placed. Because the context consists of multiple types of // entries (single classes/styles and multi classes/styles) alot of the index positions @@ -211,6 +225,9 @@ export function updateContextWithBindings( const totalCurrentStyleBindings = singlePropOffsetValues[SinglePropOffsetValuesIndex.StylesCountPosition]; + const cachedClassMapValues = context[StylingIndex.CachedMultiClasses]; + const cachedStyleMapValues = context[StylingIndex.CachedMultiStyles]; + const classesOffset = totalCurrentClassBindings * StylingIndex.Size; const stylesOffset = totalCurrentStyleBindings * StylingIndex.Size; @@ -389,27 +406,90 @@ export function updateContextWithBindings( singlePropOffsetValues[SinglePropOffsetValuesIndex.StylesCountPosition] = totalCurrentStyleBindings + filteredStyleBindingNames.length; + // the map-based values also need to know how many entries got inserted + cachedClassMapValues[MapBasedOffsetValuesIndex.EntriesCountPosition] += + filteredClassBindingNames.length; + cachedStyleMapValues[MapBasedOffsetValuesIndex.EntriesCountPosition] += + filteredStyleBindingNames.length; + const newStylesSpaceAllocationSize = filteredStyleBindingNames.length * StylingIndex.Size; + const newClassesSpaceAllocationSize = filteredClassBindingNames.length * StylingIndex.Size; + + // update the multi styles cache with a reference for the directive that was just inserted + const directiveMultiStylesStartIndex = + multiStylesStartIndex + totalCurrentStyleBindings * StylingIndex.Size; + const cachedStyleMapIndex = cachedStyleMapValues.length; + + // this means that ONLY directive style styling (like ngStyle) was used + // therefore the root directive will still need to be filled in + if (directiveIndex > 0 && + cachedStyleMapValues.length <= MapBasedOffsetValuesIndex.ValuesStartPosition) { + cachedStyleMapValues.push(0, directiveMultiStylesStartIndex, null, 0); + } + + cachedStyleMapValues.push( + 0, directiveMultiStylesStartIndex, null, filteredStyleBindingNames.length); + + for (let i = MapBasedOffsetValuesIndex.ValuesStartPosition; i < cachedStyleMapIndex; + i += MapBasedOffsetValuesIndex.Size) { + // multi values start after all the single values (which is also where classes are) in the + // context therefore the new class allocation size should be taken into account + cachedStyleMapValues[i + MapBasedOffsetValuesIndex.PositionStartOffset] += + newClassesSpaceAllocationSize + newStylesSpaceAllocationSize; + } + + // update the multi classes cache with a reference for the directive that was just inserted + const directiveMultiClassesStartIndex = + multiClassesStartIndex + totalCurrentClassBindings * StylingIndex.Size; + const cachedClassMapIndex = cachedClassMapValues.length; + + // this means that ONLY directive class styling (like ngClass) was used + // therefore the root directive will still need to be filled in + if (directiveIndex > 0 && + cachedClassMapValues.length <= MapBasedOffsetValuesIndex.ValuesStartPosition) { + cachedClassMapValues.push(0, directiveMultiClassesStartIndex, null, 0); + } + + cachedClassMapValues.push( + 0, directiveMultiClassesStartIndex, null, filteredClassBindingNames.length); + + for (let i = MapBasedOffsetValuesIndex.ValuesStartPosition; i < cachedClassMapIndex; + i += MapBasedOffsetValuesIndex.Size) { + // the reason why both the styles + classes space is allocated to the existing offsets is + // because the styles show up before the classes in the context and any new inserted + // styles will offset any existing class entries in the context (even if there are no + // new class entries added) also the reason why it's *2 is because both single + multi + // entries for each new style have been added in the context before the multi class values + // actually start + cachedClassMapValues[i + MapBasedOffsetValuesIndex.PositionStartOffset] += + (newStylesSpaceAllocationSize * 2) + newClassesSpaceAllocationSize; + } + // there is no initial value flag for the master index since it doesn't // reference an initial style value - const masterFlag = pointers(0, 0, multiStylesStartIndex) | - (onlyProcessSingleClasses ? StylingFlags.OnlyProcessSingleClasses : 0); + const masterFlag = pointers(0, 0, multiStylesStartIndex); setFlag(context, StylingIndex.MasterFlagPosition, masterFlag); } /** * Searches through the existing registry of directives */ -function findOrPatchDirectiveIntoRegistry( +export function findOrPatchDirectiveIntoRegistry( context: StylingContext, directiveRef: any, styleSanitizer?: StyleSanitizeFn | null) { const directiveRefs = context[StylingIndex.DirectiveRegistryPosition]; const nextOffsetInsertionIndex = context[StylingIndex.SinglePropOffsetPositions].length; let directiveIndex: number; - const detectedIndex = getDirectiveRegistryValuesIndexOf(directiveRefs, directiveRef); + let detectedIndex = getDirectiveRegistryValuesIndexOf(directiveRefs, directiveRef); if (detectedIndex === -1) { + detectedIndex = directiveRefs.length; directiveIndex = directiveRefs.length / DirectiveRegistryValuesIndex.Size; - directiveRefs.push(directiveRef, nextOffsetInsertionIndex, false, styleSanitizer || null); + + allocateDirectiveIntoContext(context, directiveRef); + directiveRefs[detectedIndex + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset] = + nextOffsetInsertionIndex; + directiveRefs[detectedIndex + DirectiveRegistryValuesIndex.StyleSanitizerOffset] = + styleSanitizer || null; } else { const singlePropStartPosition = detectedIndex + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset; @@ -445,27 +525,53 @@ function getMatchingBindingIndex( } /** - * Sets and resolves all `multi` styling on an `StylingContext` so that they can be - * applied to the element once `renderStyling` is called. + * Registers the provided multi styling (`[style]` and `[class]`) values to the context. * - * All missing styles/class (any values that are not provided in the new `styles` - * or `classes` params) will resolve to `null` within their respective positions - * in the context. + * This function will iterate over the provided `classesInput` and `stylesInput` map + * values and insert/update or remove them from the context at exactly the right + * spot. + * + * This function also takes in a directive which implies that the styling values will + * be evaluated for that directive with respect to any other styling that already exists + * on the context. When there are styles that conflict (e.g. say `ngStyle` and `[style]` + * both update the `width` property at the same time) then the styling algorithm code below + * will decide which one wins based on the directive styling prioritization mechanism. This + * mechanism is better explained in render3/interfaces/styling.ts#directives). + * + * This function will not render any styling values on screen, but is rather designed to + * prepare the context for that. `renderStyling` must be called afterwards to render any + * styling data that was set in this function (note that `updateClassProp` and + * `updateStyleProp` are designed to be run after this function is run). * * @param context The styling context that will be updated with the * newly provided style values. * @param classesInput The key/value map of CSS class names that will be used for the update. * @param stylesInput The key/value map of CSS styles that will be used for the update. + * @param directiveRef an optional reference to the directive responsible + * for this binding change. If present then style binding will only + * actualize if the directive has ownership over this binding + * (see styling.ts#directives for more information about the algorithm). */ export function updateStylingMap( context: StylingContext, classesInput: {[key: string]: any} | string | - BoundPlayerFactory| NO_CHANGE | null, - stylesInput?: {[key: string]: any} | BoundPlayerFactory| NO_CHANGE | - null, + BoundPlayerFactory| null, + stylesInput?: {[key: string]: any} | BoundPlayerFactory| null, directiveRef?: any): void { - stylesInput = stylesInput || null; - const directiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null); + + classesInput = classesInput || null; + stylesInput = stylesInput || null; + const ignoreAllClassUpdates = isMultiValueCacheHit(context, true, directiveIndex, classesInput); + const ignoreAllStyleUpdates = isMultiValueCacheHit(context, false, directiveIndex, stylesInput); + + // early exit (this is what's done to avoid using ctx.bind() to cache the value) + if (ignoreAllClassUpdates && ignoreAllStyleUpdates) return; + + classesInput = + classesInput === NO_CHANGE ? readCachedMapValue(context, true, directiveIndex) : classesInput; + stylesInput = + stylesInput === NO_CHANGE ? readCachedMapValue(context, false, directiveIndex) : stylesInput; + const element = context[StylingIndex.ElementPosition] !as HTMLElement; const classesPlayerBuilder = classesInput instanceof BoundPlayerFactory ? new ClassAndStylePlayerBuilder(classesInput as any, element, BindingType.Class) : @@ -478,15 +584,6 @@ export function updateStylingMap( (classesInput as BoundPlayerFactory<{[key: string]: any}|string>) !.value : classesInput; const stylesValue = stylesPlayerBuilder ? stylesInput !.value : stylesInput; - // early exit (this is what's done to avoid using ctx.bind() to cache the value) - const ignoreAllClassUpdates = limitToSingleClasses(context) || classesValue === NO_CHANGE || - classesValue === context[StylingIndex.CachedClassValueOrInitialClassString]; - const ignoreAllStyleUpdates = - stylesValue === NO_CHANGE || stylesValue === context[StylingIndex.CachedStyleValue]; - if (ignoreAllClassUpdates && ignoreAllStyleUpdates) return; - - context[StylingIndex.CachedClassValueOrInitialClassString] = classesValue; - context[StylingIndex.CachedStyleValue] = stylesValue; let classNames: string[] = EMPTY_ARRAY; let applyAllClasses = false; @@ -521,150 +618,27 @@ export function updateStylingMap( } } - const classes = (classesValue || EMPTY_OBJ) as{[key: string]: any}; - const styleProps = stylesValue ? Object.keys(stylesValue) : EMPTY_ARRAY; - const styles = stylesValue || EMPTY_OBJ; + const multiStylesStartIndex = getMultiStylesStartIndex(context); + let multiClassesStartIndex = getMultiClassStartIndex(context); + let multiClassesEndIndex = context.length; - const classesStartIndex = styleProps.length; - let multiStartIndex = getMultiStartIndex(context); - - let dirty = false; - let ctxIndex = multiStartIndex; - - let propIndex = 0; - const propLimit = styleProps.length + classNames.length; - - // the main loop here will try and figure out how the shape of the provided - // styles differ with respect to the context. Later if the context/styles/classes - // are off-balance then they will be dealt in another loop after this one - while (ctxIndex < context.length && propIndex < propLimit) { - const isClassBased = propIndex >= classesStartIndex; - const processValue = - (!isClassBased && !ignoreAllStyleUpdates) || (isClassBased && !ignoreAllClassUpdates); - - // when there is a cache-hit for a string-based class then we should - // avoid doing any work diffing any of the changes - if (processValue) { - const adjustedPropIndex = isClassBased ? propIndex - classesStartIndex : propIndex; - const newProp: string = - isClassBased ? classNames[adjustedPropIndex] : styleProps[adjustedPropIndex]; - const newValue: string|boolean = - isClassBased ? (applyAllClasses ? true : classes[newProp]) : styles[newProp]; - const playerBuilderIndex = - isClassBased ? classesPlayerBuilderIndex : stylesPlayerBuilderIndex; - - const prop = getProp(context, ctxIndex); - if (prop === newProp) { - const value = getValue(context, ctxIndex); - const flag = getPointers(context, ctxIndex); - setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); - - if (hasValueChanged(flag, value, newValue)) { - setValue(context, ctxIndex, newValue); - playerBuildersAreDirty = playerBuildersAreDirty || !!playerBuilderIndex; - - const initialValue = getInitialValue(context, flag); - - // SKIP IF INITIAL CHECK - // If the former `value` is `null` then it means that an initial value - // could be being rendered on screen. If that is the case then there is - // no point in updating the value incase it matches. In other words if the - // new value is the exact same as the previously rendered value (which - // happens to be the initial value) then do nothing. - if (value != null || hasValueChanged(flag, initialValue, newValue)) { - setDirty(context, ctxIndex, true); - dirty = true; - } - } - } else { - const indexOfEntry = findEntryPositionByProp(context, newProp, ctxIndex); - if (indexOfEntry > 0) { - // it was found at a later point ... just swap the values - const valueToCompare = getValue(context, indexOfEntry); - const flagToCompare = getPointers(context, indexOfEntry); - swapMultiContextEntries(context, ctxIndex, indexOfEntry); - if (hasValueChanged(flagToCompare, valueToCompare, newValue)) { - const initialValue = getInitialValue(context, flagToCompare); - setValue(context, ctxIndex, newValue); - - // same if statement logic as above (look for SKIP IF INITIAL CHECK). - if (valueToCompare != null || hasValueChanged(flagToCompare, initialValue, newValue)) { - setDirty(context, ctxIndex, true); - playerBuildersAreDirty = playerBuildersAreDirty || !!playerBuilderIndex; - dirty = true; - } - } - } else { - // we only care to do this if the insertion is in the middle - const newFlag = prepareInitialFlag( - context, newProp, isClassBased, getStyleSanitizer(context, directiveIndex)); - playerBuildersAreDirty = playerBuildersAreDirty || !!playerBuilderIndex; - insertNewMultiProperty( - context, ctxIndex, isClassBased, newProp, newFlag, newValue, directiveIndex, - playerBuilderIndex); - dirty = true; - } - } + if (!ignoreAllStyleUpdates) { + const styleProps = stylesValue ? Object.keys(stylesValue) : EMPTY_ARRAY; + const styles = stylesValue || EMPTY_OBJ; + const totalNewEntries = patchStylingMapIntoContext( + context, directiveIndex, stylesPlayerBuilderIndex, multiStylesStartIndex, + multiClassesStartIndex, styleProps, styles, stylesInput, false); + if (totalNewEntries) { + multiClassesStartIndex += totalNewEntries * StylingIndex.Size; + multiClassesEndIndex += totalNewEntries * StylingIndex.Size; } - - ctxIndex += StylingIndex.Size; - propIndex++; } - // this means that there are left-over values in the context that - // were not included in the provided styles/classes and in this - // case the goal is to "remove" them from the context (by nullifying) - while (ctxIndex < context.length) { - const flag = getPointers(context, ctxIndex); - const isClassBased = (flag & StylingFlags.Class) === StylingFlags.Class; - const processValue = - (!isClassBased && !ignoreAllStyleUpdates) || (isClassBased && !ignoreAllClassUpdates); - if (processValue) { - const value = getValue(context, ctxIndex); - const doRemoveValue = valueExists(value, isClassBased); - if (doRemoveValue) { - setDirty(context, ctxIndex, true); - setValue(context, ctxIndex, null); - - // we keep the player factory the same so that the `nulled` value can - // be instructed into the player because removing a style and/or a class - // is a valid animation player instruction. - const playerBuilderIndex = - isClassBased ? classesPlayerBuilderIndex : stylesPlayerBuilderIndex; - setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); - dirty = true; - } - } - ctxIndex += StylingIndex.Size; - } - - // this means that there are left-over properties in the context that - // were not detected in the context during the loop above. In that - // case we want to add the new entries into the list - const sanitizer = getStyleSanitizer(context, directiveIndex); - while (propIndex < propLimit) { - const isClassBased = propIndex >= classesStartIndex; - const processValue = - (!isClassBased && !ignoreAllStyleUpdates) || (isClassBased && !ignoreAllClassUpdates); - if (processValue) { - const adjustedPropIndex = isClassBased ? propIndex - classesStartIndex : propIndex; - const prop = isClassBased ? classNames[adjustedPropIndex] : styleProps[adjustedPropIndex]; - const value: string|boolean = - isClassBased ? (applyAllClasses ? true : classes[prop]) : styles[prop]; - const flag = prepareInitialFlag(context, prop, isClassBased, sanitizer) | StylingFlags.Dirty; - const playerBuilderIndex = - isClassBased ? classesPlayerBuilderIndex : stylesPlayerBuilderIndex; - const ctxIndex = context.length; - context.push(flag, prop, value, 0); - setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); - dirty = true; - } - propIndex++; - } - - if (dirty) { - setContextDirty(context, true); - setDirectiveDirty(context, directiveIndex, true); + if (!ignoreAllClassUpdates) { + const classes = (classesValue || EMPTY_OBJ) as{[key: string]: any}; + patchStylingMapIntoContext( + context, directiveIndex, classesPlayerBuilderIndex, multiClassesStartIndex, + multiClassesEndIndex, classNames, applyAllClasses || classes, classesInput, true); } if (playerBuildersAreDirty) { @@ -673,18 +647,275 @@ export function updateStylingMap( } /** - * This method will toggle the referenced CSS class (by the provided index) - * within the given context. + * Applies the given multi styling (styles or classes) values to the context. + * + * The styling algorithm code that applies multi-level styling (things like `[style]` and `[class]` + * values) resides here. + * + * Because this function understands that multiple directives may all write to the `[style]` and + * `[class]` bindings (through host bindings), it relies of each directive applying its binding + * value in order. This means that a directive like `classADirective` will always fire before + * `classBDirective` and therefore its styling values (classes and styles) will always be evaluated + * in the same order. Because of this consistent ordering, the first directive has a higher priority + * than the second one. It is with this prioritzation mechanism that the styling algorithm knows how + * to merge and apply redudant styling properties. + * + * The function itself applies the key/value entries (or an array of keys) to + * the context in the following steps. + * + * STEP 1: + * First check to see what properties are already set and in use by another directive in the + * context (e.g. `ngClass` set the `width` value and `[style.width]="w"` in a directive is + * attempting to set it as well). + * + * STEP 2: + * All remaining properties (that were not set prior to this directive) are now updated in + * the context. Any new properties are inserted exactly at their spot in the context and any + * previously set properties are shifted to exactly where the cursor sits while iterating over + * the context. The end result is a balanced context that includes the exact ordering of the + * styling properties/values for the provided input from the directive. + * + * STEP 3: + * Any unmatched properties in the context that belong to the directive are set to null + * + * Once the updating phase is done, then the algorithm will decide whether or not to flag the + * follow-up directives (the directives that will pass in their styling values) depending on if + * the "shape" of the multi-value map has changed (either if any keys are removed or added or + * if there are any new `null` values). If any follow-up directives are flagged as dirty then the + * algorithm will run again for them. Otherwise if the shape did not change then any follow-up + * directives will not run (so long as their binding values stay the same). + * + * @returns the total amount of new slots that were allocated into the context due to new styling + * properties that were detected. + */ +function patchStylingMapIntoContext( + context: StylingContext, directiveIndex: number, playerBuilderIndex: number, ctxStart: number, + ctxEnd: number, props: (string | null)[], values: {[key: string]: any} | true, cacheValue: any, + entryIsClassBased: boolean): number { + let dirty = false; + + const cacheIndex = MapBasedOffsetValuesIndex.ValuesStartPosition + + directiveIndex * MapBasedOffsetValuesIndex.Size; + + // the cachedValues array is the registry of all multi style values (map values). Each + // value is stored (cached) each time is updated. + const cachedValues = + context[entryIsClassBased ? StylingIndex.CachedMultiClasses : StylingIndex.CachedMultiStyles]; + + // this is the index in which this directive has ownership access to write to this + // value (anything before is owned by a previous directive that is more important) + const ownershipValuesStartIndex = + cachedValues[cacheIndex + MapBasedOffsetValuesIndex.PositionStartOffset]; + + const existingCachedValue = cachedValues[cacheIndex + MapBasedOffsetValuesIndex.ValueOffset]; + const existingCachedValueCount = + cachedValues[cacheIndex + MapBasedOffsetValuesIndex.ValueCountOffset]; + const existingCachedValueIsDirty = + cachedValues[cacheIndex + MapBasedOffsetValuesIndex.DirtyFlagOffset] === 1; + + // A shape change means the provided map value has either removed or added new properties + // compared to what were in the last time. If a shape change occurs then it means that all + // follow-up multi-styling entries are obsolete and will be examined again when CD runs + // them. If a shape change has not occurred then there is no reason to check any other + // directive values if their identity has not changed. If a previous directive set this + // value as dirty (because its own shape changed) then this means that the object has been + // offset to a different area in the context. Because its value has been offset then it + // can't write to a region that it wrote to before (which may have been apart of another + // directive) and therefore its shape changes too. + let valuesEntryShapeChange = + existingCachedValueIsDirty || ((!existingCachedValue && cacheValue) ? true : false); + + let totalUniqueValues = 0; + let totalNewAllocatedSlots = 0; + + // this is a trick to avoid building {key:value} map where all the values + // are `true` (this happens when a className string is provided instead of a + // map as an input value to this styling algorithm) + const applyAllProps = values === true; + + // STEP 1: + // loop through the earlier directives and figure out if any properties here will be placed + // in their area (this happens when the value is null because the earlier directive erased it). + let ctxIndex = ctxStart; + let totalRemainingProperties = props.length; + while (ctxIndex < ownershipValuesStartIndex) { + const currentProp = getProp(context, ctxIndex); + if (totalRemainingProperties) { + for (let i = 0; i < props.length; i++) { + const mapProp = props[i]; + const normalizedProp = mapProp ? (entryIsClassBased ? mapProp : hyphenate(mapProp)) : null; + if (normalizedProp && currentProp === normalizedProp) { + const currentValue = getValue(context, ctxIndex); + const currentDirectiveIndex = getDirectiveIndexFromEntry(context, ctxIndex); + const value = applyAllProps ? true : (values as{[key: string]: any})[normalizedProp]; + const currentFlag = getPointers(context, ctxIndex); + if (hasValueChanged(currentFlag, currentValue, value) && + allowValueChange(currentValue, value, currentDirectiveIndex, directiveIndex)) { + setValue(context, ctxIndex, value); + setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); + if (hasInitialValueChanged(context, currentFlag, value)) { + setDirty(context, ctxIndex, true); + dirty = true; + } + } + props[i] = null; + totalRemainingProperties--; + break; + } + } + } + ctxIndex += StylingIndex.Size; + } + + // STEP 2: + // apply the left over properties to the context in the correct order. + if (totalRemainingProperties) { + const sanitizer = entryIsClassBased ? null : getStyleSanitizer(context, directiveIndex); + propertiesLoop: for (let i = 0; i < props.length; i++) { + const mapProp = props[i]; + + if (!mapProp) { + // this is an early exit incase a value was already encountered above in the + // previous loop (which means that the property was applied or rejected) + continue; + } + + const value = applyAllProps ? true : (values as{[key: string]: any})[mapProp]; + const normalizedProp = entryIsClassBased ? mapProp : hyphenate(mapProp); + const isInsideOwnershipArea = ctxIndex >= ownershipValuesStartIndex; + + for (let j = ctxIndex; j < ctxEnd; j += StylingIndex.Size) { + const distantCtxProp = getProp(context, j); + if (distantCtxProp === normalizedProp) { + const distantCtxDirectiveIndex = getDirectiveIndexFromEntry(context, j); + const distantCtxPlayerBuilderIndex = getPlayerBuilderIndex(context, j); + const distantCtxValue = getValue(context, j); + const distantCtxFlag = getPointers(context, j); + + if (allowValueChange(distantCtxValue, value, distantCtxDirectiveIndex, directiveIndex)) { + // even if the entry isn't updated (by value or directiveIndex) then + // it should still be moved over to the correct spot in the array so + // the iteration loop is tighter. + if (isInsideOwnershipArea) { + swapMultiContextEntries(context, ctxIndex, j); + totalUniqueValues++; + } + + if (hasValueChanged(distantCtxFlag, distantCtxValue, value)) { + if (value === null || value === undefined && value !== distantCtxValue) { + valuesEntryShapeChange = true; + } + + setValue(context, ctxIndex, value); + + // SKIP IF INITIAL CHECK + // If the former `value` is `null` then it means that an initial value + // could be being rendered on screen. If that is the case then there is + // no point in updating the value incase it matches. In other words if the + // new value is the exact same as the previously rendered value (which + // happens to be the initial value) then do nothing. + if (distantCtxValue !== null || + hasInitialValueChanged(context, distantCtxFlag, value)) { + setDirty(context, ctxIndex, true); + dirty = true; + } + } + + if (distantCtxDirectiveIndex !== directiveIndex || + playerBuilderIndex !== distantCtxPlayerBuilderIndex) { + setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); + } + } + + ctxIndex += StylingIndex.Size; + continue propertiesLoop; + } + } + + // fallback case ... value not found at all in the context + if (value != null) { + valuesEntryShapeChange = true; + totalUniqueValues++; + const flag = prepareInitialFlag(context, normalizedProp, entryIsClassBased, sanitizer) | + StylingFlags.Dirty; + + const insertionIndex = isInsideOwnershipArea ? + ctxIndex : + (ownershipValuesStartIndex + totalNewAllocatedSlots * StylingIndex.Size); + insertNewMultiProperty( + context, insertionIndex, entryIsClassBased, normalizedProp, flag, value, directiveIndex, + playerBuilderIndex); + + totalNewAllocatedSlots++; + ctxEnd += StylingIndex.Size; + ctxIndex += StylingIndex.Size; + + dirty = true; + } + } + } + + // STEP 3: + // Remove (nullify) any existing entries in the context that were not apart of the + // map input value that was passed into this algorithm for this directive. + while (ctxIndex < ctxEnd) { + valuesEntryShapeChange = true; // some values are missing + const ctxValue = getValue(context, ctxIndex); + const ctxFlag = getPointers(context, ctxIndex); + if (ctxValue != null) { + valuesEntryShapeChange = true; + } + if (hasValueChanged(ctxFlag, ctxValue, null)) { + setValue(context, ctxIndex, null); + // only if the initial value is falsy then + if (hasInitialValueChanged(context, ctxFlag, ctxValue)) { + setDirty(context, ctxIndex, true); + dirty = true; + } + setPlayerBuilderIndex(context, ctxIndex, playerBuilderIndex, directiveIndex); + } + ctxIndex += StylingIndex.Size; + } + + // Because the object shape has changed, this means that all follow-up directives will need to + // reapply their values into the object. For this to happen, the cached array needs to be updated + // with dirty flags so that follow-up calls to `updateStylingMap` will reapply their styling code. + // the reapplication of styling code within the context will reshape it and update the offset + // values (also follow-up directives can write new values incase earlier directives set anything + // to null due to removals or falsy values). + valuesEntryShapeChange = valuesEntryShapeChange || existingCachedValueCount !== totalUniqueValues; + updateCachedMapValue( + context, directiveIndex, entryIsClassBased, cacheValue, ownershipValuesStartIndex, ctxEnd, + totalUniqueValues, valuesEntryShapeChange); + + if (dirty) { + setContextDirty(context, true); + setDirectiveDirty(context, directiveIndex, true); + } + + return totalNewAllocatedSlots; +} + +/** + * Sets and resolves a single class value on the provided `StylingContext` so + * that they can be applied to the element once `renderStyling` is called. * * @param context The styling context that will be updated with the * newly provided class value. * @param offset The index of the CSS class which is being updated. * @param addOrRemove Whether or not to add or remove the CSS class + * @param directiveRef an optional reference to the directive responsible + * for this binding change. If present then style binding will only + * actualize if the directive has ownership over this binding + * (see styling.ts#directives for more information about the algorithm). + * @param forceOverride whether or not to skip all directive prioritization + * and just apply the value regardless. */ export function updateClassProp( - context: StylingContext, offset: number, addOrRemove: boolean | BoundPlayerFactory, - directiveRef?: any): void { - _updateSingleStylingValue(context, offset, addOrRemove, true, directiveRef); + context: StylingContext, offset: number, + input: boolean | BoundPlayerFactory| null, directiveRef?: any, + forceOverride?: boolean): void { + updateSingleStylingValue(context, offset, input, true, directiveRef, forceOverride); } /** @@ -704,18 +935,20 @@ export function updateClassProp( * for this binding change. If present then style binding will only * actualize if the directive has ownership over this binding * (see styling.ts#directives for more information about the algorithm). + * @param forceOverride whether or not to skip all directive prioritization + * and just apply the value regardless. */ export function updateStyleProp( context: StylingContext, offset: number, - input: string | boolean | null | BoundPlayerFactory, - directiveRef?: any): void { - _updateSingleStylingValue(context, offset, input, false, directiveRef); + input: string | boolean | null | BoundPlayerFactory, directiveRef?: any, + forceOverride?: boolean): void { + updateSingleStylingValue(context, offset, input, false, directiveRef, forceOverride); } -function _updateSingleStylingValue( +function updateSingleStylingValue( context: StylingContext, offset: number, input: string | boolean | null | BoundPlayerFactory, isClassBased: boolean, - directiveRef: any): void { + directiveRef: any, forceOverride?: boolean): void { const directiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null); const singleIndex = getSinglePropIndexValue(context, directiveIndex, offset, isClassBased); const currValue = getValue(context, singleIndex); @@ -724,7 +957,7 @@ function _updateSingleStylingValue( const value: string|boolean|null = (input instanceof BoundPlayerFactory) ? input.value : input; if (hasValueChanged(currFlag, currValue, value) && - allowValueChange(currValue, value, currDirective, directiveIndex)) { + (forceOverride || allowValueChange(currValue, value, currDirective, directiveIndex))) { const isClassBased = (currFlag & StylingFlags.Class) === StylingFlags.Class; const element = context[StylingIndex.ElementPosition] !as HTMLElement; const playerBuilder = input instanceof BoundPlayerFactory ? @@ -815,8 +1048,7 @@ export function renderStyling( const flushPlayerBuilders: any = context[StylingIndex.MasterFlagPosition] & StylingFlags.PlayerBuildersDirty; const native = context[StylingIndex.ElementPosition] !; - const multiStartIndex = getMultiStartIndex(context); - const onlySingleClasses = limitToSingleClasses(context); + const multiStartIndex = getMultiStylesStartIndex(context); let stillDirty = false; for (let i = StylingIndex.SingleStylesStartPosition; i < context.length; @@ -837,7 +1069,6 @@ export function renderStyling( const playerBuilder = getPlayerBuilder(context, i); const isClassBased = flag & StylingFlags.Class ? true : false; const isInSingleRegion = i < multiStartIndex; - const readInitialValue = !isClassBased || !onlySingleClasses; let valueToApply: string|boolean|null = value; @@ -858,7 +1089,7 @@ export function renderStyling( // classes are turned off and should therefore defer to their initial values) // Note that we ignore class-based deferals because otherwise a class can never // be removed in the case that it exists as true in the initial classes list... - if (!isClassBased && !valueExists(valueToApply, isClassBased) && readInitialValue) { + if (!valueExists(valueToApply, isClassBased)) { valueToApply = getInitialValue(context, flag); } @@ -921,6 +1152,8 @@ export function renderStyling( } /** + * Assigns a style value to a style property for the given element. + * * This function renders a given CSS prop/value entry using the * provided renderer. If a `store` value is provided then * that will be used a render context instead of the provided @@ -946,20 +1179,22 @@ export function setStyle( } } else if (value) { value = value.toString(); // opacity, z-index and flexbox all have number values which may not - // assign as numbers + // assign as numbers ngDevMode && ngDevMode.rendererSetStyle++; isProceduralRenderer(renderer) ? renderer.setStyle(native, prop, value, RendererStyleFlags3.DashCase) : - native['style'].setProperty(prop, value); + native.style.setProperty(prop, value); } else { ngDevMode && ngDevMode.rendererRemoveStyle++; isProceduralRenderer(renderer) ? renderer.removeStyle(native, prop, RendererStyleFlags3.DashCase) : - native['style'].removeProperty(prop); + native.style.removeProperty(prop); } } /** + * Adds/removes the provided className value to the provided element. + * * This function renders a given CSS class value using the provided * renderer (by adding or removing it from the provided element). * If a `store` value is provided then that will be used a render @@ -981,14 +1216,17 @@ function setClass( if (playerBuilder) { playerBuilder.setValue(className, add); } - } else if (add) { - ngDevMode && ngDevMode.rendererAddClass++; - isProceduralRenderer(renderer) ? renderer.addClass(native, className) : - native['classList'].add(className); - } else { - ngDevMode && ngDevMode.rendererRemoveClass++; - isProceduralRenderer(renderer) ? renderer.removeClass(native, className) : - native['classList'].remove(className); + // DOMTokenList will throw if we try to add or remove an empty string. + } else if (className !== '') { + if (add) { + ngDevMode && ngDevMode.rendererAddClass++; + isProceduralRenderer(renderer) ? renderer.addClass(native, className) : + native['classList'].add(className); + } else { + ngDevMode && ngDevMode.rendererRemoveClass++; + isProceduralRenderer(renderer) ? renderer.removeClass(native, className) : + native['classList'].remove(className); + } } } @@ -1055,6 +1293,20 @@ function getMultiStartIndex(context: StylingContext): number { return getMultiOrSingleIndex(context[StylingIndex.MasterFlagPosition]) as number; } +function getMultiClassStartIndex(context: StylingContext): number { + const classCache = context[StylingIndex.CachedMultiClasses]; + return classCache + [MapBasedOffsetValuesIndex.ValuesStartPosition + + MapBasedOffsetValuesIndex.PositionStartOffset]; +} + +function getMultiStylesStartIndex(context: StylingContext): number { + const stylesCache = context[StylingIndex.CachedMultiStyles]; + return stylesCache + [MapBasedOffsetValuesIndex.ValuesStartPosition + + MapBasedOffsetValuesIndex.PositionStartOffset]; +} + function setProp(context: StylingContext, index: number, prop: string) { context[index + StylingIndex.PropertyOffset] = prop; } @@ -1144,10 +1396,6 @@ export function isContextDirty(context: StylingContext): boolean { return isDirty(context, StylingIndex.MasterFlagPosition); } -export function limitToSingleClasses(context: StylingContext) { - return context[StylingIndex.MasterFlagPosition] & StylingFlags.OnlyProcessSingleClasses; -} - export function setContextDirty(context: StylingContext, isDirtyYes: boolean): void { setDirty(context, StylingIndex.MasterFlagPosition, isDirtyYes); } @@ -1160,23 +1408,14 @@ export function setContextPlayersDirty(context: StylingContext, isDirtyYes: bool } } -function findEntryPositionByProp( - context: StylingContext, prop: string, startIndex?: number): number { - for (let i = (startIndex || 0) + StylingIndex.PropertyOffset; i < context.length; - i += StylingIndex.Size) { - const thisProp = context[i]; - if (thisProp == prop) { - return i - StylingIndex.PropertyOffset; - } - } - return -1; -} - function swapMultiContextEntries(context: StylingContext, indexA: number, indexB: number) { + if (indexA === indexB) return; + const tmpValue = getValue(context, indexA); const tmpProp = getProp(context, indexA); const tmpFlag = getPointers(context, indexA); const tmpPlayerBuilderIndex = getPlayerBuilderIndex(context, indexA); + const tmpDirectiveIndex = getDirectiveIndexFromEntry(context, indexA); let flagA = tmpFlag; let flagB = getPointers(context, indexB); @@ -1199,13 +1438,13 @@ function swapMultiContextEntries(context: StylingContext, indexA: number, indexB setProp(context, indexA, getProp(context, indexB)); setFlag(context, indexA, getPointers(context, indexB)); const playerIndexA = getPlayerBuilderIndex(context, indexB); - const directiveIndexA = 0; + const directiveIndexA = getDirectiveIndexFromEntry(context, indexB); setPlayerBuilderIndex(context, indexA, playerIndexA, directiveIndexA); setValue(context, indexB, tmpValue); setProp(context, indexB, tmpProp); setFlag(context, indexB, tmpFlag); - setPlayerBuilderIndex(context, indexB, tmpPlayerBuilderIndex, directiveIndexA); + setPlayerBuilderIndex(context, indexB, tmpPlayerBuilderIndex, tmpDirectiveIndex); } function updateSinglePointerValues(context: StylingContext, indexStartPosition: number) { @@ -1244,9 +1483,6 @@ function insertNewMultiProperty( } function valueExists(value: string | null | boolean, isClassBased?: boolean) { - if (isClassBased) { - return value ? true : false; - } return value !== null; } @@ -1269,6 +1505,11 @@ function prepareInitialFlag( return pointers(flag, initialIndex, 0); } +function hasInitialValueChanged(context: StylingContext, flag: number, newValue: any) { + const initialValue = getInitialValue(context, flag); + return !initialValue || hasValueChanged(flag, initialValue, newValue); +} + function hasValueChanged( flag: number, a: string | boolean | null, b: string | boolean | null): boolean { const isClassBased = flag & StylingFlags.Class; @@ -1332,12 +1573,11 @@ export interface LogSummary { dynamicIndex: number; // value: number; // flags: { - dirty: boolean; // - class: boolean; // - sanitize: boolean; // - playerBuildersDirty: boolean; // - onlyProcessSingleClasses: boolean; // - bindingAllocationLocked: boolean; // + dirty: boolean; // + class: boolean; // + sanitize: boolean; // + playerBuildersDirty: boolean; // + bindingAllocationLocked: boolean; // }; } @@ -1375,7 +1615,6 @@ export function generateConfigSummary(source: number | StylingContext, index?: n class: flag & StylingFlags.Class ? true : false, sanitize: flag & StylingFlags.Sanitize ? true : false, playerBuildersDirty: flag & StylingFlags.PlayerBuildersDirty ? true : false, - onlyProcessSingleClasses: flag & StylingFlags.OnlyProcessSingleClasses ? true : false, bindingAllocationLocked: flag & StylingFlags.BindingAllocationLocked ? true : false, } }; @@ -1498,9 +1737,9 @@ function allowValueChange( // prioritization of directives enables the styling algorithm to decide if a style // or class should be allowed to be updated/replaced incase an earlier directive // already wrote to the exact same style-property or className value. In other words - // ... this decides what to do if and when there is a collision. - if (currentValue) { - if (newValue) { + // this decides what to do if and when there is a collision. + if (currentValue != null) { + if (newValue != null) { // if a directive index is lower than it always has priority over the // previous directive's value... return newDirectiveOwner <= currentDirectiveOwner; @@ -1516,16 +1755,21 @@ function allowValueChange( } /** - * This function is only designed to be called for `[class]` bindings when - * `[ngClass]` (or something that uses `class` as an input) is present. Once - * directive host bindings fully work for `[class]` and `[style]` inputs - * then this can be deleted. + * Returns the className string of all the initial classes for the element. + * + * This function is designed to populate and cache all the static class + * values into a className string. The caching mechanism works by placing + * the completed className string into the initial values array into a + * dedicated slot. This will prevent the function from having to populate + * the string each time an element is created or matched. + * + * @returns the className string (e.g. `on active red`) */ export function getInitialClassNameValue(context: StylingContext): string { - let className = context[StylingIndex.CachedClassValueOrInitialClassString] as string; - if (className == null) { + const initialClassValues = context[StylingIndex.InitialClassValuesPosition]; + let className = initialClassValues[InitialStylingValuesIndex.InitialClassesStringPosition]; + if (className === null) { className = ''; - const initialClassValues = context[StylingIndex.InitialClassValuesPosition]; for (let i = InitialStylingValuesIndex.KeyValueStartPosition; i < initialClassValues.length; i += InitialStylingValuesIndex.Size) { const isPresent = initialClassValues[i + 1]; @@ -1533,7 +1777,162 @@ export function getInitialClassNameValue(context: StylingContext): string { className += (className.length ? ' ' : '') + initialClassValues[i]; } } - context[StylingIndex.CachedClassValueOrInitialClassString] = className; + initialClassValues[InitialStylingValuesIndex.InitialClassesStringPosition] = className; } return className; } + +/** + * Returns the style string of all the initial styles for the element. + * + * This function is designed to populate and cache all the static style + * values into a style string. The caching mechanism works by placing + * the completed style string into the initial values array into a + * dedicated slot. This will prevent the function from having to populate + * the string each time an element is created or matched. + * + * @returns the style string (e.g. `width:100px;height:200px`) + */ +export function getInitialStyleStringValue(context: StylingContext): string { + const initialStyleValues = context[StylingIndex.InitialStyleValuesPosition]; + let styleString = initialStyleValues[InitialStylingValuesIndex.InitialClassesStringPosition]; + if (styleString === null) { + styleString = ''; + for (let i = InitialStylingValuesIndex.KeyValueStartPosition; i < initialStyleValues.length; + i += InitialStylingValuesIndex.Size) { + const value = initialStyleValues[i + 1]; + if (value !== null) { + styleString += (styleString.length ? ';' : '') + `${initialStyleValues[i]}:${value}`; + } + } + initialStyleValues[InitialStylingValuesIndex.InitialClassesStringPosition] = styleString; + } + return styleString; +} + +/** + * Returns the current cached mutli-value for a given directiveIndex within the provided context. + */ +function readCachedMapValue( + context: StylingContext, entryIsClassBased: boolean, directiveIndex: number) { + const values: MapBasedOffsetValues = + context[entryIsClassBased ? StylingIndex.CachedMultiClasses : StylingIndex.CachedMultiStyles]; + const index = MapBasedOffsetValuesIndex.ValuesStartPosition + + directiveIndex * MapBasedOffsetValuesIndex.Size; + return values[index + MapBasedOffsetValuesIndex.ValueOffset] || null; +} + +/** + * Determines whether the provided multi styling value should be updated or not. + * + * Because `[style]` and `[class]` bindings rely on an identity change to occur before + * applying new values, the styling algorithm may not update an existing entry into + * the context if a previous directive's entry changed shape. + * + * This function will decide whether or not a value should be applied (if there is a + * cache miss) to the context based on the following rules: + * + * - If there is an identity change between the existing value and new value + * - If there is no existing value cached (first write) + * - If a previous directive flagged the existing cached value as dirty + */ +function isMultiValueCacheHit( + context: StylingContext, entryIsClassBased: boolean, directiveIndex: number, + newValue: any): boolean { + const indexOfCachedValues = + entryIsClassBased ? StylingIndex.CachedMultiClasses : StylingIndex.CachedMultiStyles; + const cachedValues = context[indexOfCachedValues] as MapBasedOffsetValues; + const index = MapBasedOffsetValuesIndex.ValuesStartPosition + + directiveIndex * MapBasedOffsetValuesIndex.Size; + if (cachedValues[index + MapBasedOffsetValuesIndex.DirtyFlagOffset]) return false; + return newValue === NO_CHANGE || + readCachedMapValue(context, entryIsClassBased, directiveIndex) === newValue; +} + +/** + * Updates the cached status of a multi-styling value in the context. + * + * The cached map array (which exists in the context) contains a manifest of + * each multi-styling entry (`[style]` and `[class]` entries) for the template + * as well as all directives. + * + * This function will update the cached status of the provided multi-style + * entry within the cache. + * + * When called, this function will update the following information: + * - The actual cached value (the raw value that was passed into `[style]` or `[class]`) + * - The total amount of unique styling entries that this value has written into the context + * - The exact position of where the multi styling entries start in the context for this binding + * - The dirty flag will be set to true + * + * If the `dirtyFutureValues` param is provided then it will update all future entries (binding + * entries that exist as apart of other directives) to be dirty as well. This will force the + * styling algorithm to reapply those values once change detection checks them (which will in + * turn cause the styling context to update itself and the correct styling values will be + * rendered on screen). + */ +function updateCachedMapValue( + context: StylingContext, directiveIndex: number, entryIsClassBased: boolean, cacheValue: any, + startPosition: number, endPosition: number, totalValues: number, dirtyFutureValues: boolean) { + const values = + context[entryIsClassBased ? StylingIndex.CachedMultiClasses : StylingIndex.CachedMultiStyles]; + + const index = MapBasedOffsetValuesIndex.ValuesStartPosition + + directiveIndex * MapBasedOffsetValuesIndex.Size; + + // in the event that this is true we assume that future values are dirty and therefore + // will be checked again in the next CD cycle + if (dirtyFutureValues) { + const nextStartPosition = startPosition + totalValues * MapBasedOffsetValuesIndex.Size; + for (let i = index + MapBasedOffsetValuesIndex.Size; i < values.length; + i += MapBasedOffsetValuesIndex.Size) { + values[i + MapBasedOffsetValuesIndex.PositionStartOffset] = nextStartPosition; + values[i + MapBasedOffsetValuesIndex.DirtyFlagOffset] = 1; + } + } + + values[index + MapBasedOffsetValuesIndex.DirtyFlagOffset] = 0; + values[index + MapBasedOffsetValuesIndex.PositionStartOffset] = startPosition; + values[index + MapBasedOffsetValuesIndex.ValueOffset] = cacheValue; + values[index + MapBasedOffsetValuesIndex.ValueCountOffset] = totalValues; + + // the code below counts the total amount of styling values that exist in + // the context up until this directive. This value will be later used to + // update the cached value map's total counter value. + let totalStylingEntries = totalValues; + for (let i = MapBasedOffsetValuesIndex.ValuesStartPosition; i < index; + i += MapBasedOffsetValuesIndex.Size) { + totalStylingEntries += values[i + MapBasedOffsetValuesIndex.ValueCountOffset]; + } + + // because style values come before class values in the context this means + // that if any new values were inserted then the cache values array for + // classes is out of sync. The code below will update the offsets to point + // to their new values. + if (!entryIsClassBased) { + const classCache = context[StylingIndex.CachedMultiClasses]; + const classesStartPosition = classCache + [MapBasedOffsetValuesIndex.ValuesStartPosition + + MapBasedOffsetValuesIndex.PositionStartOffset]; + const diffInStartPosition = endPosition - classesStartPosition; + for (let i = MapBasedOffsetValuesIndex.ValuesStartPosition; i < classCache.length; + i += MapBasedOffsetValuesIndex.Size) { + classCache[i + MapBasedOffsetValuesIndex.PositionStartOffset] += diffInStartPosition; + } + } + + values[MapBasedOffsetValuesIndex.EntriesCountPosition] = totalStylingEntries; +} + +function hyphenateEntries(entries: string[]): string[] { + const newEntries: string[] = []; + for (let i = 0; i < entries.length; i++) { + newEntries.push(hyphenate(entries[i])); + } + return newEntries; +} + +function hyphenate(value: string): string { + return value.replace( + /[a-z][A-Z]/g, match => `${match.charAt(0)}-${match.charAt(1).toLowerCase()}`); +} diff --git a/packages/core/src/render3/styling/util.ts b/packages/core/src/render3/styling/util.ts index 16eb3d6e20..b2b72800dd 100644 --- a/packages/core/src/render3/styling/util.ts +++ b/packages/core/src/render3/styling/util.ts @@ -5,38 +5,45 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import '../ng_dev_mode'; +import '../../util/ng_dev_mode'; import {StyleSanitizeFn} from '../../sanitization/style_sanitizer'; import {getLContext} from '../context_discovery'; -import {LContainer} from '../interfaces/container'; +import {LCONTAINER_LENGTH, LContainer} from '../interfaces/container'; import {LContext} from '../interfaces/context'; import {AttributeMarker, TAttributes, TNode, TNodeFlags} from '../interfaces/node'; import {PlayState, Player, PlayerContext, PlayerIndex} from '../interfaces/player'; import {RElement} from '../interfaces/renderer'; -import {InitialStylingValues, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; +import {InitialStylingValues, InitialStylingValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; import {HEADER_OFFSET, HOST, LView, RootContext} from '../interfaces/view'; import {getTNode} from '../util'; import {CorePlayerHandler} from './core_player_handler'; -const ANIMATION_PROP_PREFIX = '@'; +export const ANIMATION_PROP_PREFIX = '@'; export function createEmptyStylingContext( element?: RElement | null, sanitizer?: StyleSanitizeFn | null, initialStyles?: InitialStylingValues | null, initialClasses?: InitialStylingValues | null): StylingContext { - return [ - 0, // MasterFlags - [null, -1, false, sanitizer || null], // DirectiveRefs - initialStyles || [null], // InitialStyles - initialClasses || [null], // InitialClasses - [0, 0], // SinglePropOffsets - element || null, // Element - null, // PreviousMultiClassValue - null, // PreviousMultiStyleValue - null, // PlayerContext + const context: StylingContext = [ + 0, // MasterFlags + [] as any, // DirectiveRefs (this gets filled below) + initialStyles || [null, null], // InitialStyles + initialClasses || [null, null], // InitialClasses + [0, 0], // SinglePropOffsets + element || null, // Element + [0], // CachedMultiClassValue + [0], // CachedMultiStyleValue + null, // PlayerContext ]; + allocateDirectiveIntoContext(context, null); + return context; +} + +export function allocateDirectiveIntoContext(context: StylingContext, directiveRef: any | null) { + // this is a new directive which we have not seen yet. + context[StylingIndex.DirectiveRegistryPosition].push(directiveRef, -1, false, null); } /** @@ -93,16 +100,48 @@ export function getStylingContext(index: number, viewData: LView): StylingContex } } -export function isStylingContext(value: any): value is StylingContext { +export function isStylingContext(value: any): boolean { // Not an LView or an LContainer - return Array.isArray(value) && typeof value[StylingIndex.MasterFlagPosition] === 'number' && - Array.isArray(value[StylingIndex.InitialStyleValuesPosition]); + if (Array.isArray(value) && value.length >= StylingIndex.SingleStylesStartPosition) { + return typeof value[StylingIndex.MasterFlagPosition] === 'number' && + value[StylingIndex.InitialClassValuesPosition] + [InitialStylingValuesIndex.DefaultNullValuePosition] === null; + } + return false; } export function isAnimationProp(name: string): boolean { return name[0] === ANIMATION_PROP_PREFIX; } +export function hasClassInput(tNode: TNode) { + return (tNode.flags & TNodeFlags.hasClassInput) !== 0; +} + +export function hasStyleInput(tNode: TNode) { + return (tNode.flags & TNodeFlags.hasStyleInput) !== 0; +} + +export function forceClassesAsString(classes: string | {[key: string]: any} | null | undefined): + string { + if (classes && typeof classes !== 'string') { + classes = Object.keys(classes).join(' '); + } + return (classes as string) || ''; +} + +export function forceStylesAsString(styles: {[key: string]: any} | null | undefined): string { + let str = ''; + if (styles) { + const props = Object.keys(styles); + for (let i = 0; i < props.length; i++) { + const prop = props[i]; + str += (i ? ';' : '') + `${prop}:${styles[prop]}`; + } + } + return str; +} + export function addPlayerInternal( playerContext: PlayerContext, rootContext: RootContext, element: HTMLElement, player: Player | null, playerContextIndex: number, ref?: any): boolean { @@ -196,7 +235,3 @@ export function hasStyling(attrs: TAttributes): boolean { } return false; } - -export function hasClassInput(tNode: TNode) { - return tNode.flags & TNodeFlags.hasClassInput ? true : false; -} diff --git a/packages/core/src/render3/util.ts b/packages/core/src/render3/util.ts index c8c2d3132d..fd9fd5969b 100644 --- a/packages/core/src/render3/util.ts +++ b/packages/core/src/render3/util.ts @@ -6,17 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ -import {global} from '../util'; +import {assertDataInRange, assertDefined, assertGreaterThan, assertLessThan} from '../util/assert'; +import {global} from '../util/global'; -import {assertDataInRange, assertDefined, assertGreaterThan, assertLessThan} from './assert'; -import {ACTIVE_INDEX, LCONTAINER_LENGTH, LContainer} from './interfaces/container'; +import {LCONTAINER_LENGTH, LContainer} from './interfaces/container'; import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {ComponentDef, DirectiveDef} from './interfaces/definition'; import {NO_PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags} from './interfaces/injector'; import {TContainerNode, TElementNode, TNode, TNodeFlags, TNodeType} from './interfaces/node'; import {RComment, RElement, RText} from './interfaces/renderer'; import {StylingContext} from './interfaces/styling'; -import {CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, LView, LViewFlags, PARENT, RootContext, TData, TVIEW, TView} from './interfaces/view'; +import {CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, RootContext, TData, TVIEW, T_HOST} from './interfaces/view'; + + /** * Returns whether the values are different from a change detection stand point. @@ -29,7 +31,10 @@ export function isDifferent(a: any, b: any): boolean { return !(a !== a && b !== b) && a !== b; } -export function stringify(value: any): string { +/** + * Used for stringify render output in Ivy. + */ +export function renderStringify(value: any): string { if (typeof value == 'function') return value.name || value; if (typeof value == 'string') return value; if (value == null) return ''; @@ -231,12 +236,12 @@ export function getParentInjectorTNode( let viewOffset = getParentInjectorViewOffset(location); // view offset is 1 let parentView = startView; - let parentTNode = startView[HOST_NODE] as TElementNode; + let parentTNode = startView[T_HOST] as TElementNode; // view offset is superior to 1 while (viewOffset > 1) { parentView = parentView[DECLARATION_VIEW] !; - parentTNode = parentView[HOST_NODE] as TElementNode; + parentTNode = parentView[T_HOST] as TElementNode; viewOffset--; } return parentTNode; @@ -263,28 +268,67 @@ export function addAllToArray(items: any[], arr: any[]) { * Given a current view, finds the nearest component's host (LElement). * * @param lView LView for which we want a host element node - * @param declarationMode indicates whether DECLARATION_VIEW or PARENT should be used to climb the - * tree. * @returns The host node */ -export function findComponentView(lView: LView, declarationMode?: boolean): LView { - let rootTNode = lView[HOST_NODE]; +export function findComponentView(lView: LView): LView { + let rootTNode = lView[T_HOST]; while (rootTNode && rootTNode.type === TNodeType.View) { - ngDevMode && assertDefined( - lView[declarationMode ? DECLARATION_VIEW : PARENT], - declarationMode ? 'lView.declarationView' : 'lView.parent'); - lView = lView[declarationMode ? DECLARATION_VIEW : PARENT] !; - rootTNode = lView[HOST_NODE]; + ngDevMode && assertDefined(lView[DECLARATION_VIEW], 'lView[DECLARATION_VIEW]'); + lView = lView[DECLARATION_VIEW] !; + rootTNode = lView[T_HOST]; } return lView; } -/** - * Return the host TElementNode of the starting LView - * @param lView the starting LView. - */ -export function getHostTElementNode(lView: LView): TElementNode|null { - return findComponentView(lView, true)[HOST_NODE] as TElementNode; +export function resolveWindow(element: RElement & {ownerDocument: Document}) { + return {name: 'window', target: element.ownerDocument.defaultView}; } + +export function resolveDocument(element: RElement & {ownerDocument: Document}) { + return {name: 'document', target: element.ownerDocument}; +} + +export function resolveBody(element: RElement & {ownerDocument: Document}) { + return {name: 'body', target: element.ownerDocument.body}; +} + +/** + * The special delimiter we use to separate property names, prefixes, and suffixes + * in property binding metadata. See storeBindingMetadata(). + * + * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter + * because it is a very uncommon character that is unlikely to be part of a user's + * property names or interpolation strings. If it is in fact used in a property + * binding, DebugElement.properties will not return the correct value for that + * binding. However, there should be no runtime effect for real applications. + * + * This character is typically rendered as a question mark inside of a diamond. + * See https://en.wikipedia.org/wiki/Specials_(Unicode_block) + * + */ +export const INTERPOLATION_DELIMITER = `�`; + +/** + * Determines whether or not the given string is a property metadata string. + * See storeBindingMetadata(). + */ +export function isPropMetadataString(str: string): boolean { + return str.indexOf(INTERPOLATION_DELIMITER) >= 0; +} + +export function applyOnCreateInstructions(tNode: TNode) { + // there may be some instructions that need to run in a specific + // order because the CREATE block in a directive runs before the + // CREATE block in a template. To work around this instructions + // can get access to the function array below and defer any code + // to run after the element is created. + let fns: Function[]|null; + if (fns = tNode.onElementCreationFns) { + for (let i = 0; i < fns.length; i++) { + fns[i](); + } + tNode.onElementCreationFns = null; + } +} \ No newline at end of file diff --git a/packages/core/src/render3/view_engine_compatibility.ts b/packages/core/src/render3/view_engine_compatibility.ts index 0f924ba8c9..6c5b68af97 100644 --- a/packages/core/src/render3/view_engine_compatibility.ts +++ b/packages/core/src/render3/view_engine_compatibility.ts @@ -7,7 +7,7 @@ */ import {ChangeDetectorRef as ViewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref'; -import {Injector, NullInjector} from '../di/injector'; +import {Injector} from '../di/injector'; import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory'; import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref'; import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory'; @@ -15,15 +15,14 @@ import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref'; import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref'; import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref'; import {Renderer2} from '../render/api'; -import {assertDefined, assertGreaterThan, assertLessThan} from './assert'; +import {assertDefined, assertGreaterThan, assertLessThan} from '../util/assert'; + import {NodeInjector, getParentInjectorLocation} from './di'; import {addToViewTree, createEmbeddedViewAndNode, createLContainer, renderEmbeddedTemplate} from './instructions'; import {ACTIVE_INDEX, LContainer, NATIVE, VIEWS} from './interfaces/container'; -import {RenderFlags} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node'; -import {LQueries} from './interfaces/query'; -import {RComment, RElement, Renderer3, isProceduralRenderer} from './interfaces/renderer'; -import {CONTAINER_INDEX, CONTEXT, HOST_NODE, LView, QUERIES, RENDERER, TView} from './interfaces/view'; +import {RComment, RElement, isProceduralRenderer} from './interfaces/renderer'; +import {CONTAINER_INDEX, CONTEXT, LView, QUERIES, RENDERER, TView, T_HOST} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; import {addRemoveViewFromContainer, appendChild, detachView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode, removeView} from './node_manipulation'; import {getLView, getPreviousOrParentTNode} from './state'; @@ -31,6 +30,7 @@ import {findComponentView, getComponentViewByIndex, getNativeByTNode, getParentI import {ViewRef} from './view_ref'; + /** * Creates an ElementRef from the most recent node. * @@ -64,8 +64,7 @@ export function createElementRef( let R3TemplateRef: { new ( _declarationParentView: LView, elementRef: ViewEngine_ElementRef, _tView: TView, - _renderer: Renderer3, _queries: LQueries | null, _injectorIndex: number): - ViewEngine_TemplateRef + _hostLContainer: LContainer, _injectorIndex: number): ViewEngine_TemplateRef }; /** @@ -97,7 +96,7 @@ export function createTemplateRef( R3TemplateRef = class TemplateRef_ extends TemplateRefToken { constructor( private _declarationParentView: LView, readonly elementRef: ViewEngine_ElementRef, - private _tView: TView, private _renderer: Renderer3, private _queries: LQueries|null, + private _tView: TView, private _hostLContainer: LContainer, private _injectorIndex: number) { super(); } @@ -107,14 +106,14 @@ export function createTemplateRef( hostTNode?: TElementNode|TContainerNode|TElementContainerNode, hostView?: LView, index?: number): viewEngine_EmbeddedViewRef { const lView = createEmbeddedViewAndNode( - this._tView, context, this._declarationParentView, this._renderer, this._queries, + this._tView, context, this._declarationParentView, this._hostLContainer[QUERIES], this._injectorIndex); if (container) { insertView(lView, container, hostView !, index !, hostTNode !.index); } renderEmbeddedTemplate(lView, this._tView, context); const viewRef = new ViewRef(lView, context, -1); - viewRef._tViewNode = lView[HOST_NODE] as TViewNode; + viewRef._tViewNode = lView[T_HOST] as TViewNode; return viewRef; } }; @@ -125,7 +124,7 @@ export function createTemplateRef( ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated'); return new R3TemplateRef( hostView, createElementRef(ElementRefToken, hostTNode, hostView), hostTNode.tViews as TView, - getLView()[RENDERER], hostContainer[QUERIES], hostTNode.injectorIndex); + hostContainer, hostTNode.injectorIndex); } else { return null; } @@ -190,7 +189,7 @@ export function createContainerRef( const parentTNode = getParentInjectorTNode(parentLocation, this._hostView, this._hostTNode); return !hasParentInjector(parentLocation) || parentTNode == null ? - new NullInjector() : + new NodeInjector(null, this._hostView) : new NodeInjector(parentTNode, parentView); } @@ -264,13 +263,13 @@ export function createContainerRef( remove(index?: number): void { const adjustedIdx = this._adjustIndex(index, -1); - removeView(this._lContainer, this._hostTNode, adjustedIdx); + removeView(this._lContainer, adjustedIdx); this._viewRefs.splice(adjustedIdx, 1); } detach(index?: number): viewEngine_ViewRef|null { const adjustedIdx = this._adjustIndex(index, -1); - const view = detachView(this._lContainer, adjustedIdx, !!this._hostTNode.detached); + const view = detachView(this._lContainer, adjustedIdx); const wasDetached = this._viewRefs.splice(adjustedIdx, 1)[0] != null; return wasDetached ? new ViewRef(view, view[CONTEXT], view[CONTAINER_INDEX]) : null; } @@ -317,7 +316,7 @@ export function createContainerRef( } hostView[hostTNode.index] = lContainer = - createLContainer(slotValue, hostTNode, hostView, commentNode, true); + createLContainer(slotValue, hostView, commentNode, true); addToViewTree(hostView, hostTNode.index as number, lContainer); } @@ -345,7 +344,7 @@ export function createViewRef( const componentIndex = hostTNode.directiveStart; const componentView = getComponentViewByIndex(hostTNode.index, hostView); return new ViewRef(componentView, context, componentIndex); - } else if (hostTNode.type === TNodeType.Element) { + } else if (hostTNode.type === TNodeType.Element || hostTNode.type === TNodeType.Container) { const hostComponentView = findComponentView(hostView); return new ViewRef(hostComponentView, hostComponentView[CONTEXT], -1); } diff --git a/packages/core/src/render3/view_ref.ts b/packages/core/src/render3/view_ref.ts index b88ec8cb94..9130e87385 100644 --- a/packages/core/src/render3/view_ref.ts +++ b/packages/core/src/render3/view_ref.ts @@ -11,9 +11,9 @@ import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detec import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref'; import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref'; -import {checkNoChanges, checkNoChangesInRootView, checkView, detectChangesInRootView, detectChangesInternal, markViewDirty, storeCleanupFn, viewAttached} from './instructions'; +import {checkNoChangesInRootView, checkNoChangesInternal, detectChangesInRootView, detectChangesInternal, markViewDirty, storeCleanupFn} from './instructions'; import {TNode, TNodeType, TViewNode} from './interfaces/node'; -import {FLAGS, HOST, HOST_NODE, LView, LViewFlags, PARENT, RENDERER_FACTORY} from './interfaces/view'; +import {FLAGS, HOST, LView, LViewFlags, PARENT, T_HOST} from './interfaces/view'; import {destroyLView} from './node_manipulation'; import {getNativeByTNode} from './util'; @@ -41,7 +41,7 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int get rootNodes(): any[] { if (this._lView[HOST] == null) { - const tView = this._lView[HOST_NODE] as TViewNode; + const tView = this._lView[T_HOST] as TViewNode; return collectNativeNodes(this._lView, tView, []); } return []; @@ -252,7 +252,7 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int * This is used in development mode to verify that running change detection doesn't * introduce other changes. */ - checkNoChanges(): void { checkNoChanges(this.context); } + checkNoChanges(): void { checkNoChangesInternal(this._lView, this.context); } attachToViewContainerRef(vcRef: viewEngine_ViewContainerRef) { if (this._appRef) { diff --git a/packages/core/src/sanitization/html_sanitizer.ts b/packages/core/src/sanitization/html_sanitizer.ts index 4b69587fb4..eb39f31a13 100644 --- a/packages/core/src/sanitization/html_sanitizer.ts +++ b/packages/core/src/sanitization/html_sanitizer.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {isDevMode} from '../is_dev_mode'; +import {isDevMode} from '../util/is_dev_mode'; import {InertBodyHelper} from './inert_body'; import {_sanitizeUrl, sanitizeSrcset} from './url_sanitizer'; @@ -250,7 +250,7 @@ export function _sanitizeHtml(defaultDoc: any, unsafeHtmlInput: string): string getTemplateContent(inertBodyElement !) as Element || inertBodyElement); if (isDevMode() && sanitizer.sanitizedSomething) { console.warn( - 'WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).'); + 'WARNING: sanitizing HTML stripped some content, see http://g.co/ng/security#xss'); } return safeHtml; diff --git a/packages/core/src/sanitization/inert_body.ts b/packages/core/src/sanitization/inert_body.ts index e3bde269c7..18bc74bd21 100644 --- a/packages/core/src/sanitization/inert_body.ts +++ b/packages/core/src/sanitization/inert_body.ts @@ -74,7 +74,7 @@ export class InertBodyHelper { html = '' + html + ''; try { html = encodeURI(html); - } catch (e) { + } catch { return null; } const xhr = new XMLHttpRequest(); @@ -103,7 +103,7 @@ export class InertBodyHelper { .body as HTMLBodyElement; body.removeChild(body.firstChild !); return body; - } catch (e) { + } catch { return null; } } @@ -169,7 +169,7 @@ export class InertBodyHelper { function isDOMParserAvailable() { try { return !!(window as any).DOMParser; - } catch (e) { + } catch { return false; } } diff --git a/packages/core/src/sanitization/sanitization.ts b/packages/core/src/sanitization/sanitization.ts index 5e03458356..c4c6b7cb4f 100644 --- a/packages/core/src/sanitization/sanitization.ts +++ b/packages/core/src/sanitization/sanitization.ts @@ -8,7 +8,7 @@ import {SANITIZER} from '../render3/interfaces/view'; import {getLView} from '../render3/state'; -import {stringify} from '../render3/util'; +import {renderStringify} from '../render3/util'; import {BypassType, allowSanitizationBypass} from './bypass'; import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer'; @@ -39,7 +39,7 @@ export function sanitizeHtml(unsafeHtml: any): string { if (allowSanitizationBypass(unsafeHtml, BypassType.Html)) { return unsafeHtml.toString(); } - return _sanitizeHtml(document, stringify(unsafeHtml)); + return _sanitizeHtml(document, renderStringify(unsafeHtml)); } /** @@ -63,7 +63,7 @@ export function sanitizeStyle(unsafeStyle: any): string { if (allowSanitizationBypass(unsafeStyle, BypassType.Style)) { return unsafeStyle.toString(); } - return _sanitizeStyle(stringify(unsafeStyle)); + return _sanitizeStyle(renderStringify(unsafeStyle)); } /** @@ -88,7 +88,7 @@ export function sanitizeUrl(unsafeUrl: any): string { if (allowSanitizationBypass(unsafeUrl, BypassType.Url)) { return unsafeUrl.toString(); } - return _sanitizeUrl(stringify(unsafeUrl)); + return _sanitizeUrl(renderStringify(unsafeUrl)); } /** @@ -132,6 +132,39 @@ export function sanitizeScript(unsafeScript: any): string { throw new Error('unsafe value used in a script context'); } +/** + * Detects which sanitizer to use for URL property, based on tag name and prop name. + * + * The rules are based on the RESOURCE_URL context config from + * `packages/compiler/src/schema/dom_security_schema.ts`. + * If tag and prop names don't match Resource URL schema, use URL sanitizer. + */ +export function getUrlSanitizer(tag: string, prop: string) { + if ((prop === 'src' && (tag === 'embed' || tag === 'frame' || tag === 'iframe' || + tag === 'media' || tag === 'script')) || + (prop === 'href' && (tag === 'base' || tag === 'link'))) { + return sanitizeResourceUrl; + } + return sanitizeUrl; +} + +/** + * Sanitizes URL, selecting sanitizer function based on tag and property names. + * + * This function is used in case we can't define security context at compile time, when only prop + * name is available. This happens when we generate host bindings for Directives/Components. The + * host element is unknown at compile time, so we defer calculation of specific sanitizer to + * runtime. + * + * @param unsafeUrl untrusted `url`, typically from the user. + * @param tag target element tag name. + * @param prop name of the property that contains the value. + * @returns `url` string which is safe to bind. + */ +export function sanitizeUrlOrResourceUrl(unsafeUrl: any, tag: string, prop: string): any { + return getUrlSanitizer(tag, prop)(unsafeUrl); +} + /** * The default style sanitizer will handle sanitization for style properties by * sanitizing any CSS property that can include a `url` value (usually image-based properties) @@ -139,14 +172,31 @@ export function sanitizeScript(unsafeScript: any): string { export const defaultStyleSanitizer = (function(prop: string, value?: string): string | boolean { if (value === undefined) { return prop === 'background-image' || prop === 'background' || prop === 'border-image' || - prop === 'filter' || prop === 'filter' || prop === 'list-style' || - prop === 'list-style-image'; + prop === 'filter' || prop === 'list-style' || prop === 'list-style-image'; } return sanitizeStyle(value); } as StyleSanitizeFn); +export function validateAgainstEventProperties(name: string) { + if (name.toLowerCase().startsWith('on')) { + const msg = `Binding to event property '${name}' is disallowed for security reasons, ` + + `please use (${name.slice(2)})=...` + + `\nIf '${name}' is a directive input, make sure the directive is imported by the` + + ` current module.`; + throw new Error(msg); + } +} + +export function validateAgainstEventAttributes(name: string) { + if (name.toLowerCase().startsWith('on')) { + const msg = `Binding to event attribute '${name}' is disallowed for security reasons, ` + + `please use (${name.slice(2)})=...`; + throw new Error(msg); + } +} + function getSanitizer(): Sanitizer|null { const lView = getLView(); return lView && lView[SANITIZER]; -} \ No newline at end of file +} diff --git a/packages/core/src/sanitization/style_sanitizer.ts b/packages/core/src/sanitization/style_sanitizer.ts index aef692fa89..62a6ecbe59 100644 --- a/packages/core/src/sanitization/style_sanitizer.ts +++ b/packages/core/src/sanitization/style_sanitizer.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {isDevMode} from '../is_dev_mode'; +import {isDevMode} from '../util/is_dev_mode'; import {_sanitizeUrl} from './url_sanitizer'; diff --git a/packages/core/src/sanitization/url_sanitizer.ts b/packages/core/src/sanitization/url_sanitizer.ts index 205443d91b..9cd29e1bb5 100644 --- a/packages/core/src/sanitization/url_sanitizer.ts +++ b/packages/core/src/sanitization/url_sanitizer.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {isDevMode} from '../is_dev_mode'; +import {isDevMode} from '../util/is_dev_mode'; /** * A pattern that recognizes a commonly useful subset of URLs that are safe. diff --git a/packages/core/src/testability/testability.ts b/packages/core/src/testability/testability.ts index 229ca4f484..e555300bfb 100644 --- a/packages/core/src/testability/testability.ts +++ b/packages/core/src/testability/testability.ts @@ -7,7 +7,7 @@ */ import {Injectable} from '../di'; -import {scheduleMicroTask} from '../util'; +import {scheduleMicroTask} from '../util/microtask'; import {NgZone} from '../zone/ng_zone'; /** diff --git a/packages/core/src/util.ts b/packages/core/src/util.ts deleted file mode 100644 index 07a25685f8..0000000000 --- a/packages/core/src/util.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// TODO(jteplitz602): Load WorkerGlobalScope from lib.webworker.d.ts file #3492 -declare var WorkerGlobalScope: any /** TODO #9100 */; -// CommonJS / Node have global context exposed as "global" variable. -// We don't want to include the whole node.d.ts this this compilation unit so we'll just fake -// the global "global" var for now. -declare var global: any /** TODO #9100 */; -const __window = typeof window !== 'undefined' && window; -const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && - self instanceof WorkerGlobalScope && self; -const __global = typeof global !== 'undefined' && global; - -// Check __global first, because in Node tests both __global and __window may be defined and _global -// should be __global in that case. -const _global: {[name: string]: any} = __global || __window || __self; - -const promise: Promise = Promise.resolve(0); -/** - * Attention: whenever providing a new value, be sure to add an - * entry into the corresponding `....externs.js` file, - * so that closure won't use that global for its purposes. - */ -export {_global as global}; - -// When Symbol.iterator doesn't exist, retrieves the key used in es6-shim -declare const Symbol: any; -let _symbolIterator: any = null; -export function getSymbolIterator(): string|symbol { - if (!_symbolIterator) { - const Symbol = _global['Symbol']; - if (Symbol && Symbol.iterator) { - _symbolIterator = Symbol.iterator; - } else { - // es6-shim specific logic - const keys = Object.getOwnPropertyNames(Map.prototype); - for (let i = 0; i < keys.length; ++i) { - const key = keys[i]; - if (key !== 'entries' && key !== 'size' && - (Map as any).prototype[key] === Map.prototype['entries']) { - _symbolIterator = key; - } - } - } - } - return _symbolIterator; -} - -export function scheduleMicroTask(fn: Function) { - if (typeof Zone === 'undefined') { - // use promise to schedule microTask instead of use Zone - promise.then(() => { fn && fn.apply(null, null); }); - } else { - Zone.current.scheduleMicroTask('scheduleMicrotask', fn); - } -} - -// JS has NaN !== NaN -export function looseIdentical(a: any, b: any): boolean { - return a === b || typeof a === 'number' && typeof b === 'number' && isNaN(a) && isNaN(b); -} - -export function stringify(token: any): string { - if (typeof token === 'string') { - return token; - } - - if (token instanceof Array) { - return '[' + token.map(stringify).join(', ') + ']'; - } - - if (token == null) { - return '' + token; - } - - if (token.overriddenName) { - return `${token.overriddenName}`; - } - - if (token.name) { - return `${token.name}`; - } - - const res = token.toString(); - - if (res == null) { - return '' + res; - } - - const newLineIndex = res.indexOf('\n'); - return newLineIndex === -1 ? res : res.substring(0, newLineIndex); -} - -/** - * Convince closure compiler that the wrapped function has no side-effects. - * - * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to - * allow us to execute a function but have closure compiler mark the call as no-side-effects. - * It is important that the return value for the `noSideEffects` function be assigned - * to something which is retained otherwise the call to `noSideEffects` will be removed by closure - * compiler. - */ -export function noSideEffects(fn: () => void): string { - return '' + {toString: fn}; -} \ No newline at end of file diff --git a/packages/core/src/util/BUILD.bazel b/packages/core/src/util/BUILD.bazel new file mode 100644 index 0000000000..59e3930a63 --- /dev/null +++ b/packages/core/src/util/BUILD.bazel @@ -0,0 +1,20 @@ +package(default_visibility = [ + "//packages/core:__subpackages__", + "//tools/public_api_guard:__pkg__", +]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "util", + srcs = glob( + [ + "**/*.ts", + ], + ), + deps = [ + "//packages/core/src/interface", + "@rxjs", + "@rxjs//operators", + ], +) diff --git a/packages/core/src/util/WrappedValue.ts b/packages/core/src/util/WrappedValue.ts new file mode 100644 index 0000000000..48e5e3f76b --- /dev/null +++ b/packages/core/src/util/WrappedValue.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * Indicates that the result of a {@link Pipe} transformation has changed even though the + * reference has not changed. + * + * Wrapped values are unwrapped automatically during the change detection, and the unwrapped value + * is stored. + * + * Example: + * + * ``` + * if (this._latestValue === this._latestReturnedValue) { + * return this._latestReturnedValue; + * } else { + * this._latestReturnedValue = this._latestValue; + * return WrappedValue.wrap(this._latestValue); // this will force update + * } + * ``` + * + * @publicApi + */ +export class WrappedValue { + /** @deprecated from 5.3, use `unwrap()` instead - will switch to protected */ + wrapped: any; + + constructor(value: any) { this.wrapped = value; } + + /** Creates a wrapped value. */ + static wrap(value: any): WrappedValue { return new WrappedValue(value); } + + /** + * Returns the underlying value of a wrapped value. + * Returns the given `value` when it is not wrapped. + **/ + static unwrap(value: any): any { return WrappedValue.isWrapped(value) ? value.wrapped : value; } + + /** Returns true if `value` is a wrapped value. */ + static isWrapped(value: any): value is WrappedValue { return value instanceof WrappedValue; } +} diff --git a/packages/core/src/util/assert.ts b/packages/core/src/util/assert.ts new file mode 100644 index 0000000000..16a2466040 --- /dev/null +++ b/packages/core/src/util/assert.ts @@ -0,0 +1,74 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// The functions in this file verify that the assumptions we are making +// about state in an instruction are correct before implementing any logic. +// They are meant only to be called in dev mode as sanity checks. + +export function assertNumber(actual: any, msg: string) { + if (typeof actual != 'number') { + throwError(msg); + } +} + +export function assertEqual(actual: T, expected: T, msg: string) { + if (actual != expected) { + throwError(msg); + } +} + +export function assertNotEqual(actual: T, expected: T, msg: string) { + if (actual == expected) { + throwError(msg); + } +} + +export function assertSame(actual: T, expected: T, msg: string) { + if (actual !== expected) { + throwError(msg); + } +} + +export function assertLessThan(actual: T, expected: T, msg: string) { + if (actual >= expected) { + throwError(msg); + } +} + +export function assertGreaterThan(actual: T, expected: T, msg: string) { + if (actual <= expected) { + throwError(msg); + } +} + +export function assertNotDefined(actual: T, msg: string) { + if (actual != null) { + throwError(msg); + } +} + +export function assertDefined(actual: T, msg: string) { + if (actual == null) { + throwError(msg); + } +} + +export function throwError(msg: string): never { + // tslint:disable-next-line + debugger; // Left intentionally for better debugger experience. + throw new Error(`ASSERTION ERROR: ${msg}`); +} + +export function assertDomNode(node: any) { + assertEqual(node instanceof Node, true, 'The provided value must be an instance of a DOM Node'); +} + + +export function assertDataInRange(arr: any[], index: number) { + assertLessThan(index, arr ? arr.length : 0, 'index expected to be a valid data index'); +} diff --git a/packages/core/src/util/closure.ts b/packages/core/src/util/closure.ts new file mode 100644 index 0000000000..de36d31b0d --- /dev/null +++ b/packages/core/src/util/closure.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * Convince closure compiler that the wrapped function has no side-effects. + * + * Closure compiler always assumes that `toString` has no side-effects. We use this quirk to + * allow us to execute a function but have closure compiler mark the call as no-side-effects. + * It is important that the return value for the `noSideEffects` function be assigned + * to something which is retained otherwise the call to `noSideEffects` will be removed by closure + * compiler. + */ +export function noSideEffects(fn: () => void): string { + return '' + {toString: fn}; +} \ No newline at end of file diff --git a/packages/core/src/util/comparison.ts b/packages/core/src/util/comparison.ts new file mode 100644 index 0000000000..e726d8fa8f --- /dev/null +++ b/packages/core/src/util/comparison.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {areIterablesEqual, isListLikeIterable} from './iterable'; + + +// JS has NaN !== NaN +export function looseIdentical(a: any, b: any): boolean { + return a === b || typeof a === 'number' && typeof b === 'number' && isNaN(a) && isNaN(b); +} + +export function devModeEqual(a: any, b: any): boolean { + const isListLikeIterableA = isListLikeIterable(a); + const isListLikeIterableB = isListLikeIterable(b); + if (isListLikeIterableA && isListLikeIterableB) { + return areIterablesEqual(a, b, devModeEqual); + } else { + const isAObject = a && (typeof a === 'object' || typeof a === 'function'); + const isBObject = b && (typeof b === 'object' || typeof b === 'function'); + if (!isListLikeIterableA && isAObject && !isListLikeIterableB && isBObject) { + return true; + } else { + return looseIdentical(a, b); + } + } +} diff --git a/packages/core/src/util/decorators.ts b/packages/core/src/util/decorators.ts index 506579f24b..907f4b9695 100644 --- a/packages/core/src/util/decorators.ts +++ b/packages/core/src/util/decorators.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../type'; +import {Type} from '../interface/type'; /** * An interface implemented by all Angular type decorators, which allows them to be used as ES7 diff --git a/packages/core/src/util/empty.ts b/packages/core/src/util/empty.ts new file mode 100644 index 0000000000..46dc61bdf6 --- /dev/null +++ b/packages/core/src/util/empty.ts @@ -0,0 +1,24 @@ +/** +* @license +* Copyright Google Inc. All Rights Reserved. +* +* Use of this source code is governed by an MIT-style license that can be +* found in the LICENSE file at https://angular.io/license +*/ +import './ng_dev_mode'; + +/** + * This file contains reuseable "empty" symbols that can be used as default return values + * in different parts of the rendering code. Because the same symbols are returned, this + * allows for identity checks against these values to be consistently used by the framework + * code. + */ + +export const EMPTY_OBJ: {} = {}; +export const EMPTY_ARRAY: any[] = []; + +// freezing the values prevents any code from accidentally inserting new values in +if (typeof ngDevMode !== 'undefined' && ngDevMode) { + Object.freeze(EMPTY_OBJ); + Object.freeze(EMPTY_ARRAY); +} diff --git a/packages/core/src/util/errors.ts b/packages/core/src/util/errors.ts new file mode 100644 index 0000000000..7f895c4420 --- /dev/null +++ b/packages/core/src/util/errors.ts @@ -0,0 +1,21 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export const ERROR_TYPE = 'ngType'; +export const ERROR_DEBUG_CONTEXT = 'ngDebugContext'; +export const ERROR_ORIGINAL_ERROR = 'ngOriginalError'; +export const ERROR_LOGGER = 'ngErrorLogger'; + + +export function wrappedError(message: string, originalError: any): Error { + const msg = + `${message} caused by: ${originalError instanceof Error ? originalError.message: originalError }`; + const error = Error(msg); + (error as any)[ERROR_ORIGINAL_ERROR] = originalError; + return error; +} diff --git a/packages/core/src/util/forward_ref.ts b/packages/core/src/util/forward_ref.ts new file mode 100644 index 0000000000..89e53dd337 --- /dev/null +++ b/packages/core/src/util/forward_ref.ts @@ -0,0 +1,67 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Type} from '../interface/type'; +import {getClosureSafeProperty} from './property'; +import {stringify} from './stringify'; + + + +/** + * An interface that a function passed into {@link forwardRef} has to implement. + * + * @usageNotes + * ### Example + * + * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref_fn'} + * @publicApi + */ +export interface ForwardRefFn { (): any; } + +const __forward_ref__ = getClosureSafeProperty({__forward_ref__: getClosureSafeProperty}); + +/** + * Allows to refer to references which are not yet defined. + * + * For instance, `forwardRef` is used when the `token` which we need to refer to for the purposes of + * DI is declared, but not yet defined. It is also used when the `token` which we use when creating + * a query is not yet defined. + * + * @usageNotes + * ### Example + * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref'} + * @publicApi + */ +export function forwardRef(forwardRefFn: ForwardRefFn): Type { + (forwardRefFn).__forward_ref__ = forwardRef; + (forwardRefFn).toString = function() { return stringify(this()); }; + return (>forwardRefFn); +} + +/** + * Lazily retrieves the reference value from a forwardRef. + * + * Acts as the identity function when given a non-forward-ref value. + * + * @usageNotes + * ### Example + * + * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='resolve_forward_ref'} + * + * @see `forwardRef` + * @publicApi + */ +export function resolveForwardRef(type: T): T { + const fn: any = type; + if (typeof fn === 'function' && fn.hasOwnProperty(__forward_ref__) && + fn.__forward_ref__ === forwardRef) { + return fn(); + } else { + return type; + } +} diff --git a/packages/core/src/util/global.ts b/packages/core/src/util/global.ts new file mode 100644 index 0000000000..49d5b9034d --- /dev/null +++ b/packages/core/src/util/global.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// TODO(jteplitz602): Load WorkerGlobalScope from lib.webworker.d.ts file #3492 +declare var WorkerGlobalScope: any /** TODO #9100 */; +// CommonJS / Node have global context exposed as "global" variable. +// We don't want to include the whole node.d.ts this this compilation unit so we'll just fake +// the global "global" var for now. +declare var global: any /** TODO #9100 */; +// Not yet available in TypeScript: https://github.com/Microsoft/TypeScript/pull/29332 +declare var globalThis: any /** TODO #9100 */; + +function getGlobal(): any { + const __globalThis = typeof globalThis !== 'undefined' && globalThis; + const __window = typeof window !== 'undefined' && window; + const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' && + self instanceof WorkerGlobalScope && self; + const __global = typeof global !== 'undefined' && global; + + // Always use __globalThis if available, which is the spec-defined global variable across all + // environments, then fallback to __global first, because in Node tests both __global and + // __window may be defined and _global should be __global in that case. + return __globalThis || __global || __window || __self; +} + +const _global = getGlobal(); + +/** + * Attention: whenever providing a new value, be sure to add an + * entry into the corresponding `....externs.js` file, + * so that closure won't use that global for its purposes. + */ +export {_global as global}; diff --git a/packages/core/src/is_dev_mode.ts b/packages/core/src/util/is_dev_mode.ts similarity index 100% rename from packages/core/src/is_dev_mode.ts rename to packages/core/src/util/is_dev_mode.ts diff --git a/packages/core/src/util/iterable.ts b/packages/core/src/util/iterable.ts new file mode 100644 index 0000000000..4f85e0cbdc --- /dev/null +++ b/packages/core/src/util/iterable.ts @@ -0,0 +1,49 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {getSymbolIterator} from './symbol'; + + +export function isListLikeIterable(obj: any): boolean { + if (!isJsObject(obj)) return false; + return Array.isArray(obj) || + (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v] + getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop +} + +export function areIterablesEqual( + a: any, b: any, comparator: (a: any, b: any) => boolean): boolean { + const iterator1 = a[getSymbolIterator()](); + const iterator2 = b[getSymbolIterator()](); + + while (true) { + const item1 = iterator1.next(); + const item2 = iterator2.next(); + if (item1.done && item2.done) return true; + if (item1.done || item2.done) return false; + if (!comparator(item1.value, item2.value)) return false; + } +} + +export function iterateListLike(obj: any, fn: (p: any) => any) { + if (Array.isArray(obj)) { + for (let i = 0; i < obj.length; i++) { + fn(obj[i]); + } + } else { + const iterator = obj[getSymbolIterator()](); + let item: any; + while (!((item = iterator.next()).done)) { + fn(item.value); + } + } +} + +export function isJsObject(o: any): boolean { + return o !== null && (typeof o === 'function' || typeof o === 'object'); +} diff --git a/packages/core/src/util/microtask.ts b/packages/core/src/util/microtask.ts new file mode 100644 index 0000000000..40edbac49d --- /dev/null +++ b/packages/core/src/util/microtask.ts @@ -0,0 +1,21 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + + +const promise: Promise = Promise.resolve(0); + +declare const Zone: any; + +export function scheduleMicroTask(fn: Function) { + if (typeof Zone === 'undefined') { + // use promise to schedule microTask instead of use Zone + promise.then(() => { fn && fn.apply(null, null); }); + } else { + Zone.current.scheduleMicroTask('scheduleMicrotask', fn); + } +} diff --git a/packages/core/src/render3/ng_dev_mode.ts b/packages/core/src/util/ng_dev_mode.ts similarity index 100% rename from packages/core/src/render3/ng_dev_mode.ts rename to packages/core/src/util/ng_dev_mode.ts diff --git a/packages/core/src/util/stringify.ts b/packages/core/src/util/stringify.ts new file mode 100644 index 0000000000..0af107a1f4 --- /dev/null +++ b/packages/core/src/util/stringify.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export function stringify(token: any): string { + if (typeof token === 'string') { + return token; + } + + if (token instanceof Array) { + return '[' + token.map(stringify).join(', ') + ']'; + } + + if (token == null) { + return '' + token; + } + + if (token.overriddenName) { + return `${token.overriddenName}`; + } + + if (token.name) { + return `${token.name}`; + } + + const res = token.toString(); + + if (res == null) { + return '' + res; + } + + const newLineIndex = res.indexOf('\n'); + return newLineIndex === -1 ? res : res.substring(0, newLineIndex); +} diff --git a/packages/core/src/util/symbol.ts b/packages/core/src/util/symbol.ts new file mode 100644 index 0000000000..71dc7edec7 --- /dev/null +++ b/packages/core/src/util/symbol.ts @@ -0,0 +1,32 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {global as _global} from './global'; + +// When Symbol.iterator doesn't exist, retrieves the key used in es6-shim +declare const Symbol: any; +let _symbolIterator: any = null; +export function getSymbolIterator(): string|symbol { + if (!_symbolIterator) { + const Symbol = _global['Symbol']; + if (Symbol && Symbol.iterator) { + _symbolIterator = Symbol.iterator; + } else { + // es6-shim specific logic + const keys = Object.getOwnPropertyNames(Map.prototype); + for (let i = 0; i < keys.length; ++i) { + const key = keys[i]; + if (key !== 'entries' && key !== 'size' && + (Map as any).prototype[key] === Map.prototype['entries']) { + _symbolIterator = key; + } + } + } + } + return _symbolIterator; +} diff --git a/packages/core/src/view/entrypoint.ts b/packages/core/src/view/entrypoint.ts index ff2933baf1..7786cae734 100644 --- a/packages/core/src/view/entrypoint.ts +++ b/packages/core/src/view/entrypoint.ts @@ -7,9 +7,9 @@ */ import {Injector} from '../di/injector'; +import {Type} from '../interface/type'; import {ComponentFactory} from '../linker/component_factory'; import {NgModuleFactory, NgModuleRef} from '../linker/ng_module_factory'; -import {Type} from '../type'; import {initServicesIfNeeded} from './services'; import {NgModuleDefinition, NgModuleDefinitionFactory, NgModuleProviderDef, ProviderOverride, Services, ViewDefinition} from './types'; diff --git a/packages/core/src/view/errors.ts b/packages/core/src/view/errors.ts index 96df939fdd..d7ded67a01 100644 --- a/packages/core/src/view/errors.ts +++ b/packages/core/src/view/errors.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {ERROR_DEBUG_CONTEXT, ERROR_LOGGER, getDebugContext} from '../errors'; -import {DebugContext, ViewState} from './types'; +import {getDebugContext} from '../errors'; +import {ERROR_DEBUG_CONTEXT, ERROR_LOGGER} from '../util/errors'; + +import {DebugContext} from './types'; export function expressionChangedAfterItHasBeenCheckedError( context: DebugContext, oldValue: any, currValue: any, isFirstCheck: boolean): Error { diff --git a/packages/core/src/view/ng_module.ts b/packages/core/src/view/ng_module.ts index 50c3c6022b..a09f79943d 100644 --- a/packages/core/src/view/ng_module.ts +++ b/packages/core/src/view/ng_module.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {InjectableDef, getInjectableDef} from '../di/defs'; import {resolveForwardRef} from '../di/forward_ref'; import {INJECTOR, Injector} from '../di/injector'; import {setCurrentInjector} from '../di/injector_compatibility'; +import {InjectableDef, getInjectableDef} from '../di/interface/defs'; import {APP_ROOT} from '../di/scope'; import {NgModuleRef} from '../linker/ng_module_factory'; -import {stringify} from '../util'; +import {stringify} from '../util/stringify'; import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types'; import {splitDepsDsl, tokenKey} from './util'; @@ -158,7 +158,7 @@ function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModulePr // avoided if possible. The sequence of checks here determines whether ngOnDestroy needs to be // checked. It might not if the `injectable` isn't an object or if NodeFlags.OnDestroy is already // set (ngOnDestroy was detected statically). - if (injectable !== UNDEFINED_VALUE && injectable != null && typeof injectable === 'object' && + if (injectable !== UNDEFINED_VALUE && injectable !== null && typeof injectable === 'object' && !(providerDef.flags & NodeFlags.OnDestroy) && typeof injectable.ngOnDestroy === 'function') { providerDef.flags |= NodeFlags.OnDestroy; } diff --git a/packages/core/src/view/provider.ts b/packages/core/src/view/provider.ts index 83e046ce53..0774765dca 100644 --- a/packages/core/src/view/provider.ts +++ b/packages/core/src/view/provider.ts @@ -12,8 +12,8 @@ import {ElementRef} from '../linker/element_ref'; import {TemplateRef} from '../linker/template_ref'; import {ViewContainerRef} from '../linker/view_container_ref'; import {Renderer as RendererV1, Renderer2} from '../render/api'; -import {stringify} from '../util'; import {isObservable} from '../util/lang'; +import {stringify} from '../util/stringify'; import {createChangeDetectorRef, createInjector, createRendererV1} from './refs'; import {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData, shouldCallLifecycleInitHook} from './types'; diff --git a/packages/core/src/view/refs.ts b/packages/core/src/view/refs.ts index 0203fdd98a..6253f93f52 100644 --- a/packages/core/src/view/refs.ts +++ b/packages/core/src/view/refs.ts @@ -9,7 +9,8 @@ import {ApplicationRef} from '../application_ref'; import {ChangeDetectorRef} from '../change_detection/change_detection'; import {Injector} from '../di/injector'; -import {InjectFlags} from '../di/injector_compatibility'; +import {InjectFlags} from '../di/interface/injector'; +import {Type} from '../interface/type'; import {ComponentFactory, ComponentRef} from '../linker/component_factory'; import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from '../linker/component_factory_resolver'; import {ElementRef} from '../linker/element_ref'; @@ -18,8 +19,7 @@ import {TemplateRef} from '../linker/template_ref'; import {ViewContainerRef} from '../linker/view_container_ref'; import {EmbeddedViewRef, InternalViewRef, ViewRef} from '../linker/view_ref'; import {Renderer as RendererV1, Renderer2} from '../render/api'; -import {Type} from '../type'; -import {stringify} from '../util'; +import {stringify} from '../util/stringify'; import {VERSION} from '../version'; import {callNgModuleLifecycle, initNgModule, resolveNgModuleDep} from './ng_module'; diff --git a/packages/core/src/view/services.ts b/packages/core/src/view/services.ts index 53e93f6b6d..7906b696c0 100644 --- a/packages/core/src/view/services.ts +++ b/packages/core/src/view/services.ts @@ -8,16 +8,17 @@ import {DebugElement__PRE_R3__, DebugNode__PRE_R3__, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node'; import {Injector} from '../di'; -import {InjectableDef, getInjectableDef} from '../di/defs'; import {InjectableType} from '../di/injectable'; +import {InjectableDef, getInjectableDef} from '../di/interface/defs'; import {ErrorHandler} from '../error_handler'; -import {isDevMode} from '../is_dev_mode'; +import {Type} from '../interface/type'; import {ComponentFactory} from '../linker/component_factory'; import {NgModuleRef} from '../linker/ng_module_factory'; import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api'; import {Sanitizer} from '../sanitization/security'; -import {Type} from '../type'; +import {isDevMode} from '../util/is_dev_mode'; import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect'; + import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors'; import {resolveDep} from './provider'; import {dirtyParentQueries, getQueryValue} from './query'; diff --git a/packages/core/src/view/types.ts b/packages/core/src/view/types.ts index 870a7df872..0f43c13274 100644 --- a/packages/core/src/view/types.ts +++ b/packages/core/src/view/types.ts @@ -8,6 +8,7 @@ import {Injector} from '../di'; import {ErrorHandler} from '../error_handler'; +import {Type} from '../interface/type'; import {ComponentFactory} from '../linker/component_factory'; import {NgModuleRef} from '../linker/ng_module_factory'; import {QueryList} from '../linker/query_list'; @@ -15,7 +16,7 @@ import {TemplateRef} from '../linker/template_ref'; import {ViewContainerRef} from '../linker/view_container_ref'; import {Renderer2, RendererFactory2, RendererType2} from '../render/api'; import {Sanitizer, SecurityContext} from '../sanitization/security'; -import {Type} from '../type'; + // ------------------------------------- diff --git a/packages/core/src/view/util.ts b/packages/core/src/view/util.ts index eade00199e..aaeec68753 100644 --- a/packages/core/src/view/util.ts +++ b/packages/core/src/view/util.ts @@ -10,7 +10,8 @@ import {WrappedValue, devModeEqual} from '../change_detection/change_detection'; import {SOURCE} from '../di/injector'; import {ViewEncapsulation} from '../metadata/view'; import {RendererType2} from '../render/api'; -import {looseIdentical, stringify} from '../util'; +import {looseIdentical} from '../util/comparison'; +import {stringify} from '../util/stringify'; import {expressionChangedAfterItHasBeenCheckedError} from './errors'; import {BindingDef, BindingFlags, Definition, DefinitionFactory, DepDef, DepFlags, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asTextData} from './types'; diff --git a/packages/core/test/BUILD.bazel b/packages/core/test/BUILD.bazel index 8d066f005b..9bfbf00aa8 100644 --- a/packages/core/test/BUILD.bazel +++ b/packages/core/test/BUILD.bazel @@ -19,6 +19,10 @@ ts_library( "//packages/compiler", "//packages/compiler/testing", "//packages/core", + "//packages/core/src/di/interface", + "//packages/core/src/interface", + "//packages/core/src/reflection", + "//packages/core/src/util", "//packages/core/testing", "//packages/platform-browser", "//packages/platform-browser-dynamic", @@ -42,6 +46,7 @@ ts_library( "//packages/compiler", "//packages/compiler/testing", "//packages/core", + "//packages/core/src/compiler", "//packages/core/testing", "//packages/platform-server", "//packages/platform-server/testing", diff --git a/packages/core/test/acceptance/BUILD.bazel b/packages/core/test/acceptance/BUILD.bazel new file mode 100644 index 0000000000..6ef8cb8dd6 --- /dev/null +++ b/packages/core/test/acceptance/BUILD.bazel @@ -0,0 +1,35 @@ +package(default_visibility = ["//visibility:private"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "acceptance_lib", + testonly = True, + srcs = glob( + ["**/*.ts"], + ), + deps = [ + "//packages/common", + "//packages/compiler", + "//packages/compiler/testing", + "//packages/core", + "//packages/core/testing", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + "//packages/platform-browser/testing", + "//packages/private/testing", + "@ngdeps//zone.js", + ], +) + +jasmine_node_test( + name = "acceptance", + bootstrap = ["angular/tools/testing/init_node_spec.js"], + deps = [ + ":acceptance_lib", + "//tools/testing:node", + "@ngdeps//base64-js", + "@ngdeps//source-map", + "@ngdeps//zone.js", + ], +) diff --git a/packages/core/test/acceptance/change_detection_spec.ts b/packages/core/test/acceptance/change_detection_spec.ts new file mode 100644 index 0000000000..340a224321 --- /dev/null +++ b/packages/core/test/acceptance/change_detection_spec.ts @@ -0,0 +1,130 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + + +import {ApplicationRef, ChangeDetectionStrategy, Component, ComponentFactoryResolver, ComponentRef, Directive, EmbeddedViewRef, NgModule, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; + +describe('change detection', () => { + + describe('embedded views', () => { + + @Directive({selector: '[viewManipulation]', exportAs: 'vm'}) + class ViewManipulation { + constructor( + private _tplRef: TemplateRef<{}>, private _vcRef: ViewContainerRef, + private _appRef: ApplicationRef) {} + + insertIntoVcRef() { this._vcRef.createEmbeddedView(this._tplRef); } + + insertIntoAppRef(): EmbeddedViewRef<{}> { + const viewRef = this._tplRef.createEmbeddedView({}); + this._appRef.attachView(viewRef); + return viewRef; + } + } + + @Component({ + selector: 'test-cmp', + template: ` + {{'change-detected'}} + ` + }) + class TestCmpt { + } + + beforeEach(() => { + TestBed.configureTestingModule({declarations: [TestCmpt, ViewManipulation]}); + }); + + it('should detect changes for embedded views inserted through ViewContainerRef', () => { + const fixture = TestBed.createComponent(TestCmpt); + const vm = fixture.debugElement.childNodes[0].references['vm'] as ViewManipulation; + + vm.insertIntoVcRef(); + fixture.detectChanges(); + + expect(fixture.nativeElement).toHaveText('change-detected'); + }); + + it('should detect changes for embedded views attached to ApplicationRef', () => { + const fixture = TestBed.createComponent(TestCmpt); + const vm = fixture.debugElement.childNodes[0].references['vm'] as ViewManipulation; + + const viewRef = vm.insertIntoAppRef(); + + // A newly created view was attached to the CD tree via ApplicationRef so should be also + // change detected when ticking root component + fixture.detectChanges(); + + expect(viewRef.rootNodes[0]).toHaveText('change-detected'); + }); + + }); + + describe('markForCheck', () => { + + it('should mark OnPush ancestor of dynamically created component views as dirty', () => { + + @Component({ + selector: `test-cmpt`, + template: `{{counter}}|`, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class TestCmpt { + counter = 0; + @ViewChild('vc', {read: ViewContainerRef}) vcRef !: ViewContainerRef; + + constructor(private _cfr: ComponentFactoryResolver) {} + + createComponentView(cmptType: Type): ComponentRef { + const cf = this._cfr.resolveComponentFactory(cmptType); + return this.vcRef.createComponent(cf); + } + } + + @Component({ + selector: 'dynamic-cmpt', + template: `dynamic`, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class DynamicCmpt { + } + + @NgModule({declarations: [DynamicCmpt], entryComponents: [DynamicCmpt]}) + class DynamicModule { + } + + TestBed.configureTestingModule({imports: [DynamicModule], declarations: [TestCmpt]}); + + const fixture = TestBed.createComponent(TestCmpt); + + // initial CD to have query results + // NOTE: we call change detection without checkNoChanges to have clearer picture + fixture.detectChanges(false); + expect(fixture.nativeElement).toHaveText('0|'); + + // insert a dynamic component + const dynamicCmptRef = fixture.componentInstance.createComponentView(DynamicCmpt); + fixture.detectChanges(false); + expect(fixture.nativeElement).toHaveText('0|dynamic'); + + // update model in the OnPush component - should not update UI + fixture.componentInstance.counter = 1; + fixture.detectChanges(false); + expect(fixture.nativeElement).toHaveText('0|dynamic'); + + // now mark the dynamically inserted component as dirty + dynamicCmptRef.changeDetectorRef.markForCheck(); + fixture.detectChanges(false); + expect(fixture.nativeElement).toHaveText('1|dynamic'); + }); + }); + +}); \ No newline at end of file diff --git a/packages/core/test/acceptance/content_spec.ts b/packages/core/test/acceptance/content_spec.ts new file mode 100644 index 0000000000..da7853c9d1 --- /dev/null +++ b/packages/core/test/acceptance/content_spec.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; + +describe('projection', () => { + it('should handle projected containers inside other containers', () => { + @Component({ + selector: 'child-comp', // + template: '' + }) + class ChildComp { + } + + @Component({ + selector: 'root-comp', // + template: '' + }) + class RootComp { + } + + @Component({ + selector: 'my-app', + template: ` + + + {{ item }}| + + + ` + }) + class MyApp { + items: number[] = [1, 2, 3]; + } + + TestBed.configureTestingModule({declarations: [ChildComp, RootComp, MyApp]}); + const fixture = TestBed.createComponent(MyApp); + fixture.detectChanges(); + + // expecting # of elements to be (items.length - 1), since last element is filtered out by + // *ngIf, this applies to all other assertions below + expect(fixture.nativeElement).toHaveText('1|2|'); + + fixture.componentInstance.items = [4, 5]; + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('4|'); + + fixture.componentInstance.items = [6, 7, 8, 9]; + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('6|7|8|'); + }); +}); \ No newline at end of file diff --git a/packages/core/test/acceptance/di_spec.ts b/packages/core/test/acceptance/di_spec.ts new file mode 100644 index 0000000000..108e598b13 --- /dev/null +++ b/packages/core/test/acceptance/di_spec.ts @@ -0,0 +1,133 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {CommonModule} from '@angular/common'; +import {ChangeDetectorRef, Component, Directive, Inject, LOCALE_ID, Optional, Pipe, PipeTransform, SkipSelf, ViewChild} from '@angular/core'; +import {ViewRef} from '@angular/core/src/render3/view_ref'; +import {TestBed} from '@angular/core/testing'; + + +describe('di', () => { + describe('ChangeDetectorRef', () => { + it('should inject host component ChangeDetectorRef into directives on templates', () => { + let pipeInstance: MyPipe; + + @Pipe({name: 'pipe'}) + class MyPipe implements PipeTransform { + constructor(public cdr: ChangeDetectorRef) { pipeInstance = this; } + + transform(value: any): any { return value; } + } + + @Component({ + selector: 'my-app', + template: `
    Visible
    `, + }) + class MyApp { + showing = true; + + constructor(public cdr: ChangeDetectorRef) {} + } + + TestBed.configureTestingModule({declarations: [MyApp, MyPipe], imports: [CommonModule]}); + const fixture = TestBed.createComponent(MyApp); + fixture.detectChanges(); + expect((pipeInstance !.cdr as ViewRef).context).toBe(fixture.componentInstance); + }); + }); + + it('should not cause cyclic dependency if same token is requested in deps with @SkipSelf', () => { + @Component({ + selector: 'my-comp', + template: '...', + providers: [{ + provide: LOCALE_ID, + useFactory: () => 'ja-JP', + // Note: `LOCALE_ID` is also provided within APPLICATION_MODULE_PROVIDERS, so we use it here + // as a dep and making sure it doesn't cause cyclic dependency (since @SkipSelf is present) + deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]] + }] + }) + class MyComp { + constructor(@Inject(LOCALE_ID) public localeId: string) {} + } + + TestBed.configureTestingModule({declarations: [MyComp]}); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + expect(fixture.componentInstance.localeId).toBe('ja-JP'); + }); + + it('module-level deps should not access Component/Directive providers', () => { + @Component({ + selector: 'my-comp', + template: '...', + providers: [{ + provide: 'LOCALE_ID_DEP', // + useValue: 'LOCALE_ID_DEP_VALUE' + }] + }) + class MyComp { + constructor(@Inject(LOCALE_ID) public localeId: string) {} + } + + TestBed.configureTestingModule({ + declarations: [MyComp], + providers: [{ + provide: LOCALE_ID, + // we expect `localeDepValue` to be undefined, since it's not provided at a module level + useFactory: (localeDepValue: any) => localeDepValue || 'en-GB', + deps: [[new Inject('LOCALE_ID_DEP'), new Optional()]] + }] + }); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + expect(fixture.componentInstance.localeId).toBe('en-GB'); + }); + + it('should skip current level while retrieving tokens if @SkipSelf is defined', () => { + @Component({ + selector: 'my-comp', + template: '...', + providers: [{provide: LOCALE_ID, useFactory: () => 'en-GB'}] + }) + class MyComp { + constructor(@SkipSelf() @Inject(LOCALE_ID) public localeId: string) {} + } + + TestBed.configureTestingModule({declarations: [MyComp]}); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + // takes `LOCALE_ID` from module injector, since we skip Component level with @SkipSelf + expect(fixture.componentInstance.localeId).toBe('en-US'); + }); + + it('should work when injecting dependency in Directives', () => { + @Directive({ + selector: '[dir]', // + providers: [{provide: LOCALE_ID, useValue: 'ja-JP'}] + }) + class MyDir { + constructor(@SkipSelf() @Inject(LOCALE_ID) public localeId: string) {} + } + @Component({ + selector: 'my-comp', + template: '
    ', + providers: [{provide: LOCALE_ID, useValue: 'en-GB'}] + }) + class MyComp { + @ViewChild(MyDir) myDir !: MyDir; + constructor(@Inject(LOCALE_ID) public localeId: string) {} + } + + TestBed.configureTestingModule({declarations: [MyDir, MyComp, MyComp]}); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + expect(fixture.componentInstance.myDir.localeId).toBe('en-GB'); + }); +}); diff --git a/packages/core/test/acceptance/exports_spec.ts b/packages/core/test/acceptance/exports_spec.ts new file mode 100644 index 0000000000..42bc020b58 --- /dev/null +++ b/packages/core/test/acceptance/exports_spec.ts @@ -0,0 +1,97 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Directive, Input, Type} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {onlyInIvy} from '@angular/private/testing'; + +describe('exports', () => { + beforeEach(() => { + TestBed.configureTestingModule( + {declarations: [AppComp, ComponentToReference, DirToReference, DirWithCompInput]}); + }); + + it('should support export of DOM element', () => { + const fixture = initWithTemplate(AppComp, ' {{ myInput.value }}'); + fixture.detectChanges(); + + expect(fixture.nativeElement.innerHTML).toEqual(' one'); + }); + + it('should support basic export of component', () => { + const fixture = + initWithTemplate(AppComp, ' {{ myComp.name }}'); + fixture.detectChanges(); + expect(fixture.nativeElement.innerHTML).toEqual(' Nancy'); + }); + + it('should work with directives with exportAs set', () => { + const fixture = initWithTemplate(AppComp, '
    {{ myDir.name }}'); + fixture.detectChanges(); + expect(fixture.nativeElement.innerHTML).toEqual('
    Drew'); + }); + + onlyInIvy('Different error message is thrown in View Engine') + .it('should throw if export name is not found', () => { + expect(() => { + const fixture = initWithTemplate(AppComp, '
    '); + fixture.detectChanges(); + }).toThrowError(/Export of name 'dir' not found!/); + }); + + it('should support component instance fed into directive', () => { + const fixture = initWithTemplate( + AppComp, '
    '); + fixture.detectChanges(); + + const myComp = fixture.debugElement.children[0].injector.get(ComponentToReference); + const dirWithInput = fixture.debugElement.children[1].injector.get(DirWithCompInput); + + expect(dirWithInput.comp).toEqual(myComp); + }); + + + onlyInIvy( + 'in Ivy first declared ref is selected in case of multiple non-unique refs, when VE used the last one') + .it('should point to the first declared ref', () => { + const fixture = initWithTemplate(AppComp, ` +
    + + + + {{ ref.value }} +
    + `); + fixture.detectChanges(); + expect(fixture.nativeElement.querySelector('span').innerHTML).toBe('First'); + }); +}); + +function initWithTemplate(compType: Type, template: string) { + TestBed.overrideComponent(compType, {set: new Component({template})}); + return TestBed.createComponent(compType); +} + +@Component({selector: 'comp-to-ref', template: ''}) +class ComponentToReference { + name = 'Nancy'; +} + +@Component({selector: 'app-comp', template: ``}) +class AppComp { +} + +@Directive({selector: '[dir]', exportAs: 'dir'}) +class DirToReference { + name = 'Drew'; +} + +@Directive({selector: '[dirWithInput]'}) +class DirWithCompInput { + @Input('dirWithInput') comp: ComponentToReference|null = null; +} diff --git a/packages/core/test/acceptance/inherit_definition_feature_spec.ts b/packages/core/test/acceptance/inherit_definition_feature_spec.ts new file mode 100644 index 0000000000..f062439ff7 --- /dev/null +++ b/packages/core/test/acceptance/inherit_definition_feature_spec.ts @@ -0,0 +1,60 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Directive, Input, OnChanges, Type} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; + +describe('ngOnChanges', () => { + it('should be inherited when super is a directive', () => { + const log: string[] = []; + + @Directive({selector: '[superDir]'}) + class SuperDirective implements OnChanges { + @Input() someInput = ''; + + ngOnChanges() { log.push('on changes!'); } + } + + @Directive({selector: '[subDir]'}) + class SubDirective extends SuperDirective { + } + + TestBed.configureTestingModule({declarations: [AppComp, SubDirective]}); + TestBed.overrideComponent( + AppComp, {set: new Component({template: '
    '})}); + const fixture = TestBed.createComponent(AppComp); + fixture.detectChanges(); + + expect(log).toEqual(['on changes!']); + }); + + it('should be inherited when super is a simple class', () => { + const log: string[] = []; + + class SuperClass { + ngOnChanges() { log.push('on changes!'); } + } + + @Directive({selector: '[subDir]'}) + class SubDirective extends SuperClass { + @Input() someInput = ''; + } + + TestBed.configureTestingModule({declarations: [AppComp, SubDirective]}); + TestBed.overrideComponent( + AppComp, {set: new Component({template: '
    '})}); + const fixture = TestBed.createComponent(AppComp); + fixture.detectChanges(); + + expect(log).toEqual(['on changes!']); + }); +}); + +@Component({selector: 'app-comp', template: ``}) +class AppComp { +} diff --git a/packages/core/test/acceptance/integration_spec.ts b/packages/core/test/acceptance/integration_spec.ts new file mode 100644 index 0000000000..1ee6334991 --- /dev/null +++ b/packages/core/test/acceptance/integration_spec.ts @@ -0,0 +1,43 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {Component, HostBinding} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {onlyInIvy} from '@angular/private/testing'; + +describe('acceptance integration tests', () => { + onlyInIvy('[style] and [class] bindings are a new feature') + .it('should render host bindings on the root component', () => { + @Component({template: '...'}) + class MyApp { + @HostBinding('style') public myStylesExp = {}; + @HostBinding('class') public myClassesExp = {}; + } + + TestBed.configureTestingModule({declarations: [MyApp]}); + const fixture = TestBed.createComponent(MyApp); + const element = fixture.nativeElement; + fixture.detectChanges(); + + const component = fixture.componentInstance; + component.myStylesExp = {width: '100px'}; + component.myClassesExp = 'foo'; + fixture.detectChanges(); + + expect(element.style['width']).toEqual('100px'); + expect(element.classList.contains('foo')).toBeTruthy(); + + component.myStylesExp = {width: '200px'}; + component.myClassesExp = 'bar'; + fixture.detectChanges(); + + expect(element.style['width']).toEqual('200px'); + expect(element.classList.contains('foo')).toBeFalsy(); + expect(element.classList.contains('bar')).toBeTruthy(); + }); +}); \ No newline at end of file diff --git a/packages/core/test/acceptance/lifecycle_spec.ts b/packages/core/test/acceptance/lifecycle_spec.ts new file mode 100644 index 0000000000..3e32089dce --- /dev/null +++ b/packages/core/test/acceptance/lifecycle_spec.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; + +describe('ngOnChanges', () => { + it('should correctly support updating one Input among many', () => { + let log: string[] = []; + + @Component({selector: 'child-comp', template: 'child'}) + class ChildComp implements OnChanges { + @Input() a: number = 0; + @Input() b: number = 0; + @Input() c: number = 0; + + ngOnChanges(changes: SimpleChanges) { + for (let key in changes) { + const simpleChange = changes[key]; + log.push(key + ': ' + simpleChange.previousValue + ' -> ' + simpleChange.currentValue); + } + } + } + + @Component( + {selector: 'app-comp', template: ''}) + class AppComp { + a = 0; + b = 0; + c = 0; + } + + TestBed.configureTestingModule({declarations: [AppComp, ChildComp]}); + const fixture = TestBed.createComponent(AppComp); + fixture.detectChanges(); + const appComp = fixture.componentInstance; + expect(log).toEqual(['a: undefined -> 0', 'b: undefined -> 0', 'c: undefined -> 0']); + log.length = 0; + + appComp.a = 1; + fixture.detectChanges(); + expect(log).toEqual(['a: 0 -> 1']); + log.length = 0; + + appComp.b = 2; + fixture.detectChanges(); + expect(log).toEqual(['b: 0 -> 2']); + log.length = 0; + + appComp.c = 3; + fixture.detectChanges(); + expect(log).toEqual(['c: 0 -> 3']); + }); +}); \ No newline at end of file diff --git a/packages/core/test/acceptance/pipe_spec.ts b/packages/core/test/acceptance/pipe_spec.ts new file mode 100644 index 0000000000..003473a731 --- /dev/null +++ b/packages/core/test/acceptance/pipe_spec.ts @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Pipe, PipeTransform} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; + +describe('pipe', () => { + it('should support pipe in context of ternary operator', () => { + @Pipe({name: 'pipe'}) + class MyPipe implements PipeTransform { + transform(value: any): any { return value; } + } + + @Component({ + selector: 'my-app', + template: `{{ condition ? 'a' : 'b' | pipe }}`, + }) + class MyApp { + condition = false; + } + + TestBed.configureTestingModule({declarations: [MyApp, MyPipe]}); + const fixture = TestBed.createComponent(MyApp); + fixture.detectChanges(); + + expect(fixture.nativeElement).toHaveText('b'); + + fixture.componentInstance.condition = true; + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('a'); + }); +}); diff --git a/packages/core/test/acceptance/query_spec.ts b/packages/core/test/acceptance/query_spec.ts new file mode 100644 index 0000000000..80775e1c1a --- /dev/null +++ b/packages/core/test/acceptance/query_spec.ts @@ -0,0 +1,212 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, ContentChild, ContentChildren, ElementRef, QueryList, TemplateRef, Type, ViewChild, ViewChildren} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {onlyInIvy} from '@angular/private/testing'; + + +describe('query logic', () => { + beforeEach(() => { + TestBed.configureTestingModule({declarations: [AppComp, QueryComp, SimpleCompA, SimpleCompB]}); + }); + + it('should return Component instances when Components are labelled and retrieved via View query', + () => { + const template = ` +
    +
    + `; + const fixture = initWithTemplate(QueryComp, template); + const comp = fixture.componentInstance; + expect(comp.viewChild).toBeAnInstanceOf(SimpleCompA); + expect(comp.viewChildren.first).toBeAnInstanceOf(SimpleCompA); + expect(comp.viewChildren.last).toBeAnInstanceOf(SimpleCompB); + }); + + it('should return Component instance when Component is labelled and retrieved via Content query', + () => { + const template = ` + + + + `; + const fixture = initWithTemplate(AppComp, template); + const comp = fixture.debugElement.children[0].references['q']; + expect(comp.contentChild).toBeAnInstanceOf(SimpleCompA); + expect(comp.contentChildren.first).toBeAnInstanceOf(SimpleCompA); + }); + + onlyInIvy('multiple local refs are supported in Ivy') + .it('should return Component instances when Components are labelled and retrieved via Content query', + () => { + const template = ` + + + + + `; + const fixture = initWithTemplate(AppComp, template); + const comp = fixture.debugElement.children[0].references['q']; + expect(comp.contentChild).toBeAnInstanceOf(SimpleCompA); + expect(comp.contentChildren.first).toBeAnInstanceOf(SimpleCompA); + expect(comp.contentChildren.last).toBeAnInstanceOf(SimpleCompB); + expect(comp.contentChildren.length).toBe(2); + }); + + it('should return ElementRef when HTML element is labelled and retrieved via View query', () => { + const template = ` +
    + `; + const fixture = initWithTemplate(QueryComp, template); + const comp = fixture.componentInstance; + expect(comp.viewChild).toBeAnInstanceOf(ElementRef); + expect(comp.viewChildren.first).toBeAnInstanceOf(ElementRef); + }); + + onlyInIvy('multiple local refs are supported in Ivy') + .it('should return ElementRefs when HTML elements are labelled and retrieved via View query', + () => { + const template = ` +
    A
    +
    B
    + `; + const fixture = initWithTemplate(QueryComp, template); + const comp = fixture.componentInstance; + + expect(comp.viewChild).toBeAnInstanceOf(ElementRef); + expect(comp.viewChild.nativeElement) + .toBe(fixture.debugElement.children[0].nativeElement); + + expect(comp.viewChildren.first).toBeAnInstanceOf(ElementRef); + expect(comp.viewChildren.last).toBeAnInstanceOf(ElementRef); + expect(comp.viewChildren.length).toBe(2); + }); + + it('should return TemplateRef when template is labelled and retrieved via View query', () => { + const template = ` + + `; + const fixture = initWithTemplate(QueryComp, template); + const comp = fixture.componentInstance; + expect(comp.viewChildren.first).toBeAnInstanceOf(TemplateRef); + }); + + onlyInIvy('multiple local refs are supported in Ivy') + .it('should return TemplateRefs when templates are labelled and retrieved via View query', + () => { + const template = ` + + + `; + const fixture = initWithTemplate(QueryComp, template); + const comp = fixture.componentInstance; + expect(comp.viewChild).toBeAnInstanceOf(TemplateRef); + expect(comp.viewChild.elementRef.nativeElement) + .toBe(fixture.debugElement.childNodes[0].nativeNode); + + expect(comp.viewChildren.first).toBeAnInstanceOf(TemplateRef); + expect(comp.viewChildren.last).toBeAnInstanceOf(TemplateRef); + expect(comp.viewChildren.length).toBe(2); + }); + + it('should return ElementRef when HTML element is labelled and retrieved via Content query', + () => { + const template = ` + +
    +
    + `; + const fixture = initWithTemplate(AppComp, template); + const comp = fixture.debugElement.children[0].references['q']; + expect(comp.contentChildren.first).toBeAnInstanceOf(ElementRef); + }); + + onlyInIvy('multiple local refs are supported in Ivy') + .it('should return ElementRefs when HTML elements are labelled and retrieved via Content query', + () => { + const template = ` + +
    +
    +
    + `; + const fixture = initWithTemplate(AppComp, template); + const firstChild = fixture.debugElement.children[0]; + const comp = firstChild.references['q']; + + expect(comp.contentChild).toBeAnInstanceOf(ElementRef); + expect(comp.contentChild.nativeElement).toBe(firstChild.children[0].nativeElement); + + expect(comp.contentChildren.first).toBeAnInstanceOf(ElementRef); + expect(comp.contentChildren.last).toBeAnInstanceOf(ElementRef); + expect(comp.contentChildren.length).toBe(2); + }); + + it('should return TemplateRef when template is labelled and retrieved via Content query', () => { + const template = ` + + + + `; + const fixture = initWithTemplate(AppComp, template); + const comp = fixture.debugElement.children[0].references['q']; + expect(comp.contentChildren.first).toBeAnInstanceOf(TemplateRef); + }); + + onlyInIvy('multiple local refs are supported in Ivy') + .it('should return TemplateRefs when templates are labelled and retrieved via Content query', + () => { + const template = ` + + + + + `; + const fixture = initWithTemplate(AppComp, template); + const firstChild = fixture.debugElement.children[0]; + const comp = firstChild.references['q']; + + expect(comp.contentChild).toBeAnInstanceOf(TemplateRef); + expect(comp.contentChild.elementRef.nativeElement) + .toBe(firstChild.childNodes[0].nativeNode); + + expect(comp.contentChildren.first).toBeAnInstanceOf(TemplateRef); + expect(comp.contentChildren.last).toBeAnInstanceOf(TemplateRef); + expect(comp.contentChildren.length).toBe(2); + }); +}); + +function initWithTemplate(compType: Type, template: string) { + TestBed.overrideComponent(compType, {set: new Component({template})}); + const fixture = TestBed.createComponent(compType); + fixture.detectChanges(); + return fixture; +} + +@Component({selector: 'local-ref-query-component', template: ''}) +class QueryComp { + @ViewChild('viewQuery') viewChild !: any; + @ContentChild('contentQuery') contentChild !: any; + + @ViewChildren('viewQuery') viewChildren !: QueryList; + @ContentChildren('contentQuery') contentChildren !: QueryList; +} + +@Component({selector: 'app-comp', template: ``}) +class AppComp { +} + +@Component({selector: 'simple-comp-a', template: ''}) +class SimpleCompA { +} + +@Component({selector: 'simple-comp-b', template: ''}) +class SimpleCompB { +} \ No newline at end of file diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index 7c0734fb82..590c254b17 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -13,7 +13,7 @@ import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; import {ɵDomRendererFactory2} from '@angular/platform-browser'; import {ANIMATION_MODULE_TYPE, BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; -import {fixmeIvy, ivyEnabled} from '@angular/private/testing'; +import {ivyEnabled, modifiedInIvy} from '@angular/private/testing'; const DEFAULT_NAMESPACE_ID = 'id'; const DEFAULT_COMPONENT_ID = '1'; @@ -109,83 +109,81 @@ const DEFAULT_COMPONENT_ID = '1'; expect(cmp.status).toEqual('done'); })); - fixmeIvy('unknown').it( - 'should always run .start callbacks before .done callbacks even for noop animations', - fakeAsync(() => { - @Component({ - selector: 'cmp', - template: ` + it('should always run .start callbacks before .done callbacks even for noop animations', + fakeAsync(() => { + @Component({ + selector: 'cmp', + template: `
    `, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => go', []), - ]), - ] - }) - class Cmp { - exp: any = false; - log: string[] = []; - cb(status: string) { this.log.push(status); } - } + animations: [ + trigger( + 'myAnimation', + [ + transition('* => go', []), + ]), + ] + }) + class Cmp { + exp: any = false; + log: string[] = []; + cb(status: string) { this.log.push(status); } + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - expect(cmp.log).toEqual([]); + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + expect(cmp.log).toEqual([]); - flushMicrotasks(); - expect(cmp.log).toEqual(['start', 'done']); - })); + flushMicrotasks(); + expect(cmp.log).toEqual(['start', 'done']); + })); - fixmeIvy('unknown').it( - 'should emit the correct totalTime value for a noop-animation', fakeAsync(() => { - @Component({ - selector: 'cmp', - template: ` + it('should emit the correct totalTime value for a noop-animation', fakeAsync(() => { + @Component({ + selector: 'cmp', + template: `
    `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - animate('1s', style({opacity: 0})), - ]), - ]), - ] - }) - class Cmp { - exp: any = false; - log: AnimationEvent[] = []; - cb(event: AnimationEvent) { this.log.push(event); } - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + animate('1s', style({opacity: 0})), + ]), + ]), + ] + }) + class Cmp { + exp: any = false; + log: AnimationEvent[] = []; + cb(event: AnimationEvent) { this.log.push(event); } + } - TestBed.configureTestingModule({ - declarations: [Cmp], - providers: [ - {provide: AnimationDriver, useClass: NoopAnimationDriver}, - ], - }); + TestBed.configureTestingModule({ + declarations: [Cmp], + providers: [ + {provide: AnimationDriver, useClass: NoopAnimationDriver}, + ], + }); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - expect(cmp.log).toEqual([]); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + expect(cmp.log).toEqual([]); - flushMicrotasks(); - expect(cmp.log.length).toEqual(2); - const [start, end] = cmp.log; - expect(start.totalTime).toEqual(1000); - expect(end.totalTime).toEqual(1000); - })); + flushMicrotasks(); + expect(cmp.log.length).toEqual(2); + const [start, end] = cmp.log; + expect(start.totalTime).toEqual(1000); + expect(end.totalTime).toEqual(1000); + })); }); describe('component fixture integration', () => { @@ -299,7 +297,7 @@ const DEFAULT_COMPONENT_ID = '1'; }); describe('animation triggers', () => { - fixmeIvy('unknown').it('should trigger a state change animation from void => state', () => { + it('should trigger a state change animation from void => state', () => { @Component({ selector: 'if-cmp', template: ` @@ -329,96 +327,94 @@ const DEFAULT_COMPONENT_ID = '1'; ]); }); - fixmeIvy('unknown').it( - 'should allow a transition to use a function to determine what method to run', () => { - let valueToMatch = ''; - let capturedElement: any; - const transitionFn = (fromState: string, toState: string, element: any) => { - capturedElement = element; - return toState == valueToMatch; - }; + it('should allow a transition to use a function to determine what method to run', () => { + let valueToMatch = ''; + let capturedElement: any; + const transitionFn = (fromState: string, toState: string, element: any) => { + capturedElement = element; + return toState == valueToMatch; + }; - @Component({ - selector: 'if-cmp', - template: '
    ', - animations: [ - trigger( - 'myAnimation', - [transition( - transitionFn, [style({opacity: 0}), animate(1234, style({opacity: 1}))])]), - ] - }) - class Cmp { - @ViewChild('element') - element: any; - exp: any = ''; - } + @Component({ + selector: 'if-cmp', + template: '
    ', + animations: [ + trigger('myAnimation', [transition( + transitionFn, + [style({opacity: 0}), animate(1234, style({opacity: 1}))])]), + ] + }) + class Cmp { + @ViewChild('element') + element: any; + exp: any = ''; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - valueToMatch = cmp.exp = 'something'; - fixture.detectChanges(); - const element = cmp.element.nativeElement; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + valueToMatch = cmp.exp = 'something'; + fixture.detectChanges(); + const element = cmp.element.nativeElement; - let players = getLog(); - expect(players.length).toEqual(1); - let [p1] = players; - expect(p1.totalTime).toEqual(1234); - expect(capturedElement).toEqual(element); - resetLog(); + let players = getLog(); + expect(players.length).toEqual(1); + let [p1] = players; + expect(p1.totalTime).toEqual(1234); + expect(capturedElement).toEqual(element); + resetLog(); - valueToMatch = 'something-else'; - cmp.exp = 'this-wont-match'; - fixture.detectChanges(); + valueToMatch = 'something-else'; + cmp.exp = 'this-wont-match'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(0); - }); + players = getLog(); + expect(players.length).toEqual(0); + }); - fixmeIvy('unknown').it( - 'should allow a transition to use a function to determine what method to run and expose any parameter values', - () => { - const transitionFn = - (fromState: string, toState: string, element: any, - params: {[key: string]: any}) => { return params['doMatch'] == true; }; + it('should allow a transition to use a function to determine what method to run and expose any parameter values', + () => { + const transitionFn = + (fromState: string, toState: string, element: any, params: {[key: string]: any}) => { + return params['doMatch'] == true; + }; - @Component({ - selector: 'if-cmp', - template: '
    ', - animations: [ - trigger( - 'myAnimation', - [transition( - transitionFn, [style({opacity: 0}), animate(3333, style({opacity: 1}))])]), - ] - }) - class Cmp { - doMatch = false; - exp: any = ''; - } + @Component({ + selector: 'if-cmp', + template: '
    ', + animations: [ + trigger( + 'myAnimation', + [transition( + transitionFn, [style({opacity: 0}), animate(3333, style({opacity: 1}))])]), + ] + }) + class Cmp { + doMatch = false; + exp: any = ''; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.doMatch = true; - fixture.detectChanges(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.doMatch = true; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(1); - let [p1] = players; - expect(p1.totalTime).toEqual(3333); - resetLog(); + let players = getLog(); + expect(players.length).toEqual(1); + let [p1] = players; + expect(p1.totalTime).toEqual(3333); + resetLog(); - cmp.doMatch = false; - cmp.exp = 'this-wont-match'; - fixture.detectChanges(); + cmp.doMatch = false; + cmp.exp = 'this-wont-match'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(0); - }); + players = getLog(); + expect(players.length).toEqual(0); + }); it('should allow a state value to be `0`', () => { @Component({ @@ -573,105 +569,102 @@ const DEFAULT_COMPONENT_ID = '1'; expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']); })); - fixmeIvy('unknown').it( - 'should only turn a view removal as into `void` state transition', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should only turn a view removal as into `void` state transition', () => { + @Component({ + selector: 'if-cmp', + template: `
    `, - animations: [trigger( - 'myAnimation', - [ - transition( - 'void <=> *', - [style({width: '0px'}), animate(1000, style({width: '100px'}))]), - transition( - '* => *', - [style({height: '0px'}), animate(1000, style({height: '100px'}))]), - ])] - }) - class Cmp { - exp1: any = false; - exp2: any = false; - } + animations: [trigger( + 'myAnimation', + [ + transition( + 'void <=> *', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), + transition( + '* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]), + ])] + }) + class Cmp { + exp1: any = false; + exp2: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - function resetState() { - cmp.exp2 = 'something'; - fixture.detectChanges(); - engine.flush(); - resetLog(); - } + function resetState() { + cmp.exp2 = 'something'; + fixture.detectChanges(); + engine.flush(); + resetLog(); + } - cmp.exp1 = true; - cmp.exp2 = null; + cmp.exp1 = true; + cmp.exp2 = null; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, width: '0px'}, {offset: 1, width: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); - resetState(); - cmp.exp2 = false; + resetState(); + cmp.exp2 = false; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp2 = 0; + resetState(); + cmp.exp2 = 0; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp2 = ''; + resetState(); + cmp.exp2 = ''; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp2 = undefined; + resetState(); + cmp.exp2 = undefined; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - resetState(); - cmp.exp1 = false; - cmp.exp2 = 'abc'; + resetState(); + cmp.exp1 = false; + cmp.exp2 = 'abc'; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, width: '0px'}, {offset: 1, width: '100px'} - ]); - }); + expect(getLog().pop() !.keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); + }); - fixmeIvy('unknown').it('should stringify boolean triggers to `1` and `0`', () => { + it('should stringify boolean triggers to `1` and `0`', () => { @Component({ selector: 'if-cmp', template: ` @@ -824,95 +817,90 @@ const DEFAULT_COMPONENT_ID = '1'; }); describe('host bindings', () => { - fixmeIvy('unknown').it( - 'should trigger a state change animation from state => state on the component host element', - fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: '...', - animations: [trigger( - 'myAnimation', - [transition( - 'a => b', - [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - @HostBinding('@myAnimation') - exp = 'a'; - } + it('should trigger a state change animation from state => state on the component host element', + fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: '...', + animations: [trigger( + 'myAnimation', + [transition( + 'a => b', + [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + @HostBinding('@myAnimation') + exp = 'a'; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(1); + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(1); - const data = getLog().pop() !; - expect(data.element).toEqual(fixture.elementRef.nativeElement); - expect(data.keyframes).toEqual([ - {offset: 0, opacity: '0'}, {offset: 1, opacity: '1'} - ]); - })); + const data = getLog().pop() !; + expect(data.element).toEqual(fixture.elementRef.nativeElement); + expect(data.keyframes).toEqual([{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}]); + })); - // nonAnimationRenderer => animationRenderer - fixmeIvy('unknown').it( - 'should trigger a leave animation when the inner components host binding updates', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - template: ` + it('should trigger a leave animation when the inner components host binding updates', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + template: ` ` - }) - class ParentCmp { - public exp = true; - } + }) + class ParentCmp { + public exp = true; + } - @Component({ - selector: 'child-cmp', - template: '...', - animations: [trigger( - 'host', - [transition( - ':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])] - }) - class ChildCmp { - @HostBinding('@host') public hostAnimation = true; - } + @Component({ + selector: 'child-cmp', + template: '...', + animations: [trigger( + 'host', + [transition( + ':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])] + }) + class ChildCmp { + @HostBinding('@host') public hostAnimation = true; + } - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); - cmp.exp = false; - fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.children.length).toBe(1); + cmp.exp = false; + fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.children.length).toBe(1); - engine.flush(); - expect(getLog().length).toEqual(1); + engine.flush(); + expect(getLog().length).toEqual(1); - const [player] = getLog(); - expect(player.keyframes).toEqual([ - {opacity: '1', offset: 0}, - {opacity: '0', offset: 1}, - ]); + const [player] = getLog(); + expect(player.keyframes).toEqual([ + {opacity: '1', offset: 0}, + {opacity: '0', offset: 1}, + ]); - player.finish(); - expect(fixture.debugElement.nativeElement.children.length).toBe(0); - })); + player.finish(); + expect(fixture.debugElement.nativeElement.children.length).toBe(0); + })); // animationRenderer => nonAnimationRenderer it('should trigger a leave animation when the outer components element binding updates on the host component element', @@ -965,70 +953,67 @@ const DEFAULT_COMPONENT_ID = '1'; expect(fixture.debugElement.nativeElement.children.length).toBe(0); })); - // animationRenderer => animationRenderer - fixmeIvy('unknown').it( - 'should trigger a leave animation when both the inner and outer components trigger on the same element', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - animations: [trigger( - 'host', - [transition( - ':leave', - [style({height: '100px'}), animate(1000, style({height: '0px'}))])])], - template: ` + it('should trigger a leave animation when both the inner and outer components trigger on the same element', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + animations: [trigger( + 'host', + [transition( + ':leave', + [style({height: '100px'}), animate(1000, style({height: '0px'}))])])], + template: ` ` - }) - class ParentCmp { - public exp = true; - } + }) + class ParentCmp { + public exp = true; + } - @Component({ - selector: 'child-cmp', - template: '...', - animations: [trigger( - 'host', - [transition( - ':leave', - [style({width: '100px'}), animate(1000, style({width: '0px'}))])])] - }) - class ChildCmp { - @HostBinding('@host') public hostAnimation = true; - } + @Component({ + selector: 'child-cmp', + template: '...', + animations: [trigger( + 'host', [transition( + ':leave', + [style({width: '100px'}), animate(1000, style({width: '0px'}))])])] + }) + class ChildCmp { + @HostBinding('@host') public hostAnimation = true; + } - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); - cmp.exp = false; - fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.children.length).toBe(1); + cmp.exp = false; + fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.children.length).toBe(1); - engine.flush(); - expect(getLog().length).toEqual(2); + engine.flush(); + expect(getLog().length).toEqual(2); - const [p1, p2] = getLog(); - expect(p1.keyframes).toEqual([ - {width: '100px', offset: 0}, - {width: '0px', offset: 1}, - ]); + const [p1, p2] = getLog(); + expect(p1.keyframes).toEqual([ + {width: '100px', offset: 0}, + {width: '0px', offset: 1}, + ]); - expect(p2.keyframes).toEqual([ - {height: '100px', offset: 0}, - {height: '0px', offset: 1}, - ]); + expect(p2.keyframes).toEqual([ + {height: '100px', offset: 0}, + {height: '0px', offset: 1}, + ]); - p1.finish(); - p2.finish(); - flushMicrotasks(); - expect(fixture.debugElement.nativeElement.children.length).toBe(0); - })); + p1.finish(); + p2.finish(); + flushMicrotasks(); + expect(fixture.debugElement.nativeElement.children.length).toBe(0); + })); it('should not throw when the host element is removed and no animation triggers', fakeAsync(() => { @@ -1935,47 +1920,46 @@ const DEFAULT_COMPONENT_ID = '1'; expect(p.contains(c2)).toBeTruthy(); }); - fixmeIvy('unknown').it( - 'should detect trigger changes based on object.value properties', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should detect trigger changes based on object.value properties', () => { + @Component({ + selector: 'ani-cmp', + template: `
    `, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => 1', [animate(1234, style({opacity: 0}))]), - transition('* => 2', [animate(5678, style({opacity: 0}))]), - ]), - ] - }) - class Cmp { - public exp: any; - } + animations: [ + trigger( + 'myAnimation', + [ + transition('* => 1', [animate(1234, style({opacity: 0}))]), + transition('* => 2', [animate(5678, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + public exp: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = '1'; - fixture.detectChanges(); - engine.flush(); - let players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - resetLog(); + cmp.exp = '1'; + fixture.detectChanges(); + engine.flush(); + let players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); + resetLog(); - cmp.exp = '2'; - fixture.detectChanges(); - engine.flush(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(5678); - }); + cmp.exp = '2'; + fixture.detectChanges(); + engine.flush(); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(5678); + }); it('should not render animations when the object expression value is the same as it was previously', () => { @@ -2020,61 +2004,60 @@ const DEFAULT_COMPONENT_ID = '1'; expect(players.length).toEqual(0); }); - fixmeIvy('unknown').it( - 'should update the final state styles when params update even if the expression hasn\'t changed', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should update the final state styles when params update even if the expression hasn\'t changed', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: `
    `, - animations: [ - trigger( - 'myAnimation', - [ - state('*', style({color: '{{ color }}'}), {params: {color: 'black'}}), - transition('* => 1', animate(500)) - ]), - ] - }) - class Cmp { - public exp: any; - // TODO(issue/24571): remove '!'. - public color !: string | null; - } + animations: [ + trigger( + 'myAnimation', + [ + state('*', style({color: '{{ color }}'}), {params: {color: 'black'}}), + transition('* => 1', animate(500)) + ]), + ] + }) + class Cmp { + public exp: any; + // TODO(issue/24571): remove '!'. + public color !: string | null; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = '1'; - cmp.color = 'red'; - fixture.detectChanges(); - const player = getLog()[0] !; - const element = player.element; - player.finish(); + cmp.exp = '1'; + cmp.color = 'red'; + fixture.detectChanges(); + const player = getLog()[0] !; + const element = player.element; + player.finish(); - flushMicrotasks(); - expect(getDOM().hasStyle(element, 'color', 'red')).toBeTruthy(); + flushMicrotasks(); + expect(getDOM().hasStyle(element, 'color', 'red')).toBeTruthy(); - cmp.exp = '1'; - cmp.color = 'blue'; - fixture.detectChanges(); - resetLog(); + cmp.exp = '1'; + cmp.color = 'blue'; + fixture.detectChanges(); + resetLog(); - flushMicrotasks(); - expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy(); + flushMicrotasks(); + expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy(); - cmp.exp = '1'; - cmp.color = null; - fixture.detectChanges(); - resetLog(); + cmp.exp = '1'; + cmp.color = null; + fixture.detectChanges(); + resetLog(); - flushMicrotasks(); - expect(getDOM().hasStyle(element, 'color', 'black')).toBeTruthy(); - })); + flushMicrotasks(); + expect(getDOM().hasStyle(element, 'color', 'black')).toBeTruthy(); + })); it('should substitute in values if the provided state match is an object with values', () => { @Component({ @@ -2113,73 +2096,72 @@ const DEFAULT_COMPONENT_ID = '1'; ]); }); - fixmeIvy('unknown').it( - 'should retain substituted styles on the element once the animation is complete if referenced in the final state', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should retain substituted styles on the element once the animation is complete if referenced in the final state', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: `
    `, - animations: [ - trigger( - 'myAnimation', - [ - state( - 'start', style({ - color: '{{ color }}', - fontSize: '{{ fontSize }}px', - width: '{{ width }}' - }), - {params: {color: 'red', fontSize: '200', width: '10px'}}), + animations: [ + trigger( + 'myAnimation', + [ + state( + 'start', style({ + color: '{{ color }}', + fontSize: '{{ fontSize }}px', + width: '{{ width }}' + }), + {params: {color: 'red', fontSize: '200', width: '10px'}}), - state( - 'final', - style( - {color: '{{ color }}', fontSize: '{{ fontSize }}px', width: '888px'}), - {params: {color: 'green', fontSize: '50', width: '100px'}}), + state( + 'final', + style( + {color: '{{ color }}', fontSize: '{{ fontSize }}px', width: '888px'}), + {params: {color: 'green', fontSize: '50', width: '100px'}}), - transition('start => final', animate(500)), - ]), - ] - }) - class Cmp { - public exp: any; - public color: any; - } + transition('start => final', animate(500)), + ]), + ] + }) + class Cmp { + public exp: any; + public color: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'start'; - cmp.color = 'red'; - fixture.detectChanges(); - resetLog(); + cmp.exp = 'start'; + cmp.color = 'red'; + fixture.detectChanges(); + resetLog(); - cmp.exp = 'final'; - cmp.color = 'blue'; - fixture.detectChanges(); + cmp.exp = 'final'; + cmp.color = 'blue'; + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(1); - const [p1] = players; + const players = getLog(); + expect(players.length).toEqual(1); + const [p1] = players; - expect(p1.keyframes).toEqual([ - {color: 'red', fontSize: '200px', width: '10px', offset: 0}, - {color: 'blue', fontSize: '50px', width: '888px', offset: 1} - ]); + expect(p1.keyframes).toEqual([ + {color: 'red', fontSize: '200px', width: '10px', offset: 0}, + {color: 'blue', fontSize: '50px', width: '888px', offset: 1} + ]); - const element = p1.element; - p1.finish(); - flushMicrotasks(); + const element = p1.element; + p1.finish(); + flushMicrotasks(); - expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy(); - expect(getDOM().hasStyle(element, 'fontSize', '50px')).toBeTruthy(); - expect(getDOM().hasStyle(element, 'width', '888px')).toBeTruthy(); - })); + expect(getDOM().hasStyle(element, 'color', 'blue')).toBeTruthy(); + expect(getDOM().hasStyle(element, 'fontSize', '50px')).toBeTruthy(); + expect(getDOM().hasStyle(element, 'width', '888px')).toBeTruthy(); + })); it('should only evaluate final state param substitutions from the expression and state values and not from the transition options ', fakeAsync(() => { @@ -2459,88 +2441,85 @@ const DEFAULT_COMPONENT_ID = '1'; }); describe('animation listeners', () => { - fixmeIvy('unknown').it( - 'should trigger a `start` state change listener for when the animation changes state from void => state', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should trigger a `start` state change listener for when the animation changes state from void => state', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: `
    `, - animations: [trigger( - 'myAnimation', - [transition( - 'void => *', - [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any = false; - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + animations: [trigger( + 'myAnimation', + [transition( + 'void => *', + [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any = false; + // TODO(issue/24571): remove '!'. + event !: AnimationEvent; - callback = (event: any) => { this.event = event; }; - } + callback = (event: any) => { this.event = event; }; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'true'; - fixture.detectChanges(); - flushMicrotasks(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'true'; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation'); - expect(cmp.event.phaseName).toEqual('start'); - expect(cmp.event.totalTime).toEqual(500); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('true'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation'); + expect(cmp.event.phaseName).toEqual('start'); + expect(cmp.event.totalTime).toEqual(500); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('true'); + })); - fixmeIvy('unknown').it( - 'should trigger a `done` state change listener for when the animation changes state from a => b', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should trigger a `done` state change listener for when the animation changes state from a => b', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: `
    `, - animations: [trigger( - 'myAnimation123', - [transition( - '* => b', - [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any = false; - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + animations: [trigger( + 'myAnimation123', + [transition( + '* => b', [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any = false; + // TODO(issue/24571): remove '!'. + event !: AnimationEvent; - callback = (event: any) => { this.event = event; }; - } + callback = (event: any) => { this.event = event; }; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); - expect(cmp.event).toBeFalsy(); + expect(cmp.event).toBeFalsy(); - const player = engine.players.pop(); - player.finish(); - flushMicrotasks(); + const player = engine.players.pop(); + player.finish(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation123'); - expect(cmp.event.phaseName).toEqual('done'); - expect(cmp.event.totalTime).toEqual(999); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('b'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation123'); + expect(cmp.event.phaseName).toEqual('done'); + expect(cmp.event.totalTime).toEqual(999); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('b'); + })); it('should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => { @Component({ @@ -2728,81 +2707,79 @@ const DEFAULT_COMPONENT_ID = '1'; expect(elm.innerText.trim()).toEqual(''); })); - fixmeIvy('unknown').it( - 'should trigger a state change listener for when the animation changes state from void => state on the host element', - fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: `...`, - animations: [trigger( - 'myAnimation2', - [transition( - 'void => *', - [style({'opacity': '0'}), animate(1000, style({'opacity': '1'}))])])], - }) - class Cmp { - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + it('should trigger a state change listener for when the animation changes state from void => state on the host element', + fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: `...`, + animations: [trigger( + 'myAnimation2', + [transition( + 'void => *', + [style({'opacity': '0'}), animate(1000, style({'opacity': '1'}))])])], + }) + class Cmp { + // TODO(issue/24571): remove '!'. + event !: AnimationEvent; - @HostBinding('@myAnimation2') - exp: any = false; + @HostBinding('@myAnimation2') + exp: any = false; - @HostListener('@myAnimation2.start', ['$event']) - callback = (event: any) => { this.event = event; } - } + @HostListener('@myAnimation2.start', ['$event']) + callback = (event: any) => { this.event = event; } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'TRUE'; - fixture.detectChanges(); - flushMicrotasks(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'TRUE'; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation2'); - expect(cmp.event.phaseName).toEqual('start'); - expect(cmp.event.totalTime).toEqual(1000); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('TRUE'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation2'); + expect(cmp.event.phaseName).toEqual('start'); + expect(cmp.event.totalTime).toEqual(1000); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('TRUE'); + })); - fixmeIvy('unknown').it( - 'should always fire callbacks even when a transition is not detected', fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: ` + it('should always fire callbacks even when a transition is not detected', fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: `
    `, - animations: [trigger('myAnimation', [])] - }) - class Cmp { - // TODO(issue/24571): remove '!'. - exp !: string; - log: any[] = []; - callback = (event: any) => this.log.push(`${event.phaseName} => ${event.toState}`); - } + animations: [trigger('myAnimation', [])] + }) + class Cmp { + // TODO(issue/24571): remove '!'. + exp !: string; + log: any[] = []; + callback = (event: any) => this.log.push(`${event.phaseName} => ${event.toState}`); + } - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], - declarations: [Cmp] - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], + declarations: [Cmp] + }); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'a'; - fixture.detectChanges(); - flushMicrotasks(); - expect(cmp.log).toEqual(['start => a', 'done => a']); + cmp.exp = 'a'; + fixture.detectChanges(); + flushMicrotasks(); + expect(cmp.log).toEqual(['start => a', 'done => a']); - cmp.log = []; - cmp.exp = 'b'; - fixture.detectChanges(); - flushMicrotasks(); + cmp.log = []; + cmp.exp = 'b'; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.log).toEqual(['start => b', 'done => b']); - })); + expect(cmp.log).toEqual(['start => b', 'done => b']); + })); it('should fire callback events for leave animations even if there is no leave transition', fakeAsync(() => { @@ -2844,11 +2821,10 @@ const DEFAULT_COMPONENT_ID = '1'; expect(cmp.log).toEqual(['start => void', 'done => void']); })); - fixmeIvy('unknown').it( - 'should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: ` + it('should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: `
    `, - animations: [ - trigger( - 'parent', - [ - transition( - '* => go', - [ - style({width: '0px'}), - animate(1000, style({width: '100px'})), - query( - '.child', - [ - animateChild({duration: '1s'}), - ]), - animate(1000, style({width: '0px'})), - ]), - ]), - trigger( - 'child', - [ - transition( - '* => go', - [ - style({height: '0px'}), - animate(1000, style({height: '100px'})), - ]), - ]) - ] - }) - class Cmp { - log: string[] = []; - // TODO(issue/24571): remove '!'. - exp1 !: string; - // TODO(issue/24571): remove '!'. - exp2 !: string; + animations: [ + trigger( + 'parent', + [ + transition( + '* => go', + [ + style({width: '0px'}), + animate(1000, style({width: '100px'})), + query( + '.child', + [ + animateChild({duration: '1s'}), + ]), + animate(1000, style({width: '0px'})), + ]), + ]), + trigger( + 'child', + [ + transition( + '* => go', + [ + style({height: '0px'}), + animate(1000, style({height: '100px'})), + ]), + ]) + ] + }) + class Cmp { + log: string[] = []; + // TODO(issue/24571): remove '!'. + exp1 !: string; + // TODO(issue/24571): remove '!'. + exp2 !: string; - cb(name: string, event: AnimationEvent) { this.log.push(name); } - } + cb(name: string, event: AnimationEvent) { this.log.push(name); } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp1 = 'go'; - cmp.exp2 = 'go'; - fixture.detectChanges(); - engine.flush(); - flushMicrotasks(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp1 = 'go'; + cmp.exp2 = 'go'; + fixture.detectChanges(); + engine.flush(); + flushMicrotasks(); - expect(cmp.log).toEqual(['parent-start', 'child-start']); - cmp.log = []; + expect(cmp.log).toEqual(['parent-start', 'child-start']); + cmp.log = []; - const players = getLog(); - expect(players.length).toEqual(3); - const [p1, p2, p3] = players; + const players = getLog(); + expect(players.length).toEqual(3); + const [p1, p2, p3] = players; - p1.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual([]); + p1.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual([]); - p2.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual([]); + p2.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual([]); - p3.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual(['parent-done', 'child-done']); - })); + p3.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual(['parent-done', 'child-done']); + })); - fixmeIvy('unknown').it( - 'should fire callbacks and collect the correct the totalTime and element details for any queried sub animations', - fakeAsync( - () => { - @Component({ + it('should fire callbacks and collect the correct the totalTime and element details for any queried sub animations', + fakeAsync( + () => { + @Component({ selector: 'my-cmp', template: `
    @@ -2969,62 +2944,62 @@ const DEFAULT_COMPONENT_ID = '1'; ] }) class Cmp { - log: string[] = []; - events: {[name: string]: any} = {}; - // TODO(issue/24571): remove '!'. - exp !: string; - items: any = [0, 1, 2, 3]; + log: string[] = []; + events: {[name: string]: any} = {}; + // TODO(issue/24571): remove '!'. + exp !: string; + items: any = [0, 1, 2, 3]; - cb(name: string, phase: string, event: AnimationEvent) { - this.log.push(name + '-' + phase); - this.events[name] = event; - } - } + cb(name: string, phase: string, event: AnimationEvent) { + this.log.push(name + '-' + phase); + this.events[name] = event; + } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); - flushMicrotasks(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); + flushMicrotasks(); - expect(cmp.log).toEqual(['c-0-start', 'c-1-start', 'c-2-start', 'c-3-start']); - cmp.log = []; + expect(cmp.log).toEqual(['c-0-start', 'c-1-start', 'c-2-start', 'c-3-start']); + cmp.log = []; - const players = getLog(); - // 1 + 4 + 4 = 9 players - expect(players.length).toEqual(9); + const players = getLog(); + // 1 + 4 + 4 = 9 players + expect(players.length).toEqual(9); - const [pA, pq1a, pq1b, pq1c, pq1d, pq2a, pq2b, pq2c, pq2d] = getLog(); - pA.finish(); - pq1a.finish(); - pq1b.finish(); - pq1c.finish(); - pq1d.finish(); - flushMicrotasks(); + const [pA, pq1a, pq1b, pq1c, pq1d, pq2a, pq2b, pq2c, pq2d] = getLog(); + pA.finish(); + pq1a.finish(); + pq1b.finish(); + pq1c.finish(); + pq1d.finish(); + flushMicrotasks(); - expect(cmp.log).toEqual([]); - pq2a.finish(); - pq2b.finish(); - pq2c.finish(); - pq2d.finish(); - flushMicrotasks(); + expect(cmp.log).toEqual([]); + pq2a.finish(); + pq2b.finish(); + pq2c.finish(); + pq2d.finish(); + flushMicrotasks(); - expect(cmp.log).toEqual( - ['all-done', 'c-0-done', 'c-1-done', 'c-2-done', 'c-3-done']); + expect(cmp.log).toEqual( + ['all-done', 'c-0-done', 'c-1-done', 'c-2-done', 'c-3-done']); - expect(cmp.events['c-0'].totalTime).toEqual(4100); // 1000 + 1000 + 1800 + 300 - expect(cmp.events['c-0'].element.innerText.trim()).toEqual('0'); - expect(cmp.events['c-1'].totalTime).toEqual(4100); - expect(cmp.events['c-1'].element.innerText.trim()).toEqual('1'); - expect(cmp.events['c-2'].totalTime).toEqual(4100); - expect(cmp.events['c-2'].element.innerText.trim()).toEqual('2'); - expect(cmp.events['c-3'].totalTime).toEqual(4100); - expect(cmp.events['c-3'].element.innerText.trim()).toEqual('3'); - })); + expect(cmp.events['c-0'].totalTime).toEqual(4100); // 1000 + 1000 + 1800 + 300 + expect(cmp.events['c-0'].element.innerText.trim()).toEqual('0'); + expect(cmp.events['c-1'].totalTime).toEqual(4100); + expect(cmp.events['c-1'].element.innerText.trim()).toEqual('1'); + expect(cmp.events['c-2'].totalTime).toEqual(4100); + expect(cmp.events['c-2'].element.innerText.trim()).toEqual('2'); + expect(cmp.events['c-3'].totalTime).toEqual(4100); + expect(cmp.events['c-3'].element.innerText.trim()).toEqual('3'); + })); }); describe('animation control flags', () => { @@ -3387,43 +3362,42 @@ const DEFAULT_COMPONENT_ID = '1'; expect(getLog().length).toEqual(1); }); - fixmeIvy('unknown').it( - 'should treat the property as true when the expression is missing', () => { - @Component({ - selector: 'parent-cmp', - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - style({opacity: 0}), - animate(500, style({opacity: 1})), - ]), - ]), - ], - template: ` + it('should treat the property as true when the expression is missing', () => { + @Component({ + selector: 'parent-cmp', + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + style({opacity: 0}), + animate(500, style({opacity: 1})), + ]), + ]), + ], + template: `
    ` - }) - class Cmp { - exp = ''; - } + }) + class Cmp { + exp = ''; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + resetLog(); - cmp.exp = 'go'; - fixture.detectChanges(); - expect(getLog().length).toEqual(0); - }); + cmp.exp = 'go'; + fixture.detectChanges(); + expect(getLog().length).toEqual(0); + }); it('should respect parent/sub animations when the respective area in the DOM is disabled', fakeAsync(() => { @@ -3597,64 +3571,63 @@ const DEFAULT_COMPONENT_ID = '1'; /only state\(\) and transition\(\) definitions can sit inside of a trigger\(\)/); }); - fixmeIvy('unknown').it( - 'should combine multiple errors together into one exception when an animation fails to be built', - () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should combine multiple errors together into one exception when an animation fails to be built', + () => { + @Component({ + selector: 'if-cmp', + template: `
    `, - animations: [ - trigger( - 'foo', - [ - transition(':enter', []), - transition( - '* => *', - [ - query('foo', animate(1000, style({background: 'red'}))), - ]), - ]), - trigger( - 'bar', - [ - transition(':enter', []), - transition( - '* => *', - [ - query('bar', animate(1000, style({background: 'blue'}))), - ]), - ]), - ] - }) - class Cmp { - fooExp: any = false; - barExp: any = false; - } + animations: [ + trigger( + 'foo', + [ + transition(':enter', []), + transition( + '* => *', + [ + query('foo', animate(1000, style({background: 'red'}))), + ]), + ]), + trigger( + 'bar', + [ + transition(':enter', []), + transition( + '* => *', + [ + query('bar', animate(1000, style({background: 'blue'}))), + ]), + ]), + ] + }) + class Cmp { + fooExp: any = false; + barExp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); - cmp.fooExp = 'go'; - cmp.barExp = 'go'; + cmp.fooExp = 'go'; + cmp.barExp = 'go'; - let errorMsg: string = ''; - try { - fixture.detectChanges(); - } catch (e) { - errorMsg = e.message; - } + let errorMsg: string = ''; + try { + fixture.detectChanges(); + } catch (e) { + errorMsg = e.message; + } - expect(errorMsg).toMatch(/@foo has failed due to:/); - expect(errorMsg).toMatch(/`query\("foo"\)` returned zero elements/); - expect(errorMsg).toMatch(/@bar has failed due to:/); - expect(errorMsg).toMatch(/`query\("bar"\)` returned zero elements/); - }); + expect(errorMsg).toMatch(/@foo has failed due to:/); + expect(errorMsg).toMatch(/`query\("foo"\)` returned zero elements/); + expect(errorMsg).toMatch(/@bar has failed due to:/); + expect(errorMsg).toMatch(/`query\("bar"\)` returned zero elements/); + }); it('should not throw an error if styles overlap in separate transitions', () => { @Component({ @@ -3687,19 +3660,19 @@ const DEFAULT_COMPONENT_ID = '1'; expect(() => { TestBed.createComponent(Cmp); }).not.toThrowError(); }); - fixmeIvy('unknown').it( - 'should continue to clean up DOM-related animation artificats even if a compiler-level error is thrown midway', - () => { - @Component({ - selector: 'if-cmp', - animations: [ - trigger( - 'foo', - [ - transition('* => something', []), - ]), - ], - template: ` + modifiedInIvy('FW-952 - Error recovery is handled differently in Ivy than VE') + .it('should continue to clean up DOM-related animation artificats even if a compiler-level error is thrown midway', + () => { + @Component({ + selector: 'if-cmp', + animations: [ + trigger( + 'foo', + [ + transition('* => something', []), + ]), + ], + template: ` value = {{ foo[bar] }}
    1
    @@ -3707,32 +3680,32 @@ const DEFAULT_COMPONENT_ID = '1';
    3
    `, - }) - class Cmp { - exp: any = false; + }) + class Cmp { + exp: any = false; - @ViewChild('contents') public contents: any; - } + @ViewChild('contents') public contents: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); - const runCD = () => fixture.detectChanges(); - const cmp = fixture.componentInstance; + const runCD = () => fixture.detectChanges(); + const cmp = fixture.componentInstance; - cmp.exp = true; - expect(runCD).toThrow(); + cmp.exp = true; + expect(runCD).toThrow(); - const contents = cmp.contents.nativeElement; - expect(contents.innerText.replace(/\s+/gm, '')).toEqual('123'); + const contents = cmp.contents.nativeElement; + expect(contents.innerText.replace(/\s+/gm, '')).toEqual('123'); - cmp.exp = false; - expect(runCD).toThrow(); + cmp.exp = false; + expect(runCD).toThrow(); - expect(contents.innerText.trim()).toEqual(''); - }); + expect(contents.innerText.trim()).toEqual(''); + }); describe('errors for not using the animation module', () => { beforeEach(() => { @@ -3741,18 +3714,17 @@ const DEFAULT_COMPONENT_ID = '1'; }); }); - fixmeIvy('unknown').it( - 'should throw when using an @prop binding without the animation module', () => { - @Component({template: `
    `}) - class Cmp { - } + it('should throw when using an @prop binding without the animation module', () => { + @Component({template: `
    `}) + class Cmp { + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const comp = TestBed.createComponent(Cmp); - expect(() => comp.detectChanges()) - .toThrowError( - 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); - }); + TestBed.configureTestingModule({declarations: [Cmp]}); + const comp = TestBed.createComponent(Cmp); + expect(() => comp.detectChanges()) + .toThrowError( + 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); + }); it('should throw when using an @prop listener without the animation module', () => { @Component({template: `
    `}) diff --git a/packages/core/test/animation/animation_query_integration_spec.ts b/packages/core/test/animation/animation_query_integration_spec.ts index f30cf1d597..a2c8d90458 100644 --- a/packages/core/test/animation/animation_query_integration_spec.ts +++ b/packages/core/test/animation/animation_query_integration_spec.ts @@ -295,72 +295,71 @@ import {HostListener} from '../../src/metadata/directives'; expect(p6.element.classList.contains('b3')).toBeTruthy(); }); - fixmeIvy('unknown').it( - 'should be able to query all active animations using :animating in a query', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should be able to query all active animations using :animating in a query', () => { + @Component({ + selector: 'ani-cmp', + template: `
    `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => a', - [ - query( - '.item:nth-child(odd)', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - ]), - transition( - '* => b', - [ - query( - '.item:animating', - [ - style({opacity: 1}), - animate(1000, style({opacity: 0})), - ]), - ]), - ]), - ] - }) - class Cmp { - public exp: any; - public items: number[] = [0, 1, 2, 3, 4]; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => a', + [ + query( + '.item:nth-child(odd)', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + ]), + transition( + '* => b', + [ + query( + '.item:animating', + [ + style({opacity: 1}), + animate(1000, style({opacity: 0})), + ]), + ]), + ]), + ] + }) + class Cmp { + public exp: any; + public items: number[] = [0, 1, 2, 3, 4]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'a'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'a'; + fixture.detectChanges(); + engine.flush(); - let players = getLog(); - expect(players.length).toEqual(3); - resetLog(); + let players = getLog(); + expect(players.length).toEqual(3); + resetLog(); - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); - players = getLog(); - expect(players.length).toEqual(3); - expect(players[0].element.classList.contains('e-0')).toBeTruthy(); - expect(players[1].element.classList.contains('e-2')).toBeTruthy(); - expect(players[2].element.classList.contains('e-4')).toBeTruthy(); - }); + players = getLog(); + expect(players.length).toEqual(3); + expect(players[0].element.classList.contains('e-0')).toBeTruthy(); + expect(players[1].element.classList.contains('e-2')).toBeTruthy(); + expect(players[2].element.classList.contains('e-4')).toBeTruthy(); + }); it('should be able to query all actively queued animation triggers via `@*:animating`', () => { @@ -802,7 +801,7 @@ import {HostListener} from '../../src/metadata/directives'; expect(player.element.style.height).toEqual('444px'); }); - fixmeIvy('unknown').it('should find newly inserted items in the component via :enter', () => { + it('should find newly inserted items in the component via :enter', () => { @Component({ selector: 'ani-cmp', template: ` @@ -853,12 +852,11 @@ import {HostListener} from '../../src/metadata/directives'; }); }); - fixmeIvy('unknown').it( - 'should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', + () => { + @Component({ + selector: 'ani-cmp', + template: `
    {{ item }} @@ -866,56 +864,56 @@ import {HostListener} from '../../src/metadata/directives';
    Leave!
    `, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => 0', []), - transition( - '* => *', - [ - query( - '.child:enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - query( - '.incorrect-child:leave', - [ - animate(1000, style({opacity: 0})), - ]), - ]), - ]), - ] - }) - class Cmp { - @ViewChild('container') public container: any; - public items: any[] = []; - } + animations: [ + trigger( + 'myAnimation', + [ + transition('* => 0', []), + transition( + '* => *', + [ + query( + '.child:enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + query( + '.incorrect-child:leave', + [ + animate(1000, style({opacity: 0})), + ]), + ]), + ]), + ] + }) + class Cmp { + @ViewChild('container') public container: any; + public items: any[] = []; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.items = []; - fixture.detectChanges(); + cmp.items = []; + fixture.detectChanges(); - cmp.items = [0, 1, 2, 3, 4]; + cmp.items = [0, 1, 2, 3, 4]; - expect(() => { fixture.detectChanges(); }).toThrow(); + expect(() => { fixture.detectChanges(); }).toThrow(); - const children = cmp.container.nativeElement.querySelectorAll('.child'); - expect(children.length).toEqual(5); + const children = cmp.container.nativeElement.querySelectorAll('.child'); + expect(children.length).toEqual(5); - for (let i = 0; i < children.length; i++) { - let child = children[i]; - expect(child.classList.contains(ENTER_CLASSNAME)).toBe(false); - expect(child.classList.contains(LEAVE_CLASSNAME)).toBe(false); - } - }); + for (let i = 0; i < children.length; i++) { + let child = children[i]; + expect(child.classList.contains(ENTER_CLASSNAME)).toBe(false); + expect(child.classList.contains(LEAVE_CLASSNAME)).toBe(false); + } + }); it('should find elements that have been removed via :leave', () => { @Component({ @@ -2240,83 +2238,82 @@ import {HostListener} from '../../src/metadata/directives'; expect(p3.element.classList.contains('parent1')).toBeTruthy(); }); - fixmeIvy('unknown').it( - 'should emulate a leave animation on the nearest sub host elements when a parent is removed', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should emulate a leave animation on the nearest sub host elements when a parent is removed', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: `
    `, - animations: [ - trigger( - 'leave', - [ - transition(':leave', [animate(1000, style({color: 'gold'}))]), - ]), - trigger( - 'parent', - [ - transition(':leave', [query(':leave', animateChild())]), - ]), - ] - }) - class ParentCmp { - public exp: boolean = true; - @ViewChild('child') public childElm: any; + animations: [ + trigger( + 'leave', + [ + transition(':leave', [animate(1000, style({color: 'gold'}))]), + ]), + trigger( + 'parent', + [ + transition(':leave', [query(':leave', animateChild())]), + ]), + ] + }) + class ParentCmp { + public exp: boolean = true; + @ViewChild('child') public childElm: any; - public childEvent: any; + public childEvent: any; - animateStart(event: any) { - if (event.toState == 'void') { - this.childEvent = event; - } - } - } + animateStart(event: any) { + if (event.toState == 'void') { + this.childEvent = event; + } + } + } - @Component({ - selector: 'child-cmp', - template: '...', - animations: [ - trigger( - 'child', - [ - transition(':leave', [animate(1000, style({color: 'gold'}))]), - ]), - ] - }) - class ChildCmp { - public childEvent: any; + @Component({ + selector: 'child-cmp', + template: '...', + animations: [ + trigger( + 'child', + [ + transition(':leave', [animate(1000, style({color: 'gold'}))]), + ]), + ] + }) + class ChildCmp { + public childEvent: any; - @HostBinding('@child') public animate = true; + @HostBinding('@child') public animate = true; - @HostListener('@child.start', ['$event']) - animateStart(event: any) { - if (event.toState == 'void') { - this.childEvent = event; - } - } - } + @HostListener('@child.start', ['$event']) + animateStart(event: any) { + if (event.toState == 'void') { + this.childEvent = event; + } + } + } - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; - fixture.detectChanges(); + fixture.detectChanges(); - const childCmp = cmp.childElm; + const childCmp = cmp.childElm; - cmp.exp = false; - fixture.detectChanges(); - flushMicrotasks(); + cmp.exp = false; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.childEvent.toState).toEqual('void'); - expect(cmp.childEvent.totalTime).toEqual(1000); - expect(childCmp.childEvent.toState).toEqual('void'); - expect(childCmp.childEvent.totalTime).toEqual(1000); - })); + expect(cmp.childEvent.toState).toEqual('void'); + expect(cmp.childEvent.totalTime).toEqual(1000); + expect(childCmp.childEvent.toState).toEqual('void'); + expect(childCmp.childEvent.totalTime).toEqual(1000); + })); it('should emulate a leave animation on a sub component\'s inner elements when a parent leave animation occurs with animateChild', () => { @@ -2445,28 +2442,27 @@ import {HostListener} from '../../src/metadata/directives'; expect(element.innerText.trim()).toMatch(/this\s+child/mg); })); - fixmeIvy('unknown').it( - 'should only mark outermost *directive nodes :enter and :leave when inserts and removals occur', - () => { - @Component({ - selector: 'ani-cmp', - animations: [ - trigger( - 'anim', - [ - transition( - '* => enter', - [ - query(':enter', [animate(1000, style({color: 'red'}))]), - ]), - transition( - '* => leave', - [ - query(':leave', [animate(1000, style({color: 'blue'}))]), - ]), - ]), - ], - template: ` + it('should only mark outermost *directive nodes :enter and :leave when inserts and removals occur', + () => { + @Component({ + selector: 'ani-cmp', + animations: [ + trigger( + 'anim', + [ + transition( + '* => enter', + [ + query(':enter', [animate(1000, style({color: 'red'}))]), + ]), + transition( + '* => leave', + [ + query(':leave', [animate(1000, style({color: 'blue'}))]), + ]), + ]), + ], + template: `
    @@ -2482,47 +2478,46 @@ import {HostListener} from '../../src/metadata/directives';
    ` - }) - class Cmp { - // TODO(issue/24571): remove '!'. - public exp !: boolean; - } + }) + class Cmp { + // TODO(issue/24571): remove '!'. + public exp !: boolean; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - const container = fixture.elementRef.nativeElement; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + const container = fixture.elementRef.nativeElement; - cmp.exp = true; - fixture.detectChanges(); - engine.flush(); + cmp.exp = true; + fixture.detectChanges(); + engine.flush(); - let players = getLog(); - resetLog(); - expect(players.length).toEqual(2); - const [p1, p2] = players; + let players = getLog(); + resetLog(); + expect(players.length).toEqual(2); + const [p1, p2] = players; - expect(p1.element.classList.contains('a')); - expect(p2.element.classList.contains('d')); + expect(p1.element.classList.contains('a')); + expect(p2.element.classList.contains('d')); - cmp.exp = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp = false; + fixture.detectChanges(); + engine.flush(); - players = getLog(); - resetLog(); - expect(players.length).toEqual(2); - const [p3, p4] = players; + players = getLog(); + resetLog(); + expect(players.length).toEqual(2); + const [p3, p4] = players; - expect(p3.element.classList.contains('a')); - expect(p4.element.classList.contains('d')); - }); + expect(p3.element.classList.contains('a')); + expect(p4.element.classList.contains('d')); + }); - fixmeIvy('unknown').it( - 'should collect multiple root levels of :enter and :leave nodes', () => { - @Component({ + it('should collect multiple root levels of :enter and :leave nodes', () => { + @Component({ selector: 'ani-cmp', animations: [ trigger('pageAnimation', [ @@ -2557,88 +2552,88 @@ import {HostListener} from '../../src/metadata/directives'; ` }) class Cmp { - get title() { - if (this.page1) { - return 'hello from page1'; - } - return 'greetings from page2'; - } - - page1 = false; - page2 = false; - loading = false; - - get status() { - if (this.loading) return 'loading'; - if (this.page1) return 'page1'; - if (this.page2) return 'page2'; - return ''; - } + get title() { + if (this.page1) { + return 'hello from page1'; } + return 'greetings from page2'; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + page1 = false; + page2 = false; + loading = false; - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.loading = true; - fixture.detectChanges(); - engine.flush(); + get status() { + if (this.loading) return 'loading'; + if (this.page1) return 'page1'; + if (this.page2) return 'page2'; + return ''; + } + } - let players = getLog(); - resetLog(); - cancelAllPlayers(players); + TestBed.configureTestingModule({declarations: [Cmp]}); - cmp.page1 = true; - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.loading = true; + fixture.detectChanges(); + engine.flush(); - let p1: MockAnimationPlayer; - let p2: MockAnimationPlayer; - let p3: MockAnimationPlayer; + let players = getLog(); + resetLog(); + cancelAllPlayers(players); - players = getLog(); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; + cmp.page1 = true; + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); - expect(p1.element.classList.contains('loading')).toBe(true); - expect(p2.element.classList.contains('title')).toBe(true); - expect(p3.element.classList.contains('page1')).toBe(true); + let p1: MockAnimationPlayer; + let p2: MockAnimationPlayer; + let p3: MockAnimationPlayer; - resetLog(); - cancelAllPlayers(players); + players = getLog(); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; - cmp.page1 = false; - cmp.loading = true; - fixture.detectChanges(); + expect(p1.element.classList.contains('loading')).toBe(true); + expect(p2.element.classList.contains('title')).toBe(true); + expect(p3.element.classList.contains('page1')).toBe(true); - players = getLog(); - cancelAllPlayers(players); + resetLog(); + cancelAllPlayers(players); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; + cmp.page1 = false; + cmp.loading = true; + fixture.detectChanges(); - expect(p1.element.classList.contains('title')).toBe(true); - expect(p2.element.classList.contains('page1')).toBe(true); - expect(p3.element.classList.contains('loading')).toBe(true); + players = getLog(); + cancelAllPlayers(players); - resetLog(); - cancelAllPlayers(players); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; - cmp.page2 = true; - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); + expect(p1.element.classList.contains('title')).toBe(true); + expect(p2.element.classList.contains('page1')).toBe(true); + expect(p3.element.classList.contains('loading')).toBe(true); - players = getLog(); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; + resetLog(); + cancelAllPlayers(players); - expect(p1.element.classList.contains('loading')).toBe(true); - expect(p2.element.classList.contains('title')).toBe(true); - expect(p3.element.classList.contains('page2')).toBe(true); - }); + cmp.page2 = true; + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); + + players = getLog(); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; + + expect(p1.element.classList.contains('loading')).toBe(true); + expect(p2.element.classList.contains('title')).toBe(true); + expect(p3.element.classList.contains('page2')).toBe(true); + }); it('should emulate leave animation callbacks for all sub elements that have leave triggers within the component', fakeAsync(() => { diff --git a/packages/core/test/animation/animation_router_integration_spec.ts b/packages/core/test/animation/animation_router_integration_spec.ts index 2dbc90591e..e904623ec9 100644 --- a/packages/core/test/animation/animation_router_integration_spec.ts +++ b/packages/core/test/animation/animation_router_integration_spec.ts @@ -34,354 +34,349 @@ import {RouterTestingModule} from '@angular/router/testing'; }); }); - fixmeIvy('unknown').it( - 'should query the old and new routes via :leave and :enter', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':leave', animateChild()), - query(':enter', animateChild()), - ]), - ]), - ], - template: ` + it('should query the old and new routes via :leave and :enter', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':leave', animateChild()), + query(':enter', animateChild()), + ]), + ]), + ], + template: `
    ` - }) - class ContainerCmp { - constructor(public router: Router) {} + }) + class ContainerCmp { + constructor(public router: Router) {} - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } - } + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; + } + } - @Component({ - selector: 'page1', - template: `page1`, - animations: [ - trigger( - 'page1Animation', - [ - transition( - ':leave', - [ - style({width: '200px'}), - animate(1000, style({width: '0px'})), - ]), - ]), - ] - }) - class Page1Cmp { - @HostBinding('@page1Animation') public doAnimate = true; - } + @Component({ + selector: 'page1', + template: `page1`, + animations: [ + trigger( + 'page1Animation', + [ + transition( + ':leave', + [ + style({width: '200px'}), + animate(1000, style({width: '0px'})), + ]), + ]), + ] + }) + class Page1Cmp { + @HostBinding('@page1Animation') public doAnimate = true; + } - @Component({ - selector: 'page2', - template: `page2`, - animations: [ - trigger( - 'page2Animation', - [ - transition( - ':enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - ]), - ] - }) - class Page2Cmp { - @HostBinding('@page2Animation') public doAnimate = true; - } + @Component({ + selector: 'page2', + template: `page2`, + animations: [ + trigger( + 'page2Animation', + [ + transition( + ':enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + ]), + ] + }) + class Page2Cmp { + @HostBinding('@page2Animation') public doAnimate = true; + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); - const player = engine.players[0] !; - const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; + const player = engine.players[0] !; + const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; - expect(players.length).toEqual(2); - const [p1, p2] = players; + expect(players.length).toEqual(2); + const [p1, p2] = players; - expect(p1.duration).toEqual(1000); - expect(p1.keyframes).toEqual([ - {offset: 0, width: '200px'}, - {offset: 1, width: '0px'}, - ]); + expect(p1.duration).toEqual(1000); + expect(p1.keyframes).toEqual([ + {offset: 0, width: '200px'}, + {offset: 1, width: '0px'}, + ]); - expect(p2.duration).toEqual(2000); - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: .5, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); - })); + expect(p2.duration).toEqual(2000); + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: .5, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); + })); - fixmeIvy('unknown').it( - 'should allow inner enter animations to be emulated within a routed item', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':enter', animateChild()), - ]), - ]), - ], - template: ` + it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':enter', animateChild()), + ]), + ]), + ], + template: `
    ` - }) - class ContainerCmp { - constructor(public router: Router) {} + }) + class ContainerCmp { + constructor(public router: Router) {} - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } - } + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; + } + } - @Component({selector: 'page1', template: `page1`, animations: []}) - class Page1Cmp { - } + @Component({selector: 'page1', template: `page1`, animations: []}) + class Page1Cmp { + } - @Component({ - selector: 'page2', - template: ` + @Component({ + selector: 'page2', + template: `

    Page 2

    `, - animations: [ - trigger( - 'page2Animation', - [ - transition( - ':enter', - [query('.if-one', animateChild()), query('.if-two', animateChild())]), - ]), - trigger( - 'ifAnimation', - [transition( - ':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) - ] - }) - class Page2Cmp { - @HostBinding('@page2Animation') public doAnimate = true; + animations: [ + trigger( + 'page2Animation', + [ + transition( + ':enter', + [query('.if-one', animateChild()), query('.if-two', animateChild())]), + ]), + trigger( + 'ifAnimation', + [transition( + ':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) + ] + }) + class Page2Cmp { + @HostBinding('@page2Animation') public doAnimate = true; - public exp = true; - } + public exp = true; + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); - const player = engine.players[0] !; - const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; + const player = engine.players[0] !; + const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; - expect(players.length).toEqual(2); - const [p1, p2] = players; + expect(players.length).toEqual(2); + const [p1, p2] = players; - expect(p1.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); + expect(p1.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: .5, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); - })); + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: .5, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); + })); - fixmeIvy('unknown').it( - 'should allow inner leave animations to be emulated within a routed item', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':leave', animateChild()), - ]), - ]), - ], - template: ` + it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':leave', animateChild()), + ]), + ]), + ], + template: `
    ` - }) - class ContainerCmp { - constructor(public router: Router) {} + }) + class ContainerCmp { + constructor(public router: Router) {} - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } - } + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; + } + } - @Component({ - selector: 'page1', - template: ` + @Component({ + selector: 'page1', + template: `

    Page 1

    `, - animations: [ - trigger( - 'page1Animation', - [ - transition( - ':leave', - [query('.if-one', animateChild()), query('.if-two', animateChild())]), - ]), - trigger( - 'ifAnimation', - [transition( - ':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]), - ] - }) - class Page1Cmp { - @HostBinding('@page1Animation') public doAnimate = true; + animations: [ + trigger( + 'page1Animation', + [ + transition( + ':leave', + [query('.if-one', animateChild()), query('.if-two', animateChild())]), + ]), + trigger( + 'ifAnimation', + [transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]), + ] + }) + class Page1Cmp { + @HostBinding('@page1Animation') public doAnimate = true; - public exp = true; - } + public exp = true; + } - @Component({selector: 'page2', template: `page2`, animations: []}) - class Page2Cmp { - } + @Component({selector: 'page2', template: `page2`, animations: []}) + class Page2Cmp { + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); - const player = engine.players[0] !; - const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; + const player = engine.players[0] !; + const groupPlayer = player.getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; - expect(players.length).toEqual(2); - const [p1, p2] = players; + expect(players.length).toEqual(2); + const [p1, p2] = players; - expect(p1.keyframes).toEqual([ - {offset: 0, opacity: '1'}, - {offset: 1, opacity: '0'}, - ]); + expect(p1.keyframes).toEqual([ + {offset: 0, opacity: '1'}, + {offset: 1, opacity: '0'}, + ]); - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '1'}, - {offset: .5, opacity: '1'}, - {offset: 1, opacity: '0'}, - ]); - })); + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '1'}, + {offset: .5, opacity: '1'}, + {offset: 1, opacity: '0'}, + ]); + })); - fixmeIvy('unknown').it( - 'should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - animations: [ - trigger( - 'pageAnimation', - [ - transition( - 'page1 => page2', - [ - query('.router-container :leave', animate('1s', style({opacity: 0}))), - query('.router-container :enter', animate('1s', style({opacity: 1}))), - ]), - ]), - ], - template: ` + it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + animations: [ + trigger( + 'pageAnimation', + [ + transition( + 'page1 => page2', + [ + query('.router-container :leave', animate('1s', style({opacity: 0}))), + query('.router-container :enter', animate('1s', style({opacity: 1}))), + ]), + ]), + ], + template: `
    @@ -394,139 +389,136 @@ import {RouterTestingModule} from '@angular/router/testing';
    ` - }) - class ContainerCmp { - loading = false; + }) + class ContainerCmp { + loading = false; - constructor(public router: Router) {} + constructor(public router: Router) {} - prepRoute(outlet: any) { return outlet.activatedRouteData['animation']; } - } + prepRoute(outlet: any) { return outlet.activatedRouteData['animation']; } + } - @Component({selector: 'page1', template: `page1`}) - class Page1Cmp { - } + @Component({selector: 'page1', template: `page1`}) + class Page1Cmp { + } - @Component({selector: 'page2', template: `page2`}) - class Page2Cmp { - } + @Component({selector: 'page2', template: `page2`}) + class Page2Cmp { + } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page1'); - tick(); - cmp.loading = true; - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page1'); + tick(); + cmp.loading = true; + fixture.detectChanges(); + engine.flush(); - cmp.router.navigateByUrl('/page2'); - tick(); - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); + cmp.router.navigateByUrl('/page2'); + tick(); + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); - const players = engine.players; - expect(players.length).toEqual(1); - const [p1] = players; + const players = engine.players; + expect(players.length).toEqual(1); + const [p1] = players; - const innerPlayers = p1.getRealPlayer().players; - expect(innerPlayers.length).toEqual(2); + const innerPlayers = p1.getRealPlayer().players; + expect(innerPlayers.length).toEqual(2); - const [ip1, ip2] = innerPlayers; - expect(ip1.element.innerText).toEqual('page1'); - expect(ip2.element.innerText).toEqual('page2'); - })); + const [ip1, ip2] = innerPlayers; + expect(ip1.element.innerText).toEqual('page1'); + expect(ip2.element.innerText).toEqual('page2'); + })); - fixmeIvy('unknown').it( - 'should allow a recursive set of :leave animations to occur for nested routes', - fakeAsync(() => { - @Component( - {selector: 'ani-cmp', template: ''}) - class ContainerCmp { - constructor(private _router: Router) {} - log: string[] = []; + it('should allow a recursive set of :leave animations to occur for nested routes', + fakeAsync(() => { + @Component({selector: 'ani-cmp', template: ''}) + class ContainerCmp { + constructor(private _router: Router) {} + log: string[] = []; - enter() { this._router.navigateByUrl('/(recur:recur/nested)'); } + enter() { this._router.navigateByUrl('/(recur:recur/nested)'); } - leave() { this._router.navigateByUrl('/'); } - } + leave() { this._router.navigateByUrl('/'); } + } - @Component({ - selector: 'recur-page', - template: 'Depth: {{ depth }} \n ', - animations: [ - trigger( - 'pageAnimations', - [ - transition( - ':leave', [group([ - sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]), - query('@*', animateChild(), {optional: true}) - ])]), - ]), - ] - }) - class RecurPageCmp { - @HostBinding('@pageAnimations') public animatePage = true; + @Component({ + selector: 'recur-page', + template: 'Depth: {{ depth }} \n ', + animations: [ + trigger( + 'pageAnimations', + [ + transition(':leave', [group([ + sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]), + query('@*', animateChild(), {optional: true}) + ])]), + ]), + ] + }) + class RecurPageCmp { + @HostBinding('@pageAnimations') public animatePage = true; - @HostBinding('attr.data-depth') public depth = 0; + @HostBinding('attr.data-depth') public depth = 0; - constructor(private container: ContainerCmp, private route: ActivatedRoute) { - this.route.data.subscribe(data => { - this.container.log.push(`DEPTH ${data.depth}`); - this.depth = data.depth; - }); - } - } + constructor(private container: ContainerCmp, private route: ActivatedRoute) { + this.route.data.subscribe(data => { + this.container.log.push(`DEPTH ${data.depth}`); + this.depth = data.depth; + }); + } + } - TestBed.configureTestingModule({ - declarations: [ContainerCmp, RecurPageCmp], - imports: [RouterTestingModule.withRoutes([{ - path: 'recur', - component: RecurPageCmp, - outlet: 'recur', - data: {depth: 0}, - children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}] - }])] - }); + TestBed.configureTestingModule({ + declarations: [ContainerCmp, RecurPageCmp], + imports: [RouterTestingModule.withRoutes([{ + path: 'recur', + component: RecurPageCmp, + outlet: 'recur', + data: {depth: 0}, + children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}] + }])] + }); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.enter(); - tick(); - fixture.detectChanges(); - flushMicrotasks(); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.enter(); + tick(); + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.log).toEqual([ - 'DEPTH 0', - 'DEPTH 1', - ]); + expect(cmp.log).toEqual([ + 'DEPTH 0', + 'DEPTH 1', + ]); - cmp.leave(); - tick(); - fixture.detectChanges(); + cmp.leave(); + tick(); + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); + const players = getLog(); + expect(players.length).toEqual(2); - const [p1, p2] = players; - expect(p1.element.getAttribute('data-depth')).toEqual('0'); - expect(p2.element.getAttribute('data-depth')).toEqual('1'); - })); + const [p1, p2] = players; + expect(p1.element.getAttribute('data-depth')).toEqual('0'); + expect(p2.element.getAttribute('data-depth')).toEqual('1'); + })); }); }); diff --git a/packages/core/test/animation/animations_with_web_animations_integration_spec.ts b/packages/core/test/animation/animations_with_web_animations_integration_spec.ts index 7b2ec1ec2a..e510e7bd2d 100644 --- a/packages/core/test/animation/animations_with_web_animations_integration_spec.ts +++ b/packages/core/test/animation/animations_with_web_animations_integration_spec.ts @@ -242,10 +242,9 @@ import {fixmeIvy} from '@angular/private/testing'; ]); }); - fixmeIvy('unknown').it( - 'should treat * styles as ! for queried items that are collected in a container that is being removed', - () => { - @Component({ + it('should treat * styles as ! for queried items that are collected in a container that is being removed', + () => { + @Component({ selector: 'my-app', styles: [` .list .outer { @@ -286,58 +285,58 @@ import {fixmeIvy} from '@angular/private/testing'; ] }) class Cmp { - items: any[] = []; + items: any[] = []; - get exp() { return this.items.length ? 'full' : 'empty'; } + get exp() { return this.items.length ? 'full' : 'empty'; } - empty() { this.items = []; } + empty() { this.items = []; } - full() { this.items = [0, 1, 2, 3, 4]; } - } + full() { this.items = [0, 1, 2, 3, 4]; } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.get(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.get(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.empty(); - fixture.detectChanges(); - let player = engine.players[0] !as TransitionAnimationPlayer; - player.finish(); + cmp.empty(); + fixture.detectChanges(); + let player = engine.players[0] !as TransitionAnimationPlayer; + player.finish(); - cmp.full(); - fixture.detectChanges(); + cmp.full(); + fixture.detectChanges(); - player = engine.players[0] !as TransitionAnimationPlayer; - let queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; - expect(queriedPlayers.length).toEqual(5); + player = engine.players[0] !as TransitionAnimationPlayer; + let queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; + expect(queriedPlayers.length).toEqual(5); - let i = 0; - for (i = 0; i < queriedPlayers.length; i++) { - let player = queriedPlayers[i] as ɵWebAnimationsPlayer; - expect(player.keyframes).toEqual([ - {height: '0px', offset: 0}, - {height: '50px', offset: 1}, - ]); - player.finish(); - } + let i = 0; + for (i = 0; i < queriedPlayers.length; i++) { + let player = queriedPlayers[i] as ɵWebAnimationsPlayer; + expect(player.keyframes).toEqual([ + {height: '0px', offset: 0}, + {height: '50px', offset: 1}, + ]); + player.finish(); + } - cmp.empty(); - fixture.detectChanges(); + cmp.empty(); + fixture.detectChanges(); - player = engine.players[0] !as TransitionAnimationPlayer; - queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; - expect(queriedPlayers.length).toEqual(5); + player = engine.players[0] !as TransitionAnimationPlayer; + queriedPlayers = (player.getRealPlayer() as AnimationGroupPlayer).players; + expect(queriedPlayers.length).toEqual(5); - for (i = 0; i < queriedPlayers.length; i++) { - let player = queriedPlayers[i] as ɵWebAnimationsPlayer; - expect(player.keyframes).toEqual([ - {height: '50px', offset: 0}, - {height: '0px', offset: 1}, - ]); - } - }); + for (i = 0; i < queriedPlayers.length; i++) { + let player = queriedPlayers[i] as ɵWebAnimationsPlayer; + expect(player.keyframes).toEqual([ + {height: '50px', offset: 0}, + {height: '0px', offset: 1}, + ]); + } + }); it('should compute intermediate styles properly when an animation is cancelled', () => { @Component({ diff --git a/packages/core/test/application_ref_spec.ts b/packages/core/test/application_ref_spec.ts index 5a5f9e38c8..48f5544863 100644 --- a/packages/core/test/application_ref_spec.ts +++ b/packages/core/test/application_ref_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, Compiler, CompilerFactory, Component, NgModule, NgZone, PlatformRef, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core'; +import {APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, Compiler, CompilerFactory, Component, InjectionToken, NgModule, NgZone, PlatformRef, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core'; import {ApplicationRef} from '@angular/core/src/application_ref'; import {ErrorHandler} from '@angular/core/src/error_handler'; import {ComponentRef} from '@angular/core/src/linker/component_factory'; @@ -15,7 +15,7 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens'; import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, ivyEnabled, modifiedInIvy} from '@angular/private/testing'; +import {ivyEnabled} from '@angular/private/testing'; import {NoopNgZone} from '../src/zone/ng_zone'; import {ComponentFixtureNoNgZone, TestBed, async, inject, withModule} from '../testing'; @@ -74,63 +74,65 @@ class SomeComponent { return MyModule; } - fixmeIvy('FW-776: Cannot bootstrap as there are still asynchronous initializers running') - .it('should bootstrap a component from a child module', - async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => { - @Component({ - selector: 'bootstrap-app', - template: '', - }) - class SomeComponent { - } + it('should bootstrap a component from a child module', + async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => { + @Component({ + selector: 'bootstrap-app', + template: '', + }) + class SomeComponent { + } - @NgModule({ - providers: [{provide: 'hello', useValue: 'component'}], - declarations: [SomeComponent], - entryComponents: [SomeComponent], - }) - class SomeModule { - } + const helloToken = new InjectionToken('hello'); - createRootEl(); - const modFactory = compiler.compileModuleSync(SomeModule); - const module = modFactory.create(TestBed); - const cmpFactory = - module.componentFactoryResolver.resolveComponentFactory(SomeComponent) !; - const component = app.bootstrap(cmpFactory); + @NgModule({ + providers: [{provide: helloToken, useValue: 'component'}], + declarations: [SomeComponent], + entryComponents: [SomeComponent], + }) + class SomeModule { + } - // The component should see the child module providers - expect(component.injector.get('hello')).toEqual('component'); - }))); + createRootEl(); + const modFactory = compiler.compileModuleSync(SomeModule); + const module = modFactory.create(TestBed); + const cmpFactory = + module.componentFactoryResolver.resolveComponentFactory(SomeComponent) !; + const component = app.bootstrap(cmpFactory); - fixmeIvy('FW-776: Cannot bootstrap as there are still asynchronous initializers running') - .it('should bootstrap a component with a custom selector', - async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => { - @Component({ - selector: 'bootstrap-app', - template: '', - }) - class SomeComponent { - } + // The component should see the child module providers + expect(component.injector.get(helloToken)).toEqual('component'); + }))); - @NgModule({ - providers: [{provide: 'hello', useValue: 'component'}], - declarations: [SomeComponent], - entryComponents: [SomeComponent], - }) - class SomeModule { - } + it('should bootstrap a component with a custom selector', + async(inject([ApplicationRef, Compiler], (app: ApplicationRef, compiler: Compiler) => { + @Component({ + selector: 'bootstrap-app', + template: '', + }) + class SomeComponent { + } - createRootEl('custom-selector'); - const modFactory = compiler.compileModuleSync(SomeModule); - const module = modFactory.create(TestBed); - const cmpFactory = - module.componentFactoryResolver.resolveComponentFactory(SomeComponent) !; - const component = app.bootstrap(cmpFactory, 'custom-selector'); + const helloToken = new InjectionToken('hello'); - // The component should see the child module providers - expect(component.injector.get('hello')).toEqual('component'); - }))); + @NgModule({ + providers: [{provide: helloToken, useValue: 'component'}], + declarations: [SomeComponent], + entryComponents: [SomeComponent], + }) + class SomeModule { + } + + createRootEl('custom-selector'); + const modFactory = compiler.compileModuleSync(SomeModule); + const module = modFactory.create(TestBed); + const cmpFactory = + module.componentFactoryResolver.resolveComponentFactory(SomeComponent) !; + const component = app.bootstrap(cmpFactory, 'custom-selector'); + + // The component should see the child module providers + expect(component.injector.get(helloToken)).toEqual('component'); + }))); describe('ApplicationRef', () => { beforeEach(() => { TestBed.configureTestingModule({imports: [createModule()]}); }); diff --git a/packages/core/test/bundling/animation_world/base.css b/packages/core/test/bundling/animation_world/base.css index 9f6ac1bd74..ebd81e6170 100644 --- a/packages/core/test/bundling/animation_world/base.css +++ b/packages/core/test/bundling/animation_world/base.css @@ -137,5 +137,10 @@ hr { .learn-bar > .learn { left: 8px; - } -} \ No newline at end of file + } +} + +.border { + outline:2px solid maroon; + display:block; +} diff --git a/packages/core/test/bundling/animation_world/index.ts b/packages/core/test/bundling/animation_world/index.ts index 001c8b3ea7..0f4e892a92 100644 --- a/packages/core/test/bundling/animation_world/index.ts +++ b/packages/core/test/bundling/animation_world/index.ts @@ -9,7 +9,7 @@ import '@angular/core/test/bundling/util/src/reflect_metadata'; import {CommonModule} from '@angular/common'; -import {Component, Directive, ElementRef, HostBinding, NgModule, ɵPlayState as PlayState, ɵPlayer as Player, ɵPlayerHandler as PlayerHandler, ɵaddPlayer as addPlayer, ɵbindPlayerFactory as bindPlayerFactory, ɵmarkDirty as markDirty, ɵrenderComponent as renderComponent} from '@angular/core'; +import {Component, Directive, ElementRef, HostBinding, HostListener, NgModule, ɵPlayState as PlayState, ɵPlayer as Player, ɵPlayerHandler as PlayerHandler, ɵaddPlayer as addPlayer, ɵbindPlayerFactory as bindPlayerFactory, ɵmarkDirty as markDirty, ɵrenderComponent as renderComponent} from '@angular/core'; @Directive({ selector: '[make-color-grey]', @@ -33,6 +33,36 @@ class MakeColorGreyDirective { toggle() { this._backgroundColor ? this.off() : this.on(); } } +@Component({selector: 'box-with-overridden-styles', template: '...'}) +class BoxWithOverriddenStylesComponent { + public active = false; + + @HostBinding('style') + styles = {}; + + constructor() { this.onInActive(); } + + @HostListener('click', ['$event']) + toggle() { + if (this.active) { + this.onInActive(); + } else { + this.onActive(); + } + markDirty(this); + } + + onActive() { + this.active = true; + this.styles = {height: '500px', 'font-size': '200px', background: 'red'}; + } + + onInActive() { + this.active = false; + this.styles = {width: '200px', height: '500px', border: '10px solid black', background: 'grey'}; + } +} + @Component({ selector: 'animation-world', template: ` @@ -48,7 +78,7 @@ class MakeColorGreyDirective { class="record" [style.transform]="item.active ? 'scale(1.5)' : 'none'" [class]="makeClass(item)" - style="border-radius: 10px" + style="border-radius: 10px" [style]="styles" [style.color]="item.value == 4 ? 'red' : null" [style.background-color]="item.value == 4 ? 'white' : null" @@ -56,9 +86,18 @@ class MakeColorGreyDirective { {{ item.value }}
    + +
    + + + `, }) class AnimationWorldComponent { + @HostBinding('class') classVal = 'border'; + items: any[] = [ {value: 1, active: false}, {value: 2, active: false}, {value: 3, active: false}, {value: 4, active: false}, {value: 5, active: false}, {value: 6, active: false}, @@ -93,8 +132,10 @@ class AnimationWorldComponent { } } -@NgModule( - {declarations: [AnimationWorldComponent, MakeColorGreyDirective], imports: [CommonModule]}) +@NgModule({ + declarations: [AnimationWorldComponent, MakeColorGreyDirective, BoxWithOverriddenStylesComponent], + imports: [CommonModule] +}) class AnimationWorldModule { } diff --git a/packages/core/test/bundling/cyclic_import/BUILD.bazel b/packages/core/test/bundling/cyclic_import/BUILD.bazel new file mode 100644 index 0000000000..72de586885 --- /dev/null +++ b/packages/core/test/bundling/cyclic_import/BUILD.bazel @@ -0,0 +1,88 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ng_module", "ng_rollup_bundle", "ts_library") +load("//tools/symbol-extractor:index.bzl", "js_expected_symbol_test") +load("//tools/http-server:http_server.bzl", "http_server") + +ng_module( + name = "cyclic_import", + srcs = [ + "index.ts", + "trigger.ts", + ], + tags = [ + "ivy-only", + ], + deps = [ + "//packages/core", + ], +) + +ng_rollup_bundle( + name = "bundle", + # TODO(alexeagle): This is inconsistent. + # We try to teach users to always have their workspace at the start of a + # path, to disambiguate from other workspaces. + # Here, the rule implementation is looking in an execroot where the layout + # has an "external" directory for external dependencies. + # This should probably start with "angular/" and let the rule deal with it. + entry_point = "packages/core/test/bundling/cyclic_import/index.js", + tags = [ + "ivy-only", + ], + deps = [ + ":cyclic_import", + "//packages/core", + ], +) + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob(["*_spec.ts"]), + tags = [ + "ivy-only", + ], + deps = [ + "//packages:types", + "//packages/compiler", + "//packages/core/testing", + "//packages/private/testing", + ], +) + +jasmine_node_test( + name = "test", + data = [ + ":bundle", + ":bundle.js", + ":bundle.min.js.br", + ":bundle.min_debug.js", + ], + tags = [ + "ivy-only", + ], + deps = [":test_lib"], +) + +js_expected_symbol_test( + name = "symbol_test", + src = ":bundle.min_debug.js", + golden = ":bundle.golden_symbols.json", + tags = [ + "ivy-aot", + "ivy-only", + ], +) + +http_server( + name = "devserver", + data = [ + "index.html", + ":bundle.min.js", + ":bundle.min_debug.js", + ], + tags = [ + "ivy-only", + ], +) diff --git a/packages/core/test/bundling/cyclic_import/README.md b/packages/core/test/bundling/cyclic_import/README.md new file mode 100644 index 0000000000..e62994c4c9 --- /dev/null +++ b/packages/core/test/bundling/cyclic_import/README.md @@ -0,0 +1,22 @@ +# Purpose + +This test exists to validate that ngtsc, when compiling an application where Ivy would otherwise +require a circular dependency, uses "remote scoping" via the `setComponentScope` function instead. + +# How it works + +There are two files, `index.ts` and `trigger.ts`. `index.ts` contains the NgModule and a simple +component (``). + +`trigger.ts` contains a component `TriggerComponent` that uses `` in its template. Normally, +Ivy would want `DepComponent` to be listed in `TriggerComponent`'s definition. However, this +requires adding an import from `trigger.ts` -> `index.ts`, and there's already an import from +`index.ts` to `trigger.ts` (for the NgModule). + +In this case, ngtsc decides to set the directives in `TriggerComponent`'s definition via a different +mechanism: remote scoping. Alongside the NgModule (in `index.ts`) a call to `setComponentScope` is +generated which sets up `TriggerComponent`'s definition correctly, without introducing any imports. +This call is not tree-shakeable, but does not create a cycle. + +The symbol test here verifies that `setComponentScope` is used, and the e2e spec verifies that the +application works correctly. \ No newline at end of file diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json new file mode 100644 index 0000000000..a18848355a --- /dev/null +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -0,0 +1,650 @@ +[ + { + "name": "ACTIVE_INDEX" + }, + { + "name": "ANIMATION_PROP_PREFIX" + }, + { + "name": "BINDING_INDEX" + }, + { + "name": "BLOOM_MASK" + }, + { + "name": "CLEAN_PROMISE" + }, + { + "name": "CONTAINER_INDEX" + }, + { + "name": "CONTEXT" + }, + { + "name": "ChangeDetectionStrategy" + }, + { + "name": "DECLARATION_VIEW" + }, + { + "name": "DepComponent" + }, + { + "name": "EMPTY_ARRAY" + }, + { + "name": "EMPTY_OBJ" + }, + { + "name": "EmptyErrorImpl" + }, + { + "name": "FLAGS" + }, + { + "name": "FactoryPrototype" + }, + { + "name": "HEADER_OFFSET" + }, + { + "name": "HOST" + }, + { + "name": "INJECTOR" + }, + { + "name": "INJECTOR_BLOOM_PARENT_SIZE" + }, + { + "name": "MONKEY_PATCH_KEY_NAME" + }, + { + "name": "Module" + }, + { + "name": "NATIVE" + }, + { + "name": "NEXT" + }, + { + "name": "NG_COMPONENT_DEF" + }, + { + "name": "NG_DIRECTIVE_DEF" + }, + { + "name": "NG_ELEMENT_ID" + }, + { + "name": "NG_PIPE_DEF" + }, + { + "name": "NG_PROJECT_AS_ATTR_NAME" + }, + { + "name": "NG_TEMPLATE_SELECTOR" + }, + { + "name": "NO_CHANGE" + }, + { + "name": "NO_PARENT_INJECTOR" + }, + { + "name": "NodeInjectorFactory" + }, + { + "name": "ObjectUnsubscribedErrorImpl" + }, + { + "name": "PARENT" + }, + { + "name": "PARENT_INJECTOR" + }, + { + "name": "QUERIES" + }, + { + "name": "RENDERER" + }, + { + "name": "RENDERER_FACTORY" + }, + { + "name": "RendererStyleFlags3" + }, + { + "name": "SANITIZER" + }, + { + "name": "TAIL" + }, + { + "name": "TVIEW" + }, + { + "name": "T_HOST" + }, + { + "name": "TriggerComponent" + }, + { + "name": "UnsubscriptionErrorImpl" + }, + { + "name": "VIEWS" + }, + { + "name": "ViewEncapsulation" + }, + { + "name": "__values" + }, + { + "name": "_currentNamespace" + }, + { + "name": "_global" + }, + { + "name": "_renderCompCount" + }, + { + "name": "addComponentLogic" + }, + { + "name": "addToViewTree" + }, + { + "name": "allocStylingContext" + }, + { + "name": "allocateDirectiveIntoContext" + }, + { + "name": "appendChild" + }, + { + "name": "applyOnCreateInstructions" + }, + { + "name": "attachPatchData" + }, + { + "name": "baseResolveDirective" + }, + { + "name": "bloomAdd" + }, + { + "name": "cacheMatchingLocalNames" + }, + { + "name": "callHooks" + }, + { + "name": "checkNoChangesMode" + }, + { + "name": "checkView" + }, + { + "name": "componentRefresh" + }, + { + "name": "createDirectivesAndLocals" + }, + { + "name": "createEmptyStylingContext" + }, + { + "name": "createLView" + }, + { + "name": "createNodeAtIndex" + }, + { + "name": "createRootComponent" + }, + { + "name": "createRootComponentView" + }, + { + "name": "createRootContext" + }, + { + "name": "createTNode" + }, + { + "name": "createTView" + }, + { + "name": "createTextNode" + }, + { + "name": "createViewBlueprint" + }, + { + "name": "decreaseElementDepthCount" + }, + { + "name": "defaultScheduler" + }, + { + "name": "defineComponent" + }, + { + "name": "defineInjector" + }, + { + "name": "defineNgModule" + }, + { + "name": "diPublicInInjector" + }, + { + "name": "domRendererFactory3" + }, + { + "name": "element" + }, + { + "name": "elementCreate" + }, + { + "name": "elementEnd" + }, + { + "name": "elementStart" + }, + { + "name": "enterView" + }, + { + "name": "executeContentQueries" + }, + { + "name": "executeHooks" + }, + { + "name": "executeInitHooks" + }, + { + "name": "executeViewQueryFn" + }, + { + "name": "extractDirectiveDef" + }, + { + "name": "extractPipeDef" + }, + { + "name": "findAttrIndexInNode" + }, + { + "name": "findDirectiveMatches" + }, + { + "name": "generateExpandoInstructionBlock" + }, + { + "name": "generateInitialInputs" + }, + { + "name": "generatePropertyAliases" + }, + { + "name": "getBeforeNodeForView" + }, + { + "name": "getBindingsEnabled" + }, + { + "name": "getCheckNoChangesMode" + }, + { + "name": "getClosureSafeProperty" + }, + { + "name": "getComponentDef" + }, + { + "name": "getComponentViewByIndex" + }, + { + "name": "getContainerRenderParent" + }, + { + "name": "getDirectiveDef" + }, + { + "name": "getElementDepthCount" + }, + { + "name": "getGlobal" + }, + { + "name": "getHighestElementOrICUContainer" + }, + { + "name": "getHostNative" + }, + { + "name": "getInitialClassNameValue" + }, + { + "name": "getInitialStyleStringValue" + }, + { + "name": "getInjectorIndex" + }, + { + "name": "getIsParent" + }, + { + "name": "getLContainer" + }, + { + "name": "getLView" + }, + { + "name": "getLViewChild" + }, + { + "name": "getNativeAnchorNode" + }, + { + "name": "getNativeByTNode" + }, + { + "name": "getNodeInjectable" + }, + { + "name": "getOrCreateNodeInjectorForNode" + }, + { + "name": "getOrCreateTView" + }, + { + "name": "getParentInjectorIndex" + }, + { + "name": "getParentInjectorLocation" + }, + { + "name": "getParentInjectorView" + }, + { + "name": "getParentInjectorViewOffset" + }, + { + "name": "getPipeDef" + }, + { + "name": "getPreviousOrParentTNode" + }, + { + "name": "getRenderFlags" + }, + { + "name": "getRenderParent" + }, + { + "name": "getRootContext" + }, + { + "name": "getRootView" + }, + { + "name": "getStylingContext" + }, + { + "name": "getTNode" + }, + { + "name": "hasClassInput" + }, + { + "name": "hasParentInjector" + }, + { + "name": "hasStyleInput" + }, + { + "name": "hasStyling" + }, + { + "name": "hasTagAndTypeMatch" + }, + { + "name": "includeViewProviders" + }, + { + "name": "increaseElementDepthCount" + }, + { + "name": "initNodeFlags" + }, + { + "name": "initializeStaticContext" + }, + { + "name": "initializeTNodeInputs" + }, + { + "name": "insertBloom" + }, + { + "name": "instantiateAllDirectives" + }, + { + "name": "instantiateRootComponent" + }, + { + "name": "invertObject" + }, + { + "name": "invokeDirectivesHostBindings" + }, + { + "name": "invokeHostBindingsInCreationMode" + }, + { + "name": "isAnimationProp" + }, + { + "name": "isComponentDef" + }, + { + "name": "isContentQueryHost" + }, + { + "name": "isCreationMode" + }, + { + "name": "isCssClassMatching" + }, + { + "name": "isFactory" + }, + { + "name": "isNodeMatchingSelector" + }, + { + "name": "isNodeMatchingSelectorList" + }, + { + "name": "isPositive" + }, + { + "name": "isProceduralRenderer" + }, + { + "name": "isRootView" + }, + { + "name": "isStylingContext" + }, + { + "name": "leaveView" + }, + { + "name": "locateHostElement" + }, + { + "name": "namespaceHTML" + }, + { + "name": "nativeAppendChild" + }, + { + "name": "nativeAppendOrInsertBefore" + }, + { + "name": "nativeInsertBefore" + }, + { + "name": "nativeParentNode" + }, + { + "name": "nextNgElementId" + }, + { + "name": "noSideEffects" + }, + { + "name": "postProcessBaseDirective" + }, + { + "name": "postProcessDirective" + }, + { + "name": "queueComponentIndexForCheck" + }, + { + "name": "readClassValueFromTNode" + }, + { + "name": "readElementValue" + }, + { + "name": "readPatchedData" + }, + { + "name": "readPatchedLView" + }, + { + "name": "refreshChildComponents" + }, + { + "name": "refreshContentQueries" + }, + { + "name": "refreshDescendantViews" + }, + { + "name": "refreshDynamicEmbeddedViews" + }, + { + "name": "registerPostOrderHooks" + }, + { + "name": "registerPreOrderHooks" + }, + { + "name": "renderComponent" + }, + { + "name": "renderComponentOrTemplate" + }, + { + "name": "renderEmbeddedTemplate" + }, + { + "name": "renderInitialClasses" + }, + { + "name": "renderInitialStyles" + }, + { + "name": "renderInitialStylingValues" + }, + { + "name": "renderStringify" + }, + { + "name": "resetComponentState" + }, + { + "name": "resolveDirectives" + }, + { + "name": "saveNameToExportMap" + }, + { + "name": "saveResolvedLocalsInData" + }, + { + "name": "setBindingRoot" + }, + { + "name": "setClass" + }, + { + "name": "setComponentScope" + }, + { + "name": "setCurrentDirectiveDef" + }, + { + "name": "setCurrentQueryIndex" + }, + { + "name": "setHostBindings" + }, + { + "name": "setIncludeViewProviders" + }, + { + "name": "setInjectImplementation" + }, + { + "name": "setInputsForProperty" + }, + { + "name": "setInputsFromAttrs" + }, + { + "name": "setIsParent" + }, + { + "name": "setPreviousOrParentTNode" + }, + { + "name": "setStyle" + }, + { + "name": "setTNodeAndViewData" + }, + { + "name": "setUpAttributes" + }, + { + "name": "syncViewWithBlueprint" + }, + { + "name": "text" + }, + { + "name": "throwMultipleComponentError" + }, + { + "name": "tickRootContext" + }, + { + "name": "viewAttached" + } +] \ No newline at end of file diff --git a/packages/core/test/bundling/cyclic_import/index.html b/packages/core/test/bundling/cyclic_import/index.html new file mode 100644 index 0000000000..ab44f4f0aa --- /dev/null +++ b/packages/core/test/bundling/cyclic_import/index.html @@ -0,0 +1,31 @@ + + + + + Angular Cyclic Import Example + + + + + + + + + \ No newline at end of file diff --git a/packages/core/test/bundling/cyclic_import/index.ts b/packages/core/test/bundling/cyclic_import/index.ts new file mode 100644 index 0000000000..b3c2b5160c --- /dev/null +++ b/packages/core/test/bundling/cyclic_import/index.ts @@ -0,0 +1,26 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, NgModule, ɵrenderComponent as renderComponent} from '@angular/core'; + +import {TriggerComponent} from './trigger'; + +@Component({ + selector: 'dep', + template: 'dep', +}) +export class DepComponent { +} + +@NgModule({ + declarations: [DepComponent, TriggerComponent], +}) +export class Module { +} + +renderComponent(TriggerComponent); diff --git a/packages/core/test/bundling/cyclic_import/integration_spec.ts b/packages/core/test/bundling/cyclic_import/integration_spec.ts new file mode 100644 index 0000000000..e1a2d4f318 --- /dev/null +++ b/packages/core/test/bundling/cyclic_import/integration_spec.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import '@angular/compiler'; +import {withBody} from '@angular/private/testing'; +import * as fs from 'fs'; +import * as path from 'path'; + +const UTF8 = { + encoding: 'utf-8' +}; +const PACKAGE = 'angular/packages/core/test/bundling/cyclic_import'; + +describe('treeshaking with uglify', () => { + + let content: string; + const contentPath = require.resolve(path.join(PACKAGE, 'bundle.min_debug.js')); + beforeAll(() => { content = fs.readFileSync(contentPath, UTF8); }); + + describe('functional test in domino', () => { + it('should render hello world when not minified', withBody('', () => { + require(path.join(PACKAGE, 'bundle.js')); + expect(document.body.textContent).toEqual('dep'); + })); + + it('should render hello world when debug minified', withBody('', () => { + require(path.join(PACKAGE, 'bundle.min_debug.js')); + expect(document.body.textContent).toEqual('dep'); + })); + + it('should render hello world when fully minified', withBody('', () => { + require(path.join(PACKAGE, 'bundle.min.js')); + expect(document.body.textContent).toEqual('dep'); + })); + }); +}); diff --git a/packages/core/test/bundling/cyclic_import/trigger.ts b/packages/core/test/bundling/cyclic_import/trigger.ts new file mode 100644 index 0000000000..b51ba10cc5 --- /dev/null +++ b/packages/core/test/bundling/cyclic_import/trigger.ts @@ -0,0 +1,16 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component} from '@angular/core'; + +@Component({ + selector: 'trigger', + template: '', +}) +export class TriggerComponent { +} diff --git a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json index 71e8af4671..d68730da4c 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -2,9 +2,6 @@ { "name": "ACTIVE_INDEX" }, - { - "name": "ANIMATION_PROP_PREFIX" - }, { "name": "BINDING_INDEX" }, @@ -47,9 +44,6 @@ { "name": "HOST" }, - { - "name": "HOST_NODE" - }, { "name": "INJECTOR" }, @@ -77,18 +71,12 @@ { "name": "NG_PIPE_DEF" }, - { - "name": "NG_PROJECT_AS_ATTR_NAME" - }, { "name": "NO_CHANGE" }, { "name": "NO_PARENT_INJECTOR" }, - { - "name": "NgOnChangesFeature" - }, { "name": "NodeInjectorFactory" }, @@ -101,27 +89,24 @@ { "name": "PARENT_INJECTOR" }, - { - "name": "PRIVATE_PREFIX" - }, { "name": "RENDERER" }, { "name": "RENDERER_FACTORY" }, - { - "name": "RENDER_PARENT" - }, { "name": "SANITIZER" }, { - "name": "SimpleChange" + "name": "TAIL" }, { "name": "TVIEW" }, + { + "name": "T_HOST" + }, { "name": "UnsubscriptionErrorImpl" }, @@ -132,10 +117,7 @@ "name": "ViewEncapsulation" }, { - "name": "__self" - }, - { - "name": "__window" + "name": "__values" }, { "name": "_global" @@ -143,9 +125,15 @@ { "name": "_renderCompCount" }, + { + "name": "addToViewTree" + }, { "name": "appendChild" }, + { + "name": "applyOnCreateInstructions" + }, { "name": "attachPatchData" }, @@ -158,15 +146,6 @@ { "name": "callHooks" }, - { - "name": "canInsertNativeChildOfElement" - }, - { - "name": "canInsertNativeChildOfView" - }, - { - "name": "canInsertNativeNode" - }, { "name": "checkNoChangesMode" }, @@ -203,9 +182,6 @@ { "name": "createViewBlueprint" }, - { - "name": "createViewQuery" - }, { "name": "defaultScheduler" }, @@ -227,6 +203,9 @@ { "name": "executeInitHooks" }, + { + "name": "executeViewQueryFn" + }, { "name": "extractDirectiveDef" }, @@ -258,10 +237,10 @@ "name": "getDirectiveDef" }, { - "name": "getFirstParentNative" + "name": "getGlobal" }, { - "name": "getHighestElementContainer" + "name": "getHighestElementOrICUContainer" }, { "name": "getHostNative" @@ -281,6 +260,9 @@ { "name": "getLViewChild" }, + { + "name": "getNativeAnchorNode" + }, { "name": "getNativeByTNode" }, @@ -305,9 +287,6 @@ { "name": "getParentInjectorViewOffset" }, - { - "name": "getParentNative" - }, { "name": "getPipeDef" }, @@ -345,7 +324,7 @@ "name": "invertObject" }, { - "name": "isAnimationProp" + "name": "invokeHostBindingsInCreationMode" }, { "name": "isComponentDef" @@ -371,6 +350,12 @@ { "name": "namespaceHTML" }, + { + "name": "nativeAppendChild" + }, + { + "name": "nativeAppendOrInsertBefore" + }, { "name": "nativeInsertBefore" }, @@ -383,9 +368,6 @@ { "name": "noSideEffects" }, - { - "name": "onChangesWrapper" - }, { "name": "postProcessBaseDirective" }, @@ -422,6 +404,9 @@ { "name": "renderEmbeddedTemplate" }, + { + "name": "renderStringify" + }, { "name": "resetComponentState" }, @@ -432,7 +417,7 @@ "name": "setCurrentDirectiveDef" }, { - "name": "setFirstTemplatePass" + "name": "setCurrentQueryIndex" }, { "name": "setHostBindings" @@ -452,12 +437,6 @@ { "name": "setTNodeAndViewData" }, - { - "name": "setUpAttributes" - }, - { - "name": "stringify$1" - }, { "name": "syncViewWithBlueprint" }, @@ -467,9 +446,6 @@ { "name": "tickRootContext" }, - { - "name": "updateViewQuery" - }, { "name": "viewAttached" } diff --git a/packages/core/test/bundling/injection/bundle.golden_symbols.json b/packages/core/test/bundling/injection/bundle.golden_symbols.json index d3e45977b3..d4dabca8c2 100644 --- a/packages/core/test/bundling/injection/bundle.golden_symbols.json +++ b/packages/core/test/bundling/injection/bundle.golden_symbols.json @@ -3,16 +3,25 @@ "name": "APP_ROOT" }, { - "name": "CIRCULAR$1" + "name": "CIRCULAR" }, { - "name": "EMPTY_ARRAY$1" + "name": "CIRCULAR" + }, + { + "name": "EMPTY" + }, + { + "name": "EMPTY_ARRAY" }, { "name": "EmptyErrorImpl" }, { - "name": "INJECTOR$1" + "name": "IDENT" + }, + { + "name": "INJECTOR" }, { "name": "Inject" @@ -23,20 +32,38 @@ { "name": "InjectionToken" }, + { + "name": "Injector" + }, + { + "name": "MULTI_PROVIDER_FN" + }, + { + "name": "NEW_LINE" + }, { "name": "NG_INJECTABLE_DEF" }, { "name": "NG_INJECTOR_DEF" }, + { + "name": "NG_TEMP_TOKEN_PATH" + }, + { + "name": "NG_TOKEN_PATH" + }, { "name": "NOT_YET" }, { - "name": "NULL_INJECTOR$2" + "name": "NO_NEW_LINE" }, { - "name": "NgOnChangesFeature" + "name": "NULL_INJECTOR" + }, + { + "name": "NULL_INJECTOR" }, { "name": "NullInjector" @@ -51,10 +78,10 @@ "name": "PARAMETERS" }, { - "name": "PRIVATE_PREFIX" + "name": "R3Injector" }, { - "name": "R3Injector" + "name": "SOURCE" }, { "name": "ScopedService" @@ -62,14 +89,11 @@ { "name": "Self" }, - { - "name": "SimpleChange" - }, { "name": "SkipSelf" }, { - "name": "THROW_IF_NOT_FOUND" + "name": "StaticInjector" }, { "name": "USE_VALUE" @@ -92,6 +116,12 @@ { "name": "_currentInjector" }, + { + "name": "catchInjectorError" + }, + { + "name": "computeDeps" + }, { "name": "couldBeInjectableType" }, @@ -107,6 +137,9 @@ { "name": "defineInjector" }, + { + "name": "formatError" + }, { "name": "forwardRef" }, @@ -165,7 +198,7 @@ "name": "makeRecord" }, { - "name": "onChangesWrapper" + "name": "multiProviderMixError" }, { "name": "providerToFactory" @@ -173,13 +206,28 @@ { "name": "providerToRecord" }, + { + "name": "recursivelyProcessProviders" + }, { "name": "resolveForwardRef" }, + { + "name": "resolveProvider" + }, + { + "name": "resolveToken" + }, { "name": "setCurrentInjector" }, + { + "name": "staticError" + }, { "name": "stringify" + }, + { + "name": "tryResolveToken" } ] \ No newline at end of file diff --git a/packages/core/test/bundling/injection/usage.ts b/packages/core/test/bundling/injection/usage.ts index 01d7fdce24..748715817d 100644 --- a/packages/core/test/bundling/injection/usage.ts +++ b/packages/core/test/bundling/injection/usage.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, createInjector, defineInjectable, defineInjector} from '@angular/core'; +import {Injector, defineInjectable, defineInjector, ɵcreateInjector as createInjector} from '@angular/core'; export class RootService { static ngInjectableDef = defineInjectable({ diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 9b295d6b60..dd22242097 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -50,12 +50,24 @@ { "name": "EMPTY_OBJ" }, + { + "name": "ERROR_DEBUG_CONTEXT" + }, + { + "name": "ERROR_LOGGER" + }, + { + "name": "ERROR_ORIGINAL_ERROR" + }, { "name": "ElementRef" }, { "name": "EmptyErrorImpl" }, + { + "name": "ErrorHandler" + }, { "name": "FLAGS" }, @@ -68,15 +80,15 @@ { "name": "HOST" }, - { - "name": "HOST_NODE" - }, { "name": "INJECTOR" }, { "name": "INJECTOR_BLOOM_PARENT_SIZE" }, + { + "name": "INTERPOLATION_DELIMITER" + }, { "name": "InjectFlags" }, @@ -143,18 +155,12 @@ { "name": "NgModuleRef" }, - { - "name": "NgOnChangesFeature" - }, { "name": "NodeInjector" }, { "name": "NodeInjectorFactory" }, - { - "name": "NullInjector" - }, { "name": "ObjectUnsubscribedErrorImpl" }, @@ -170,9 +176,6 @@ { "name": "PARENT_INJECTOR" }, - { - "name": "PRIVATE_PREFIX" - }, { "name": "QUERIES" }, @@ -182,9 +185,6 @@ { "name": "RENDERER_FACTORY" }, - { - "name": "RENDER_PARENT" - }, { "name": "RecordViewTuple" }, @@ -203,9 +203,6 @@ { "name": "SWITCH_VIEW_CONTAINER_REF_FACTORY" }, - { - "name": "SimpleChange" - }, { "name": "SkipSelf" }, @@ -218,26 +215,29 @@ { "name": "TVIEW" }, + { + "name": "T_HOST" + }, { "name": "TemplateRef" }, { - "name": "ToDoAppComponent_footer_Template_6" + "name": "ToDoAppComponent_footer_6_Template" }, { - "name": "ToDoAppComponent_footer_button_Template_5" + "name": "ToDoAppComponent_footer_6_button_5_Template" }, { - "name": "ToDoAppComponent_section_Template_5" + "name": "ToDoAppComponent_section_5_Template" }, { - "name": "ToDoAppComponent_section_input_Template_1" + "name": "ToDoAppComponent_section_5_input_1_Template" }, { - "name": "ToDoAppComponent_section_li_Template_3" + "name": "ToDoAppComponent_section_5_li_3_Template" }, { - "name": "ToDoAppComponent_section_li_input_Template_6" + "name": "ToDoAppComponent_section_5_li_3_input_6_Template" }, { "name": "Todo" @@ -269,9 +269,6 @@ { "name": "_DuplicateMap" }, - { - "name": "_THROW_IF_NOT_FOUND" - }, { "name": "__extends" }, @@ -281,14 +278,11 @@ { "name": "__read" }, - { - "name": "__self" - }, { "name": "__spread" }, { - "name": "__window" + "name": "__values" }, { "name": "_c0" @@ -362,9 +356,6 @@ { "name": "_symbolIterator" }, - { - "name": "_updateSingleStylingValue" - }, { "name": "addComponentLogic" }, @@ -374,6 +365,9 @@ { "name": "addRemoveViewFromContainer" }, + { + "name": "addTContainerToQueries" + }, { "name": "addToViewTree" }, @@ -383,15 +377,24 @@ { "name": "allocStylingContext" }, + { + "name": "allocateDirectiveIntoContext" + }, { "name": "allowValueChange" }, { "name": "appendChild" }, + { + "name": "applyOnCreateInstructions" + }, { "name": "assertTemplate" }, + { + "name": "assignTViewNodeToLView" + }, { "name": "attachPatchData" }, @@ -413,6 +416,9 @@ { "name": "bloomHashBitOrFactory" }, + { + "name": "booleanOrNull" + }, { "name": "cacheMatchingLocalNames" }, @@ -420,16 +426,7 @@ "name": "callHooks" }, { - "name": "canInsertNativeChildOfElement" - }, - { - "name": "canInsertNativeChildOfView" - }, - { - "name": "canInsertNativeNode" - }, - { - "name": "checkNoChanges" + "name": "checkNoChangesInternal" }, { "name": "checkNoChangesMode" @@ -503,15 +500,12 @@ { "name": "createViewBlueprint" }, - { - "name": "createViewNode" - }, - { - "name": "createViewQuery" - }, { "name": "decreaseElementDepthCount" }, + { + "name": "defaultErrorLogger" + }, { "name": "defaultScheduler" }, @@ -533,9 +527,6 @@ { "name": "detachView" }, - { - "name": "detectChanges" - }, { "name": "detectChangesInternal" }, @@ -563,6 +554,9 @@ { "name": "elementProperty" }, + { + "name": "elementPropertyInternal" + }, { "name": "elementStart" }, @@ -575,6 +569,9 @@ { "name": "enterView" }, + { + "name": "executeContentQueries" + }, { "name": "executeHooks" }, @@ -588,7 +585,7 @@ "name": "executeOnDestroys" }, { - "name": "executePipeOnDestroys" + "name": "executeViewQueryFn" }, { "name": "extendStatics" @@ -614,9 +611,6 @@ { "name": "findViaComponent" }, - { - "name": "firstTemplatePass" - }, { "name": "forwardRef" }, @@ -662,6 +656,9 @@ { "name": "getCurrentView" }, + { + "name": "getDebugContext" + }, { "name": "getDirectiveDef" }, @@ -678,26 +675,26 @@ "name": "getElementDepthCount" }, { - "name": "getFirstParentNative" + "name": "getErrorLogger" }, { - "name": "getFirstTemplatePass" + "name": "getGlobal" }, { - "name": "getHighestElementContainer" + "name": "getHighestElementOrICUContainer" }, { "name": "getHostNative" }, - { - "name": "getHostTElementNode" - }, { "name": "getInitialClassNameValue" }, { "name": "getInitialIndex" }, + { + "name": "getInitialStyleStringValue" + }, { "name": "getInitialStylingValuesIndexOf" }, @@ -729,7 +726,10 @@ "name": "getMultiOrSingleIndex" }, { - "name": "getMultiStartIndex" + "name": "getMultiStylesStartIndex" + }, + { + "name": "getNativeAnchorNode" }, { "name": "getNativeByIndex" @@ -749,6 +749,9 @@ { "name": "getOrCreateTView" }, + { + "name": "getOriginalError" + }, { "name": "getParentInjectorIndex" }, @@ -764,9 +767,6 @@ { "name": "getParentInjectorViewOffset" }, - { - "name": "getParentNative" - }, { "name": "getParentState" }, @@ -824,14 +824,17 @@ { "name": "getTViewCleanup" }, + { + "name": "getTypeName" + }, { "name": "getTypeNameForDebugging" }, { - "name": "getTypeNameForDebugging$1" + "name": "getValue" }, { - "name": "getValue" + "name": "handleError" }, { "name": "hasClassInput" @@ -842,6 +845,9 @@ { "name": "hasPlayerBuilderChanged" }, + { + "name": "hasStyleInput" + }, { "name": "hasStyling" }, @@ -851,12 +857,21 @@ { "name": "hasValueChanged" }, + { + "name": "hyphenate" + }, + { + "name": "hyphenateEntries" + }, { "name": "includeViewProviders" }, { "name": "increaseElementDepthCount" }, + { + "name": "initElementStyling" + }, { "name": "initNodeFlags" }, @@ -899,6 +914,9 @@ { "name": "invokeDirectivesHostBindings" }, + { + "name": "invokeHostBindingsInCreationMode" + }, { "name": "isAnimationProp" }, @@ -908,6 +926,9 @@ { "name": "isComponentDef" }, + { + "name": "isContentQueryHost" + }, { "name": "isContextDirty" }, @@ -966,10 +987,10 @@ "name": "leaveView" }, { - "name": "limitToSingleClasses" + "name": "listener" }, { - "name": "listener" + "name": "listenerInternal" }, { "name": "loadInternal" @@ -1001,6 +1022,12 @@ { "name": "namespaceHTML" }, + { + "name": "nativeAppendChild" + }, + { + "name": "nativeAppendOrInsertBefore" + }, { "name": "nativeInsertBefore" }, @@ -1010,6 +1037,12 @@ { "name": "nativeParentNode" }, + { + "name": "nativeRemoveChild" + }, + { + "name": "nativeRemoveNode" + }, { "name": "nextContext" }, @@ -1022,9 +1055,6 @@ { "name": "noSideEffects" }, - { - "name": "onChangesWrapper" - }, { "name": "pointers" }, @@ -1044,19 +1074,7 @@ "name": "queueComponentIndexForCheck" }, { - "name": "queueContentHooks" - }, - { - "name": "queueDestroyHooks" - }, - { - "name": "queueInitHooks" - }, - { - "name": "queueLifecycleHooks" - }, - { - "name": "queueViewHooks" + "name": "readClassValueFromTNode" }, { "name": "readElementValue" @@ -1082,6 +1100,12 @@ { "name": "refreshDynamicEmbeddedViews" }, + { + "name": "registerPostOrderHooks" + }, + { + "name": "registerPreOrderHooks" + }, { "name": "removeListeners" }, @@ -1098,11 +1122,17 @@ "name": "renderEmbeddedTemplate" }, { - "name": "renderInitialStylesAndClasses" + "name": "renderInitialClasses" + }, + { + "name": "renderInitialStyles" }, { "name": "renderInitialStylingValues" }, + { + "name": "renderStringify" + }, { "name": "renderStyling" }, @@ -1121,6 +1151,9 @@ { "name": "saveNameToExportMap" }, + { + "name": "savePropertyDebugData" + }, { "name": "saveResolvedLocalsInData" }, @@ -1148,15 +1181,15 @@ { "name": "setCurrentDirectiveDef" }, + { + "name": "setCurrentQueryIndex" + }, { "name": "setDirectiveDirty" }, { "name": "setDirty" }, - { - "name": "setFirstTemplatePass" - }, { "name": "setFlag" }, @@ -1208,15 +1241,15 @@ { "name": "shouldSearchParent" }, + { + "name": "storeBindingMetadata" + }, { "name": "storeCleanupFn" }, { "name": "stringify" }, - { - "name": "stringify$1" - }, { "name": "syncViewWithBlueprint" }, @@ -1245,7 +1278,7 @@ "name": "updateContextWithBindings" }, { - "name": "updateViewQuery" + "name": "updateSingleStylingValue" }, { "name": "valueExists" @@ -1260,6 +1293,6 @@ "name": "walkUpViews" }, { - "name": "wrapListenerWithPreventDefault" + "name": "wrapListener" } ] \ No newline at end of file diff --git a/packages/core/test/bundling/todo/todo.css b/packages/core/test/bundling/todo/todo.css index c1f2c5913b..ea30e15ff5 100644 --- a/packages/core/test/bundling/todo/todo.css +++ b/packages/core/test/bundling/todo/todo.css @@ -16,9 +16,6 @@ button { color: inherit; -webkit-appearance: none; appearance: none; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; } body { @@ -29,9 +26,6 @@ body { min-width: 230px; max-width: 550px; margin: 0 auto; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; font-weight: 300; } @@ -99,9 +93,6 @@ input[type="checkbox"] { border: 1px solid #999; box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; } .new-todo { @@ -374,4 +365,4 @@ html .clear-completed:active { .filters { bottom: 10px; } -} \ No newline at end of file +} diff --git a/packages/core/test/bundling/todo_i18n/todo.css b/packages/core/test/bundling/todo_i18n/todo.css index 19dadcf7e4..eee8a90142 100644 --- a/packages/core/test/bundling/todo_i18n/todo.css +++ b/packages/core/test/bundling/todo_i18n/todo.css @@ -16,9 +16,6 @@ button { color: inherit; -webkit-appearance: none; appearance: none; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; } body { @@ -29,9 +26,6 @@ body { min-width: 230px; max-width: 550px; margin: 0 auto; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; font-weight: 300; } @@ -100,9 +94,6 @@ input[type="checkbox"] { border: 1px solid #999; box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; } .new-todo { diff --git a/packages/core/test/bundling/todo_r2/todo.css b/packages/core/test/bundling/todo_r2/todo.css index 5c139f868c..32435e182b 100644 --- a/packages/core/test/bundling/todo_r2/todo.css +++ b/packages/core/test/bundling/todo_r2/todo.css @@ -16,9 +16,6 @@ button { color: inherit; -webkit-appearance: none; appearance: none; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; } body { @@ -29,9 +26,6 @@ body { min-width: 230px; max-width: 550px; margin: 0 auto; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; font-weight: 300; } @@ -99,9 +93,6 @@ input[type="checkbox"] { border: 1px solid #999; box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); box-sizing: border-box; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - font-smoothing: antialiased; } .new-todo { diff --git a/packages/core/test/change_detection/iterable.ts b/packages/core/test/change_detection/iterable.ts index b78de13bf9..97e2401bcd 100644 --- a/packages/core/test/change_detection/iterable.ts +++ b/packages/core/test/change_detection/iterable.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {getSymbolIterator} from '@angular/core/src/util'; +import {getSymbolIterator} from '@angular/core/src/util/symbol'; export class TestIterable { list: number[]; diff --git a/packages/core/test/change_detection/util.ts b/packages/core/test/change_detection/util.ts index 2a6b28f8d5..97d68f52dc 100644 --- a/packages/core/test/change_detection/util.ts +++ b/packages/core/test/change_detection/util.ts @@ -9,7 +9,8 @@ import {IterableChangeRecord, IterableChanges} from '@angular/core/src/change_detection/differs/iterable_differs'; import {KeyValueChangeRecord, KeyValueChanges} from '@angular/core/src/change_detection/differs/keyvalue_differs'; -import {looseIdentical, stringify} from '../../src/util'; +import {looseIdentical} from '../../src/util/comparison'; +import {stringify} from '../../src/util/stringify'; export function iterableDifferToString(iterableChanges: IterableChanges) { const collection: string[] = []; diff --git a/packages/core/test/debug/debug_node_spec.ts b/packages/core/test/debug/debug_node_spec.ts index d96cdb5a23..5577ed49ac 100644 --- a/packages/core/test/debug/debug_node_spec.ts +++ b/packages/core/test/debug/debug_node_spec.ts @@ -138,7 +138,12 @@ class LocalsComp { template: ` Bank Name: {{bank}} Account Id: {{id}} - ` + `, + host: { + 'class': 'static-class', + '[class.absent-class]': 'false', + '[class.present-class]': 'true', + }, }) class BankAccount { // TODO(issue/24571): remove '!'. @@ -185,6 +190,7 @@ class TestApp { ParentComp, TestApp, UsingFor, + BankAccount, ], providers: [Logger], schemas: [NO_ERRORS_SCHEMA], @@ -276,6 +282,17 @@ class TestApp { expect(bankElem.classes['open']).toBe(false); }); + it('should get element classes from host bindings', () => { + fixture = TestBed.createComponent(TestApp); + fixture.detectChanges(); + const debugElement = fixture.debugElement.children[0]; + + expect(debugElement.classes['present-class']) + .toBe(true, 'Expected bound host CSS class "present-class" to be present'); + expect(debugElement.classes['absent-class']) + .toBe(false, 'Expected bound host CSS class "absent-class" to be absent'); + }); + it('should list element styles', () => { fixture = TestBed.createComponent(TestApp); fixture.detectChanges(); diff --git a/packages/core/test/di/r3_injector_spec.ts b/packages/core/test/di/r3_injector_spec.ts index df1311a75c..cf7328801d 100644 --- a/packages/core/test/di/r3_injector_spec.ts +++ b/packages/core/test/di/r3_injector_spec.ts @@ -6,11 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {defineInjectable, defineInjector} from '../../src/di/defs'; -import {InjectionToken} from '../../src/di/injection_token'; -import {INJECTOR, Injector} from '../../src/di/injector'; -import {inject} from '../../src/di/injector_compatibility'; -import {R3Injector, createInjector} from '../../src/di/r3_injector'; +import {INJECTOR, InjectFlags, InjectionToken, Injector, Optional, defineInjectable, defineInjector, inject} from '@angular/core'; +import {R3Injector, createInjector} from '@angular/core/src/di/r3_injector'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('InjectorDef-based createInjector()', () => { class CircularA { @@ -34,6 +32,13 @@ describe('InjectorDef-based createInjector()', () => { }); } + class OptionalService { + static ngInjectableDef = defineInjectable({ + providedIn: null, + factory: () => new OptionalService(), + }); + } + class StaticService { constructor(readonly dep: Service) {} } @@ -56,6 +61,24 @@ describe('InjectorDef-based createInjector()', () => { }); } + class ServiceWithOptionalDep { + constructor(@Optional() readonly service: OptionalService|null) {} + + static ngInjectableDef = defineInjectable({ + providedIn: null, + factory: () => new ServiceWithOptionalDep(inject(OptionalService, InjectFlags.Optional)), + }); + } + + class ServiceWithMissingDep { + constructor(readonly service: Service) {} + + static ngInjectableDef = defineInjectable({ + providedIn: null, + factory: () => new ServiceWithMissingDep(inject(Service)), + }); + } + class ServiceWithMultiDep { constructor(readonly locale: string[]) {} @@ -135,6 +158,7 @@ describe('InjectorDef-based createInjector()', () => { imports: [IntermediateModule], providers: [ ServiceWithDep, + ServiceWithOptionalDep, ServiceWithMultiDep, {provide: LOCALE, multi: true, useValue: 'en'}, {provide: LOCALE, multi: true, useValue: 'es'}, @@ -158,6 +182,14 @@ describe('InjectorDef-based createInjector()', () => { }); } + class ModuleWithMissingDep { + static ngInjectorDef = defineInjector({ + factory: () => new ModuleWithMissingDep(), + imports: undefined, + providers: [ServiceWithMissingDep], + }); + } + class NotAModule {} class ImportsNotAModule { @@ -198,12 +230,41 @@ describe('InjectorDef-based createInjector()', () => { it('returns the default value if a provider isn\'t present', () => { expect(injector.get(ServiceTwo, null)).toBeNull(); }); + it('should throw when no provider defined', () => { + expect(() => injector.get(ServiceTwo)) + .toThrowError( + `R3InjectorError(Module)[ServiceTwo]: \n` + + ` NullInjectorError: No provider for ServiceTwo!`); + }); + + it('should throw without the module name when no module', () => { + const injector = createInjector([ServiceTwo]); + expect(() => injector.get(ServiceTwo)) + .toThrowError( + `R3InjectorError[ServiceTwo]: \n` + + ` NullInjectorError: No provider for ServiceTwo!`); + }); + + it('should throw with the full path when no provider', () => { + const injector = createInjector(ModuleWithMissingDep); + expect(() => injector.get(ServiceWithMissingDep)) + .toThrowError( + `R3InjectorError(ModuleWithMissingDep)[ServiceWithMissingDep -> Service]: \n` + + ` NullInjectorError: No provider for Service!`); + }); + it('injects a service with dependencies', () => { const instance = injector.get(ServiceWithDep); expect(instance instanceof ServiceWithDep); expect(instance.service).toBe(injector.get(Service)); }); + it('injects a service with optional dependencies', () => { + const instance = injector.get(ServiceWithOptionalDep); + expect(instance instanceof ServiceWithOptionalDep); + expect(instance.service).toBe(null); + }); + it('injects a service with dependencies on multi-providers', () => { const instance = injector.get(ServiceWithMultiDep); expect(instance instanceof ServiceWithMultiDep); diff --git a/packages/core/test/di/reflective_injector_spec.ts b/packages/core/test/di/reflective_injector_spec.ts index 28bfc0aca7..139f8d1eab 100644 --- a/packages/core/test/di/reflective_injector_spec.ts +++ b/packages/core/test/di/reflective_injector_spec.ts @@ -11,7 +11,7 @@ import {ReflectiveInjector_} from '@angular/core/src/di/reflective_injector'; import {ResolvedReflectiveProvider_} from '@angular/core/src/di/reflective_provider'; import {getOriginalError} from '@angular/core/src/errors'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {stringify} from '../../src/util'; +import {stringify} from '../../src/util/stringify'; class Engine {} diff --git a/packages/core/test/di/static_injector_spec.ts b/packages/core/test/di/static_injector_spec.ts index c00c8fa97c..778cc96ecf 100644 --- a/packages/core/test/di/static_injector_spec.ts +++ b/packages/core/test/di/static_injector_spec.ts @@ -6,11 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject, InjectionToken, Injector, Optional, ReflectiveKey, Self, SkipSelf, forwardRef} from '@angular/core'; -import {getOriginalError} from '@angular/core/src/errors'; +import {Inject, InjectionToken, Injector, Optional, Self, SkipSelf, forwardRef} from '@angular/core'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {stringify} from '../../src/util'; +import {stringify} from '../../src/util/stringify'; class Engine { static PROVIDER = {provide: Engine, useClass: Engine, deps: []}; diff --git a/packages/core/test/error_handler_spec.ts b/packages/core/test/error_handler_spec.ts index 69d4249544..e52fd36eba 100644 --- a/packages/core/test/error_handler_spec.ts +++ b/packages/core/test/error_handler_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {ERROR_DEBUG_CONTEXT, ERROR_LOGGER, ERROR_TYPE} from '@angular/core/src/errors'; +import {ERROR_DEBUG_CONTEXT, ERROR_LOGGER, ERROR_TYPE, wrappedError} from '@angular/core/src/util/errors'; -import {ErrorHandler, wrappedError} from '../src/error_handler'; +import {ErrorHandler} from '../src/error_handler'; class MockConsole { res: any[][] = []; diff --git a/packages/core/test/fake_async_spec.ts b/packages/core/test/fake_async_spec.ts index c98498fd22..ffbaeb82a6 100644 --- a/packages/core/test/fake_async_spec.ts +++ b/packages/core/test/fake_async_spec.ts @@ -8,11 +8,8 @@ import {discardPeriodicTasks, fakeAsync, flush, flushMicrotasks, tick} from '@angular/core/testing'; import {Log, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal'; +import {EventManager} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy} from '@angular/private/testing'; - -import {Parser} from '../../compiler/src/expression_parser/parser'; - const resolvedPromise = Promise.resolve(null); const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec']; @@ -33,11 +30,10 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' })('foo', 'bar'); }); - fixmeIvy('FW-806: Ivy\'s TestBed implementation doesn\'t inject compiler-related tokens') - .it('should work with inject()', - fakeAsync(inject([Parser], (parser: any /** TODO #9100 */) => { - expect(parser).toBeAnInstanceOf(Parser); - }))); + it('should work with inject()', + fakeAsync(inject([EventManager], (eventManager: EventManager) => { + expect(eventManager).toBeAnInstanceOf(EventManager); + }))); it('should throw on nested calls', () => { expect(() => { diff --git a/packages/core/test/forward_ref_integration_spec.ts b/packages/core/test/forward_ref_integration_spec.ts index 1389642298..e83651cb06 100644 --- a/packages/core/test/forward_ref_integration_spec.ts +++ b/packages/core/test/forward_ref_integration_spec.ts @@ -10,19 +10,16 @@ import {CommonModule} from '@angular/common'; import {Component, ContentChildren, Directive, Inject, NO_ERRORS_SCHEMA, NgModule, QueryList, asNativeElements, forwardRef} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy} from '@angular/private/testing'; describe('forwardRef integration', function() { beforeEach(() => { TestBed.configureTestingModule({imports: [Module], declarations: [App]}); }); - fixmeIvy('FW-756: Pipes and directives from imported modules are not taken into account') - .it('should instantiate components which are declared using forwardRef', () => { - const a = - TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]}).createComponent(App); - a.detectChanges(); - expect(asNativeElements(a.debugElement.children)).toHaveText('frame(lock)'); - expect(TestBed.get(ModuleFrame)).toBeDefined(); - }); + it('should instantiate components which are declared using forwardRef', () => { + const a = TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]}).createComponent(App); + a.detectChanges(); + expect(asNativeElements(a.debugElement.children)).toHaveText('frame(lock)'); + expect(TestBed.get(ModuleFrame)).toBeDefined(); + }); }); @NgModule({ @@ -43,8 +40,8 @@ class App { } @Component({ - selector: 'lock', - template: `{{frame.name}}({{lock.name}})`, + selector: 'door', + template: `{{frame.name}}({{lock.name}})`, }) class Door { // TODO(issue/24571): remove '!'. diff --git a/packages/core/test/i18n_integration_spec.ts b/packages/core/test/i18n_integration_spec.ts new file mode 100644 index 0000000000..06f51e631d --- /dev/null +++ b/packages/core/test/i18n_integration_spec.ts @@ -0,0 +1,584 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {onlyInIvy, polyfillGoogGetMsg} from '@angular/private/testing'; + +@Directive({ + selector: '[tplRef]', +}) +class DirectiveWithTplRef { + constructor(public vcRef: ViewContainerRef, public tplRef: TemplateRef<{}>) {} + ngOnInit() { this.vcRef.createEmbeddedView(this.tplRef, {}); } +} + +@Component({selector: 'my-comp', template: ''}) +class MyComp { + name = 'John'; + items = ['1', '2', '3']; + visible = true; + age = 20; + count = 2; + otherLabel = 'other label'; +} + +const TRANSLATIONS: any = { + 'one': 'un', + 'two': 'deux', + 'more than two': 'plus que deux', + 'ten': 'dix', + 'twenty': 'vingt', + 'other': 'autres', + 'Hello': 'Bonjour', + 'Hello {$interpolation}': 'Bonjour {$interpolation}', + 'Bye': 'Au revoir', + 'Item {$interpolation}': 'Article {$interpolation}', + '\'Single quotes\' and "Double quotes"': '\'Guillemets simples\' et "Guillemets doubles"', + 'My logo': 'Mon logo', + '{$startTagSpan}My logo{$tagImg}{$closeTagSpan}': + '{$startTagSpan}Mon logo{$tagImg}{$closeTagSpan}', + '{$startTagNgTemplate} Hello {$closeTagNgTemplate}{$startTagNgContainer} Bye {$closeTagNgContainer}': + '{$startTagNgTemplate} Bonjour {$closeTagNgTemplate}{$startTagNgContainer} Au revoir {$closeTagNgContainer}', + '{$startTagNgTemplate}{$startTagSpan}Hello{$closeTagSpan}{$closeTagNgTemplate}{$startTagNgContainer}{$startTagSpan}Hello{$closeTagSpan}{$closeTagNgContainer}': + '{$startTagNgTemplate}{$startTagSpan}Bonjour{$closeTagSpan}{$closeTagNgTemplate}{$startTagNgContainer}{$startTagSpan}Bonjour{$closeTagSpan}{$closeTagNgContainer}', + '{$startTagNgTemplate}{$startTagSpan}Hello{$closeTagSpan}{$closeTagNgTemplate}{$startTagNgContainer}{$startTagSpan_1}Hello{$closeTagSpan}{$closeTagNgContainer}': + '{$startTagNgTemplate}{$startTagSpan}Bonjour{$closeTagSpan}{$closeTagNgTemplate}{$startTagNgContainer}{$startTagSpan_1}Bonjour{$closeTagSpan}{$closeTagNgContainer}', + '{$startTagSpan} Hello - 1 {$closeTagSpan}{$startTagSpan_1} Hello - 2 {$startTagSpan_1} Hello - 3 {$startTagSpan_1} Hello - 4 {$closeTagSpan}{$closeTagSpan}{$closeTagSpan}{$startTagSpan} Hello - 5 {$closeTagSpan}': + '{$startTagSpan} Bonjour - 1 {$closeTagSpan}{$startTagSpan_1} Bonjour - 2 {$startTagSpan_1} Bonjour - 3 {$startTagSpan_1} Bonjour - 4 {$closeTagSpan}{$closeTagSpan}{$closeTagSpan}{$startTagSpan} Bonjour - 5 {$closeTagSpan}', + '{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}': + '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autres}}', + '{VAR_SELECT, select, 1 {one} 2 {two} other {more than two}}': + '{VAR_SELECT, select, 1 {un} 2 {deux} other {plus que deux}}', + '{VAR_SELECT, select, 10 {10 - {$startBoldText}ten{$closeBoldText}} 20 {20 - {$startItalicText}twenty{$closeItalicText}} other {{$startTagDiv}{$startUnderlinedText}other{$closeUnderlinedText}{$closeTagDiv}}}': + '{VAR_SELECT, select, 10 {10 - {$startBoldText}dix{$closeBoldText}} 20 {20 - {$startItalicText}vingt{$closeItalicText}} other {{$startTagDiv}{$startUnderlinedText}autres{$closeUnderlinedText}{$closeTagDiv}}}', + '{VAR_SELECT_2, select, 10 {ten - {VAR_SELECT, select, 1 {one} 2 {two} other {more than two}}} 20 {twenty - {VAR_SELECT_1, select, 1 {one} 2 {two} other {more than two}}} other {other}}': + '{VAR_SELECT_2, select, 10 {dix - {VAR_SELECT, select, 1 {un} 2 {deux} other {plus que deux}}} 20 {vingt - {VAR_SELECT_1, select, 1 {un} 2 {deux} other {plus que deux}}} other {autres}}', + '{$startTagNgTemplate}{$startTagDiv_1}{$startTagDiv}{$startTagSpan}Content{$closeTagSpan}{$closeTagDiv}{$closeTagDiv}{$closeTagNgTemplate}': + '{$startTagNgTemplate}Contenu{$closeTagNgTemplate}' +}; + +const getFixtureWithOverrides = (overrides = {}) => { + TestBed.overrideComponent(MyComp, {set: overrides}); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + return fixture; +}; + +onlyInIvy('Ivy i18n logic').describe('i18n', function() { + + beforeEach(() => { + polyfillGoogGetMsg(TRANSLATIONS); + TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithTplRef]}); + }); + + describe('attributes', () => { + it('should translate static attributes', () => { + const title = 'Hello'; + const template = `
    `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element.title).toBe('Bonjour'); + }); + + it('should support interpolation', () => { + const title = 'Hello {{ name }}'; + const template = `
    `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element.title).toBe('Bonjour John'); + }); + + it('should support interpolation with custom interpolation config', () => { + const title = 'Hello {% name %}'; + const template = `
    `; + const interpolation = ['{%', '%}'] as[string, string]; + const fixture = getFixtureWithOverrides({template, interpolation}); + + const element = fixture.nativeElement.firstChild; + expect(element.title).toBe('Bonjour John'); + }); + + it('should correctly bind to context in nested template', () => { + const title = 'Item {{ id }}'; + const template = ` +
    +
    +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + for (let i = 0; i < element.children.length; i++) { + const child = element.children[i]; + expect((child as any).innerHTML).toBe(`
    `); + } + }); + + it('should work correctly when placed on i18n root node', () => { + const title = 'Hello {{ name }}'; + const content = 'Hello'; + const template = ` +
    ${content}
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element.title).toBe('Bonjour John'); + expect(element).toHaveText('Bonjour'); + }); + + it('should add i18n attributes on self-closing tags', () => { + const title = 'Hello {{ name }}'; + const template = ``; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element.title).toBe('Bonjour John'); + }); + }); + + describe('nested nodes', () => { + it('should handle static content', () => { + const content = 'Hello'; + const template = `
    ${content}
    `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('Bonjour'); + }); + + it('should support interpolation', () => { + const content = 'Hello {{ name }}'; + const template = `
    ${content}
    `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('Bonjour John'); + }); + + it('should support interpolation with custom interpolation config', () => { + const content = 'Hello {% name %}'; + const template = `
    ${content}
    `; + const interpolation = ['{%', '%}'] as[string, string]; + const fixture = getFixtureWithOverrides({template, interpolation}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('Bonjour John'); + }); + + it('should properly escape quotes in content', () => { + const content = `'Single quotes' and "Double quotes"`; + const template = `
    ${content}
    `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('\'Guillemets simples\' et "Guillemets doubles"'); + }); + + it('should correctly bind to context in nested template', () => { + const content = 'Item {{ id }}'; + const template = ` +
    +
    ${content}
    +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + for (let i = 0; i < element.children.length; i++) { + const child = element.children[i]; + expect(child).toHaveText(`Article ${i + 1}`); + } + }); + + it('should handle i18n attributes inside i18n section', () => { + const title = 'Hello {{ name }}'; + const template = ` +
    +
    +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + const content = `
    `; + expect(element.innerHTML).toBe(content); + }); + + it('should handle i18n blocks in nested templates', () => { + const content = 'Hello {{ name }}'; + const template = ` +
    +
    ${content}
    +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element.children[0]).toHaveText('Bonjour John'); + }); + + it('should ignore i18n attributes on self-closing tags', () => { + const template = ''; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element.innerHTML).toBe(template.replace(' i18n', '')); + }); + + it('should handle i18n attribute with directives', () => { + const content = 'Hello {{ name }}'; + const template = ` +
    ${content}
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('Bonjour John'); + }); + }); + + describe('ng-container and ng-template support', () => { + it('should handle single translation message within ng-container', () => { + const content = 'Hello {{ name }}'; + const template = ` + ${content} + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('Bonjour John'); + }); + + it('should handle single translation message within ng-template', () => { + const content = 'Hello {{ name }}'; + const template = ` + ${content} + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element).toHaveText('Bonjour John'); + }); + + it('should be able to act as child elements inside i18n block (plain text content)', () => { + const hello = 'Hello'; + const bye = 'Bye'; + const template = ` +
    + + ${hello} + + + ${bye} + +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element.textContent.replace(/\s+/g, ' ').trim()).toBe('Bonjour Au revoir'); + }); + + it('should be able to act as child elements inside i18n block (text + tags)', () => { + const content = 'Hello'; + const template = ` +
    + + ${content} + + + ${content} + +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + const spans = element.getElementsByTagName('span'); + for (let i = 0; i < spans.length; i++) { + expect(spans[i]).toHaveText('Bonjour'); + } + }); + + it('should be able to handle deep nested levels with templates', () => { + const content = 'Hello'; + const template = ` +
    + + ${content} - 1 + + + ${content} - 2 + + ${content} - 3 + + ${content} - 4 + + + + + ${content} - 5 + +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + const spans = element.getElementsByTagName('span'); + for (let i = 0; i < spans.length; i++) { + expect(spans[i].innerHTML).toContain(`Bonjour - ${i + 1}`); + } + }); + + it('should handle self-closing tags as content', () => { + const label = 'My logo'; + const content = `${label}`; + const template = ` + + ${content} + + + ${content} + + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + const spans = element.getElementsByTagName('span'); + for (let i = 0; i < spans.length; i++) { + const child = spans[i]; + expect(child).toHaveText('Mon logo'); + } + }); + }); + + describe('ICU logic', () => { + it('should handle single ICUs', () => { + const template = ` +
    {age, select, 10 {ten} 20 {twenty} other {other}}
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element).toHaveText('vingt'); + }); + + it('should support ICU-only templates', () => { + const template = ` + {age, select, 10 {ten} 20 {twenty} other {other}} + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element).toHaveText('vingt'); + }); + + it('should support ICUs generated outside of i18n blocks', () => { + const template = ` +
    {age, select, 10 {ten} 20 {twenty} other {other}}
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element).toHaveText('vingt'); + }); + + it('should support interpolation', () => { + const template = ` +
    {age, select, 10 {ten} other {{{ otherLabel }}}}
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element).toHaveText(fixture.componentInstance.otherLabel); + }); + + it('should support interpolation with custom interpolation config', () => { + const template = ` +
    {age, select, 10 {ten} other {{% otherLabel %}}}
    + `; + const interpolation = ['{%', '%}'] as[string, string]; + const fixture = getFixtureWithOverrides({template, interpolation}); + + const element = fixture.nativeElement; + expect(element).toHaveText(fixture.componentInstance.otherLabel); + }); + + it('should handle ICUs with HTML tags inside', () => { + const template = ` +
    + {age, select, 10 {10 - ten} 20 {20 - twenty} other {
    other
    }} +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + const italicTags = element.getElementsByTagName('i'); + expect(italicTags.length).toBe(1); + expect(italicTags[0].innerHTML).toBe('vingt'); + }); + + it('should handle multiple ICUs in one block', () => { + const template = ` +
    + {age, select, 10 {ten} 20 {twenty} other {other}} - + {count, select, 1 {one} 2 {two} other {more than two}} +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('vingt - deux'); + }); + + it('should handle multiple ICUs in one i18n block wrapped in HTML elements', () => { + const template = ` +
    + + {age, select, 10 {ten} 20 {twenty} other {other}} + + + {count, select, 1 {one} 2 {two} other {more than two}} + +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + const spans = element.getElementsByTagName('span'); + expect(spans.length).toBe(2); + expect(spans[0]).toHaveText('vingt'); + expect(spans[1]).toHaveText('deux'); + }); + + it('should handle ICUs inside a template in i18n block', () => { + const template = ` +
    + + {age, select, 10 {ten} 20 {twenty} other {other}} + +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + const spans = element.getElementsByTagName('span'); + expect(spans.length).toBe(1); + expect(spans[0]).toHaveText('vingt'); + }); + + it('should handle nested icus', () => { + const template = ` +
    + {age, select, + 10 {ten - {count, select, 1 {one} 2 {two} other {more than two}}} + 20 {twenty - {count, select, 1 {one} 2 {two} other {more than two}}} + other {other}} +
    + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement.firstChild; + expect(element).toHaveText('vingt - deux'); + }); + + it('should handle ICUs inside ', () => { + const template = ` + + {age, select, 10 {ten} 20 {twenty} other {other}} + + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element).toHaveText('vingt'); + }); + + it('should handle ICUs inside ', () => { + const template = ` + + {age, select, 10 {ten} 20 {twenty} other {other}} + + `; + const fixture = getFixtureWithOverrides({template}); + + const element = fixture.nativeElement; + expect(element).toHaveText('vingt'); + }); + }); + + describe('queries', () => { + function toHtml(element: Element): string { + return element.innerHTML.replace(/\sng-reflect-\S*="[^"]*"/g, '') + .replace(//g, ''); + } + + it('detached nodes should still be part of query', () => { + const template = ` + + +
    +
    + Content +
    +
    +
    +
    + `; + + @Directive({selector: '[text]', inputs: ['text'], exportAs: 'textDir'}) + class TextDirective { + // TODO(issue/24571): remove '!'. + text !: string; + constructor() {} + } + + @Component({selector: 'div-query', template: ''}) + class DivQuery { + // TODO(issue/24571): remove '!'. + @ContentChild(TemplateRef) template !: TemplateRef; + + // TODO(issue/24571): remove '!'. + @ViewChild('vc', {read: ViewContainerRef}) + vc !: ViewContainerRef; + + // TODO(issue/24571): remove '!'. + @ContentChildren(TextDirective, {descendants: true}) + query !: QueryList; + + create() { this.vc.createEmbeddedView(this.template); } + + destroy() { this.vc.clear(); } + } + + TestBed.configureTestingModule({declarations: [TextDirective, DivQuery]}); + const fixture = getFixtureWithOverrides({template}); + const q = fixture.debugElement.children[0].references.q; + expect(q.query.length).toEqual(0); + + // Create embedded view + q.create(); + fixture.detectChanges(); + expect(q.query.length).toEqual(1); + expect(toHtml(fixture.nativeElement)) + .toEqual(`Contenu`); + + // Disable ng-if + fixture.componentInstance.visible = false; + fixture.detectChanges(); + expect(q.query.length).toEqual(0); + expect(toHtml(fixture.nativeElement)) + .toEqual(`Contenu`); + }); + }); +}); diff --git a/packages/core/test/linker/change_detection_integration_spec.ts b/packages/core/test/linker/change_detection_integration_spec.ts index 3f3d5f5b20..7d1322f772 100644 --- a/packages/core/test/linker/change_detection_integration_spec.ts +++ b/packages/core/test/linker/change_detection_integration_spec.ts @@ -6,28 +6,26 @@ * found in the LICENSE file at https://angular.io/license */ -import {DomElementSchemaRegistry, ElementSchemaRegistry, ResourceLoader, UrlResolver} from '@angular/compiler'; -import {MockResourceLoader, MockSchemaRegistry} from '@angular/compiler/testing'; +import {ResourceLoader, UrlResolver} from '@angular/compiler'; +import {MockResourceLoader} from '@angular/compiler/testing'; import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, DebugElement, Directive, DoCheck, EventEmitter, HostBinding, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, Provider, RenderComponentType, Renderer, RendererFactory2, RootRenderer, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core'; import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, ivyEnabled, modifiedInIvy} from '@angular/private/testing'; +import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; export function createUrlResolverWithoutPackagePrefix(): UrlResolver { return new UrlResolver(); } const TEST_COMPILER_PROVIDERS: Provider[] = [ - {provide: ElementSchemaRegistry, useValue: new MockSchemaRegistry({}, {}, {}, [], [])}, {provide: ResourceLoader, useClass: MockResourceLoader, deps: []}, {provide: UrlResolver, useFactory: createUrlResolverWithoutPackagePrefix, deps: []} ]; (function() { - let elSchema: MockSchemaRegistry; let renderLog: RenderLog; let directiveLog: DirectiveLog; @@ -43,10 +41,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ } function initHelpers(): void { - elSchema = TestBed.get(ElementSchemaRegistry); renderLog = TestBed.get(RenderLog); directiveLog = TestBed.get(DirectiveLog); - elSchema.existingProperties['someProp'] = true; patchLoggingRenderer2(TestBed.get(RendererFactory2), renderLog); } @@ -67,7 +63,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ function _bindSimpleValue(expression: any, compType: Type): ComponentFixture; function _bindSimpleValue( expression: any, compType: Type = TestComponent): ComponentFixture { - return _bindSimpleProp(`[someProp]='${expression}'`, compType); + return _bindSimpleProp(`[id]='${expression}'`, compType); } function _bindAndCheckSimpleValue( @@ -117,145 +113,125 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ describe('expressions', () => { it('should support literals', - fakeAsync(() => { expect(_bindAndCheckSimpleValue(10)).toEqual(['someProp=10']); })); + fakeAsync(() => { expect(_bindAndCheckSimpleValue(10)).toEqual(['id=10']); })); it('should strip quotes from literals', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('"str"')).toEqual(['someProp=str']); })); + fakeAsync(() => { expect(_bindAndCheckSimpleValue('"str"')).toEqual(['id=str']); })); - it('should support newlines in literals', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['someProp=a\n\nb']); - })); + it('should support newlines in literals', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['id=a\n\nb']); })); it('should support + operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['someProp=12']); })); + fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['id=12']); })); it('should support - operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['someProp=8']); })); + fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['id=8']); })); it('should support * operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['someProp=20']); })); + fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['id=20']); })); it('should support / operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('10 / 2')).toEqual([`someProp=${5.0}`]); + expect(_bindAndCheckSimpleValue('10 / 2')).toEqual([`id=${5.0}`]); })); // dart exp=5.0, js exp=5 it('should support % operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['someProp=1']); })); + fakeAsync(() => { expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['id=1']); })); - it('should support == operations on identical', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['someProp=true']); - })); + it('should support == operations on identical', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['id=true']); })); - it('should support != operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['someProp=false']); - })); + it('should support != operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['id=false']); })); - it('should support == operations on coerceible', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`someProp=true`]); - })); + it('should support == operations on coerceible', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`id=true`]); })); - it('should support === operations on identical', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['someProp=true']); - })); + it('should support === operations on identical', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['id=true']); })); - it('should support !== operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['someProp=false']); - })); + it('should support !== operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['id=false']); })); it('should support === operations on coerceible', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 === true')).toEqual(['someProp=false']); + expect(_bindAndCheckSimpleValue('1 === true')).toEqual(['id=false']); })); - it('should support true < operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['someProp=true']); - })); + it('should support true < operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['id=true']); })); - it('should support false < operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['someProp=false']); - })); + it('should support false < operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['id=false']); })); - it('should support false > operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['someProp=false']); - })); + it('should support false > operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['id=false']); })); - it('should support true > operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['someProp=true']); - })); + it('should support true > operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['id=true']); })); - it('should support true <= operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['someProp=true']); - })); + it('should support true <= operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['id=true']); })); - it('should support equal <= operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['someProp=true']); - })); + it('should support equal <= operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['id=true']); })); - it('should support false <= operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['someProp=false']); - })); + it('should support false <= operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['id=false']); })); - it('should support true >= operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['someProp=true']); - })); + it('should support true >= operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['id=true']); })); - it('should support equal >= operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['someProp=true']); - })); + it('should support equal >= operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['id=true']); })); - it('should support false >= operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['someProp=false']); - })); + it('should support false >= operations', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['id=false']); })); it('should support true && operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('true && true')).toEqual(['someProp=true']); + expect(_bindAndCheckSimpleValue('true && true')).toEqual(['id=true']); })); it('should support false && operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('true && false')).toEqual(['someProp=false']); + expect(_bindAndCheckSimpleValue('true && false')).toEqual(['id=false']); })); it('should support true || operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('true || false')).toEqual(['someProp=true']); + expect(_bindAndCheckSimpleValue('true || false')).toEqual(['id=true']); })); it('should support false || operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('false || false')).toEqual(['someProp=false']); + expect(_bindAndCheckSimpleValue('false || false')).toEqual(['id=false']); })); - it('should support negate', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('!true')).toEqual(['someProp=false']); - })); + it('should support negate', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('!true')).toEqual(['id=false']); })); - it('should support double negate', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('!!true')).toEqual(['someProp=true']); - })); + it('should support double negate', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('!!true')).toEqual(['id=true']); })); - it('should support true conditionals', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['someProp=1']); - })); + it('should support true conditionals', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['id=1']); })); - it('should support false conditionals', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['someProp=2']); - })); + it('should support false conditionals', + fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['id=2']); })); it('should support keyed access to a list item', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('["foo", "bar"][0]')).toEqual(['someProp=foo']); + expect(_bindAndCheckSimpleValue('["foo", "bar"][0]')).toEqual(['id=foo']); })); it('should support keyed access to a map item', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('{"foo": "bar"}["foo"]')).toEqual(['someProp=bar']); + expect(_bindAndCheckSimpleValue('{"foo": "bar"}["foo"]')).toEqual(['id=bar']); })); it('should report all changes on the first run including uninitialized values', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('value', Uninitialized)).toEqual(['someProp=null']); + expect(_bindAndCheckSimpleValue('value', Uninitialized)).toEqual(['id=null']); })); it('should report all changes on the first run including null values', fakeAsync(() => { const ctx = _bindSimpleValue('a', TestData); ctx.componentInstance.a = null; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=null']); + expect(renderLog.log).toEqual(['id=null']); })); it('should support simple chained property access', fakeAsync(() => { @@ -263,7 +239,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ ctx.componentInstance.name = 'Victor'; ctx.componentInstance.address = new Address('Grenoble'); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=Grenoble']); + expect(renderLog.log).toEqual(['id=Grenoble']); })); describe('safe navigation operator', () => { @@ -271,54 +247,54 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ const ctx = _bindSimpleValue('address?.city', Person); ctx.componentInstance.address = null !; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=null']); + expect(renderLog.log).toEqual(['id=null']); })); it('should support calling methods on nulls', fakeAsync(() => { const ctx = _bindSimpleValue('address?.toString()', Person); ctx.componentInstance.address = null !; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=null']); + expect(renderLog.log).toEqual(['id=null']); })); it('should support reading properties on non nulls', fakeAsync(() => { const ctx = _bindSimpleValue('address?.city', Person); ctx.componentInstance.address = new Address('MTV'); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=MTV']); + expect(renderLog.log).toEqual(['id=MTV']); })); it('should support calling methods on non nulls', fakeAsync(() => { const ctx = _bindSimpleValue('address?.toString()', Person); ctx.componentInstance.address = new Address('MTV'); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=MTV']); + expect(renderLog.log).toEqual(['id=MTV']); })); it('should support short-circuting safe navigation', fakeAsync(() => { const ctx = _bindSimpleValue('value?.address.city', PersonHolder); ctx.componentInstance.value = null !; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=null']); + expect(renderLog.log).toEqual(['id=null']); })); it('should support nested short-circuting safe navigation', fakeAsync(() => { const ctx = _bindSimpleValue('value.value?.address.city', PersonHolderHolder); ctx.componentInstance.value = new PersonHolder(); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=null']); + expect(renderLog.log).toEqual(['id=null']); })); it('should support chained short-circuting safe navigation', fakeAsync(() => { const ctx = _bindSimpleValue('value?.value?.address.city', PersonHolderHolder); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=null']); + expect(renderLog.log).toEqual(['id=null']); })); it('should support short-circuting array index operations', fakeAsync(() => { const ctx = _bindSimpleValue('value?.phones[0]', PersonHolder); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=null']); + expect(renderLog.log).toEqual(['id=null']); })); it('should still throw if right-side would throw', fakeAsync(() => { @@ -335,21 +311,21 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ it('should support method calls', fakeAsync(() => { const ctx = _bindSimpleValue('sayHi("Jim")', Person); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=Hi, Jim']); + expect(renderLog.log).toEqual(['id=Hi, Jim']); })); it('should support function calls', fakeAsync(() => { const ctx = _bindSimpleValue('a()(99)', TestData); ctx.componentInstance.a = () => (a: any) => a; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=99']); + expect(renderLog.log).toEqual(['id=99']); })); it('should support chained method calls', fakeAsync(() => { const ctx = _bindSimpleValue('address.toString()', Person); ctx.componentInstance.address = new Address('MTV'); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=MTV']); + expect(renderLog.log).toEqual(['id=MTV']); })); it('should support NaN', fakeAsync(() => { @@ -357,7 +333,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ ctx.componentInstance.age = NaN; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=NaN']); + expect(renderLog.log).toEqual(['id=NaN']); renderLog.clear(); ctx.detectChanges(false); @@ -369,7 +345,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ ctx.componentInstance.name = 'misko'; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=misko']); + expect(renderLog.log).toEqual(['id=misko']); renderLog.clear(); ctx.detectChanges(false); @@ -378,7 +354,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ ctx.componentInstance.name = 'Misko'; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=Misko']); + expect(renderLog.log).toEqual(['id=Misko']); })); it('should support literal array made of literals', fakeAsync(() => { @@ -444,33 +420,32 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ })); - fixmeIvy('FW-814: Bindings with an empty value should be ignored in the compiler') - .it('should ignore empty bindings', fakeAsync(() => { - const ctx = _bindSimpleProp('[someProp]', TestData); - ctx.componentInstance.a = 'value'; - ctx.detectChanges(false); - - expect(renderLog.log).toEqual([]); - })); - - it('should support interpolation', fakeAsync(() => { - const ctx = _bindSimpleProp('someProp="B{{a}}A"', TestData); + it('should ignore empty bindings', fakeAsync(() => { + const ctx = _bindSimpleProp('[id]', TestData); ctx.componentInstance.a = 'value'; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=BvalueA']); + expect(renderLog.log).toEqual([]); + })); + + it('should support interpolation', fakeAsync(() => { + const ctx = _bindSimpleProp('id="B{{a}}A"', TestData); + ctx.componentInstance.a = 'value'; + ctx.detectChanges(false); + + expect(renderLog.log).toEqual(['id=BvalueA']); })); it('should output empty strings for null values in interpolation', fakeAsync(() => { - const ctx = _bindSimpleProp('someProp="B{{a}}A"', TestData); + const ctx = _bindSimpleProp('id="B{{a}}A"', TestData); ctx.componentInstance.a = null; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=BA']); + expect(renderLog.log).toEqual(['id=BA']); })); it('should escape values in literals that indicate interpolation', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('"$"')).toEqual(['someProp=$']); })); + fakeAsync(() => { expect(_bindAndCheckSimpleValue('"$"')).toEqual(['id=$']); })); it('should read locals', fakeAsync(() => { const ctx = createCompFixture( @@ -516,7 +491,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=Megatron']); + expect(renderLog.log).toEqual(['id=Megatron']); renderLog.clear(); ctx.detectChanges(false); @@ -529,36 +504,35 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=Megatron']); + expect(renderLog.log).toEqual(['id=Megatron']); renderLog.clear(); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['someProp=Megatron']); + expect(renderLog.log).toEqual(['id=Megatron']); })); - fixmeIvy('FW-820: Pipes returning WrappedValue corrupt unrelated bindings ') - .it('should record unwrapped values via ngOnChanges', fakeAsync(() => { - const ctx = createCompFixture( - '
    '); - const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0]; - ctx.detectChanges(false); - dir.changes = {}; - ctx.detectChanges(false); + it('should record unwrapped values via ngOnChanges', fakeAsync(() => { + const ctx = createCompFixture( + '
    '); + const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0]; + ctx.detectChanges(false); + dir.changes = {}; + ctx.detectChanges(false); - // Note: the binding for `b` did not change and has no ValueWrapper, - // and should therefore stay unchanged. - expect(dir.changes).toEqual({ - 'name': new SimpleChange('aName', 'aName', false), - 'b': new SimpleChange(2, 2, false) - }); + // Note: the binding for `a` did not change and has no ValueWrapper, + // and should therefore stay unchanged. + expect(dir.changes).toEqual({ + 'name': new SimpleChange('aName', 'aName', false), + 'b': new SimpleChange(2, 2, false) + }); - ctx.detectChanges(false); - expect(dir.changes).toEqual({ - 'name': new SimpleChange('aName', 'aName', false), - 'b': new SimpleChange(2, 2, false) - }); - })); + ctx.detectChanges(false); + expect(dir.changes).toEqual({ + 'name': new SimpleChange('aName', 'aName', false), + 'b': new SimpleChange(2, 2, false) + }); + })); it('should call pure pipes only if the arguments change', fakeAsync(() => { const ctx = _bindSimpleValue('name | countingPipe', Person); @@ -589,12 +563,12 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ })); - modifiedInIvy('FW-821: Pure pipes are instantiated differently in view engine and ivy') + modifiedInIvy('Pure pipes are instantiated differently in view engine and ivy') .it('should call pure pipes that are used multiple times only when the arguments change and share state between pipe instances', fakeAsync(() => { const ctx = createCompFixture( - `
    ` + - '
    ', + `
    ` + + '
    ', Person); ctx.componentInstance.name = 'a'; ctx.componentInstance.age = 10; @@ -620,8 +594,8 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ it('should call pure pipes that are used multiple times only when the arguments change', fakeAsync(() => { const ctx = createCompFixture( - `
    ` + - '
    ', + `
    ` + + '
    ', Person); ctx.componentInstance.name = 'a'; ctx.componentInstance.age = 10; @@ -733,7 +707,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ describe('reading directives', () => { it('should read directive properties', fakeAsync(() => { const ctx = createCompFixture( - '
    '); + '
    '); ctx.detectChanges(false); expect(renderLog.loggedValues).toEqual([42]); })); @@ -1023,33 +997,31 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); })); - fixmeIvy( - 'FW-830: Exception thrown in ngAfterViewInit triggers ngAfterViewInit re-execution') - .it('should not call ngAfterViewInit again if it throws', fakeAsync(() => { - const ctx = createCompFixture( - '
    '); + it('should not call ngAfterViewInit again if it throws', fakeAsync(() => { + const ctx = + createCompFixture('
    '); - let errored = false; - // First pass fails, but ngAfterViewInit should be called. - try { - ctx.detectChanges(false); - } catch (e) { - errored = true; - } - expect(errored).toBe(true); + let errored = false; + // First pass fails, but ngAfterViewInit should be called. + try { + ctx.detectChanges(false); + } catch (e) { + errored = true; + } + expect(errored).toBe(true); - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); - directiveLog.clear(); + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); + directiveLog.clear(); - // Second change detection also fails, but this time ngAfterViewInit should not be - // called. - try { - ctx.detectChanges(false); - } catch (e) { - throw new Error('Second detectChanges() should not have run detection.'); - } - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); - })); + // Second change detection also fails, but this time ngAfterViewInit should not be + // called. + try { + ctx.detectChanges(false); + } catch (e) { + throw new Error('Second detectChanges() should not have run detection.'); + } + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); + })); }); describe('ngAfterViewChecked', () => { @@ -1167,53 +1139,75 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ ]); })); - fixmeIvy('FW-848: ngOnDestroy hooks are not called on providers') - .it('should call ngOnDestroy on an injectable class', fakeAsync(() => { - TestBed.overrideDirective( - TestDirective, {set: {providers: [InjectableWithLifecycle]}}); + it('should call ngOnDestroy on an injectable class', fakeAsync(() => { + TestBed.overrideDirective( + TestDirective, {set: {providers: [InjectableWithLifecycle]}}); - const ctx = createCompFixture('
    ', TestComponent); + const ctx = createCompFixture('
    ', TestComponent); - ctx.debugElement.children[0].injector.get(InjectableWithLifecycle); - ctx.detectChanges(false); + ctx.debugElement.children[0].injector.get(InjectableWithLifecycle); + ctx.detectChanges(false); - ctx.destroy(); + ctx.destroy(); - // We don't care about the exact order in this test. - expect(directiveLog.filter(['ngOnDestroy']).sort()).toEqual([ - 'dir.ngOnDestroy', 'injectable.ngOnDestroy' - ]); - })); + // We don't care about the exact order in this test. + expect(directiveLog.filter(['ngOnDestroy']).sort()).toEqual([ + 'dir.ngOnDestroy', 'injectable.ngOnDestroy' + ]); + })); }); }); describe('enforce no new changes', () => { - fixmeIvy('FW-823: ComponentFixture.checkNoChanges doesn\'t throw under TestBed') - .it('should throw when a record gets changed after it has been checked', fakeAsync(() => { - @Directive({selector: '[changed]'}) - class ChangingDirective { - @Input() changed: any; - } + it('should throw when a record gets changed after it has been checked', fakeAsync(() => { + @Directive({selector: '[changed]'}) + class ChangingDirective { + @Input() changed: any; + } - TestBed.configureTestingModule({declarations: [ChangingDirective]}); + TestBed.configureTestingModule({declarations: [ChangingDirective]}); - const ctx = createCompFixture('
    ', TestData); + const ctx = createCompFixture('
    ', TestData); - ctx.componentInstance.b = 1; + ctx.componentInstance.b = 1; + const errMsgRegExp = ivyEnabled ? + /Previous value: 'undefined'\. Current value: '1'/g : + /Previous value: 'changed: undefined'\. Current value: 'changed: 1'/g; + expect(() => ctx.checkNoChanges()).toThrowError(errMsgRegExp); + })); - expect(() => ctx.checkNoChanges()) - .toThrowError( - /Previous value: 'changed: undefined'\. Current value: 'changed: 1'/g); - })); - fixmeIvy('FW-831: Views created in a cd hooks throw in view engine') - .it('should warn when the view has been created in a cd hook', fakeAsync(() => { - const ctx = createCompFixture('
    {{ a }}
    ', TestData); - ctx.componentInstance.a = 1; - expect(() => ctx.detectChanges()) - .toThrowError( - /It seems like the view has been created after its parent and its children have been dirty checked/); - })); + it('should throw when a record gets changed after the first change detection pass', + fakeAsync(() => { + @Directive({selector: '[changed]'}) + class ChangingDirective { + @Input() changed: any; + } + + TestBed.configureTestingModule({declarations: [ChangingDirective]}); + + const ctx = createCompFixture('
    ', TestData); + + ctx.componentInstance.b = 1; + ctx.detectChanges(); + + ctx.componentInstance.b = 2; + const errMsgRegExp = ivyEnabled ? + /Previous value: '1'\. Current value: '2'/g : + /Previous value: 'changed: 1'\. Current value: 'changed: 2'/g; + expect(() => ctx.checkNoChanges()).toThrowError(errMsgRegExp); + })); + + it('should warn when the view has been created in a cd hook', fakeAsync(() => { + const ctx = createCompFixture('
    {{ a }}
    ', TestData); + ctx.componentInstance.a = 1; + expect(() => ctx.detectChanges()) + .toThrowError( + /It seems like the view has been created after its parent and its children have been dirty checked/); + + // subsequent change detection should run without issues + ctx.detectChanges(); + })); it('should not throw when two arrays are structurally the same', fakeAsync(() => { const ctx = _bindSimpleValue('a', TestData); @@ -1223,15 +1217,27 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ expect(() => ctx.checkNoChanges()).not.toThrow(); })); - fixmeIvy('FW-823: ComponentFixture.checkNoChanges doesn\'t throw under TestBed') - .it('should not break the next run', fakeAsync(() => { - const ctx = _bindSimpleValue('a', TestData); - ctx.componentInstance.a = 'value'; - expect(() => ctx.checkNoChanges()).toThrow(); + it('should not break the next run', fakeAsync(() => { + const ctx = _bindSimpleValue('a', TestData); + ctx.componentInstance.a = 'value'; + expect(() => ctx.checkNoChanges()).toThrow(); - ctx.detectChanges(); - expect(renderLog.loggedValues).toEqual(['value']); - })); + ctx.detectChanges(); + expect(renderLog.loggedValues).toEqual(['value']); + })); + + it('should not break the next run (view engine and ivy)', fakeAsync(() => { + const ctx = _bindSimpleValue('a', TestData); + + ctx.detectChanges(); + renderLog.clear(); + + ctx.componentInstance.a = 'value'; + expect(() => ctx.checkNoChanges()).toThrow(); + + ctx.detectChanges(); + expect(renderLog.loggedValues).toEqual(['value']); + })); }); describe('mode', () => { @@ -1317,7 +1323,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ }); describe('multi directive order', () => { - fixmeIvy('FW-822: Order of bindings to directive inputs different in ivy') + modifiedInIvy('order of bindings to directive inputs is different in ivy') .it('should follow the DI order for the same element', fakeAsync(() => { const ctx = createCompFixture( '
    '); @@ -1463,8 +1469,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ expect(log).toEqual(['inner-start', 'main-tpl', 'outer-tpl']); }); - fixmeIvy( - 'FW-842: View engine dirty-checks projected views when the declaration place is checked') + modifiedInIvy('Views should not be dirty checked if inserted into CD-detached view tree') .it('should dirty check projected views if the declaration place is dirty checked', () => { ctx.detectChanges(false); @@ -1485,6 +1490,28 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ expect(log).toEqual(['main-start', 'main-tpl']); }); + + onlyInIvy('Views should not be dirty checked if inserted into CD-detached view tree') + .it('should not dirty check views that are inserted into a detached tree, even if the declaration place is dirty checked', + () => { + ctx.detectChanges(false); + log = []; + innerComp.cdRef.detach(); + mainComp.cdRef.detectChanges(); + + expect(log).toEqual(['main-start', 'outer-start']); + + log = []; + outerComp.cdRef.detectChanges(); + + expect(log).toEqual(['outer-start']); + + log = []; + outerComp.cdRef.detach(); + mainComp.cdRef.detectChanges(); + + expect(log).toEqual(['main-start']); + }); }); }); @@ -1502,13 +1529,7 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ } const ctx = - TestBed - .configureCompiler({ - providers: - [{provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry}] - }) - .configureTestingModule({declarations: [Comp, SomeDir]}) - .createComponent(Comp); + TestBed.configureTestingModule({declarations: [Comp, SomeDir]}).createComponent(Comp); ctx.detectChanges(); @@ -1558,111 +1579,110 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ childThrows: LifetimeMethods; } - fixmeIvy('FW-832: View engine supports recursive detectChanges() calls') - .describe('calling init', () => { - function initialize(options: Options) { - @Component({selector: 'my-child', template: ''}) - class MyChild { - private thrown = LifetimeMethods.None; + describe('calling init', () => { + function initialize(options: Options) { + @Component({selector: 'my-child', template: ''}) + class MyChild { + private thrown = LifetimeMethods.None; - // TODO(issue/24571): remove '!'. - @Input() inp !: boolean; - @Output() outp = new EventEmitter(); + // TODO(issue/24571): remove '!'. + @Input() inp !: boolean; + @Output() outp = new EventEmitter(); - constructor() {} + constructor() {} - ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } - ngOnInit() { this.check(LifetimeMethods.ngOnInit); } - ngOnChanges() { this.check(LifetimeMethods.ngOnChanges); } - ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } - ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } + ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } + ngOnInit() { this.check(LifetimeMethods.ngOnInit); } + ngOnChanges() { this.check(LifetimeMethods.ngOnChanges); } + ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } + ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } - private check(method: LifetimeMethods) { - log(`MyChild::${LifetimeMethods[method]}()`); + private check(method: LifetimeMethods) { + log(`MyChild::${LifetimeMethods[method]}()`); - if ((options.childRecursion & method) !== 0) { - if (logged.length < 20) { - this.outp.emit(null); - } else { - fail(`Unexpected MyChild::${LifetimeMethods[method]} recursion`); - } - } - if ((options.childThrows & method) !== 0) { - if ((this.thrown & method) === 0) { - this.thrown |= method; - log(`()`); - throw new Error(`Throw from MyChild::${LifetimeMethods[method]}`); - } - } + if ((options.childRecursion & method) !== 0) { + if (logged.length < 20) { + this.outp.emit(null); + } else { + fail(`Unexpected MyChild::${LifetimeMethods[method]} recursion`); } } - - @Component({ - selector: 'my-component', - template: `` - }) - class MyComponent { - constructor(private changeDetectionRef: ChangeDetectorRef) {} - ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } - ngOnInit() { this.check(LifetimeMethods.ngOnInit); } - ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } - ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } - onOutp() { - log(''); - this.changeDetectionRef.detectChanges(); - log(''); - } - - private check(method: LifetimeMethods) { - log(`MyComponent::${LifetimeMethods[method]}()`); + if ((options.childThrows & method) !== 0) { + if ((this.thrown & method) === 0) { + this.thrown |= method; + log(`()`); + throw new Error(`Throw from MyChild::${LifetimeMethods[method]}`); } } + } + } - TestBed.configureTestingModule({declarations: [MyChild, MyComponent]}); - - return createCompFixture(``); + @Component({ + selector: 'my-component', + template: `` + }) + class MyComponent { + constructor(private changeDetectionRef: ChangeDetectorRef) {} + ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } + ngOnInit() { this.check(LifetimeMethods.ngOnInit); } + ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } + ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } + onOutp() { + log(''); + this.changeDetectionRef.detectChanges(); + log(''); } - function ensureOneInit(options: Options) { - const ctx = initialize(options); + private check(method: LifetimeMethods) { + log(`MyComponent::${LifetimeMethods[method]}()`); + } + } + + TestBed.configureTestingModule({declarations: [MyChild, MyComponent]}); + + return createCompFixture(``); + } + + function ensureOneInit(options: Options) { + const ctx = initialize(options); - const throws = options.childThrows != LifetimeMethods.None; - if (throws) { - log(``); - expect(() => { - // Expect child to throw. - ctx.detectChanges(); - }).toThrow(); - log(``); - log(``); - } + const throws = options.childThrows != LifetimeMethods.None; + if (throws) { + log(``); + expect(() => { + // Expect child to throw. ctx.detectChanges(); - if (throws) log(``); - expectOnceAndOnlyOnce('MyComponent::ngOnInit()'); - expectOnceAndOnlyOnce('MyChild::ngOnInit()'); - expectOnceAndOnlyOnce('MyComponent::ngAfterViewInit()'); - expectOnceAndOnlyOnce('MyComponent::ngAfterContentInit()'); - expectOnceAndOnlyOnce('MyChild::ngAfterViewInit()'); - expectOnceAndOnlyOnce('MyChild::ngAfterContentInit()'); - } + }).toThrow(); + log(``); + log(``); + } + ctx.detectChanges(); + if (throws) log(``); + expectOnceAndOnlyOnce('MyComponent::ngOnInit()'); + expectOnceAndOnlyOnce('MyChild::ngOnInit()'); + expectOnceAndOnlyOnce('MyComponent::ngAfterViewInit()'); + expectOnceAndOnlyOnce('MyComponent::ngAfterContentInit()'); + expectOnceAndOnlyOnce('MyChild::ngAfterViewInit()'); + expectOnceAndOnlyOnce('MyChild::ngAfterContentInit()'); + } - forEachMethod(LifetimeMethods.InitMethodsAndChanges, method => { - it(`should ensure that init hooks are called once an only once with recursion in ${LifetimeMethods[method]} `, - () => { - // Ensure all the init methods are called once. - ensureOneInit({childRecursion: method, childThrows: LifetimeMethods.None}); - }); - }); - forEachMethod(LifetimeMethods.All, method => { - it(`should ensure that init hooks are called once an only once with a throw in ${LifetimeMethods[method]} `, - () => { - // Ensure all the init methods are called once. - // the first cycle throws but the next cycle should complete the inits. - ensureOneInit({childRecursion: LifetimeMethods.None, childThrows: method}); - }); - }); - }); + forEachMethod(LifetimeMethods.InitMethodsAndChanges, method => { + it(`should ensure that init hooks are called once an only once with recursion in ${LifetimeMethods[method]} `, + () => { + // Ensure all the init methods are called once. + ensureOneInit({childRecursion: method, childThrows: LifetimeMethods.None}); + }); + }); + forEachMethod(LifetimeMethods.All, method => { + it(`should ensure that init hooks are called once an only once with a throw in ${LifetimeMethods[method]} `, + () => { + // Ensure all the init methods are called once. + // the first cycle throws but the next cycle should complete the inits. + ensureOneInit({childRecursion: LifetimeMethods.None, childThrows: method}); + }); + }); + }); }); }); })(); diff --git a/packages/core/test/linker/entry_components_integration_spec.ts b/packages/core/test/linker/entry_components_integration_spec.ts index 8ee1bf9ccb..7c0adff4aa 100644 --- a/packages/core/test/linker/entry_components_integration_spec.ts +++ b/packages/core/test/linker/entry_components_integration_spec.ts @@ -10,7 +10,7 @@ import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ComponentFactoryResolver, ɵivy import {Console} from '@angular/core/src/console'; import {noComponentFactoryError} from '@angular/core/src/linker/component_factory_resolver'; import {TestBed} from '@angular/core/testing'; -import {fixmeIvy} from '@angular/private/testing'; +import {obsoleteInIvy} from '@angular/private/testing'; if (ivyEnabled) { @@ -69,8 +69,7 @@ function declareTests(config?: {useJit: boolean}) { expect(childComp.cfr.resolveComponentFactory(ChildComp) !.componentType).toBe(ChildComp); }); - fixmeIvy( - 'FW-805: Ivy\'s implementation of ComponentFactoryResolver doesn\'t have checks present in the view engine') + obsoleteInIvy('In Ivy, the ComponentFactoryResolver can resolve any component factory') .it('should not be able to get components from a parent component (content hierarchy)', () => { TestBed.overrideComponent( diff --git a/packages/core/test/linker/inheritance_integration_spec.ts b/packages/core/test/linker/inheritance_integration_spec.ts new file mode 100644 index 0000000000..24f7129079 --- /dev/null +++ b/packages/core/test/linker/inheritance_integration_spec.ts @@ -0,0 +1,93 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, Directive, HostBinding} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; +import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; + +@Directive({selector: '[directiveA]'}) +class DirectiveA { +} + +@Directive({selector: '[directiveB]'}) +class DirectiveB { + @HostBinding('title') + title = 'DirectiveB Title'; +} + +@Component({selector: 'component-a', template: 'ComponentA Template'}) +class ComponentA { +} + +@Component( + {selector: 'component-extends-directive', template: 'ComponentExtendsDirective Template'}) +class ComponentExtendsDirective extends DirectiveA { +} + +class ComponentWithNoAnnotation extends ComponentA {} + +@Directive({selector: '[directiveExtendsComponent]'}) +class DirectiveExtendsComponent extends ComponentA { + @HostBinding('title') + title = 'DirectiveExtendsComponent Title'; +} + +class DirectiveWithNoAnnotation extends DirectiveB {} + +@Component({selector: 'my-app', template: '...'}) +class App { +} + +describe('Inheritance logic', () => { + it('should handle Components that extend Directives', () => { + TestBed.configureTestingModule({declarations: [ComponentExtendsDirective, App]}); + const template = ''; + TestBed.overrideComponent(App, {set: {template}}); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + expect(fixture.nativeElement.firstChild.innerHTML).toBe('ComponentExtendsDirective Template'); + }); + + it('should handle classes with no annotations that extend Components', () => { + TestBed.configureTestingModule({declarations: [ComponentWithNoAnnotation, App]}); + const template = ''; + TestBed.overrideComponent(App, {set: {template}}); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + expect(fixture.nativeElement.firstChild.innerHTML).toBe('ComponentA Template'); + }); + + it('should handle classes with no annotations that extend Directives', () => { + TestBed.configureTestingModule({declarations: [DirectiveWithNoAnnotation, App]}); + const template = '
    '; + TestBed.overrideComponent(App, {set: {template}}); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + expect(fixture.nativeElement.firstChild.title).toBe('DirectiveB Title'); + }); + + modifiedInIvy('View Engine allows Directives to extend Components') + .it('should handle Directives that extend Components', () => { + TestBed.configureTestingModule({declarations: [DirectiveExtendsComponent, App]}); + const template = '
    Some content
    '; + TestBed.overrideComponent(App, {set: {template}}); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + expect(fixture.nativeElement.firstChild.title).toBe('DirectiveExtendsComponent Title'); + }); + + onlyInIvy('Ivy does not allow Directives to extend Components') + .it('should throw in case a Directive tries to extend a Component', () => { + TestBed.configureTestingModule({declarations: [DirectiveExtendsComponent, App]}); + const template = '
    Some content
    '; + TestBed.overrideComponent(App, {set: {template}}); + expect(() => TestBed.createComponent(App)) + .toThrowError('Directives cannot inherit Components'); + }); +}); diff --git a/packages/core/test/linker/integration_spec.ts b/packages/core/test/linker/integration_spec.ts index 8cec47ee8b..b705cd2af8 100644 --- a/packages/core/test/linker/integration_spec.ts +++ b/packages/core/test/linker/integration_spec.ts @@ -22,9 +22,9 @@ import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens'; import {dispatchEvent, el} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, modifiedInIvy, obsoleteInIvy} from '@angular/private/testing'; +import {modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; -import {stringify} from '../../src/util'; +import {stringify} from '../../src/util/stringify'; const ANCHOR_ELEMENT = new InjectionToken('AnchorElement'); @@ -347,22 +347,20 @@ function declareTests(config?: {useJit: boolean}) { expect(tc.injector.get(EventDir)).not.toBeNull(); }); - fixmeIvy('FW-680: Throw meaningful error for uninitialized @Output') - .it('should display correct error message for uninitialized @Output', () => { - @Component({selector: 'my-uninitialized-output', template: '

    It works!

    '}) - class UninitializedOutputComp { - @Output() customEvent !: EventEmitter; - } + it('should display correct error message for uninitialized @Output', () => { + @Component({selector: 'my-uninitialized-output', template: '

    It works!

    '}) + class UninitializedOutputComp { + @Output() customEvent !: EventEmitter; + } - const template = - ''; - TestBed.overrideComponent(MyComp, {set: {template}}); + const template = + ''; + TestBed.overrideComponent(MyComp, {set: {template}}); - TestBed.configureTestingModule({declarations: [MyComp, UninitializedOutputComp]}); - expect(() => TestBed.createComponent(MyComp)) - .toThrowError( - '@Output customEvent not initialized in \'UninitializedOutputComp\'.'); - }); + TestBed.configureTestingModule({declarations: [MyComp, UninitializedOutputComp]}); + expect(() => TestBed.createComponent(MyComp)) + .toThrowError('@Output customEvent not initialized in \'UninitializedOutputComp\'.'); + }); it('should read directives metadata from their binding token', () => { TestBed.configureTestingModule({declarations: [MyComp, PrivateImpl, NeedsPublicApi]}); @@ -477,20 +475,19 @@ function declareTests(config?: {useJit: boolean}) { .toBeAnInstanceOf(ExportDir); }); - fixmeIvy('FW-708: Directives with multiple exports are not supported') - .it('should assign a directive to a ref when it has multiple exportAs names', () => { - TestBed.configureTestingModule( - {declarations: [MyComp, DirectiveWithMultipleExportAsNames]}); + it('should assign a directive to a ref when it has multiple exportAs names', () => { + TestBed.configureTestingModule( + {declarations: [MyComp, DirectiveWithMultipleExportAsNames]}); - const template = '
    '; - TestBed.overrideComponent(MyComp, {set: {template}}); + const template = '
    '; + TestBed.overrideComponent(MyComp, {set: {template}}); - const fixture = TestBed.createComponent(MyComp); - expect(fixture.debugElement.children[0].references !['x']) - .toBeAnInstanceOf(DirectiveWithMultipleExportAsNames); - expect(fixture.debugElement.children[0].references !['y']) - .toBeAnInstanceOf(DirectiveWithMultipleExportAsNames); - }); + const fixture = TestBed.createComponent(MyComp); + expect(fixture.debugElement.children[0].references !['x']) + .toBeAnInstanceOf(DirectiveWithMultipleExportAsNames); + expect(fixture.debugElement.children[0].references !['y']) + .toBeAnInstanceOf(DirectiveWithMultipleExportAsNames); + }); it('should make the assigned component accessible in property bindings, even if they were declared before the component', () => { @@ -542,18 +539,16 @@ function declareTests(config?: {useJit: boolean}) { expect(value.tagName.toLowerCase()).toEqual('div'); }); - fixmeIvy( - 'FW-870: DebugNode.references gets comment node instead of TemplateRef for template nodes') - .it('should assign the TemplateRef to a user-defined variable', () => { - const fixture = - TestBed.configureTestingModule({declarations: [MyComp]}) - .overrideComponent( - MyComp, {set: {template: ''}}) - .createComponent(MyComp); + it('should assign the TemplateRef to a user-defined variable', () => { + const fixture = + TestBed.configureTestingModule({declarations: [MyComp]}) + .overrideComponent( + MyComp, {set: {template: ''}}) + .createComponent(MyComp); - const value = fixture.debugElement.childNodes[0].references !['alice']; - expect(value.createEmbeddedView).toBeTruthy(); - }); + const value = fixture.debugElement.childNodes[0].references !['alice']; + expect(value.createEmbeddedView).toBeTruthy(); + }); it('should preserve case', () => { TestBed.configureTestingModule({declarations: [MyComp, ChildComp]}); @@ -642,44 +637,43 @@ function declareTests(config?: {useJit: boolean}) { })); } - fixmeIvy('FW-758: OnPush events not marking view dirty when using renderer2') - .it('should be checked when an event is fired', () => { - TestBed.configureTestingModule( - {declarations: [MyComp, PushCmp, EventCmp], imports: [CommonModule]}); - const template = ''; - TestBed.overrideComponent(MyComp, {set: {template}}); - const fixture = TestBed.createComponent(MyComp); + it('should be checked when an event is fired', () => { + TestBed.configureTestingModule( + {declarations: [MyComp, PushCmp, EventCmp], imports: [CommonModule]}); + const template = ''; + TestBed.overrideComponent(MyComp, {set: {template}}); + const fixture = TestBed.createComponent(MyComp); - const cmpEl = fixture.debugElement.children[0]; - const cmp = cmpEl.componentInstance; - fixture.detectChanges(); - fixture.detectChanges(); - expect(cmp.numberOfChecks).toEqual(1); + const cmpEl = fixture.debugElement.children[0]; + const cmp = cmpEl.componentInstance; + fixture.detectChanges(); + fixture.detectChanges(); + expect(cmp.numberOfChecks).toEqual(1); - // regular element - cmpEl.children[0].triggerEventHandler('click', {}); - fixture.detectChanges(); - fixture.detectChanges(); - expect(cmp.numberOfChecks).toEqual(2); + // regular element + cmpEl.children[0].triggerEventHandler('click', {}); + fixture.detectChanges(); + fixture.detectChanges(); + expect(cmp.numberOfChecks).toEqual(2); - // element inside of an *ngIf - cmpEl.children[1].triggerEventHandler('click', {}); - fixture.detectChanges(); - fixture.detectChanges(); - expect(cmp.numberOfChecks).toEqual(3); + // element inside of an *ngIf + cmpEl.children[1].triggerEventHandler('click', {}); + fixture.detectChanges(); + fixture.detectChanges(); + expect(cmp.numberOfChecks).toEqual(3); - // element inside a nested component - cmpEl.children[2].children[0].triggerEventHandler('click', {}); - fixture.detectChanges(); - fixture.detectChanges(); - expect(cmp.numberOfChecks).toEqual(4); + // element inside a nested component + cmpEl.children[2].children[0].triggerEventHandler('click', {}); + fixture.detectChanges(); + fixture.detectChanges(); + expect(cmp.numberOfChecks).toEqual(4); - // host element - cmpEl.triggerEventHandler('click', {}); - fixture.detectChanges(); - fixture.detectChanges(); - expect(cmp.numberOfChecks).toEqual(5); - }); + // host element + cmpEl.triggerEventHandler('click', {}); + fixture.detectChanges(); + fixture.detectChanges(); + expect(cmp.numberOfChecks).toEqual(5); + }); it('should not affect updating properties on the component', () => { TestBed.configureTestingModule({declarations: [MyComp, [[PushCmpWithRef]]]}); @@ -845,52 +839,48 @@ function declareTests(config?: {useJit: boolean}) { dir.triggerChange('two'); })); - fixmeIvy( - 'FW-743: Registering events on global objects (document, window, body) is not supported') - .it('should support render events', () => { - TestBed.configureTestingModule({declarations: [MyComp, DirectiveListeningDomEvent]}); - const template = '
    '; - TestBed.overrideComponent(MyComp, {set: {template}}); - const fixture = TestBed.createComponent(MyComp); + it('should support render events', () => { + TestBed.configureTestingModule({declarations: [MyComp, DirectiveListeningDomEvent]}); + const template = '
    '; + TestBed.overrideComponent(MyComp, {set: {template}}); + const fixture = TestBed.createComponent(MyComp); - const tc = fixture.debugElement.children[0]; - const listener = tc.injector.get(DirectiveListeningDomEvent); + const tc = fixture.debugElement.children[0]; + const listener = tc.injector.get(DirectiveListeningDomEvent); - dispatchEvent(tc.nativeElement, 'domEvent'); + dispatchEvent(tc.nativeElement, 'domEvent'); - expect(listener.eventTypes).toEqual([ - 'domEvent', 'body_domEvent', 'document_domEvent', 'window_domEvent' - ]); + expect(listener.eventTypes).toEqual([ + 'domEvent', 'body_domEvent', 'document_domEvent', 'window_domEvent' + ]); - fixture.destroy(); - listener.eventTypes = []; - dispatchEvent(tc.nativeElement, 'domEvent'); - expect(listener.eventTypes).toEqual([]); - }); + fixture.destroy(); + listener.eventTypes = []; + dispatchEvent(tc.nativeElement, 'domEvent'); + expect(listener.eventTypes).toEqual([]); + }); - fixmeIvy( - 'FW-743: Registering events on global objects (document, window, body) is not supported') - .it('should support render global events', () => { - TestBed.configureTestingModule({declarations: [MyComp, DirectiveListeningDomEvent]}); - const template = '
    '; - TestBed.overrideComponent(MyComp, {set: {template}}); - const fixture = TestBed.createComponent(MyComp); - const doc = TestBed.get(DOCUMENT); + it('should support render global events', () => { + TestBed.configureTestingModule({declarations: [MyComp, DirectiveListeningDomEvent]}); + const template = '
    '; + TestBed.overrideComponent(MyComp, {set: {template}}); + const fixture = TestBed.createComponent(MyComp); + const doc = TestBed.get(DOCUMENT); - const tc = fixture.debugElement.children[0]; - const listener = tc.injector.get(DirectiveListeningDomEvent); - dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); - expect(listener.eventTypes).toEqual(['window_domEvent']); + const tc = fixture.debugElement.children[0]; + const listener = tc.injector.get(DirectiveListeningDomEvent); + dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); + expect(listener.eventTypes).toEqual(['window_domEvent']); - listener.eventTypes = []; - dispatchEvent(getDOM().getGlobalEventTarget(doc, 'document'), 'domEvent'); - expect(listener.eventTypes).toEqual(['document_domEvent', 'window_domEvent']); + listener.eventTypes = []; + dispatchEvent(getDOM().getGlobalEventTarget(doc, 'document'), 'domEvent'); + expect(listener.eventTypes).toEqual(['document_domEvent', 'window_domEvent']); - fixture.destroy(); - listener.eventTypes = []; - dispatchEvent(getDOM().getGlobalEventTarget(doc, 'body'), 'domEvent'); - expect(listener.eventTypes).toEqual([]); - }); + fixture.destroy(); + listener.eventTypes = []; + dispatchEvent(getDOM().getGlobalEventTarget(doc, 'body'), 'domEvent'); + expect(listener.eventTypes).toEqual([]); + }); it('should support updating host element via hostAttributes on root elements', () => { @Component({host: {'role': 'button'}, template: ''}) @@ -933,39 +923,36 @@ function declareTests(config?: {useJit: boolean}) { expect(getDOM().getProperty(tc.nativeElement, 'id')).toEqual('newId'); }); - fixmeIvy('FW-681: not possible to retrieve host property bindings from TView') - .it('should not use template variables for expressions in hostProperties', () => { - @Directive( - {selector: '[host-properties]', host: {'[id]': 'id', '[title]': 'unknownProp'}}) - class DirectiveWithHostProps { - id = 'one'; - } + it('should not use template variables for expressions in hostProperties', () => { + @Directive({selector: '[host-properties]', host: {'[id]': 'id', '[title]': 'unknownProp'}}) + class DirectiveWithHostProps { + id = 'one'; + } - const fixture = - TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]}) - .overrideComponent(MyComp, { - set: {template: `
    `} - }) - .createComponent(MyComp); - fixture.detectChanges(); + const fixture = + TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]}) + .overrideComponent( + MyComp, + {set: {template: `
    `}}) + .createComponent(MyComp); + fixture.detectChanges(); - const tc = fixture.debugElement.children[0]; - expect(tc.properties['id']).toBe('one'); - expect(tc.properties['title']).toBe(undefined); - }); + const tc = fixture.debugElement.children[0]; + expect(tc.properties['id']).toBe('one'); + expect(tc.properties['title']).toBe(undefined); + }); - fixmeIvy('FW-725: Pipes in host bindings fail with a cryptic error') - .it('should not allow pipes in hostProperties', () => { - @Directive({selector: '[host-properties]', host: {'[id]': 'id | uppercase'}}) - class DirectiveWithHostProps { - } + it('should not allow pipes in hostProperties', () => { + @Directive({selector: '[host-properties]', host: {'[id]': 'id | uppercase'}}) + class DirectiveWithHostProps { + } - TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]}); - const template = '
    '; - TestBed.overrideComponent(MyComp, {set: {template}}); - expect(() => TestBed.createComponent(MyComp)) - .toThrowError(/Host binding expression cannot contain pipes/); - }); + TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostProps]}); + const template = '
    '; + TestBed.overrideComponent(MyComp, {set: {template}}); + expect(() => TestBed.createComponent(MyComp)) + .toThrowError(/Host binding expression cannot contain pipes/); + }); it('should not use template variables for expressions in hostListeners', () => { @Directive({selector: '[host-listener]', host: {'(click)': 'doIt(id, unknownProp)'}}) @@ -990,18 +977,17 @@ function declareTests(config?: {useJit: boolean}) { expect(dir.receivedArgs).toEqual(['one', undefined]); }); - fixmeIvy('FW-742: Pipes in host listeners should throw a descriptive error') - .it('should not allow pipes in hostListeners', () => { - @Directive({selector: '[host-listener]', host: {'(click)': 'doIt() | somePipe'}}) - class DirectiveWithHostListener { - } + it('should not allow pipes in hostListeners', () => { + @Directive({selector: '[host-listener]', host: {'(click)': 'doIt() | somePipe'}}) + class DirectiveWithHostListener { + } - TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostListener]}); - const template = '
    '; - TestBed.overrideComponent(MyComp, {set: {template}}); - expect(() => TestBed.createComponent(MyComp)) - .toThrowError(/Cannot have a pipe in an action expression/); - }); + TestBed.configureTestingModule({declarations: [MyComp, DirectiveWithHostListener]}); + const template = '
    '; + TestBed.overrideComponent(MyComp, {set: {template}}); + expect(() => TestBed.createComponent(MyComp)) + .toThrowError(/Cannot have a pipe in an action expression/); + }); @@ -1027,44 +1013,41 @@ function declareTests(config?: {useJit: boolean}) { }); } - fixmeIvy( - 'FW-743: Registering events on global objects (document, window, body) is not supported') - .it('should support render global events from multiple directives', () => { - TestBed.configureTestingModule({ - declarations: [MyComp, DirectiveListeningDomEvent, DirectiveListeningDomEventOther] - }); - const template = '
    '; - TestBed.overrideComponent(MyComp, {set: {template}}); - const fixture = TestBed.createComponent(MyComp); - const doc = TestBed.get(DOCUMENT); + it('should support render global events from multiple directives', () => { + TestBed.configureTestingModule( + {declarations: [MyComp, DirectiveListeningDomEvent, DirectiveListeningDomEventOther]}); + const template = '
    '; + TestBed.overrideComponent(MyComp, {set: {template}}); + const fixture = TestBed.createComponent(MyComp); + const doc = TestBed.get(DOCUMENT); - globalCounter = 0; - fixture.componentInstance.ctxBoolProp = true; - fixture.detectChanges(); + globalCounter = 0; + fixture.componentInstance.ctxBoolProp = true; + fixture.detectChanges(); - const tc = fixture.debugElement.children[0]; + const tc = fixture.debugElement.children[0]; - const listener = tc.injector.get(DirectiveListeningDomEvent); - const listenerother = tc.injector.get(DirectiveListeningDomEventOther); - dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); - expect(listener.eventTypes).toEqual(['window_domEvent']); - expect(listenerother.eventType).toEqual('other_domEvent'); - expect(globalCounter).toEqual(1); + const listener = tc.injector.get(DirectiveListeningDomEvent); + const listenerother = tc.injector.get(DirectiveListeningDomEventOther); + dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); + expect(listener.eventTypes).toEqual(['window_domEvent']); + expect(listenerother.eventType).toEqual('other_domEvent'); + expect(globalCounter).toEqual(1); - fixture.componentInstance.ctxBoolProp = false; - fixture.detectChanges(); - dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); - expect(globalCounter).toEqual(1); + fixture.componentInstance.ctxBoolProp = false; + fixture.detectChanges(); + dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); + expect(globalCounter).toEqual(1); - fixture.componentInstance.ctxBoolProp = true; - fixture.detectChanges(); - dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); - expect(globalCounter).toEqual(2); + fixture.componentInstance.ctxBoolProp = true; + fixture.detectChanges(); + dispatchEvent(getDOM().getGlobalEventTarget(doc, 'window'), 'domEvent'); + expect(globalCounter).toEqual(2); - // need to destroy to release all remaining global event listeners - fixture.destroy(); - }); + // need to destroy to release all remaining global event listeners + fixture.destroy(); + }); describe('ViewContainerRef', () => { beforeEach(() => { @@ -1109,129 +1092,124 @@ function declareTests(config?: {useJit: boolean}) { .toHaveText('dynamic greet'); })); - fixmeIvy('FW-707: TestBed: No LView in getParentInjectorLocation') - .it('should create a component that has been freshly compiled', () => { - @Component({template: ''}) - class RootComp { - constructor(public vc: ViewContainerRef) {} - } + it('should create a component that has been freshly compiled', () => { + @Component({template: ''}) + class RootComp { + constructor(public vc: ViewContainerRef) {} + } - @NgModule({ - declarations: [RootComp], - providers: [{provide: 'someToken', useValue: 'someRootValue'}], - }) - class RootModule { - } + @NgModule({ + declarations: [RootComp], + providers: [{provide: 'someToken', useValue: 'someRootValue'}], + }) + class RootModule { + } - @Component({template: ''}) - class MyComp { - constructor(@Inject('someToken') public someToken: string) {} - } + @Component({template: ''}) + class MyComp { + constructor(@Inject('someToken') public someToken: string) {} + } - @NgModule({ - declarations: [MyComp], - providers: [{provide: 'someToken', useValue: 'someValue'}], - }) - class MyModule { - } + @NgModule({ + declarations: [MyComp], + providers: [{provide: 'someToken', useValue: 'someValue'}], + }) + class MyModule { + } - const compFixture = TestBed.configureTestingModule({imports: [RootModule]}) - .createComponent(RootComp); - const compiler = TestBed.get(Compiler); - const myCompFactory = - >compiler.compileModuleAndAllComponentsSync(MyModule) - .componentFactories[0]; + const compFixture = + TestBed.configureTestingModule({imports: [RootModule]}).createComponent(RootComp); + const compiler = TestBed.get(Compiler); + const myCompFactory = + >compiler.compileModuleAndAllComponentsSync(MyModule) + .componentFactories[0]; - // Note: the ComponentFactory was created directly via the compiler, i.e. it - // does not have an association to an NgModuleRef. - // -> expect the providers of the module that the view container belongs to. - const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory); - expect(compRef.instance.someToken).toBe('someRootValue'); - }); + // Note: the ComponentFactory was created directly via the compiler, i.e. it + // does not have an association to an NgModuleRef. + // -> expect the providers of the module that the view container belongs to. + const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory); + expect(compRef.instance.someToken).toBe('someRootValue'); + }); - fixmeIvy('FW-707: TestBed: No LView in getParentInjectorLocation') - .it('should create a component with the passed NgModuleRef', () => { - @Component({template: ''}) - class RootComp { - constructor(public vc: ViewContainerRef) {} - } + it('should create a component with the passed NgModuleRef', () => { + @Component({template: ''}) + class RootComp { + constructor(public vc: ViewContainerRef) {} + } - @Component({template: ''}) - class MyComp { - constructor(@Inject('someToken') public someToken: string) {} - } + @Component({template: ''}) + class MyComp { + constructor(@Inject('someToken') public someToken: string) {} + } - @NgModule({ - declarations: [RootComp, MyComp], - entryComponents: [MyComp], - providers: [{provide: 'someToken', useValue: 'someRootValue'}], - }) - class RootModule { - } + @NgModule({ + declarations: [RootComp, MyComp], + entryComponents: [MyComp], + providers: [{provide: 'someToken', useValue: 'someRootValue'}], + }) + class RootModule { + } - @NgModule({providers: [{provide: 'someToken', useValue: 'someValue'}]}) - class MyModule { - } + @NgModule({providers: [{provide: 'someToken', useValue: 'someValue'}]}) + class MyModule { + } - const compFixture = TestBed.configureTestingModule({imports: [RootModule]}) - .createComponent(RootComp); - const compiler = TestBed.get(Compiler); - const myModule = - compiler.compileModuleSync(MyModule).create(TestBed.get(NgModuleRef)); - const myCompFactory = - (TestBed.get(ComponentFactoryResolver)) - .resolveComponentFactory(MyComp); + const compFixture = + TestBed.configureTestingModule({imports: [RootModule]}).createComponent(RootComp); + const compiler = TestBed.get(Compiler); + const myModule = compiler.compileModuleSync(MyModule).create(TestBed.get(NgModuleRef)); + const myCompFactory = (TestBed.get(ComponentFactoryResolver)) + .resolveComponentFactory(MyComp); - // Note: MyComp was declared as entryComponent in the RootModule, - // but we pass MyModule to the createComponent call. - // -> expect the providers of MyModule! - const compRef = compFixture.componentInstance.vc.createComponent( - myCompFactory, undefined, undefined, undefined, myModule); - expect(compRef.instance.someToken).toBe('someValue'); - }); + // Note: MyComp was declared as entryComponent in the RootModule, + // but we pass MyModule to the createComponent call. + // -> expect the providers of MyModule! + const compRef = compFixture.componentInstance.vc.createComponent( + myCompFactory, undefined, undefined, undefined, myModule); + expect(compRef.instance.someToken).toBe('someValue'); + }); - fixmeIvy('FW-707: TestBed: No LView in getParentInjectorLocation') - .it('should create a component with the NgModuleRef of the ComponentFactoryResolver', - () => { - @Component({template: ''}) - class RootComp { - constructor(public vc: ViewContainerRef) {} - } + it('should create a component with the NgModuleRef of the ComponentFactoryResolver', + () => { + @Component({template: ''}) + class RootComp { + constructor(public vc: ViewContainerRef) {} + } - @NgModule({ - declarations: [RootComp], - providers: [{provide: 'someToken', useValue: 'someRootValue'}], - }) - class RootModule { - } + @NgModule({ + declarations: [RootComp], + providers: [{provide: 'someToken', useValue: 'someRootValue'}], + }) + class RootModule { + } - @Component({template: ''}) - class MyComp { - constructor(@Inject('someToken') public someToken: string) {} - } + @Component({template: ''}) + class MyComp { + constructor(@Inject('someToken') public someToken: string) {} + } - @NgModule({ - declarations: [MyComp], - entryComponents: [MyComp], - providers: [{provide: 'someToken', useValue: 'someValue'}], - }) - class MyModule { - } + @NgModule({ + declarations: [MyComp], + entryComponents: [MyComp], + providers: [{provide: 'someToken', useValue: 'someValue'}], + }) + class MyModule { + } - const compFixture = TestBed.configureTestingModule({imports: [RootModule]}) - .createComponent(RootComp); - const compiler = TestBed.get(Compiler); - const myModule = - compiler.compileModuleSync(MyModule).create(TestBed.get(NgModuleRef)); - const myCompFactory = - myModule.componentFactoryResolver.resolveComponentFactory(MyComp); + const compFixture = TestBed.configureTestingModule({imports: [RootModule]}) + .createComponent(RootComp); + const compiler = TestBed.get(Compiler); + const myModule = + compiler.compileModuleSync(MyModule).create(TestBed.get(NgModuleRef)); + const myCompFactory = + myModule.componentFactoryResolver.resolveComponentFactory(MyComp); - // Note: MyComp was declared as entryComponent in MyModule, - // and we don't pass an explicit ModuleRef to the createComponent call. - // -> expect the providers of MyModule! - const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory); - expect(compRef.instance.someToken).toBe('someValue'); - }); + // Note: MyComp was declared as entryComponent in MyModule, + // and we don't pass an explicit ModuleRef to the createComponent call. + // -> expect the providers of MyModule! + const compRef = compFixture.componentInstance.vc.createComponent(myCompFactory); + expect(compRef.instance.someToken).toBe('someValue'); + }); }); describe('.insert', () => { @@ -1434,21 +1412,19 @@ function declareTests(config?: {useJit: boolean}) { expect(getDOM().querySelectorAll(fixture.nativeElement, 'script').length).toEqual(0); }); - fixmeIvy('FW-662: Components without selector are not supported') - .it('should throw when using directives without selector', () => { - @Directive({}) - class SomeDirective { - } + it('should throw when using directives without selector', () => { + @Directive({}) + class SomeDirective { + } - @Component({selector: 'comp', template: ''}) - class SomeComponent { - } + @Component({selector: 'comp', template: ''}) + class SomeComponent { + } - TestBed.configureTestingModule({declarations: [MyComp, SomeDirective, SomeComponent]}); - expect(() => TestBed.createComponent(MyComp)) - .toThrowError( - `Directive ${stringify(SomeDirective)} has no selector, please add it!`); - }); + TestBed.configureTestingModule({declarations: [MyComp, SomeDirective, SomeComponent]}); + expect(() => TestBed.createComponent(MyComp)) + .toThrowError(`Directive ${stringify(SomeDirective)} has no selector, please add it!`); + }); it('should use a default element name for components without selectors', () => { let noSelectorComponentFactory: ComponentFactory = undefined !; @@ -1616,7 +1592,7 @@ function declareTests(config?: {useJit: boolean}) { }); describe('Property bindings', () => { - fixmeIvy('FW-721: Bindings to unknown properties are not reported as errors') + modifiedInIvy('Unknown property error thrown during update mode, not creation mode') .it('should throw on bindings to unknown properties', () => { TestBed.configureTestingModule({declarations: [MyComp]}); const template = '
    '; @@ -1630,6 +1606,21 @@ function declareTests(config?: {useJit: boolean}) { } }); + onlyInIvy('Unknown property error thrown during update mode, not creation mode') + .it('should throw on bindings to unknown properties', () => { + TestBed.configureTestingModule({declarations: [MyComp]}); + const template = '
    '; + TestBed.overrideComponent(MyComp, {set: {template}}); + try { + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + throw 'Should throw'; + } catch (e) { + expect(e.message).toMatch( + /Template error: Can't bind to 'unknown' since it isn't a known property of 'div'./); + } + }); + it('should not throw for property binding to a non-existing property when there is a matching directive property', () => { TestBed.configureTestingModule({declarations: [MyComp, MyDir]}); @@ -1851,83 +1842,79 @@ function declareTests(config?: {useJit: boolean}) { if (getDOM().supportsDOMEvents()) { describe('svg', () => { - fixmeIvy('FW-672: SVG attribute xlink:href is output as :xlink:href (extra ":")') - .it('should support svg elements', () => { - TestBed.configureTestingModule({declarations: [MyComp]}); - const template = ''; - TestBed.overrideComponent(MyComp, {set: {template}}); - const fixture = TestBed.createComponent(MyComp); + it('should support svg elements', () => { + TestBed.configureTestingModule({declarations: [MyComp]}); + const template = ''; + TestBed.overrideComponent(MyComp, {set: {template}}); + const fixture = TestBed.createComponent(MyComp); - const el = fixture.nativeElement; - const svg = getDOM().childNodes(el)[0]; - const use = getDOM().childNodes(svg)[0]; - expect(getDOM().getProperty(svg, 'namespaceURI')) - .toEqual('http://www.w3.org/2000/svg'); - expect(getDOM().getProperty(use, 'namespaceURI')) - .toEqual('http://www.w3.org/2000/svg'); + const el = fixture.nativeElement; + const svg = getDOM().childNodes(el)[0]; + const use = getDOM().childNodes(svg)[0]; + expect(getDOM().getProperty(svg, 'namespaceURI')) + .toEqual('http://www.w3.org/2000/svg'); + expect(getDOM().getProperty(use, 'namespaceURI')) + .toEqual('http://www.w3.org/2000/svg'); - const firstAttribute = getDOM().getProperty(use, 'attributes')[0]; - expect(firstAttribute.name).toEqual('xlink:href'); - expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink'); - }); + const firstAttribute = getDOM().getProperty(use, 'attributes')[0]; + expect(firstAttribute.name).toEqual('xlink:href'); + expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink'); + }); - fixmeIvy('FW-811: Align HTML namespaces between Ivy and Render2') - .it('should support foreignObjects with document fragments', () => { - TestBed.configureTestingModule({declarations: [MyComp]}); - const template = - '

    Test

    '; - TestBed.overrideComponent(MyComp, {set: {template}}); - const fixture = TestBed.createComponent(MyComp); + it('should support foreignObjects with document fragments', () => { + TestBed.configureTestingModule({declarations: [MyComp]}); + const template = + '

    Test

    '; + TestBed.overrideComponent(MyComp, {set: {template}}); + const fixture = TestBed.createComponent(MyComp); - const el = fixture.nativeElement; - const svg = getDOM().childNodes(el)[0]; - const foreignObject = getDOM().childNodes(svg)[0]; - const p = getDOM().childNodes(foreignObject)[0]; - expect(getDOM().getProperty(svg, 'namespaceURI')) - .toEqual('http://www.w3.org/2000/svg'); - expect(getDOM().getProperty(foreignObject, 'namespaceURI')) - .toEqual('http://www.w3.org/2000/svg'); - expect(getDOM().getProperty(p, 'namespaceURI')) - .toEqual('http://www.w3.org/1999/xhtml'); - }); + const el = fixture.nativeElement; + const svg = getDOM().childNodes(el)[0]; + const foreignObject = getDOM().childNodes(svg)[0]; + const p = getDOM().childNodes(foreignObject)[0]; + expect(getDOM().getProperty(svg, 'namespaceURI')) + .toEqual('http://www.w3.org/2000/svg'); + expect(getDOM().getProperty(foreignObject, 'namespaceURI')) + .toEqual('http://www.w3.org/2000/svg'); + expect(getDOM().getProperty(p, 'namespaceURI')) + .toEqual('http://www.w3.org/1999/xhtml'); + }); }); describe('attributes', () => { - fixmeIvy('FW-672: SVG attribute xlink:href is output as :xlink:href (extra ":")') - .it('should support attributes with namespace', () => { - TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]}); - const template = ''; - TestBed.overrideComponent(SomeCmp, {set: {template}}); - const fixture = TestBed.createComponent(SomeCmp); + it('should support attributes with namespace', () => { + TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]}); + const template = ''; + TestBed.overrideComponent(SomeCmp, {set: {template}}); + const fixture = TestBed.createComponent(SomeCmp); - const useEl = getDOM().firstChild(fixture.nativeElement); - expect(getDOM().getAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href')) - .toEqual('#id'); - }); + const useEl = getDOM().firstChild(fixture.nativeElement); + expect(getDOM().getAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href')) + .toEqual('#id'); + }); - fixmeIvy('FW-672: SVG attribute xlink:href is output as :xlink:href (extra ":")') - .it('should support binding to attributes with namespace', () => { - TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]}); - const template = ''; - TestBed.overrideComponent(SomeCmp, {set: {template}}); - const fixture = TestBed.createComponent(SomeCmp); + it('should support binding to attributes with namespace', () => { + TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]}); + const template = ''; + TestBed.overrideComponent(SomeCmp, {set: {template}}); + const fixture = TestBed.createComponent(SomeCmp); - const cmp = fixture.componentInstance; - const useEl = getDOM().firstChild(fixture.nativeElement); + const cmp = fixture.componentInstance; + const useEl = getDOM().firstChild(fixture.nativeElement); - cmp.value = '#id'; - fixture.detectChanges(); + cmp.value = '#id'; + fixture.detectChanges(); - expect(getDOM().getAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href')) - .toEqual('#id'); + expect(getDOM().getAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href')) + .toEqual('#id'); - cmp.value = null; - fixture.detectChanges(); + cmp.value = null; + fixture.detectChanges(); - expect(getDOM().hasAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href')) - .toEqual(false); - }); + expect(getDOM().hasAttributeNS(useEl, 'http://www.w3.org/1999/xlink', 'href')) + .toEqual(false); + }); }); } }); diff --git a/packages/core/test/linker/jit_summaries_integration_spec.ts b/packages/core/test/linker/jit_summaries_integration_spec.ts index c1cb61ada6..170bd288f0 100644 --- a/packages/core/test/linker/jit_summaries_integration_spec.ts +++ b/packages/core/test/linker/jit_summaries_integration_spec.ts @@ -12,133 +12,136 @@ import {MockResourceLoader} from '@angular/compiler/testing/src/resource_loader_ import {Component, Directive, Injectable, NgModule, OnDestroy, Pipe} from '@angular/core'; import {TestBed, async, getTestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy} from '@angular/private/testing'; +import {obsoleteInIvy} from '@angular/private/testing'; { - describe('Jit Summaries', () => { - let instances: Map; - let summaries: () => any[]; + obsoleteInIvy('Summaries are not used/supported/able to be produced in Ivy. See FW-838.') + .describe('Jit Summaries', () => { + let instances: Map; + let summaries: () => any[]; - class SomeDep {} + class SomeDep {} - class Base { - static annotations: any[]; - static parameters: any[][]; + class Base { + static annotations: any[]; + static parameters: any[][]; - constructor(public dep: SomeDep) { - instances.set(Object.getPrototypeOf(this).constructor, this); - } - } + constructor(public dep: SomeDep) { + instances.set(Object.getPrototypeOf(this).constructor, this); + } + } - function expectInstanceCreated(type: any) { - const instance = instances.get(type) !; - expect(instance).toBeDefined(); - expect(instance.dep instanceof SomeDep).toBe(true); - } + function expectInstanceCreated(type: any) { + const instance = instances.get(type) !; + expect(instance).toBeDefined(); + expect(instance.dep instanceof SomeDep).toBe(true); + } - class SomeModule extends Base {} + class SomeModule extends Base {} - class SomePrivateComponent extends Base {} + class SomePrivateComponent extends Base {} - class SomePublicComponent extends Base {} + class SomePublicComponent extends Base {} - class SomeDirective extends Base {} + class SomeDirective extends Base {} - class SomePipe extends Base { - transform(value: any) { return value; } - } + class SomePipe extends Base { + transform(value: any) { return value; } + } - class SomeService extends Base {} + class SomeService extends Base {} - // Move back into the it which needs it after https://github.com/angular/tsickle/issues/547 is - // fixed. - @Component({template: '
    {{1 | somePipe}}
    '}) - class TestComp3 { - constructor(service: SomeService) {} - } + // Move back into the it which needs it after https://github.com/angular/tsickle/issues/547 + // is + // fixed. + @Component({template: '
    {{1 | somePipe}}
    '}) + class TestComp3 { + constructor(service: SomeService) {} + } - @Component({template: ''}) - class TestCompErrorOnDestroy implements OnDestroy { - ngOnDestroy() {} - } + @Component({template: ''}) + class TestCompErrorOnDestroy implements OnDestroy { + ngOnDestroy() {} + } - function resetTestEnvironmentWithSummaries(summaries?: () => any[]) { - const {platform, ngModule} = getTestBed(); - TestBed.resetTestEnvironment(); - TestBed.initTestEnvironment(ngModule, platform, summaries); - } + function resetTestEnvironmentWithSummaries(summaries?: () => any[]) { + const {platform, ngModule} = getTestBed(); + TestBed.resetTestEnvironment(); + TestBed.initTestEnvironment(ngModule, platform, summaries); + } - function createSummaries() { - const resourceLoader = new MockResourceLoader(); + function createSummaries() { + const resourceLoader = new MockResourceLoader(); - setMetadata(resourceLoader); + setMetadata(resourceLoader); - TestBed.configureCompiler({providers: [{provide: ResourceLoader, useValue: resourceLoader}]}); - TestBed.configureTestingModule({imports: [SomeModule], providers: [SomeDep]}); + TestBed.configureCompiler( + {providers: [{provide: ResourceLoader, useValue: resourceLoader}]}); + TestBed.configureTestingModule({imports: [SomeModule], providers: [SomeDep]}); - let summariesPromise = TestBed.compileComponents().then(() => { - const metadataResolver = TestBed.get(CompileMetadataResolver) as CompileMetadataResolver; - const summaries = [ - metadataResolver.getNgModuleSummary(SomeModule), - // test nesting via closures, as we use this in the generated code too. - () => - [metadataResolver.getDirectiveSummary(SomePublicComponent), - metadataResolver.getDirectiveSummary(SomePrivateComponent), - ], - metadataResolver.getDirectiveSummary(SomeDirective), - metadataResolver.getPipeSummary(SomePipe), - metadataResolver.getInjectableSummary(SomeService) - ]; - clearMetadata(); - TestBed.resetTestingModule(); - return () => summaries; - }); + let summariesPromise = TestBed.compileComponents().then(() => { + const metadataResolver = + TestBed.get(CompileMetadataResolver) as CompileMetadataResolver; + const summaries = [ + metadataResolver.getNgModuleSummary(SomeModule), + // test nesting via closures, as we use this in the generated code too. + () => + [metadataResolver.getDirectiveSummary(SomePublicComponent), + metadataResolver.getDirectiveSummary(SomePrivateComponent), + ], + metadataResolver.getDirectiveSummary(SomeDirective), + metadataResolver.getPipeSummary(SomePipe), + metadataResolver.getInjectableSummary(SomeService) + ]; + clearMetadata(); + TestBed.resetTestingModule(); + return () => summaries; + }); - resourceLoader.flush(); - return summariesPromise; - } + resourceLoader.flush(); + return summariesPromise; + } - function setMetadata(resourceLoader: MockResourceLoader) { - Base.parameters = [[SomeDep]]; + function setMetadata(resourceLoader: MockResourceLoader) { + Base.parameters = [[SomeDep]]; - SomeModule.annotations = [new NgModule({ - declarations: [SomePublicComponent, SomePrivateComponent, SomeDirective, SomePipe], - exports: [SomeDirective, SomePipe, SomePublicComponent], - providers: [SomeService] - })]; + SomeModule.annotations = [new NgModule({ + declarations: [SomePublicComponent, SomePrivateComponent, SomeDirective, SomePipe], + exports: [SomeDirective, SomePipe, SomePublicComponent], + providers: [SomeService] + })]; - SomePublicComponent.annotations = [new Component({templateUrl: 'somePublicUrl.html'})]; - resourceLoader.expect('somePublicUrl.html', `Hello public world!`); + SomePublicComponent.annotations = [new Component({templateUrl: 'somePublicUrl.html'})]; + resourceLoader.expect('somePublicUrl.html', `Hello public world!`); - SomePrivateComponent.annotations = [new Component({templateUrl: 'somePrivateUrl.html'})]; - resourceLoader.expect('somePrivateUrl.html', `Hello private world!`); + SomePrivateComponent.annotations = [new Component({templateUrl: 'somePrivateUrl.html'})]; + resourceLoader.expect('somePrivateUrl.html', `Hello private world!`); - SomeDirective.annotations = [new Directive({selector: '[someDir]'})]; + SomeDirective.annotations = [new Directive({selector: '[someDir]'})]; - SomePipe.annotations = [new Pipe({name: 'somePipe'})]; + SomePipe.annotations = [new Pipe({name: 'somePipe'})]; - SomeService.annotations = [new Injectable()]; - } + SomeService.annotations = [new Injectable()]; + } - function clearMetadata() { - Base.parameters = []; - SomeModule.annotations = []; - SomePublicComponent.annotations = []; - SomePrivateComponent.annotations = []; - SomeDirective.annotations = []; - SomePipe.annotations = []; - SomeService.annotations = []; - } + function clearMetadata() { + Base.parameters = []; + SomeModule.annotations = []; + SomePublicComponent.annotations = []; + SomePrivateComponent.annotations = []; + SomeDirective.annotations = []; + SomePipe.annotations = []; + SomeService.annotations = []; + } - beforeEach(async(() => { - instances = new Map(); - createSummaries().then(s => summaries = s); - })); + beforeEach(async(() => { + instances = new Map(); + createSummaries().then(s => summaries = s); + })); - afterEach(() => { resetTestEnvironmentWithSummaries(); }); + afterEach(() => { resetTestEnvironmentWithSummaries(); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should use directive metadata from summaries', () => { + it('should use directive metadata from summaries', () => { resetTestEnvironmentWithSummaries(summaries); @Component({template: '
    '}) @@ -152,8 +155,8 @@ import {fixmeIvy} from '@angular/private/testing'; expectInstanceCreated(SomeDirective); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should use pipe metadata from summaries', () => { + + it('should use pipe metadata from summaries', () => { resetTestEnvironmentWithSummaries(summaries); @Component({template: '{{1 | somePipe}}'}) @@ -165,8 +168,7 @@ import {fixmeIvy} from '@angular/private/testing'; expectInstanceCreated(SomePipe); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should use Service metadata from summaries', () => { + it('should use Service metadata from summaries', () => { resetTestEnvironmentWithSummaries(summaries); TestBed.configureTestingModule({ @@ -176,8 +178,7 @@ import {fixmeIvy} from '@angular/private/testing'; expectInstanceCreated(SomeService); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should use NgModule metadata from summaries', () => { + it('should use NgModule metadata from summaries', () => { resetTestEnvironmentWithSummaries(summaries); TestBed @@ -191,8 +192,7 @@ import {fixmeIvy} from '@angular/private/testing'; expectInstanceCreated(SomeService); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should allow to create private components from imported NgModule summaries', () => { + it('should allow to create private components from imported NgModule summaries', () => { resetTestEnvironmentWithSummaries(summaries); TestBed.configureTestingModule({providers: [SomeDep], imports: [SomeModule]}) @@ -200,8 +200,7 @@ import {fixmeIvy} from '@angular/private/testing'; expectInstanceCreated(SomePrivateComponent); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should throw when trying to mock a type with a summary', () => { + it('should throw when trying to mock a type with a summary', () => { resetTestEnvironmentWithSummaries(summaries); TestBed.resetTestingModule(); @@ -220,35 +219,33 @@ import {fixmeIvy} from '@angular/private/testing'; .toThrowError('SomeModule was AOT compiled, so its metadata cannot be changed.'); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should return stack trace and component data on resetTestingModule when error is thrown', - () => { - resetTestEnvironmentWithSummaries(); + it('should return stack trace and component data on resetTestingModule when error is thrown', + () => { + resetTestEnvironmentWithSummaries(); - const fixture = - TestBed.configureTestingModule({declarations: [TestCompErrorOnDestroy]}) - .createComponent(TestCompErrorOnDestroy); + const fixture = + TestBed.configureTestingModule({declarations: [TestCompErrorOnDestroy]}) + .createComponent(TestCompErrorOnDestroy); - const expectedError = 'Error from ngOnDestroy'; + const expectedError = 'Error from ngOnDestroy'; - const component: TestCompErrorOnDestroy = fixture.componentInstance; + const component: TestCompErrorOnDestroy = fixture.componentInstance; - spyOn(console, 'error'); - spyOn(component, 'ngOnDestroy').and.throwError(expectedError); + spyOn(console, 'error'); + spyOn(component, 'ngOnDestroy').and.throwError(expectedError); - const expectedObject = { - stacktrace: new Error(expectedError), - component, - }; + const expectedObject = { + stacktrace: new Error(expectedError), + component, + }; - TestBed.resetTestingModule(); + TestBed.resetTestingModule(); - expect(console.error) - .toHaveBeenCalledWith('Error during cleanup of component', expectedObject); - }); + expect(console.error) + .toHaveBeenCalledWith('Error during cleanup of component', expectedObject); + }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should allow to add summaries via configureTestingModule', () => { + it('should allow to add summaries via configureTestingModule', () => { resetTestEnvironmentWithSummaries(); @Component({template: '
    '}) @@ -265,8 +262,7 @@ import {fixmeIvy} from '@angular/private/testing'; expectInstanceCreated(SomeDirective); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should allow to override a provider', () => { + it('should allow to override a provider', () => { resetTestEnvironmentWithSummaries(summaries); const overwrittenValue = {}; @@ -279,8 +275,7 @@ import {fixmeIvy} from '@angular/private/testing'; expect(fixture.componentInstance.dep).toBe(overwrittenValue); }); - fixmeIvy('FW-838: ivy testbed doesn\'t support jit summaries') - .it('should allow to override a template', () => { + it('should allow to override a template', () => { resetTestEnvironmentWithSummaries(summaries); TestBed.overrideTemplateUsingTestingModule(SomePublicComponent, 'overwritten'); @@ -292,5 +287,5 @@ import {fixmeIvy} from '@angular/private/testing'; expect(fixture.nativeElement).toHaveText('overwritten'); }); - }); + }); } diff --git a/packages/core/test/linker/ng_container_integration_spec.ts b/packages/core/test/linker/ng_container_integration_spec.ts index 8d5a93a6e7..7382d7ac1b 100644 --- a/packages/core/test/linker/ng_container_integration_spec.ts +++ b/packages/core/test/linker/ng_container_integration_spec.ts @@ -11,7 +11,7 @@ import {AfterContentInit, AfterViewInit, Component, ContentChildren, Directive, import {TestBed} from '@angular/core/testing'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, modifiedInIvy, polyfillGoogGetMsg} from '@angular/private/testing'; +import {modifiedInIvy, polyfillGoogGetMsg} from '@angular/private/testing'; if (ivyEnabled) { describe('ivy', () => { declareTests(); }); @@ -136,7 +136,7 @@ function declareTests(config?: {useJit: boolean}) { expect(dir.text).toEqual('container'); }); - fixmeIvy('FW-795: Queries with descendants: true don\'t descent into ') + modifiedInIvy('Queries with descendants: true don\'t descent into ') .it('should contain all direct child directives in a (content dom)', () => { const template = '
    '; diff --git a/packages/core/test/linker/ng_module_integration_spec.ts b/packages/core/test/linker/ng_module_integration_spec.ts index de680d08fe..669d48da96 100644 --- a/packages/core/test/linker/ng_module_integration_spec.ts +++ b/packages/core/test/linker/ng_module_integration_spec.ts @@ -6,19 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ -import {ANALYZE_FOR_ENTRY_COMPONENTS, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, ComponentFactoryResolver, Directive, HostBinding, Inject, Injectable, InjectionToken, Injector, Input, NgModule, NgModuleRef, Optional, Pipe, Provider, Self, Type, forwardRef, getModuleFactory, ɵivyEnabled as ivyEnabled} from '@angular/core'; +import {ANALYZE_FOR_ENTRY_COMPONENTS, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, Compiler, Component, ComponentFactoryResolver, Directive, HostBinding, Inject, Injectable, InjectionToken, Injector, Input, NgModule, NgModuleRef, Optional, Pipe, Provider, Self, Type, forwardRef, getModuleFactory, ɵivyEnabled as ivyEnabled} from '@angular/core'; import {Console} from '@angular/core/src/console'; -import {InjectableDef, defineInjectable} from '@angular/core/src/di/defs'; +import {InjectableDef, defineInjectable} from '@angular/core/src/di/interface/defs'; import {getNgModuleDef} from '@angular/core/src/render3/definition'; import {NgModuleData} from '@angular/core/src/view/types'; import {tokenKey} from '@angular/core/src/view/util'; import {ComponentFixture, TestBed, inject} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, modifiedInIvy, obsoleteInIvy} from '@angular/private/testing'; +import {fixmeIvy, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; import {InternalNgModuleRef, NgModuleFactory} from '../../src/linker/ng_module_factory'; import {clearModulesForTest} from '../../src/linker/ng_module_factory_loader'; -import {stringify} from '../../src/util'; +import {stringify} from '../../src/util/stringify'; class Engine {} @@ -239,7 +239,7 @@ function declareTests(config?: {useJit: boolean}) { }); describe('schemas', () => { - fixmeIvy('FW-819: ngtsc compiler should support schemas') + modifiedInIvy('Unknown property error thrown during update mode, not creation mode') .it('should error on unknown bound properties on custom elements by default', () => { @Component({template: ''}) class ComponentUsingInvalidProperty { @@ -252,18 +252,42 @@ function declareTests(config?: {useJit: boolean}) { expect(() => createModule(SomeModule)).toThrowError(/Can't bind to 'someUnknownProp'/); }); + onlyInIvy('Unknown property error thrown during update mode, not creation mode') + .it('should error on unknown bound properties on custom elements by default', () => { + @Component({template: ''}) + class ComponentUsingInvalidProperty { + } + + @NgModule({declarations: [ComponentUsingInvalidProperty]}) + class SomeModule { + } + + const fixture = createComp(ComponentUsingInvalidProperty, SomeModule); + expect(() => fixture.detectChanges()).toThrowError(/Can't bind to 'someUnknownProp'/); + }); + it('should not error on unknown bound properties on custom elements when using the CUSTOM_ELEMENTS_SCHEMA', () => { @Component({template: ''}) class ComponentUsingInvalidProperty { } - @NgModule( - {schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [ComponentUsingInvalidProperty]}) + @NgModule({ + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [ComponentUsingInvalidProperty], + + // Note that we need to add the component to `entryComponents`, because of the + // `createComp` call below. In Ivy the property validation happens during the + // update phase so we need to create the component, in order for it to run. + entryComponents: [ComponentUsingInvalidProperty] + }) class SomeModule { } - expect(() => createModule(SomeModule)).not.toThrow(); + expect(() => { + const fixture = createComp(ComponentUsingInvalidProperty, SomeModule); + fixture.detectChanges(); + }).not.toThrow(); }); }); @@ -423,163 +447,155 @@ function declareTests(config?: {useJit: boolean}) { }); describe('directives and pipes', () => { - fixmeIvy('FW-681: not possible to retrieve host property bindings from TView') - .describe('declarations', () => { - it('should be supported in root modules', () => { - @NgModule({ - declarations: [CompUsingModuleDirectiveAndPipe, SomeDirective, SomePipe], - entryComponents: [CompUsingModuleDirectiveAndPipe] - }) - class SomeModule { - } + describe('declarations', () => { + it('should be supported in root modules', () => { + @NgModule({ + declarations: [CompUsingModuleDirectiveAndPipe, SomeDirective, SomePipe], + entryComponents: [CompUsingModuleDirectiveAndPipe] + }) + class SomeModule { + } - const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); + const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].properties['title']) - .toBe('transformed someValue'); - }); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].properties['title']) + .toBe('transformed someValue'); + }); - it('should be supported in imported modules', () => { - @NgModule({ - declarations: [CompUsingModuleDirectiveAndPipe, SomeDirective, SomePipe], - entryComponents: [CompUsingModuleDirectiveAndPipe] - }) - class SomeImportedModule { - } + it('should be supported in imported modules', () => { + @NgModule({ + declarations: [CompUsingModuleDirectiveAndPipe, SomeDirective, SomePipe], + entryComponents: [CompUsingModuleDirectiveAndPipe] + }) + class SomeImportedModule { + } - @NgModule({imports: [SomeImportedModule]}) - class SomeModule { - } + @NgModule({imports: [SomeImportedModule]}) + class SomeModule { + } - const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].properties['title']) - .toBe('transformed someValue'); - }); + const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].properties['title']) + .toBe('transformed someValue'); + }); - it('should be supported in nested components', () => { - @Component({ - selector: 'parent', - template: '', - }) - class ParentCompUsingModuleDirectiveAndPipe { - } + it('should be supported in nested components', () => { + @Component({ + selector: 'parent', + template: '', + }) + class ParentCompUsingModuleDirectiveAndPipe { + } - @NgModule({ - declarations: [ - ParentCompUsingModuleDirectiveAndPipe, CompUsingModuleDirectiveAndPipe, - SomeDirective, SomePipe - ], - entryComponents: [ParentCompUsingModuleDirectiveAndPipe] - }) - class SomeModule { - } + @NgModule({ + declarations: [ + ParentCompUsingModuleDirectiveAndPipe, CompUsingModuleDirectiveAndPipe, SomeDirective, + SomePipe + ], + entryComponents: [ParentCompUsingModuleDirectiveAndPipe] + }) + class SomeModule { + } - const compFixture = createComp(ParentCompUsingModuleDirectiveAndPipe, SomeModule); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].children[0].properties['title']) - .toBe('transformed someValue'); - }); - }); + const compFixture = createComp(ParentCompUsingModuleDirectiveAndPipe, SomeModule); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].children[0].properties['title']) + .toBe('transformed someValue'); + }); + }); describe('import/export', () => { - fixmeIvy('FW-756: Pipes and directives from imported modules are not taken into account') - .it('should support exported directives and pipes', () => { - @NgModule( - {declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) - class SomeImportedModule { - } + it('should support exported directives and pipes', () => { + @NgModule({declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) + class SomeImportedModule { + } - @NgModule({ - declarations: [CompUsingModuleDirectiveAndPipe], - imports: [SomeImportedModule], - entryComponents: [CompUsingModuleDirectiveAndPipe] - }) - class SomeModule { - } + @NgModule({ + declarations: [CompUsingModuleDirectiveAndPipe], + imports: [SomeImportedModule], + entryComponents: [CompUsingModuleDirectiveAndPipe] + }) + class SomeModule { + } - const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].properties['title']) - .toBe('transformed someValue'); - }); + const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].properties['title']) + .toBe('transformed someValue'); + }); - fixmeIvy('FW-756: Pipes and directives from imported modules are not taken into account') - .it('should support exported directives and pipes if the module is wrapped into an `ModuleWithProviders`', - () => { - @NgModule( - {declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) - class SomeImportedModule { - } + it('should support exported directives and pipes if the module is wrapped into an `ModuleWithProviders`', + () => { + @NgModule( + {declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) + class SomeImportedModule { + } - @NgModule({ - declarations: [CompUsingModuleDirectiveAndPipe], - imports: [{ngModule: SomeImportedModule}], - entryComponents: [CompUsingModuleDirectiveAndPipe] - }) - class SomeModule { - } + @NgModule({ + declarations: [CompUsingModuleDirectiveAndPipe], + imports: [{ngModule: SomeImportedModule}], + entryComponents: [CompUsingModuleDirectiveAndPipe] + }) + class SomeModule { + } - const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].properties['title']) - .toBe('transformed someValue'); - }); + const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].properties['title']) + .toBe('transformed someValue'); + }); - fixmeIvy('FW-756: Pipes and directives from imported modules are not taken into account') - .it('should support reexported modules', () => { - @NgModule( - {declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) - class SomeReexportedModule { - } + it('should support reexported modules', () => { + @NgModule({declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) + class SomeReexportedModule { + } - @NgModule({exports: [SomeReexportedModule]}) - class SomeImportedModule { - } + @NgModule({exports: [SomeReexportedModule]}) + class SomeImportedModule { + } - @NgModule({ - declarations: [CompUsingModuleDirectiveAndPipe], - imports: [SomeImportedModule], - entryComponents: [CompUsingModuleDirectiveAndPipe] - }) - class SomeModule { - } + @NgModule({ + declarations: [CompUsingModuleDirectiveAndPipe], + imports: [SomeImportedModule], + entryComponents: [CompUsingModuleDirectiveAndPipe] + }) + class SomeModule { + } - const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].properties['title']) - .toBe('transformed someValue'); - }); + const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].properties['title']) + .toBe('transformed someValue'); + }); - fixmeIvy('FW-756: Pipes and directives from imported modules are not taken into account') - .it('should support exporting individual directives of an imported module', () => { - @NgModule( - {declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) - class SomeReexportedModule { - } + it('should support exporting individual directives of an imported module', () => { + @NgModule({declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) + class SomeReexportedModule { + } - @NgModule({imports: [SomeReexportedModule], exports: [SomeDirective, SomePipe]}) - class SomeImportedModule { - } + @NgModule({imports: [SomeReexportedModule], exports: [SomeDirective, SomePipe]}) + class SomeImportedModule { + } - @NgModule({ - declarations: [CompUsingModuleDirectiveAndPipe], - imports: [SomeImportedModule], - entryComponents: [CompUsingModuleDirectiveAndPipe] - }) - class SomeModule { - } + @NgModule({ + declarations: [CompUsingModuleDirectiveAndPipe], + imports: [SomeImportedModule], + entryComponents: [CompUsingModuleDirectiveAndPipe] + }) + class SomeModule { + } - const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].properties['title']) - .toBe('transformed someValue'); - }); + const compFixture = createComp(CompUsingModuleDirectiveAndPipe, SomeModule); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].properties['title']) + .toBe('transformed someValue'); + }); it('should not use non exported pipes of an imported module', () => { @NgModule({ @@ -742,8 +758,11 @@ function declareTests(config?: {useJit: boolean}) { it('should throw when the aliased provider does not exist', () => { const injector = createInjector([{provide: 'car', useExisting: SportsCar}]); - const e = `NullInjectorError: No provider for ${stringify(SportsCar)}!`; - expect(() => injector.get('car')).toThrowError(e); + let errorMsg = `NullInjectorError: No provider for ${stringify(SportsCar)}!`; + if (ivyEnabled) { + errorMsg = `R3InjectorError(SomeModule)[car -> SportsCar]: \n ` + errorMsg; + } + expect(() => injector.get('car')).toThrowError(errorMsg); }); it('should handle forwardRef in useExisting', () => { @@ -938,8 +957,11 @@ function declareTests(config?: {useJit: boolean}) { it('should throw when no provider defined', () => { const injector = createInjector([]); - expect(() => injector.get('NonExisting')) - .toThrowError('NullInjectorError: No provider for NonExisting!'); + let errorMsg = 'NullInjectorError: No provider for NonExisting!'; + if (ivyEnabled) { + errorMsg = `R3InjectorError(SomeModule)[NonExisting]: \n ` + errorMsg; + } + expect(() => injector.get('NonExisting')).toThrowError(errorMsg); }); it('should throw when trying to instantiate a cyclic dependency', () => { @@ -1045,55 +1067,53 @@ function declareTests(config?: {useJit: boolean}) { expect(created).toBe(false); }); - fixmeIvy('FW-739: TestBed: destroy on NgModuleRef is not being called') - .it('should support ngOnDestroy on any provider', () => { - let destroyed = false; + it('should support ngOnDestroy on any provider', () => { + let destroyed = false; - class SomeInjectable { - ngOnDestroy() { destroyed = true; } - } + class SomeInjectable { + ngOnDestroy() { destroyed = true; } + } - @NgModule({providers: [SomeInjectable]}) - class SomeModule { - // Inject SomeInjectable to make it eager... - constructor(i: SomeInjectable) {} - } + @NgModule({providers: [SomeInjectable]}) + class SomeModule { + // Inject SomeInjectable to make it eager... + constructor(i: SomeInjectable) {} + } - const moduleRef = createModule(SomeModule); - expect(destroyed).toBe(false); - moduleRef.destroy(); - expect(destroyed).toBe(true); - }); + const moduleRef = createModule(SomeModule); + expect(destroyed).toBe(false); + moduleRef.destroy(); + expect(destroyed).toBe(true); + }); - fixmeIvy('FW-739: TestBed: destroy on NgModuleRef is not being called') - .it('should support ngOnDestroy for lazy providers', () => { - let created = false; - let destroyed = false; + it('should support ngOnDestroy for lazy providers', () => { + let created = false; + let destroyed = false; - class SomeInjectable { - constructor() { created = true; } - ngOnDestroy() { destroyed = true; } - } + class SomeInjectable { + constructor() { created = true; } + ngOnDestroy() { destroyed = true; } + } - @NgModule({providers: [SomeInjectable]}) - class SomeModule { - } + @NgModule({providers: [SomeInjectable]}) + class SomeModule { + } - let moduleRef = createModule(SomeModule); - expect(created).toBe(false); - expect(destroyed).toBe(false); + let moduleRef = createModule(SomeModule); + expect(created).toBe(false); + expect(destroyed).toBe(false); - // no error if the provider was not yet created - moduleRef.destroy(); - expect(created).toBe(false); - expect(destroyed).toBe(false); + // no error if the provider was not yet created + moduleRef.destroy(); + expect(created).toBe(false); + expect(destroyed).toBe(false); - moduleRef = createModule(SomeModule); - moduleRef.injector.get(SomeInjectable); - expect(created).toBe(true); - moduleRef.destroy(); - expect(destroyed).toBe(true); - }); + moduleRef = createModule(SomeModule); + moduleRef.injector.get(SomeInjectable); + expect(created).toBe(true); + moduleRef.destroy(); + expect(destroyed).toBe(true); + }); }); describe('imported and exported modules', () => { @@ -1326,7 +1346,7 @@ function declareTests(config?: {useJit: boolean}) { }); describe('tree shakable providers', () => { - fixmeIvy('FW-794: NgModuleDefinition not exposed on NgModuleData') + modifiedInIvy('Ivy and VE have different internal fields to access providers') .it('definition should not persist across NgModuleRef instances', () => { @NgModule() class SomeModule { @@ -1357,6 +1377,36 @@ function declareTests(config?: {useJit: boolean}) { (ngModuleRef2 as NgModuleData)._def.providersByKey[tokenKey(Bar)]; expect(providerDef2).toBeUndefined(); }); + + onlyInIvy(`Ivy and VE have different internal fields to access providers`) + .it('definition should not persist across NgModuleRef instances', () => { + @NgModule() + class SomeModule { + } + + class Bar { + static ngInjectableDef: InjectableDef = defineInjectable({ + factory: () => new Bar(), + providedIn: SomeModule, + }); + } + + const factory = createModuleFactory(SomeModule); + const ngModuleRef1 = factory.create(null); + + // Inject a tree shakeable provider token. + ngModuleRef1.injector.get(Bar); + + // Tree Shakeable provider definition should be available. + const providerDef1 = (ngModuleRef1 as any)._r3Injector.records.get(Bar); + expect(providerDef1).not.toBeUndefined(); + + // Instantiate the same module. The tree shakeable provider definition should not be + // present. + const ngModuleRef2 = factory.create(null); + const providerDef2 = (ngModuleRef2 as any)._r3Injector.records.get(Bar); + expect(providerDef2).toBeUndefined(); + }); }); }); }); diff --git a/packages/core/test/linker/projection_integration_spec.ts b/packages/core/test/linker/projection_integration_spec.ts index d41a092e41..65a2233fdc 100644 --- a/packages/core/test/linker/projection_integration_spec.ts +++ b/packages/core/test/linker/projection_integration_spec.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Directive, ElementRef, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core'; -import {TestBed} from '@angular/core/testing'; +import {Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, Injector, NgModule, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -81,22 +81,35 @@ describe('projection', () => { expect(main.nativeElement).toHaveText(''); }); - fixmeIvy('FW-833: Directive / projected node matching against class name') - .it('should support multiple content tags', () => { - TestBed.configureTestingModule({declarations: [MultipleContentTagsComponent]}); - TestBed.overrideComponent(MainComp, { - set: { - template: '' + - '
    B
    ' + - '
    C
    ' + - '
    A
    ' + - '
    ' - } - }); - const main = TestBed.createComponent(MainComp); + it('should project a single class-based tag', () => { + TestBed.configureTestingModule({declarations: [SingleContentTagComponent]}); + TestBed.overrideComponent(MainComp, { + set: { + template: '' + + '
    I AM PROJECTED
    ' + + '
    ' + } + }); + const main = TestBed.createComponent(MainComp); - expect(main.nativeElement).toHaveText('(A, BC)'); - }); + expect(main.nativeElement).toHaveText('I AM PROJECTED'); + }); + + it('should support multiple content tags', () => { + TestBed.configureTestingModule({declarations: [MultipleContentTagsComponent]}); + TestBed.overrideComponent(MainComp, { + set: { + template: '' + + '
    B
    ' + + '
    C
    ' + + '
    A
    ' + + '
    ' + } + }); + const main = TestBed.createComponent(MainComp); + + expect(main.nativeElement).toHaveText('(A, BC)'); + }); it('should redistribute only direct children', () => { TestBed.configureTestingModule({declarations: [MultipleContentTagsComponent]}); @@ -182,35 +195,34 @@ describe('projection', () => { expect(main.nativeElement).toHaveText('OUTER(INNER(INNERINNER(A,BC)))'); }); - fixmeIvy('FW-833: Directive / projected node matching against class name') - .it('should redistribute when the shadow dom changes', () => { - TestBed.configureTestingModule( - {declarations: [ConditionalContentComponent, ManualViewportDirective]}); - TestBed.overrideComponent(MainComp, { - set: { - template: '' + - '
    A
    ' + - '
    B
    ' + - '
    C
    ' + - '
    ' - } - }); - const main = TestBed.createComponent(MainComp); + it('should redistribute when the shadow dom changes', () => { + TestBed.configureTestingModule( + {declarations: [ConditionalContentComponent, ManualViewportDirective]}); + TestBed.overrideComponent(MainComp, { + set: { + template: '' + + '
    A
    ' + + '
    B
    ' + + '
    C
    ' + + '
    ' + } + }); + const main = TestBed.createComponent(MainComp); - const viewportDirective = - main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get( - ManualViewportDirective); + const viewportDirective = + main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get( + ManualViewportDirective); - expect(main.nativeElement).toHaveText('(, BC)'); + expect(main.nativeElement).toHaveText('(, BC)'); - viewportDirective.show(); - main.detectChanges(); - expect(main.nativeElement).toHaveText('(A, BC)'); + viewportDirective.show(); + main.detectChanges(); + expect(main.nativeElement).toHaveText('(A, BC)'); - viewportDirective.hide(); - main.detectChanges(); - expect(main.nativeElement).toHaveText('(, BC)'); - }); + viewportDirective.hide(); + main.detectChanges(); + expect(main.nativeElement).toHaveText('(, BC)'); + }); // GH-2095 - https://github.com/angular/angular/issues/2095 // important as we are removing the ng-content element during compilation, @@ -290,38 +302,36 @@ describe('projection', () => { expect(main.nativeElement).toHaveText('SIMPLE()START(A)END'); }); - fixmeIvy('FW-833: Directive / projected node matching against class name') - .it('should support moving ng-content around', () => { - TestBed.configureTestingModule({ - declarations: [ConditionalContentComponent, ProjectDirective, ManualViewportDirective] - }); - TestBed.overrideComponent(MainComp, { - set: { - template: '' + - '
    A
    ' + - '
    B
    ' + - '
    ' + - 'START(
    )END' - } - }); - const main = TestBed.createComponent(MainComp); + it('should support moving ng-content around', () => { + TestBed.configureTestingModule( + {declarations: [ConditionalContentComponent, ProjectDirective, ManualViewportDirective]}); + TestBed.overrideComponent(MainComp, { + set: { + template: '' + + '
    A
    ' + + '
    B
    ' + + '
    ' + + 'START(
    )END' + } + }); + const main = TestBed.createComponent(MainComp); - const sourceDirective: ManualViewportDirective = - main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get( - ManualViewportDirective); - const projectDirective: ProjectDirective = - main.debugElement.queryAllNodes(By.directive(ProjectDirective))[0].injector.get( - ProjectDirective); - expect(main.nativeElement).toHaveText('(, B)START()END'); + const sourceDirective: ManualViewportDirective = + main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get( + ManualViewportDirective); + const projectDirective: ProjectDirective = + main.debugElement.queryAllNodes(By.directive(ProjectDirective))[0].injector.get( + ProjectDirective); + expect(main.nativeElement).toHaveText('(, B)START()END'); - projectDirective.show(sourceDirective.templateRef); - expect(main.nativeElement).toHaveText('(, B)START(A)END'); + projectDirective.show(sourceDirective.templateRef); + expect(main.nativeElement).toHaveText('(, B)START(A)END'); - // Stamping ng-content multiple times should not produce the content multiple - // times... - projectDirective.show(sourceDirective.templateRef); - expect(main.nativeElement).toHaveText('(, B)START(A)END'); - }); + // Stamping ng-content multiple times should not produce the content multiple + // times... + projectDirective.show(sourceDirective.templateRef); + expect(main.nativeElement).toHaveText('(, B)START(A)END'); + }); // Note: This does not use a ng-content element, but // is still important as we are merging proto views independent of @@ -371,22 +381,21 @@ describe('projection', () => { }); if (getDOM().supportsNativeShadowDOM()) { - fixmeIvy('FW-841: Content projection with ShadovDom v0 doesn\'t work') - .it('should support native content projection and isolate styles per component', () => { - TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]}); - TestBed.overrideComponent(MainComp, { - set: { - template: '
    A
    ' + - '
    B
    ' - } - }); - const main = TestBed.createComponent(MainComp); + it('should support native content projection and isolate styles per component', () => { + TestBed.configureTestingModule({declarations: [SimpleNative1, SimpleNative2]}); + TestBed.overrideComponent(MainComp, { + set: { + template: '
    A
    ' + + '
    B
    ' + } + }); + const main = TestBed.createComponent(MainComp); - const childNodes = getDOM().childNodes(main.nativeElement); - expect(childNodes[0]).toHaveText('div {color: red}SIMPLE1(A)'); - expect(childNodes[1]).toHaveText('div {color: blue}SIMPLE2(B)'); - main.destroy(); - }); + const childNodes = getDOM().childNodes(main.nativeElement); + expect(childNodes[0]).toHaveText('div {color: red}SIMPLE1(A)'); + expect(childNodes[1]).toHaveText('div {color: blue}SIMPLE2(B)'); + main.destroy(); + }); } if (getDOM().supportsDOMEvents()) { @@ -533,7 +542,32 @@ describe('projection', () => { expect(main.nativeElement).toHaveText('B(A)'); }); - fixmeIvy('FW-833: Directive / projected node matching against class name') + it('should project view containers', () => { + TestBed.configureTestingModule( + {declarations: [SingleContentTagComponent, ManualViewportDirective]}); + TestBed.overrideComponent(MainComp, { + set: { + template: '' + + '
    A
    ' + + 'B' + + '
    C
    ' + + '
    ' + } + }); + + const main = TestBed.createComponent(MainComp); + const manualDirective = + main.debugElement.queryAllNodes(By.directive(ManualViewportDirective))[0].injector.get( + ManualViewportDirective); + + expect(main.nativeElement).toHaveText('AC'); + + manualDirective.show(); + main.detectChanges(); + expect(main.nativeElement).toHaveText('ABC'); + }); + + fixmeIvy('FW-869: debugElement.queryAllNodes returns nodes in the wrong order') .it('should project filled view containers into a view container', () => { TestBed.configureTestingModule( {declarations: [ConditionalContentComponent, ManualViewportDirective]}); @@ -576,6 +610,121 @@ describe('projection', () => { main.detectChanges(); expect(main.nativeElement).toHaveText('(, D)'); }); + + describe('projectable nodes', () => { + + @Component({selector: 'test', template: ''}) + class TestComponent { + constructor(public cfr: ComponentFactoryResolver) {} + } + + @Component({selector: 'with-content', template: ''}) + class WithContentCmpt { + @ViewChild('ref') directiveRef: any; + } + + @Component({selector: 're-project', template: ''}) + class ReProjectCmpt { + } + + @Directive({selector: '[insert]'}) + class InsertTplRef implements OnInit { + constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {} + + ngOnInit() { this._vcRef.createEmbeddedView(this._tplRef); } + } + + @Directive({selector: '[delayedInsert]', exportAs: 'delayedInsert'}) + class DelayedInsertTplRef { + constructor(public vc: ViewContainerRef, public templateRef: TemplateRef) {} + show() { this.vc.createEmbeddedView(this.templateRef); } + hide() { this.vc.clear(); } + } + + @NgModule({ + declarations: [WithContentCmpt, InsertTplRef, DelayedInsertTplRef, ReProjectCmpt], + entryComponents: [WithContentCmpt] + }) + class TestModule { + } + + let fixture: ComponentFixture; + + function createCmptInstance( + tpl: string, projectableNodes: any[][]): ComponentRef { + TestBed.configureTestingModule({declarations: [TestComponent], imports: [TestModule]}); + TestBed.overrideTemplate(WithContentCmpt, tpl); + + fixture = TestBed.createComponent(TestComponent); + const cfr = fixture.componentInstance.cfr; + const cf = cfr.resolveComponentFactory(WithContentCmpt); + const cmptRef = cf.create(Injector.NULL, projectableNodes); + + cmptRef.changeDetectorRef.detectChanges(); + + return cmptRef; + } + + it('should pass nodes to the default ng-content without selectors', () => { + const cmptRef = createCmptInstance( + '
    ()
    ', [[document.createTextNode('A')]]); + expect(cmptRef.location.nativeElement).toHaveText('(A)'); + }); + + it('should pass nodes to the default ng-content at the root', () => { + const cmptRef = + createCmptInstance('', [[document.createTextNode('A')]]); + expect(cmptRef.location.nativeElement).toHaveText('A'); + }); + + it('should pass nodes to multiple ng-content tags', () => { + const cmptRef = createCmptInstance( + 'A:()B:()C:()', + [ + [document.createTextNode('A')], [document.createTextNode('B')], + [document.createTextNode('C')] + ]); + expect(cmptRef.location.nativeElement).toHaveText('A:(A)B:(B)C:(C)'); + }); + + it('should pass nodes to the default ng-content inside ng-container', () => { + const cmptRef = createCmptInstance( + 'A()C', + [[document.createTextNode('B')]]); + expect(cmptRef.location.nativeElement).toHaveText('A(B)C'); + }); + + it('should pass nodes to the default ng-content inside an embedded view', () => { + const cmptRef = createCmptInstance( + 'A()C', + [[document.createTextNode('B')]]); + expect(cmptRef.location.nativeElement).toHaveText('A(B)C'); + }); + + it('should pass nodes to the default ng-content inside a delayed embedded view', () => { + const cmptRef = createCmptInstance( + 'A([])C', + [[document.createTextNode('B')]]); + expect(cmptRef.location.nativeElement).toHaveText('A()C'); + + const delayedInsert = cmptRef.instance.directiveRef as DelayedInsertTplRef; + + delayedInsert.show(); + cmptRef.changeDetectorRef.detectChanges(); + expect(cmptRef.location.nativeElement).toHaveText('A([B])C'); + + delayedInsert.hide(); + cmptRef.changeDetectorRef.detectChanges(); + expect(cmptRef.location.nativeElement).toHaveText('A()C'); + }); + + it('should re-project at the root', () => { + const cmptRef = createCmptInstance( + 'A[()]C', + [[document.createTextNode('B')]]); + expect(cmptRef.location.nativeElement).toHaveText('A[(B)]C'); + }); + }); }); @Component({selector: 'main', template: ''}) @@ -626,6 +775,13 @@ class Empty { class MultipleContentTagsComponent { } +@Component({ + selector: 'single-content-tag', + template: '', +}) +class SingleContentTagComponent { +} + @Directive({selector: '[manual]'}) class ManualViewportDirective { constructor(public vc: ViewContainerRef, public templateRef: TemplateRef) {} diff --git a/packages/core/test/linker/query_integration_spec.ts b/packages/core/test/linker/query_integration_spec.ts index 41aa635ccb..e93faa1139 100644 --- a/packages/core/test/linker/query_integration_spec.ts +++ b/packages/core/test/linker/query_integration_spec.ts @@ -7,12 +7,13 @@ */ import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, asNativeElements} from '@angular/core'; +import {ElementRef} from '@angular/core/src/core'; import {ComponentFixture, TestBed, async} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, ivyEnabled, modifiedInIvy} from '@angular/private/testing'; +import {fixmeIvy, ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; import {Subject} from 'rxjs'; -import {stringify} from '../../src/util'; +import {stringify} from '../../src/util/stringify'; describe('Query API', () => { @@ -45,6 +46,7 @@ describe('Query API', () => { NeedsContentChildWithRead, NeedsViewChildrenWithRead, NeedsViewChildWithRead, + NeedsContentChildrenShallow, NeedsContentChildTemplateRef, NeedsContentChildTemplateRefApp, NeedsViewContainerWithRead, @@ -53,10 +55,8 @@ describe('Query API', () => { })); describe('querying by directive type', () => { - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should contain all direct child directives in the light dom (constructor)', () => { - const template = ` + it('should contain all direct child directives in the light dom (constructor)', () => { + const template = `
    @@ -65,10 +65,12 @@ describe('Query API', () => {
    `; - const view = createTestCmpAndDetectChanges(MyComp0, template); + const view = createTestCmpAndDetectChanges(MyComp0, template); - expect(asNativeElements(view.debugElement.children)).toHaveText('2|3|'); - }); + // Difference in expected text in ivy comes from the fact that ivy queries don't match host + // nodes of a directive that defines a content query. + expect(asNativeElements(view.debugElement.children)).toHaveText(ivyEnabled ? '3|' : '2|3|'); + }); it('should contain all direct child directives in the content dom', () => { const template = '
    '; @@ -96,21 +98,19 @@ describe('Query API', () => { ]); }); - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should contain the first content child when target is on with embedded view (issue #16568)', - () => { - const template = - '
    ' + - '
    '; - const view = createTestCmp(MyComp0, template); - view.detectChanges(); - const q: NeedsContentChild = view.debugElement.children[1].references !['q']; - expect(q.child.text).toEqual('foo'); - const directive: DirectiveNeedsContentChild = - view.debugElement.children[0].injector.get(DirectiveNeedsContentChild); - expect(directive.child.text).toEqual('foo'); - }); + it('should contain the first content child when target is on with embedded view (issue #16568)', + () => { + const template = + '
    ' + + '
    '; + const view = createTestCmp(MyComp0, template); + view.detectChanges(); + const q: NeedsContentChild = view.debugElement.children[1].references !['q']; + expect(q.child.text).toEqual('foo'); + const directive: DirectiveNeedsContentChild = + view.debugElement.children[0].injector.get(DirectiveNeedsContentChild); + expect(directive.child.text).toEqual('foo'); + }); it('should contain the first view child', () => { const template = ''; @@ -168,43 +168,46 @@ describe('Query API', () => { expect(q.logs).toEqual([['setter', null], ['check', null]]); }); - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should contain all directives in the light dom when descendants flag is used', () => { - const template = '
    ' + - '
    ' + - '
    ' + - '
    ' + - '
    '; - const view = createTestCmpAndDetectChanges(MyComp0, template); + it('should contain all directives in the light dom when descendants flag is used', () => { + const template = '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    '; + const view = createTestCmpAndDetectChanges(MyComp0, template); - expect(asNativeElements(view.debugElement.children)).toHaveText('2|3|4|'); - }); + // Difference in expected text in ivy comes from the fact that ivy queries don't match host + // nodes of a directive that defines a content query. + expect(asNativeElements(view.debugElement.children)) + .toHaveText(ivyEnabled ? '3|4|' : '2|3|4|'); + }); - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should contain all directives in the light dom', () => { - const template = '
    ' + - '
    ' + - '
    '; - const view = createTestCmpAndDetectChanges(MyComp0, template); + it('should contain all directives in the light dom', () => { + const template = '
    ' + + '
    ' + + '
    '; + const view = createTestCmpAndDetectChanges(MyComp0, template); - expect(asNativeElements(view.debugElement.children)).toHaveText('2|3|'); - }); + // Difference in expected text in ivy comes from the fact that ivy queries don't match host + // nodes of a directive that defines a content query. + expect(asNativeElements(view.debugElement.children)).toHaveText(ivyEnabled ? '3|' : '2|3|'); + }); - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should reflect dynamically inserted directives', () => { - const template = '
    ' + - '
    ' + - '
    '; - const view = createTestCmpAndDetectChanges(MyComp0, template); - expect(asNativeElements(view.debugElement.children)).toHaveText('2|'); + it('should reflect dynamically inserted directives', () => { + const template = '
    ' + + '
    ' + + '
    '; + const view = createTestCmpAndDetectChanges(MyComp0, template); + // Difference in expected text in ivy comes from the fact that ivy queries don't match host + // nodes of a directive that defines a content query. + expect(asNativeElements(view.debugElement.children)).toHaveText(ivyEnabled ? '' : '2|'); - view.componentInstance.shouldShow = true; - view.detectChanges(); - expect(asNativeElements(view.debugElement.children)).toHaveText('2|3|'); - }); + view.componentInstance.shouldShow = true; + view.detectChanges(); + // Difference in expected text in ivy comes from the fact that ivy queries don't match host + // nodes of a directive that defines a content query. + expect(asNativeElements(view.debugElement.children)).toHaveText(ivyEnabled ? '3|' : '2|3|'); + }); it('should be cleanly destroyed when a query crosses view boundaries', () => { const template = '
    ' + @@ -217,19 +220,23 @@ describe('Query API', () => { view.destroy(); }); - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should reflect moved directives', () => { - const template = '
    ' + - '
    ' + - '
    '; - const view = createTestCmpAndDetectChanges(MyComp0, template); - expect(asNativeElements(view.debugElement.children)).toHaveText('2|1d|2d|3d|'); + it('should reflect moved directives', () => { + const template = '
    ' + + '
    ' + + '
    '; + const view = createTestCmpAndDetectChanges(MyComp0, template); + // Difference in expected text in ivy comes from the fact that ivy queries don't match host + // nodes of a directive that defines a content query. + expect(asNativeElements(view.debugElement.children)) + .toHaveText(ivyEnabled ? '1d|2d|3d|' : '2|1d|2d|3d|'); - view.componentInstance.list = ['3d', '2d']; - view.detectChanges(); - expect(asNativeElements(view.debugElement.children)).toHaveText('2|3d|2d|'); - }); + view.componentInstance.list = ['3d', '2d']; + view.detectChanges(); + // Difference in expected text in ivy comes from the fact that ivy queries don't match host + // nodes of a directive that defines a content query. + expect(asNativeElements(view.debugElement.children)) + .toHaveText(ivyEnabled ? '3d|2d|' : '2|3d|2d|'); + }); it('should throw with descriptive error when query selectors are not present', () => { TestBed.configureTestingModule({declarations: [MyCompBroken0, HasNullQueryCondition]}); @@ -263,8 +270,7 @@ describe('Query API', () => { }); describe('read a different token', () => { - modifiedInIvy( - 'Breaking change in Ivy: no longer allow multiple local refs with the same name, all local refs are now unique') + modifiedInIvy('Host nodes no longer match in ContentChild queries in Ivy') .it('should contain all content children', () => { const template = '
    '; @@ -298,6 +304,68 @@ describe('Query API', () => { expect(comp.textDirChild.text).toEqual('ca'); }); + it('should contain the first descendant content child for shallow queries', () => { + const template = ` +
    +
    `; + const view = createTestCmpAndDetectChanges(MyComp0, template); + + const comp = view.debugElement.children[0].injector.get(NeedsContentChildrenShallow); + expect(comp.children.length).toBe(1); + }); + + it('should contain the first descendant content child in an embedded template for shallow queries', + () => { + const template = ` + +
    +
    +
    `; + const view = createTestCmpAndDetectChanges(MyComp0, template); + + const comp = view.debugElement.children[0].injector.get(NeedsContentChildrenShallow); + expect(comp.children.length).toBe(1); + }); + + + it('should contain the first descendant content child in an embedded template for shallow queries and additional directive', + () => { + const template = ` + +
    +
    +
    `; + const view = createTestCmpAndDetectChanges(MyComp0, template); + + const comp = view.debugElement.children[0].injector.get(NeedsContentChildrenShallow); + expect(comp.children.length).toBe(1); + }); + + it('should contain the first descendant content child in an embedded template for shallow queries and additional directive (star syntax)', + () => { + const template = ` +
    +
    `; + const view = createTestCmpAndDetectChanges(MyComp0, template); + + const comp = view.debugElement.children[0].injector.get(NeedsContentChildrenShallow); + expect(comp.children.length).toBe(1); + }); + + onlyInIvy( + 'Shallow queries don\'t cross ng-container boundaries in ivy (ng-container is treated as a regular element') + .it('should not cross ng-container boundaries with shallow queries', () => { + const template = ` + +
    +
    +
    `; + const view = createTestCmpAndDetectChanges(MyComp0, template); + + const comp = view.debugElement.children[0].injector.get(NeedsContentChildrenShallow); + expect(comp.children.length).toBe(0); + }); + it('should contain the first descendant content child templateRef', () => { const template = '' + ''; @@ -472,25 +540,19 @@ describe('Query API', () => { }); describe('querying in the view', () => { - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should contain all the elements in the view with that have the given directive', - () => { - const template = - '
    '; - const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQuery = view.debugElement.children[0].references !['q']; - expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); - }); + it('should contain all the elements in the view with that have the given directive', () => { + const template = '
    '; + const view = createTestCmpAndDetectChanges(MyComp0, template); + const q: NeedsViewQuery = view.debugElement.children[0].references !['q']; + expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); + }); - fixmeIvy( - 'FW-781 - Directives invocation sequence on root and nested elements is different in Ivy') - .it('should not include directive present on the host element', () => { - const template = ''; - const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQuery = view.debugElement.children[0].references !['q']; - expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); - }); + it('should not include directive present on the host element', () => { + const template = ''; + const view = createTestCmpAndDetectChanges(MyComp0, template); + const q: NeedsViewQuery = view.debugElement.children[0].references !['q']; + expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); + }); it('should reflect changes in the component', () => { const template = ''; @@ -586,7 +648,7 @@ describe('Query API', () => { }); // Note: this test is just document our current behavior, which we do for performance reasons. - fixmeIvy('FW-853: Query results are cleared if embedded views are detached / moved') + modifiedInIvy('Query results from views are reported upon view insert / detach') .it('should not affect queries for projected templates if views are detached or moved', () => { const template = ` @@ -616,8 +678,43 @@ describe('Query API', () => { expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2']); }); - fixmeIvy('unknown').it( - 'should remove manually projected templates if their parent view is destroyed', () => { + onlyInIvy('Query results from views are reported upon view insert / detach') + .it('should update queries when a view is detached and re-inserted', () => { + const template = ` + +
    +
    +
    `; + const view = createTestCmpAndDetectChanges(MyComp0, template); + const q = view.debugElement.children[0].references !['q'] as ManualProjecting; + expect(q.query.length).toBe(0); + + const view1 = q.vc.createEmbeddedView(q.template, {'x': '1'}); + const view2 = q.vc.createEmbeddedView(q.template, {'x': '2'}); + + // 2 views were created and inserted so we've got 2 matching results + view.detectChanges(); + expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2']); + + q.vc.detach(1); + q.vc.detach(0); + + // both views were detached so query results from those views should not be reported + view.detectChanges(); + expect(q.query.map((d: TextDirective) => d.text)).toEqual([]); + + q.vc.insert(view2); + q.vc.insert(view1); + + // previously detached views are re-inserted in the different order so: + // - query results from the inserted views are reported again + // - the order results from views reflects orders of views + view.detectChanges(); + expect(q.query.map((d: TextDirective) => d.text)).toEqual(['2', '1']); + }); + + fixmeIvy('FW-920: Queries in nested views are not destroyed properly') + .it('should remove manually projected templates if their parent view is destroyed', () => { const template = `
    @@ -941,6 +1038,12 @@ class NeedsContentChildWithRead { @ContentChild('nonExisting', {read: TextDirective}) nonExistingVar !: TextDirective; } +@Component({selector: 'needs-content-children-shallow', template: ''}) +class NeedsContentChildrenShallow { + @ContentChildren('q', {descendants: false}) + children !: QueryList; +} + @Component({ selector: 'needs-content-child-template-ref', template: '
    ' diff --git a/packages/core/test/linker/regression_integration_spec.ts b/packages/core/test/linker/regression_integration_spec.ts index f9ad4fc06f..8c19283f64 100644 --- a/packages/core/test/linker/regression_integration_spec.ts +++ b/packages/core/test/linker/regression_integration_spec.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {ANALYZE_FOR_ENTRY_COMPONENTS, ApplicationRef, Component, ComponentRef, ContentChild, Directive, ErrorHandler, EventEmitter, HostListener, InjectionToken, Injector, Input, NgModule, NgModuleRef, NgZone, Output, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChildren, ViewContainerRef, destroyPlatform, ɵivyEnabled as ivyEnabled} from '@angular/core'; +import {ANALYZE_FOR_ENTRY_COMPONENTS, ApplicationRef, Component, ComponentRef, ContentChild, Directive, ErrorHandler, EventEmitter, HostListener, InjectionToken, Injector, Input, NgModule, NgModuleRef, NgZone, Output, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, destroyPlatform, ɵivyEnabled as ivyEnabled} from '@angular/core'; import {TestBed, fakeAsync, inject, tick} from '@angular/core/testing'; import {BrowserModule, By, DOCUMENT} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, modifiedInIvy} from '@angular/private/testing'; +import {fixmeIvy, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; if (ivyEnabled) { describe('ivy', () => { declareTests(); }); @@ -32,16 +32,15 @@ function declareTests(config?: {useJit: boolean}) { describe('platform pipes', () => { beforeEach(() => { TestBed.configureCompiler({...config}); }); - fixmeIvy('FW-798: Handle pipes with duplicate names') - .it('should overwrite them by custom pipes', () => { - TestBed.configureTestingModule({declarations: [CustomPipe]}); - const template = '{{true | somePipe}}'; - TestBed.overrideComponent(MyComp1, {set: {template}}); - const fixture = TestBed.createComponent(MyComp1); + it('should overwrite them by custom pipes', () => { + TestBed.configureTestingModule({declarations: [CustomPipe]}); + const template = '{{true | somePipe}}'; + TestBed.overrideComponent(MyComp1, {set: {template}}); + const fixture = TestBed.createComponent(MyComp1); - fixture.detectChanges(); - expect(fixture.nativeElement).toHaveText('someCustomPipe'); - }); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('someCustomPipe'); + }); }); describe('expressions', () => { @@ -318,6 +317,13 @@ function declareTests(config?: {useJit: boolean}) { expect(ctx.componentInstance.viewContainers.first).toBe(vc); }); + it('should not throw when encountering an empty class attribute', () => { + const template = '
    '; + TestBed.overrideComponent(MyComp1, {set: {template}}); + + expect(() => TestBed.createComponent(MyComp1)).not.toThrow(); + }); + describe('empty templates - #15143', () => { it('should allow empty components', () => { @Component({template: ''}) @@ -349,7 +355,7 @@ function declareTests(config?: {useJit: boolean}) { }); }); - fixmeIvy('FW-797: @ContentChildren results are assigned after @Input bindings') + modifiedInIvy('Static ViewChild and ContentChild queries are resolved in update mode') .it('should support @ContentChild and @Input on the same property for static queries', () => { @Directive({selector: 'test'}) @@ -381,6 +387,22 @@ function declareTests(config?: {useJit: boolean}) { expect(testDirs[2].tpl).toBeDefined(); }); + onlyInIvy('Ivy does not support @ContentChild and @Input on the same property') + .it('should throw if @ContentChild and @Input are on the same property', () => { + @Directive({selector: 'test'}) + class Test { + @Input() @ContentChild(TemplateRef) tpl !: TemplateRef; + } + + @Component({selector: 'my-app', template: ``}) + class App { + } + + expect(() => { + TestBed.configureTestingModule({declarations: [App, Test]}).createComponent(App); + }).toThrowError(/Cannot combine @Input decorators with query decorators/); + }); + it('should not add ng-version for dynamically created components', () => { @Component({template: ''}) class App { @@ -428,84 +450,97 @@ function declareTestsUsingBootstrap() { if (getDOM().supportsDOMEvents()) { // This test needs a real DOM.... - fixmeIvy('FW-840: Exceptions thrown in event handlers are not reported to ErrorHandler') - .it('should keep change detecting if there was an error', (done) => { - @Component({ - selector: COMP_SELECTOR, - template: - 'Value:{{value}}{{throwIfNeeded()}}' - }) - class ErrorComp { - value = 0; - thrownValue = 0; - next() { this.value++; } - nextAndThrow() { - this.value++; - this.throwIfNeeded(); - } - throwIfNeeded() { - NgZone.assertInAngularZone(); - if (this.thrownValue !== this.value) { - this.thrownValue = this.value; - throw new Error(`Error: ${this.value}`); - } - } + it('should keep change detecting if there was an error', (done) => { + @Component({ + selector: COMP_SELECTOR, + template: + 'Value:{{value}}{{throwIfNeeded()}}' + }) + class ErrorComp { + value = 0; + thrownValue = 0; + next() { this.value++; } + nextAndThrow() { + this.value++; + this.throwIfNeeded(); + } + throwIfNeeded() { + NgZone.assertInAngularZone(); + if (this.thrownValue !== this.value) { + this.thrownValue = this.value; + throw new Error(`Error: ${this.value}`); } + } + } - @Directive({selector: '[dirClick]'}) - class EventDir { - @Output() - dirClick = new EventEmitter(); + @Directive({selector: '[dirClick]'}) + class EventDir { + @Output() + dirClick = new EventEmitter(); - @HostListener('click', ['$event']) - onClick(event: any) { this.dirClick.next(event); } - } + @HostListener('click', ['$event']) + onClick(event: any) { this.dirClick.next(event); } + } - @NgModule({ - imports: [BrowserModule], - declarations: [ErrorComp, EventDir], - bootstrap: [ErrorComp], - providers: [{provide: ErrorHandler, useValue: errorHandler}], - }) - class TestModule { - } + @NgModule({ + imports: [BrowserModule], + declarations: [ErrorComp, EventDir], + bootstrap: [ErrorComp], + providers: [{provide: ErrorHandler, useValue: errorHandler}], + }) + class TestModule { + } - platformBrowserDynamic().bootstrapModule(TestModule).then((ref) => { - NgZone.assertNotInAngularZone(); - const appRef = ref.injector.get(ApplicationRef) as ApplicationRef; - const compRef = appRef.components[0] as ComponentRef; - const compEl = compRef.location.nativeElement; - const nextBtn = compEl.children[0]; - const nextAndThrowBtn = compEl.children[1]; - const nextAndThrowDirBtn = compEl.children[2]; + platformBrowserDynamic().bootstrapModule(TestModule).then((ref) => { + NgZone.assertNotInAngularZone(); + const appRef = ref.injector.get(ApplicationRef) as ApplicationRef; + const compRef = appRef.components[0] as ComponentRef; + const compEl = compRef.location.nativeElement; + const nextBtn = compEl.children[0]; + const nextAndThrowBtn = compEl.children[1]; + const nextAndThrowDirBtn = compEl.children[2]; - nextBtn.click(); - assertValueAndErrors(compEl, 1, 0); - nextBtn.click(); - assertValueAndErrors(compEl, 2, 2); + // Note: the amount of events sent to the logger will differ between ViewEngine + // and Ivy, because Ivy doesn't attach an error context. This means that the amount + // of logged errors increases by 1 for Ivy and 2 for ViewEngine after each event. + const errorDelta = ivyEnabled ? 1 : 2; + let currentErrorIndex = 0; - nextAndThrowBtn.click(); - assertValueAndErrors(compEl, 3, 4); - nextAndThrowBtn.click(); - assertValueAndErrors(compEl, 4, 6); + nextBtn.click(); + assertValueAndErrors(compEl, 1, currentErrorIndex); + currentErrorIndex += errorDelta; + nextBtn.click(); + assertValueAndErrors(compEl, 2, currentErrorIndex); + currentErrorIndex += errorDelta; - nextAndThrowDirBtn.click(); - assertValueAndErrors(compEl, 5, 8); - nextAndThrowDirBtn.click(); - assertValueAndErrors(compEl, 6, 10); + nextAndThrowBtn.click(); + assertValueAndErrors(compEl, 3, currentErrorIndex); + currentErrorIndex += errorDelta; + nextAndThrowBtn.click(); + assertValueAndErrors(compEl, 4, currentErrorIndex); + currentErrorIndex += errorDelta; - // Assert that there were no more errors - expect(logger.errors.length).toBe(12); - done(); - }); + nextAndThrowDirBtn.click(); + assertValueAndErrors(compEl, 5, currentErrorIndex); + currentErrorIndex += errorDelta; + nextAndThrowDirBtn.click(); + assertValueAndErrors(compEl, 6, currentErrorIndex); + currentErrorIndex += errorDelta; - function assertValueAndErrors(compEl: any, value: number, errorIndex: number) { - expect(compEl).toHaveText(`Value:${value}`); - expect(logger.errors[errorIndex][0]).toBe('ERROR'); - expect(logger.errors[errorIndex][1].message).toBe(`Error: ${value}`); - expect(logger.errors[errorIndex + 1][0]).toBe('ERROR CONTEXT'); - } - }); + // Assert that there were no more errors + expect(logger.errors.length).toBe(currentErrorIndex); + done(); + }); + + function assertValueAndErrors(compEl: any, value: number, errorIndex: number) { + expect(compEl).toHaveText(`Value:${value}`); + expect(logger.errors[errorIndex][0]).toBe('ERROR'); + expect(logger.errors[errorIndex][1].message).toBe(`Error: ${value}`); + + // Ivy doesn't attach an error context. + !ivyEnabled && expect(logger.errors[errorIndex + 1][0]).toBe('ERROR CONTEXT'); + } + }); } }); } diff --git a/packages/core/test/linker/security_integration_spec.ts b/packages/core/test/linker/security_integration_spec.ts index 9fcab8d774..8908822d05 100644 --- a/packages/core/test/linker/security_integration_spec.ts +++ b/packages/core/test/linker/security_integration_spec.ts @@ -10,7 +10,7 @@ import {Component, Directive, HostBinding, Input, NO_ERRORS_SCHEMA, ɵivyEnabled import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service'; -import {fixmeIvy} from '@angular/private/testing'; +import {fixmeIvy, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; { if (ivyEnabled) { @@ -52,47 +52,79 @@ function declareTests(config?: {useJit: boolean}) { afterEach(() => { getDOM().log = originalLog; }); describe('events', () => { - it('should disallow binding to attr.on*', () => { - const template = `
    `; - TestBed.overrideComponent(SecuredComponent, {set: {template}}); + modifiedInIvy('on-prefixed attributes validation happens at runtime in Ivy') + .it('should disallow binding to attr.on*', () => { + const template = `
    `; + TestBed.overrideComponent(SecuredComponent, {set: {template}}); - expect(() => TestBed.createComponent(SecuredComponent)) - .toThrowError( - /Binding to event attribute 'onclick' is disallowed for security reasons, please use \(click\)=.../); - }); + expect(() => TestBed.createComponent(SecuredComponent)) + .toThrowError( + /Binding to event attribute 'onclick' is disallowed for security reasons, please use \(click\)=.../); + }); - it('should disallow binding to on* with NO_ERRORS_SCHEMA', () => { - const template = `
    `; - TestBed.overrideComponent(SecuredComponent, {set: {template}}).configureTestingModule({ - schemas: [NO_ERRORS_SCHEMA] - }); + // this test is similar to the previous one, but since on-prefixed attributes validation now + // happens at runtime, we need to invoke change detection to trigger elementProperty call + onlyInIvy('on-prefixed attributes validation happens at runtime in Ivy') + .it('should disallow binding to attr.on*', () => { + const template = `
    `; + TestBed.overrideComponent(SecuredComponent, {set: {template}}); - expect(() => TestBed.createComponent(SecuredComponent)) - .toThrowError( - /Binding to event property 'onclick' is disallowed for security reasons, please use \(click\)=.../); - }); + expect(() => { + const cmp = TestBed.createComponent(SecuredComponent); + cmp.detectChanges(); + }) + .toThrowError( + /Binding to event attribute 'onclick' is disallowed for security reasons, please use \(click\)=.../); + }); - fixmeIvy( - 'FW-786: Element properties and directive inputs are not distinguished for sanitisation purposes') - .it('should disallow binding to on* unless it is consumed by a directive', () => { - const template = `
    `; + modifiedInIvy('on-prefixed attributes validation happens at runtime in Ivy') + .it('should disallow binding to on* with NO_ERRORS_SCHEMA', () => { + const template = `
    `; TestBed.overrideComponent(SecuredComponent, {set: {template}}).configureTestingModule({ schemas: [NO_ERRORS_SCHEMA] }); - // should not throw for inputs starting with "on" - let cmp: ComponentFixture = undefined !; - expect(() => cmp = TestBed.createComponent(SecuredComponent)).not.toThrow(); - - // must bind to the directive not to the property of the div - const value = cmp.componentInstance.ctxProp = {}; - cmp.detectChanges(); - const div = cmp.debugElement.children[0]; - expect(div.injector.get(OnPrefixDir).onclick).toBe(value); - expect(getDOM().getProperty(div.nativeElement, 'onclick')).not.toBe(value); - expect(getDOM().hasAttribute(div.nativeElement, 'onclick')).toEqual(false); + expect(() => TestBed.createComponent(SecuredComponent)) + .toThrowError( + /Binding to event property 'onclick' is disallowed for security reasons, please use \(click\)=.../); }); + // this test is similar to the previous one, but since on-prefixed attributes validation now + // happens at runtime, we need to invoke change detection to trigger elementProperty call + onlyInIvy('on-prefixed attributes validation happens at runtime in Ivy') + .it('should disallow binding to on* with NO_ERRORS_SCHEMA', () => { + const template = `
    `; + TestBed.overrideComponent(SecuredComponent, {set: {template}}).configureTestingModule({ + schemas: [NO_ERRORS_SCHEMA] + }); + + expect(() => { + const cmp = TestBed.createComponent(SecuredComponent); + cmp.detectChanges(); + }) + .toThrowError( + /Binding to event property 'onclick' is disallowed for security reasons, please use \(click\)=.../); + }); + + it('should disallow binding to on* unless it is consumed by a directive', () => { + const template = `
    `; + TestBed.overrideComponent(SecuredComponent, {set: {template}}).configureTestingModule({ + schemas: [NO_ERRORS_SCHEMA] + }); + + // should not throw for inputs starting with "on" + let cmp: ComponentFixture = undefined !; + expect(() => cmp = TestBed.createComponent(SecuredComponent)).not.toThrow(); + + // must bind to the directive not to the property of the div + const value = cmp.componentInstance.ctxProp = {}; + cmp.detectChanges(); + const div = cmp.debugElement.children[0]; + expect(div.injector.get(OnPrefixDir).onclick).toBe(value); + expect(getDOM().getProperty(div.nativeElement, 'onclick')).not.toBe(value); + expect(getDOM().hasAttribute(div.nativeElement, 'onclick')).toEqual(false); + }); + }); describe('safe HTML values', function() { @@ -171,39 +203,37 @@ function declareTests(config?: {useJit: boolean}) { checkEscapeOfHrefProperty(fixture, true); }); - fixmeIvy('FW-785: Host bindings are not sanitised') - .it('should escape unsafe properties if they are used in host bindings', () => { - @Directive({selector: '[dirHref]'}) - class HrefDirective { - // TODO(issue/24571): remove '!'. - @HostBinding('href') @Input() - dirHref !: string; - } + it('should escape unsafe properties if they are used in host bindings', () => { + @Directive({selector: '[dirHref]'}) + class HrefDirective { + // TODO(issue/24571): remove '!'. + @HostBinding('href') @Input() + dirHref !: string; + } - const template = `Link Title`; - TestBed.configureTestingModule({declarations: [HrefDirective]}); - TestBed.overrideComponent(SecuredComponent, {set: {template}}); - const fixture = TestBed.createComponent(SecuredComponent); + const template = `Link Title`; + TestBed.configureTestingModule({declarations: [HrefDirective]}); + TestBed.overrideComponent(SecuredComponent, {set: {template}}); + const fixture = TestBed.createComponent(SecuredComponent); - checkEscapeOfHrefProperty(fixture, false); - }); + checkEscapeOfHrefProperty(fixture, false); + }); - fixmeIvy('FW-785: Host bindings are not sanitised') - .it('should escape unsafe attributes if they are used in host bindings', () => { - @Directive({selector: '[dirHref]'}) - class HrefDirective { - // TODO(issue/24571): remove '!'. - @HostBinding('attr.href') @Input() - dirHref !: string; - } + it('should escape unsafe attributes if they are used in host bindings', () => { + @Directive({selector: '[dirHref]'}) + class HrefDirective { + // TODO(issue/24571): remove '!'. + @HostBinding('attr.href') @Input() + dirHref !: string; + } - const template = `Link Title`; - TestBed.configureTestingModule({declarations: [HrefDirective]}); - TestBed.overrideComponent(SecuredComponent, {set: {template}}); - const fixture = TestBed.createComponent(SecuredComponent); + const template = `Link Title`; + TestBed.configureTestingModule({declarations: [HrefDirective]}); + TestBed.overrideComponent(SecuredComponent, {set: {template}}); + const fixture = TestBed.createComponent(SecuredComponent); - checkEscapeOfHrefProperty(fixture, true); - }); + checkEscapeOfHrefProperty(fixture, true); + }); it('should escape unsafe style values', () => { const template = `
    Text
    `; @@ -225,7 +255,7 @@ function declareTests(config?: {useJit: boolean}) { expect(getDOM().getStyle(e, 'background')).not.toContain('javascript'); }); - fixmeIvy('FW-850: Should throw on unsafe SVG attributes') + modifiedInIvy('Unknown property error thrown during update mode, not creation mode') .it('should escape unsafe SVG attributes', () => { const template = `Text`; TestBed.overrideComponent(SecuredComponent, {set: {template}}); @@ -234,6 +264,15 @@ function declareTests(config?: {useJit: boolean}) { .toThrowError(/Can't bind to 'xlink:href'/); }); + onlyInIvy('Unknown property error thrown during update mode, not creation mode') + .it('should escape unsafe SVG attributes', () => { + const template = `Text`; + TestBed.overrideComponent(SecuredComponent, {set: {template}}); + + const fixture = TestBed.createComponent(SecuredComponent); + expect(() => fixture.detectChanges()).toThrowError(/Can't bind to 'xlink:href'/); + }); + it('should escape unsafe HTML values', () => { const template = `
    Text
    `; TestBed.overrideComponent(SecuredComponent, {set: {template}}); diff --git a/packages/core/test/linker/source_map_integration_node_only_spec.ts b/packages/core/test/linker/source_map_integration_node_only_spec.ts index ce3cd63746..1ea8e36f62 100644 --- a/packages/core/test/linker/source_map_integration_node_only_spec.ts +++ b/packages/core/test/linker/source_map_integration_node_only_spec.ts @@ -6,93 +6,238 @@ * found in the LICENSE file at https://angular.io/license */ -import {ResourceLoader} from '@angular/compiler'; -import {SourceMap} from '@angular/compiler/src/output/source_map'; +import {ResourceLoader, SourceMap} from '@angular/compiler'; +import {CompilerFacadeImpl} from '@angular/compiler/src/jit_compiler_facade'; +import {JitEvaluator} from '@angular/compiler/src/output/output_jit'; +import {escapeRegExp} from '@angular/compiler/src/util'; import {extractSourceMap, originalPositionFor} from '@angular/compiler/testing/src/output/source_map_util'; import {MockResourceLoader} from '@angular/compiler/testing/src/resource_loader_mock'; import {Attribute, Component, Directive, ErrorHandler, ɵglobal} from '@angular/core'; +import {CompilerFacade, ExportedCompilerFacade} from '@angular/core/src/compiler/compiler_facade'; import {getErrorLogger} from '@angular/core/src/errors'; -import {ivyEnabled} from '@angular/core/src/ivy_switch'; import {resolveComponentResources} from '@angular/core/src/metadata/resource_loading'; import {TestBed, fakeAsync, tick} from '@angular/core/testing'; -import {fixmeIvy} from '@angular/private/testing'; +import {fixmeIvy, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; -{ - describe('jit source mapping', () => { - let jitSpy: jasmine.Spy; - let resourceLoader: MockResourceLoader; +describe('jit source mapping', () => { + let resourceLoader: MockResourceLoader; + let jitEvaluator: MockJitEvaluator; - beforeEach(() => { - // Jasmine relies on methods on `Function.prototype`, so restore the prototype on the spy. - // Work around for: https://github.com/jasmine/jasmine/issues/1573 - // TODO: Figure out a better way to retrieve the JIT sources, without spying on `Function`. - const originalProto = ɵglobal.Function.prototype; - jitSpy = spyOn(ɵglobal, 'Function').and.callThrough(); - ɵglobal.Function.prototype = originalProto; - - resourceLoader = new MockResourceLoader(); - TestBed.configureCompiler({providers: [{provide: ResourceLoader, useValue: resourceLoader}]}); + beforeEach(() => { + resourceLoader = new MockResourceLoader(); + jitEvaluator = new MockJitEvaluator(); + TestBed.configureCompiler({ + providers: [ + { + provide: ResourceLoader, + useValue: resourceLoader, + }, + { + provide: JitEvaluator, + useValue: jitEvaluator, + } + ] }); + }); - function getErrorLoggerStack(e: Error): string { - let logStack: string = undefined !; - getErrorLogger(e)({error: () => logStack = new Error().stack !}, e.message); - return logStack; - } + modifiedInIvy('Generated filenames and stack traces have changed in ivy') + .describe('(View Engine)', () => { + describe('inline templates', () => { + const ngUrl = 'ng:///DynamicTestModule/MyComp.html'; + function templateDecorator(template: string) { return {template}; } + declareTests({ngUrl, templateDecorator}); + }); - function getSourceMap(genFile: string): SourceMap { - const jitSources = jitSpy.calls.all().map((call) => call.args[call.args.length - 1]); - return jitSources.map(source => extractSourceMap(source)) - .find(map => !!(map && map.file === genFile)) !; - } + describe('external templates', () => { + const ngUrl = 'ng:///some/url.html'; + const templateUrl = 'http://localhost:1234/some/url.html'; + function templateDecorator(template: string) { + resourceLoader.expect(templateUrl, template); + return {templateUrl}; + } + declareTests({ngUrl, templateDecorator}); + }); - function getSourcePositionForStack(stack: string): - {source: string, line: number, column: number} { - const ngFactoryLocations = - stack - .split('\n') - // e.g. at View_MyComp_0 (ng:///DynamicTestModule/MyComp.ngfactory.js:153:40) - .map(line => /\((.*\.ngfactory\.js):(\d+):(\d+)/.exec(line)) - .filter(match => !!match) - .map(match => ({ - file: match ![1], - line: parseInt(match ![2], 10), - column: parseInt(match ![3], 10) - })); - const ngFactoryLocation = ngFactoryLocations[0]; + function declareTests({ngUrl, templateDecorator}: TestConfig) { + const ngFactoryUrl = 'ng:///DynamicTestModule/MyComp.ngfactory.js'; - const sourceMap = getSourceMap(ngFactoryLocation.file); - return originalPositionFor( - sourceMap, {line: ngFactoryLocation.line, column: ngFactoryLocation.column}); - } + it('should use the right source url in html parse errors', fakeAsync(() => { + @Component({...templateDecorator('
    \n ')}) + class MyComp { + } - function compileAndCreateComponent(comType: any) { - TestBed.configureTestingModule({declarations: [comType]}); + expect(() => { compileAndCreateComponent(MyComp); }) + .toThrowError( + new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:2`)); + })); - let error: any; - TestBed.compileComponents().catch((e) => error = e); - if (resourceLoader.hasPendingRequests()) { - resourceLoader.flush(); - } - tick(); - if (error) { - throw error; - } - return TestBed.createComponent(comType); - } + it('should use the right source url in template parse errors', fakeAsync(() => { + @Component({...templateDecorator('
    \n
    ')}) + class MyComp { + } + + expect(() => { compileAndCreateComponent(MyComp); }) + .toThrowError( + new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:7`)); + })); + + it('should create a sourceMap for templates', fakeAsync(() => { + const template = `Hello World!`; + + @Component({...templateDecorator(template)}) + class MyComp { + } + + compileAndCreateComponent(MyComp); + + const sourceMap = jitEvaluator.getSourceMap(ngFactoryUrl); + expect(sourceMap.sources).toEqual([ngFactoryUrl, ngUrl]); + expect(sourceMap.sourcesContent).toEqual([' ', template]); + })); + + + it('should report source location for di errors', fakeAsync(() => { + const template = `
    \n
    `; + + @Component({...templateDecorator(template)}) + class MyComp { + } + + @Directive({selector: '[someDir]'}) + class SomeDir { + constructor() { throw new Error('Test'); } + } + + TestBed.configureTestingModule({declarations: [SomeDir]}); + let error: any; + try { + compileAndCreateComponent(MyComp); + } catch (e) { + error = e; + } + // The error should be logged from the element + expect( + jitEvaluator.getSourcePositionForStack(getErrorLoggerStack(error), ngFactoryUrl)) + .toEqual({ + line: 2, + column: 4, + source: ngUrl, + }); + })); + + it('should report di errors with multiple elements and directives', fakeAsync(() => { + const template = `
    `; + + @Component({...templateDecorator(template)}) + class MyComp { + } + + @Directive({selector: '[someDir]'}) + class SomeDir { + constructor(@Attribute('someDir') someDir: string) { + if (someDir === 'throw') { + throw new Error('Test'); + } + } + } + + TestBed.configureTestingModule({declarations: [SomeDir]}); + let error: any; + try { + compileAndCreateComponent(MyComp); + } catch (e) { + error = e; + } + // The error should be logged from the 2nd-element + expect( + jitEvaluator.getSourcePositionForStack(getErrorLoggerStack(error), ngFactoryUrl)) + .toEqual({ + line: 1, + column: 19, + source: ngUrl, + }); + })); + + it('should report source location for binding errors', fakeAsync(() => { + const template = `
    \n
    `; + + @Component({...templateDecorator(template)}) + class MyComp { + createError() { throw new Error('Test'); } + } + + const comp = compileAndCreateComponent(MyComp); + + let error: any; + try { + comp.detectChanges(); + } catch (e) { + error = e; + } + // the stack should point to the binding + expect(jitEvaluator.getSourcePositionForStack(error.stack, ngFactoryUrl)).toEqual({ + line: 2, + column: 12, + source: ngUrl, + }); + // The error should be logged from the element + expect( + jitEvaluator.getSourcePositionForStack(getErrorLoggerStack(error), ngFactoryUrl)) + .toEqual({ + line: 2, + column: 4, + source: ngUrl, + }); + })); + + it('should report source location for event errors', fakeAsync(() => { + const template = `
    \n
    `; + + @Component({...templateDecorator(template)}) + class MyComp { + createError() { throw new Error('Test'); } + } + + const comp = compileAndCreateComponent(MyComp); + + let error: any; + const errorHandler = TestBed.get(ErrorHandler); + spyOn(errorHandler, 'handleError').and.callFake((e: any) => error = e); + comp.debugElement.children[0].children[0].triggerEventHandler('click', 'EVENT'); + expect(error).toBeTruthy(); + // the stack should point to the binding + expect(jitEvaluator.getSourcePositionForStack(error.stack, ngFactoryUrl)).toEqual({ + line: 2, + column: 12, + source: ngUrl, + }); + // The error should be logged from the element + expect( + jitEvaluator.getSourcePositionForStack(getErrorLoggerStack(error), ngFactoryUrl)) + .toEqual({ + line: 2, + column: 4, + source: ngUrl, + }); + + })); + } + }); + + onlyInIvy('Generated filenames and stack traces have changed in ivy').describe('(Ivy)', () => { + + beforeEach(() => overrideCompilerFacade()); + afterEach(() => restoreCompilerFacade()); describe('inline templates', () => { - const ngUrl = 'ng:///DynamicTestModule/MyComp.html'; - + const ngUrl = 'ng:///MyComp/template.html'; function templateDecorator(template: string) { return {template}; } - declareTests({ngUrl, templateDecorator}); }); describe('external templates', () => { - const ngUrl = 'ng:///some/url.html'; const templateUrl = 'http://localhost:1234/some/url.html'; - + const ngUrl = templateUrl; function templateDecorator(template: string) { resourceLoader.expect(templateUrl, template); return {templateUrl}; @@ -101,176 +246,251 @@ import {fixmeIvy} from '@angular/private/testing'; declareTests({ngUrl, templateDecorator}); }); - function declareTests( - {ngUrl, templateDecorator}: - {ngUrl: string, templateDecorator: (template: string) => { [key: string]: any }}) { - fixmeIvy('FW-223: Generate source maps during template compilation') - .it('should use the right source url in html parse errors', fakeAsync(() => { - @Component({...templateDecorator('
    \n ')}) - class MyComp { - } + function declareTests({ngUrl, templateDecorator}: TestConfig) { + const generatedUrl = 'ng:///MyComp.js'; - expect(() => { - ivyEnabled && resolveComponentResources(null !); - compileAndCreateComponent(MyComp); - }) - .toThrowError(new RegExp( - `Template parse errors[\\s\\S]*${ngUrl.replace('$', '\\$')}@1:2`)); - })); + it('should use the right source url in html parse errors', fakeAsync(() => { + const template = '
    \n '; + @Component({...templateDecorator(template)}) + class MyComp { + } - fixmeIvy('FW-223: Generate source maps during template compilation') + expect(() => { + resolveCompileAndCreateComponent(MyComp, template); + }).toThrowError(new RegExp(`${escapeRegExp(ngUrl)}@1:2`)); + })); + + + fixmeIvy('FW-511: Report template typing errors') .it('should use the right source url in template parse errors', fakeAsync(() => { - @Component({...templateDecorator('
    \n
    ')}) - class MyComp { - } - - expect(() => { - ivyEnabled && resolveComponentResources(null !); - compileAndCreateComponent(MyComp); - }) - .toThrowError(new RegExp( - `Template parse errors[\\s\\S]*${ngUrl.replace('$', '\\$')}@1:7`)); - })); - - fixmeIvy('FW-223: Generate source maps during template compilation') - .it('should create a sourceMap for templates', fakeAsync(() => { - const template = `Hello World!`; - + const template = '
    \n
    '; @Component({...templateDecorator(template)}) class MyComp { } - compileAndCreateComponent(MyComp); - - const sourceMap = getSourceMap('ng:///DynamicTestModule/MyComp.ngfactory.js'); - expect(sourceMap.sources).toEqual([ - 'ng:///DynamicTestModule/MyComp.ngfactory.js', ngUrl - ]); - expect(sourceMap.sourcesContent).toEqual([' ', template]); + expect(() => { resolveCompileAndCreateComponent(MyComp, template); }) + .toThrowError( + new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:7`)); })); + it('should create a sourceMap for templates', fakeAsync(() => { + const template = `Hello World!`; - fixmeIvy('FW-223: Generate source maps during template compilation') - .it('should report source location for di errors', fakeAsync(() => { - const template = `
    \n
    `; + @Component({...templateDecorator(template)}) + class MyComp { + } - @Component({...templateDecorator(template)}) - class MyComp { - } + resolveCompileAndCreateComponent(MyComp, template); - @Directive({selector: '[someDir]'}) - class SomeDir { - constructor() { throw new Error('Test'); } - } + const sourceMap = jitEvaluator.getSourceMap(generatedUrl); + expect(sourceMap.sources).toEqual([generatedUrl, ngUrl]); + expect(sourceMap.sourcesContent).toEqual([' ', template]); + })); - TestBed.configureTestingModule({declarations: [SomeDir]}); - let error: any; - try { - compileAndCreateComponent(MyComp); - } catch (e) { - error = e; - } - // The error should be logged from the element - expect(getSourcePositionForStack(getErrorLoggerStack(error))).toEqual({ - line: 2, - column: 4, - source: ngUrl, - }); - })); - fixmeIvy('FW-223: Generate source maps during template compilation') - .it('should report di errors with multiple elements and directives', fakeAsync(() => { - const template = `
    `; + it('should report source location for di errors', fakeAsync(() => { + const template = `
    \n
    `; - @Component({...templateDecorator(template)}) - class MyComp { - } + @Component({...templateDecorator(template)}) + class MyComp { + } - @Directive({selector: '[someDir]'}) - class SomeDir { - constructor(@Attribute('someDir') someDir: string) { - if (someDir === 'throw') { - throw new Error('Test'); - } - } - } + @Directive({selector: '[someDir]'}) + class SomeDir { + constructor() { throw new Error('Test'); } + } - TestBed.configureTestingModule({declarations: [SomeDir]}); - let error: any; - try { - compileAndCreateComponent(MyComp); - } catch (e) { - error = e; - } - // The error should be logged from the 2nd-element - expect(getSourcePositionForStack(getErrorLoggerStack(error))).toEqual({ - line: 1, - column: 19, - source: ngUrl, - }); - })); + TestBed.configureTestingModule({declarations: [SomeDir]}); + let error: any; + try { + resolveCompileAndCreateComponent(MyComp, template); + } catch (e) { + error = e; + } + // The error should be logged from the element + expect(jitEvaluator.getSourcePositionForStack(error.stack, generatedUrl)).toEqual({ + line: 2, + column: 4, + source: ngUrl, + }); + })); - fixmeIvy('FW-223: Generate source maps during template compilation') - .it('should report source location for binding errors', fakeAsync(() => { - const template = `
    \n
    `; + it('should report di errors with multiple elements and directives', fakeAsync(() => { + const template = `
    `; - @Component({...templateDecorator(template)}) - class MyComp { - createError() { throw new Error('Test'); } - } + @Component({...templateDecorator(template)}) + class MyComp { + } - const comp = compileAndCreateComponent(MyComp); + @Directive({selector: '[someDir]'}) + class SomeDir { + constructor(@Attribute('someDir') someDir: string) { + if (someDir === 'throw') { + throw new Error('Test'); + } + } + } - let error: any; - try { - comp.detectChanges(); - } catch (e) { - error = e; - } - // the stack should point to the binding - expect(getSourcePositionForStack(error.stack)).toEqual({ - line: 2, - column: 12, - source: ngUrl, - }); - // The error should be logged from the element - expect(getSourcePositionForStack(getErrorLoggerStack(error))).toEqual({ - line: 2, - column: 4, - source: ngUrl, - }); - })); + TestBed.configureTestingModule({declarations: [SomeDir]}); + let error: any; + try { + resolveCompileAndCreateComponent(MyComp, template); + } catch (e) { + error = e; + } + // The error should be logged from the 2nd-element + expect(jitEvaluator.getSourcePositionForStack(error.stack, generatedUrl)).toEqual({ + line: 1, + column: 19, + source: ngUrl, + }); + })); - fixmeIvy('FW-223: Generate source maps during template compilation') - .it('should report source location for event errors', fakeAsync(() => { - const template = `
    \n
    `; + it('should report source location for binding errors', fakeAsync(() => { + const template = `
    \n
    `; - @Component({...templateDecorator(template)}) - class MyComp { - createError() { throw new Error('Test'); } - } + @Component({...templateDecorator(template)}) + class MyComp { + createError() { throw new Error('Test'); } + } - const comp = compileAndCreateComponent(MyComp); + const comp = resolveCompileAndCreateComponent(MyComp, template); - let error: any; - const errorHandler = TestBed.get(ErrorHandler); - spyOn(errorHandler, 'handleError').and.callFake((e: any) => error = e); - comp.debugElement.children[0].children[0].triggerEventHandler('click', 'EVENT'); - expect(error).toBeTruthy(); - // the stack should point to the binding - expect(getSourcePositionForStack(error.stack)).toEqual({ - line: 2, - column: 12, - source: ngUrl, - }); - // The error should be logged from the element - expect(getSourcePositionForStack(getErrorLoggerStack(error))).toEqual({ - line: 2, - column: 4, - source: ngUrl, - }); + let error: any; + try { + comp.detectChanges(); + } catch (e) { + error = e; + } + // the stack should point to the binding + expect(jitEvaluator.getSourcePositionForStack(error.stack, generatedUrl)).toEqual({ + line: 2, + column: 12, + source: ngUrl, + }); + })); - })); + it('should report source location for event errors', fakeAsync(() => { + const template = `
    \n
    `; + + @Component({...templateDecorator(template)}) + class MyComp { + createError() { throw new Error('Test'); } + } + + const comp = resolveCompileAndCreateComponent(MyComp, template); + + let error: any; + const errorHandler = TestBed.get(ErrorHandler); + spyOn(errorHandler, 'handleError').and.callFake((e: any) => error = e); + try { + comp.debugElement.children[0].children[0].triggerEventHandler('click', 'EVENT'); + } catch (e) { + error = e; + } + expect(error).toBeTruthy(); + // the stack should point to the binding + expect(jitEvaluator.getSourcePositionForStack(error.stack, generatedUrl)).toEqual({ + line: 2, + column: 21, + source: ngUrl, + }); + })); } }); -} + + function compileAndCreateComponent(comType: any) { + TestBed.configureTestingModule({declarations: [comType]}); + + let error: any; + TestBed.compileComponents().catch((e) => error = e); + if (resourceLoader.hasPendingRequests()) { + resourceLoader.flush(); + } + tick(); + if (error) { + throw error; + } + return TestBed.createComponent(comType); + } + + function createResolver(contents: string) { return (_url: string) => Promise.resolve(contents); } + + function resolveCompileAndCreateComponent(comType: any, template: string) { + resolveComponentResources(createResolver(template)); + return compileAndCreateComponent(comType); + } + + let ɵcompilerFacade: CompilerFacade; + function overrideCompilerFacade() { + const ng: ExportedCompilerFacade = (global as any).ng; + if (ng) { + ɵcompilerFacade = ng.ɵcompilerFacade; + ng.ɵcompilerFacade = new CompilerFacadeImpl(jitEvaluator); + } + } + function restoreCompilerFacade() { + if (ɵcompilerFacade) { + const ng: ExportedCompilerFacade = (global as any).ng; + ng.ɵcompilerFacade = ɵcompilerFacade; + } + } + + interface TestConfig { + ngUrl: string; + templateDecorator: (template: string) => { [key: string]: any }; + } + + interface SourcePos { + source: string; + line: number; + column: number; + } + + /** + * A helper class that captures the sources that have been JIT compiled. + */ + class MockJitEvaluator extends JitEvaluator { + sources: string[] = []; + + executeFunction(fn: Function, args: any[]) { + // Capture the source that has been generated. + this.sources.push(fn.toString()); + // Then execute it anyway. + return super.executeFunction(fn, args); + } + + /** + * Get the source-map for a specified JIT compiled file. + * @param genFile the URL of the file whose source-map we want. + */ + getSourceMap(genFile: string): SourceMap { + return this.sources.map(source => extractSourceMap(source)) + .find(map => !!(map && map.file === genFile)) !; + } + + getSourcePositionForStack(stack: string, genFile: string): SourcePos { + const urlRegexp = new RegExp(`(${escapeRegExp(genFile)}):(\\d+):(\\d+)`); + const pos = stack.split('\n') + .map(line => urlRegexp.exec(line)) + .filter(match => !!match) + .map(match => ({ + file: match ![1], + line: parseInt(match ![2], 10), + column: parseInt(match ![3], 10) + })) + .shift(); + if (!pos) { + throw new Error(`${genFile} was not mentioned in this stack:\n${stack}`); + } + const sourceMap = this.getSourceMap(pos.file); + return originalPositionFor(sourceMap, pos); + } + } + + function getErrorLoggerStack(e: Error): string { + let logStack: string = undefined !; + getErrorLogger(e)({error: () => logStack = new Error().stack !}, e.message); + return logStack; + } +}); diff --git a/packages/core/test/linker/system_ng_module_factory_loader_spec.ts b/packages/core/test/linker/system_ng_module_factory_loader_spec.ts index fbbaa0f591..ceb031c251 100644 --- a/packages/core/test/linker/system_ng_module_factory_loader_spec.ts +++ b/packages/core/test/linker/system_ng_module_factory_loader_spec.ts @@ -7,7 +7,7 @@ */ import {Compiler, SystemJsNgModuleLoader} from '@angular/core'; -import {global} from '@angular/core/src/util'; +import {global} from '@angular/core/src/util/global'; import {async} from '@angular/core/testing'; import {afterEach, beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal'; diff --git a/packages/core/test/linker/view_injector_integration_spec.ts b/packages/core/test/linker/view_injector_integration_spec.ts index d9c5e6070c..f6604d552b 100644 --- a/packages/core/test/linker/view_injector_integration_spec.ts +++ b/packages/core/test/linker/view_injector_integration_spec.ts @@ -6,11 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, DebugElement, Directive, ElementRef, Host, Inject, InjectionToken, Injector, Input, NgModule, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core'; +import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, DebugElement, Directive, ElementRef, EmbeddedViewRef, Host, Inject, InjectionToken, Injector, Input, NgModule, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core'; import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing'; -import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; +import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; @Directive({selector: '[simpleDirective]'}) class SimpleDirective { @@ -183,846 +182,877 @@ export class DuplicatePipe2 implements PipeTransform { class TestComp { } -(function() { - function createComponentFixture( - template: string, providers?: Provider[] | null, comp?: Type): ComponentFixture { - if (!comp) { - comp = TestComp; - } - TestBed.overrideComponent(comp !, {set: {template}}); - if (providers && providers.length) { - TestBed.overrideComponent(comp !, {add: {providers: providers}}); - } - return TestBed.createComponent(comp !); +function createComponentFixture( + template: string, providers?: Provider[] | null, comp?: Type): ComponentFixture { + if (!comp) { + comp = TestComp; } - - function createComponent( - template: string, providers?: Provider[], comp?: Type): DebugElement { - const fixture = createComponentFixture(template, providers, comp); - fixture.detectChanges(); - return fixture.debugElement; + TestBed.overrideComponent(comp !, {set: {template}}); + if (providers && providers.length) { + TestBed.overrideComponent(comp !, {add: {providers: providers}}); } - - describe('View injector', () => { - // On CJS fakeAsync is not supported... - if (!getDOM().supportsDOMEvents()) return; - - const TOKEN = new InjectionToken('token'); - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [TestComp], - providers: [ - {provide: TOKEN, useValue: 'appService'}, - {provide: 'appService', useFactory: (v: string) => v, deps: [TOKEN]}, - ], - }); - }); - - describe('injection', () => { - it('should instantiate directives that have no dependencies', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective]}); - const el = createComponent('
    '); - expect(el.children[0].injector.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective); - }); - - it('should instantiate directives that depend on another directive', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]}); - const el = createComponent('
    '); - - const d = el.children[0].injector.get(NeedsDirective); - - expect(d).toBeAnInstanceOf(NeedsDirective); - expect(d.dependency).toBeAnInstanceOf(SimpleDirective); - }); - - it('should support useValue with different values', () => { - const el = createComponent('', [ - {provide: 'numLiteral', useValue: 0}, - {provide: 'boolLiteral', useValue: true}, - {provide: 'strLiteral', useValue: 'a'}, - {provide: 'null', useValue: null}, - {provide: 'array', useValue: [1]}, - {provide: 'map', useValue: {'a': 1}}, - {provide: 'instance', useValue: new TestValue('a')}, - {provide: 'nested', useValue: [{'a': [1]}, new TestValue('b')]}, - ]); - expect(el.injector.get('numLiteral')).toBe(0); - expect(el.injector.get('boolLiteral')).toBe(true); - expect(el.injector.get('strLiteral')).toBe('a'); - expect(el.injector.get('null')).toBe(null); - expect(el.injector.get('array')).toEqual([1]); - expect(el.injector.get('map')).toEqual({'a': 1}); - expect(el.injector.get('instance')).toEqual(new TestValue('a')); - expect(el.injector.get('nested')).toEqual([{'a': [1]}, new TestValue('b')]); - }); - - it('should instantiate providers that have dependencies with SkipSelf', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective, SomeOtherDirective]}); - TestBed.overrideDirective( - SimpleDirective, - {add: {providers: [{provide: 'injectable1', useValue: 'injectable1'}]}}); - TestBed.overrideDirective(SomeOtherDirective, { - add: { - providers: [ - {provide: 'injectable1', useValue: 'new-injectable1'}, { - provide: 'injectable2', - useFactory: (val: any) => `${val}-injectable2`, - deps: [[new Inject('injectable1'), new SkipSelf()]] - } - ] - } - }); - const el = createComponent('
    '); - expect(el.children[0].children[0].injector.get('injectable2')) - .toEqual('injectable1-injectable2'); - }); - - it('should instantiate providers that have dependencies', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective]}); - const providers = [ - {provide: 'injectable1', useValue: 'injectable1'}, { - provide: 'injectable2', - useFactory: (val: any) => `${val}-injectable2`, - deps: ['injectable1'] - } - ]; - TestBed.overrideDirective(SimpleDirective, {add: {providers}}); - const el = createComponent('
    '); - expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2'); - }); - - fixmeIvy('unknown').it('should instantiate viewProviders that have dependencies', () => { - TestBed.configureTestingModule({declarations: [SimpleComponent]}); - const viewProviders = [ - {provide: 'injectable1', useValue: 'injectable1'}, { - provide: 'injectable2', - useFactory: (val: any) => `${val}-injectable2`, - deps: ['injectable1'] - } - ]; - TestBed.overrideComponent(SimpleComponent, {set: {viewProviders}}); - const el = createComponent('
    '); - expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2'); - }); - - it('should instantiate components that depend on viewProviders providers', () => { - TestBed.configureTestingModule({declarations: [NeedsServiceComponent]}); - TestBed.overrideComponent( - NeedsServiceComponent, {set: {providers: [{provide: 'service', useValue: 'service'}]}}); - const el = createComponent('
    '); - expect(el.children[0].injector.get(NeedsServiceComponent).service).toEqual('service'); - }); - - it('should instantiate multi providers', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective]}); - const providers = [ - {provide: 'injectable1', useValue: 'injectable11', multi: true}, - {provide: 'injectable1', useValue: 'injectable12', multi: true} - ]; - TestBed.overrideDirective(SimpleDirective, {set: {providers}}); - const el = createComponent('
    '); - expect(el.children[0].injector.get('injectable1')).toEqual([ - 'injectable11', 'injectable12' - ]); - }); - - it('should instantiate providers lazily', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective]}); - - let created = false; - TestBed.overrideDirective( - SimpleDirective, - {set: {providers: [{provide: 'service', useFactory: () => created = true}]}}); - const el = createComponent('
    '); - - expect(created).toBe(false); - - el.children[0].injector.get('service'); - - expect(created).toBe(true); - }); - - it('should provide undefined', () => { - let factoryCounter = 0; - - const el = createComponent('', [{ - provide: 'token', - useFactory: () => { - factoryCounter++; - return undefined; - } - }]); - - expect(el.injector.get('token')).toBeUndefined(); - expect(el.injector.get('token')).toBeUndefined(); - expect(factoryCounter).toBe(1); - }); - - describe('injecting lazy providers into an eager provider via Injector.get', () => { - - it('should inject providers that were declared before it', () => { - @Component({ - template: '', - providers: [ - {provide: 'lazy', useFactory: () => 'lazyValue'}, - { - provide: 'eager', - useFactory: (i: Injector) => `eagerValue: ${i.get('lazy')}`, - deps: [Injector] - }, - ] - }) - class MyComp { - // Component is eager, which makes all of its deps eager - constructor(@Inject('eager') eager: any) {} - } - - const ctx = - TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); - expect(ctx.debugElement.injector.get('eager')).toBe('eagerValue: lazyValue'); - }); - - it('should inject providers that were declared after it', () => { - @Component({ - template: '', - providers: [ - { - provide: 'eager', - useFactory: (i: Injector) => `eagerValue: ${i.get('lazy')}`, - deps: [Injector] - }, - {provide: 'lazy', useFactory: () => 'lazyValue'}, - ] - }) - class MyComp { - // Component is eager, which makes all of its deps eager - constructor(@Inject('eager') eager: any) {} - } - - const ctx = - TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); - expect(ctx.debugElement.injector.get('eager')).toBe('eagerValue: lazyValue'); - }); - }); - - describe('injecting eager providers into an eager provider via Injector.get', () => { - it('should inject providers that were declared before it', () => { - @Component({ - template: '', - providers: [ - {provide: 'eager1', useFactory: () => 'v1'}, - { - provide: 'eager2', - useFactory: (i: Injector) => `v2: ${i.get('eager1')}`, - deps: [Injector] - }, - ] - }) - class MyComp { - // Component is eager, which makes all of its deps eager - constructor(@Inject('eager1') eager1: any, @Inject('eager2') eager2: any) {} - } - - const ctx = - TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); - expect(ctx.debugElement.injector.get('eager2')).toBe('v2: v1'); - }); - - fixmeIvy('unknown').it('should inject providers that were declared after it', () => { - @Component({ - template: '', - providers: [ - { - provide: 'eager1', - useFactory: (i: Injector) => `v1: ${i.get('eager2')}`, - deps: [Injector] - }, - {provide: 'eager2', useFactory: () => 'v2'}, - ] - }) - class MyComp { - // Component is eager, which makes all of its deps eager - constructor(@Inject('eager1') eager1: any, @Inject('eager2') eager2: any) {} - } - - const ctx = - TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); - expect(ctx.debugElement.injector.get('eager1')).toBe('v1: v2'); - }); - }); - - it('should allow injecting lazy providers via Injector.get from an eager provider that is declared earlier', - () => { - @Component({providers: [{provide: 'a', useFactory: () => 'aValue'}], template: ''}) - class SomeComponent { - public a: string; - constructor(injector: Injector) { this.a = injector.get('a'); } - } - - const comp = TestBed.configureTestingModule({declarations: [SomeComponent]}) - .createComponent(SomeComponent); - expect(comp.componentInstance.a).toBe('aValue'); - }); - - fixmeIvy('unknown').it('should support ngOnDestroy for lazy providers', () => { - let created = false; - let destroyed = false; - - class SomeInjectable { - constructor() { created = true; } - ngOnDestroy() { destroyed = true; } - } - - @Component({providers: [SomeInjectable], template: ''}) - class SomeComp { - } - - TestBed.configureTestingModule({declarations: [SomeComp]}); - - - let compRef = TestBed.createComponent(SomeComp).componentRef; - expect(created).toBe(false); - expect(destroyed).toBe(false); - - // no error if the provider was not yet created - compRef.destroy(); - expect(created).toBe(false); - expect(destroyed).toBe(false); - - compRef = TestBed.createComponent(SomeComp).componentRef; - compRef.injector.get(SomeInjectable); - expect(created).toBe(true); - compRef.destroy(); - expect(destroyed).toBe(true); - }); - - fixmeIvy('unknown').it('should instantiate view providers lazily', () => { - let created = false; - TestBed.configureTestingModule({declarations: [SimpleComponent]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {viewProviders: [{provide: 'service', useFactory: () => created = true}]}}); - const el = createComponent('
    '); - - expect(created).toBe(false); - - el.children[0].injector.get('service'); - - expect(created).toBe(true); - }); - - it('should not instantiate other directives that depend on viewProviders providers (same element)', - () => { - TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {viewProviders: [{provide: 'service', useValue: 'service'}]}}); - expect(() => createComponent('
    ')) - .toThrowError(/No provider for service!/); - }); - - it('should not instantiate other directives that depend on viewProviders providers (child element)', - () => { - TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {viewProviders: [{provide: 'service', useValue: 'service'}]}}); - expect(() => createComponent('
    ')) - .toThrowError(/No provider for service!/); - }); - - it('should instantiate directives that depend on providers of other directives', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsService]}); - TestBed.overrideDirective( - SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}}); - - const el = createComponent('
    '); - expect(el.children[0].children[0].injector.get(NeedsService).service) - .toEqual('parentService'); - }); - - it('should instantiate directives that depend on providers in a parent view', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsService]}); - TestBed.overrideDirective( - SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}}); - const el = createComponent( - '
    '); - expect(el.children[0].children[0].injector.get(NeedsService).service) - .toEqual('parentService'); - }); - - fixmeIvy('unknown').it( - 'should instantiate directives that depend on providers of a component', () => { - TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - const el = createComponent('
    '); - expect(el.children[0].children[0].injector.get(NeedsService).service) - .toEqual('hostService'); - }); - - fixmeIvy('unknown').it( - 'should instantiate directives that depend on view providers of a component', () => { - TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - const el = createComponent('
    '); - expect(el.children[0].children[0].injector.get(NeedsService).service) - .toEqual('hostService'); - }); - - fixmeIvy('unknown').it( - 'should instantiate directives in a root embedded view that depend on view providers of a component', - () => { - TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - const el = createComponent('
    '); - expect(el.children[0].children[0].injector.get(NeedsService).service) - .toEqual('hostService'); - }); - - it('should instantiate directives that depend on instances in the app injector', () => { - TestBed.configureTestingModule({declarations: [NeedsAppService]}); - const el = createComponent('
    '); - expect(el.children[0].injector.get(NeedsAppService).service).toEqual('appService'); - }); - - obsoleteInIvy('This error is no longer generated by the compiler') - .it('should not instantiate a directive with cyclic dependencies', () => { - TestBed.configureTestingModule({declarations: [CycleDirective]}); - expect(() => createComponent('
    ')) - .toThrowError( - /Template parse errors:\nCannot instantiate cyclic dependency! CycleDirective \("\[ERROR ->\]
    <\/div>"\): .*TestComp.html@0:0/); - }); - - onlyInIvy('This error is generated by the runtime of Ivy') - .it('should not instantiate a directive with cyclic dependencies', () => { - TestBed.configureTestingModule({declarations: [CycleDirective]}); - expect(() => createComponent('
    ')) - .toThrowError('Circular dep for CycleDirective'); - }); - - obsoleteInIvy('This error is no longer generated by the compiler') - .it('should not instantiate a directive in a view that has a host dependency on providers' + - ' of the component', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleComponent, NeedsServiceFromHost]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - - expect(() => createComponent('
    ')) - .toThrowError( - /Template parse errors:\nNo provider for service \("\[ERROR ->\]
    "\): .*SimpleComponent.html@0:0/); - }); - - onlyInIvy('This error is generated by the runtime of Ivy') - .it('should not instantiate a directive in a view that has a host dependency on providers' + - ' of the component', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleComponent, NeedsServiceFromHost]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - - expect(() => createComponent('
    ')) - .toThrowError('NodeInjector: NOT_FOUND [service]'); - }); - - obsoleteInIvy('This error is no longer generated by the compiler') - .it('should not instantiate a directive in a view that has a host dependency on providers' + - ' of a decorator directive', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - - expect(() => createComponent('
    ')) - .toThrowError( - /Template parse errors:\nNo provider for service \("\[ERROR ->\]
    "\): .*SimpleComponent.html@0:0/); - }); - - onlyInIvy('This error is generated by the runtime of Ivy') - .it('should not instantiate a directive in a view that has a host dependency on providers' + - ' of a decorator directive', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]}); - TestBed.overrideComponent( - SimpleComponent, - {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - - expect(() => createComponent('
    ')) - .toThrowError('NodeInjector: NOT_FOUND [service]'); - }); - - obsoleteInIvy('This error is no longer generated by the compiler') - .it('should not instantiate a directive in a view that has a self dependency on a parent directive', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleDirective, NeedsDirectiveFromSelf]}); - expect( - () => createComponent( - '
    ')) - .toThrowError( - /Template parse errors:\nNo provider for SimpleDirective \("
    \[ERROR ->\]
    <\/div><\/div>"\): .*TestComp.html@0:21/); - }); - - onlyInIvy('This error is generated by the runtime of Ivy') - .it('should not instantiate a directive in a view that has a self dependency on a parent directive', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleDirective, NeedsDirectiveFromSelf]}); - expect( - () => createComponent( - '
    ')) - .toThrowError('NodeInjector: NOT_FOUND [SimpleDirective]'); - }); - - it('should instantiate directives that depend on other directives', fakeAsync(() => { - TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]}); - const el = createComponent('
    '); - const d = el.children[0].children[0].injector.get(NeedsDirective); - - expect(d).toBeAnInstanceOf(NeedsDirective); - expect(d.dependency).toBeAnInstanceOf(SimpleDirective); - })); - - it('should throw when a dependency cannot be resolved', fakeAsync(() => { - TestBed.configureTestingModule({declarations: [NeedsService]}); - - expect(() => createComponent('
    ')) - .toThrowError(/No provider for service!/); - })); - - it('should inject null when an optional dependency cannot be resolved', () => { - TestBed.configureTestingModule({declarations: [OptionallyNeedsDirective]}); - const el = createComponent('
    '); - const d = el.children[0].injector.get(OptionallyNeedsDirective); - expect(d.dependency).toBeNull(); - }); - - it('should instantiate directives that depends on the host component', () => { - TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsComponentFromHost]}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - const el = createComponent('
    '); - const d = el.children[0].children[0].injector.get(NeedsComponentFromHost); - expect(d.dependency).toBeAnInstanceOf(SimpleComponent); - }); - - fixmeIvy('unknown').it( - 'should instantiate host views for components that have a @Host dependency ', () => { - TestBed.configureTestingModule({declarations: [NeedsHostAppService]}); - const el = createComponent('', [], NeedsHostAppService); - expect(el.componentInstance.service).toEqual('appService'); - }); - - obsoleteInIvy('This error is no longer generated by the compiler') - .it('should not instantiate directives that depend on other directives on the host element', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - expect(() => createComponent('
    ')) - .toThrowError( - /Template parse errors:\nNo provider for SimpleDirective \("\[ERROR ->\]
    <\/div>"\): .*SimpleComponent.html@0:0/); - }); - - onlyInIvy('This error is generated by the runtime of Ivy') - .it('should not instantiate directives that depend on other directives on the host element', - () => { - TestBed.configureTestingModule( - {declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]}); - TestBed.overrideComponent( - SimpleComponent, {set: {template: '
    '}}); - expect(() => createComponent('
    ')) - .toThrowError('NodeInjector: NOT_FOUND [SimpleDirective]'); - }); - - fixmeIvy('unknown').it( - 'should allow to use the NgModule injector from a root ViewContainerRef.parentInjector', - () => { - @Component({template: ''}) - class MyComp { - constructor(public vc: ViewContainerRef) {} - } - - const compFixture = TestBed - .configureTestingModule({ - declarations: [MyComp], - providers: [{provide: 'someToken', useValue: 'someValue'}] - }) - .createComponent(MyComp); - - expect(compFixture.componentInstance.vc.parentInjector.get('someToken')) - .toBe('someValue'); - }); - }); - - describe('static attributes', () => { - it('should be injectable', () => { - TestBed.configureTestingModule({declarations: [NeedsAttribute]}); - const el = createComponent('
    '); - const needsAttribute = el.children[0].injector.get(NeedsAttribute); - - expect(needsAttribute.typeAttribute).toEqual('text'); - expect(needsAttribute.titleAttribute).toEqual(''); - expect(needsAttribute.fooAttribute).toEqual(null); - }); - - it('should be injectable without type annotation', () => { - TestBed.configureTestingModule({declarations: [NeedsAttributeNoType]}); - const el = createComponent('
    '); - const needsAttribute = el.children[0].injector.get(NeedsAttributeNoType); - - expect(needsAttribute.fooAttribute).toEqual('bar'); - }); - }); - - describe('refs', () => { - it('should inject ElementRef', () => { - TestBed.configureTestingModule({declarations: [NeedsElementRef]}); - const el = createComponent('
    '); - expect(el.children[0].injector.get(NeedsElementRef).elementRef.nativeElement) - .toBe(el.children[0].nativeElement); - }); - - fixmeIvy('unknown').it( - 'should inject ChangeDetectorRef of the component\'s view into the component', () => { - TestBed.configureTestingModule({declarations: [PushComponentNeedsChangeDetectorRef]}); - const cf = createComponentFixture('
    '); - cf.detectChanges(); - const compEl = cf.debugElement.children[0]; - const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef); - comp.counter = 1; - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('0'); - comp.changeDetectorRef.markForCheck(); - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('1'); - }); - - fixmeIvy('unknown').it( - 'should inject ChangeDetectorRef of the containing component into directives', () => { - TestBed.configureTestingModule({ - declarations: - [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] - }); - TestBed.overrideComponent(PushComponentNeedsChangeDetectorRef, { - set: { - template: - '{{counter}}
    ' - } - }); - const cf = createComponentFixture('
    '); - cf.detectChanges(); - const compEl = cf.debugElement.children[0]; - const comp: PushComponentNeedsChangeDetectorRef = - compEl.injector.get(PushComponentNeedsChangeDetectorRef); - comp.counter = 1; - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('0'); - expect( - compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef) - .toEqual(comp.changeDetectorRef); - expect( - compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef) - .toEqual(comp.changeDetectorRef); - comp.changeDetectorRef.markForCheck(); - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('1'); - }); - - fixmeIvy('unknown').it( - 'should inject ChangeDetectorRef of a same element component into a directive', () => { - TestBed.configureTestingModule({ - declarations: - [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] - }); - const cf = createComponentFixture( - '
    '); - cf.detectChanges(); - const compEl = cf.debugElement.children[0]; - const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef); - const dir = compEl.injector.get(DirectiveNeedsChangeDetectorRef); - comp.counter = 1; - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('0'); - dir.changeDetectorRef.markForCheck(); - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('1'); - }); - - fixmeIvy('unknown').it( - `should not inject ChangeDetectorRef of a parent element's component into a directive`, - () => { - TestBed - .configureTestingModule({ - declarations: - [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] - }) - .overrideComponent( - PushComponentNeedsChangeDetectorRef, - {set: {template: '{{counter}}'}}); - const cf = createComponentFixture( - '
    '); - cf.detectChanges(); - const compEl = cf.debugElement.children[0]; - const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef); - const dirEl = compEl.children[0]; - const dir = dirEl.injector.get(DirectiveNeedsChangeDetectorRef); - comp.counter = 1; - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('0'); - dir.changeDetectorRef.markForCheck(); - cf.detectChanges(); - expect(compEl.nativeElement).toHaveText('0'); - }); - - it('should inject ViewContainerRef', () => { - TestBed.configureTestingModule({declarations: [NeedsViewContainerRef]}); - const el = createComponent('
    '); - expect( - el.children[0].injector.get(NeedsViewContainerRef).viewContainer.element.nativeElement) - .toBe(el.children[0].nativeElement); - }); - - fixmeIvy('unknown').it('should inject ViewContainerRef', () => { - @Component({template: ''}) - class TestComp { - constructor(public vcr: ViewContainerRef) {} - } - - @NgModule({ - declarations: [TestComp], - entryComponents: [TestComp], - }) - class TestModule { - } - - const testInjector = { - get: (token: any, notFoundValue: any) => - token === 'someToken' ? 'someNewValue' : notFoundValue - }; - - const compFactory = TestBed.configureTestingModule({imports: [TestModule]}) - .get(ComponentFactoryResolver) - .resolveComponentFactory(TestComp); - const component = compFactory.create(testInjector); - expect(component.instance.vcr.parentInjector.get('someToken')).toBe('someNewValue'); - }); - - fixmeIvy('unknown').it('should inject TemplateRef', () => { - TestBed.configureTestingModule({declarations: [NeedsViewContainerRef, NeedsTemplateRef]}); - const el = - createComponent(''); - expect(el.childNodes[0].injector.get(NeedsTemplateRef).templateRef.elementRef) - .toEqual(el.childNodes[0].injector.get(NeedsViewContainerRef).viewContainer.element); - }); - - it('should throw if there is no TemplateRef', () => { - TestBed.configureTestingModule({declarations: [NeedsTemplateRef]}); - expect(() => createComponent('
    ')) - .toThrowError(/No provider for TemplateRef!/); - }); - - it('should inject null if there is no TemplateRef when the dependency is optional', () => { - TestBed.configureTestingModule({declarations: [OptionallyNeedsTemplateRef]}); - const el = createComponent('
    '); - const instance = el.children[0].injector.get(OptionallyNeedsTemplateRef); - expect(instance.templateRef).toBeNull(); - }); - }); - - describe('pipes', () => { - fixmeIvy('unknown').it('should instantiate pipes that have dependencies', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective, PipeNeedsService]}); - - const el = createComponent( - '
    ', - [{provide: 'service', useValue: 'pipeService'}]); - expect(el.children[0].injector.get(SimpleDirective).value.service).toEqual('pipeService'); - }); - - fixmeIvy('unknown').it('should overwrite pipes with later entry in the pipes array', () => { - TestBed.configureTestingModule( - {declarations: [SimpleDirective, DuplicatePipe1, DuplicatePipe2]}); - const el = createComponent('
    '); - expect(el.children[0].injector.get(SimpleDirective).value).toBeAnInstanceOf(DuplicatePipe2); - }); - - it('should inject ChangeDetectorRef into pipes', () => { - TestBed.configureTestingModule({ - declarations: - [SimpleDirective, PipeNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] - }); - const el = createComponent( - '
    '); - const cdRef = - el.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef; - expect(el.children[0].injector.get(SimpleDirective).value.changeDetectorRef).toEqual(cdRef); - }); - - fixmeIvy('unknown').it('should cache pure pipes', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective, PurePipe]}); - const el = createComponent( - '
    ' + - '
    '); - const purePipe1 = el.children[0].injector.get(SimpleDirective).value; - const purePipe2 = el.children[1].injector.get(SimpleDirective).value; - const purePipe3 = el.children[2].injector.get(SimpleDirective).value; - const purePipe4 = el.children[3].injector.get(SimpleDirective).value; - expect(purePipe1).toBeAnInstanceOf(PurePipe); - expect(purePipe2).toBe(purePipe1); - expect(purePipe3).toBe(purePipe1); - expect(purePipe4).toBe(purePipe1); - }); - - it('should not cache impure pipes', () => { - TestBed.configureTestingModule({declarations: [SimpleDirective, ImpurePipe]}); - const el = createComponent( - '
    ' + - '
    '); - const impurePipe1 = el.children[0].injector.get(SimpleDirective).value; - const impurePipe2 = el.children[1].injector.get(SimpleDirective).value; - const impurePipe3 = el.children[2].injector.get(SimpleDirective).value; - const impurePipe4 = el.children[3].injector.get(SimpleDirective).value; - expect(impurePipe1).toBeAnInstanceOf(ImpurePipe); - expect(impurePipe2).toBeAnInstanceOf(ImpurePipe); - expect(impurePipe2).not.toBe(impurePipe1); - expect(impurePipe3).toBeAnInstanceOf(ImpurePipe); - expect(impurePipe3).not.toBe(impurePipe1); - expect(impurePipe4).toBeAnInstanceOf(ImpurePipe); - expect(impurePipe4).not.toBe(impurePipe1); - }); + return TestBed.createComponent(comp !); +} + +function createComponent(template: string, providers?: Provider[], comp?: Type): DebugElement { + const fixture = createComponentFixture(template, providers, comp); + fixture.detectChanges(); + return fixture.debugElement; +} + +describe('View injector', () => { + const TOKEN = new InjectionToken('token'); + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TestComp], + providers: [ + {provide: TOKEN, useValue: 'appService'}, + {provide: 'appService', useFactory: (v: string) => v, deps: [TOKEN]}, + ], }); }); -})(); + + describe('injection', () => { + it('should instantiate directives that have no dependencies', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective]}); + const el = createComponent('
    '); + expect(el.children[0].injector.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective); + }); + + it('should instantiate directives that depend on another directive', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]}); + const el = createComponent('
    '); + + const d = el.children[0].injector.get(NeedsDirective); + + expect(d).toBeAnInstanceOf(NeedsDirective); + expect(d.dependency).toBeAnInstanceOf(SimpleDirective); + }); + + it('should support useValue with different values', () => { + const el = createComponent('', [ + {provide: 'numLiteral', useValue: 0}, + {provide: 'boolLiteral', useValue: true}, + {provide: 'strLiteral', useValue: 'a'}, + {provide: 'null', useValue: null}, + {provide: 'array', useValue: [1]}, + {provide: 'map', useValue: {'a': 1}}, + {provide: 'instance', useValue: new TestValue('a')}, + {provide: 'nested', useValue: [{'a': [1]}, new TestValue('b')]}, + ]); + expect(el.injector.get('numLiteral')).toBe(0); + expect(el.injector.get('boolLiteral')).toBe(true); + expect(el.injector.get('strLiteral')).toBe('a'); + expect(el.injector.get('null')).toBe(null); + expect(el.injector.get('array')).toEqual([1]); + expect(el.injector.get('map')).toEqual({'a': 1}); + expect(el.injector.get('instance')).toEqual(new TestValue('a')); + expect(el.injector.get('nested')).toEqual([{'a': [1]}, new TestValue('b')]); + }); + + it('should instantiate providers that have dependencies with SkipSelf', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective, SomeOtherDirective]}); + TestBed.overrideDirective( + SimpleDirective, {add: {providers: [{provide: 'injectable1', useValue: 'injectable1'}]}}); + TestBed.overrideDirective(SomeOtherDirective, { + add: { + providers: [ + {provide: 'injectable1', useValue: 'new-injectable1'}, { + provide: 'injectable2', + useFactory: (val: any) => `${val}-injectable2`, + deps: [[new Inject('injectable1'), new SkipSelf()]] + } + ] + } + }); + const el = createComponent('
    '); + expect(el.children[0].children[0].injector.get('injectable2')) + .toEqual('injectable1-injectable2'); + }); + + it('should instantiate providers that have dependencies', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective]}); + const providers = [ + {provide: 'injectable1', useValue: 'injectable1'}, { + provide: 'injectable2', + useFactory: (val: any) => `${val}-injectable2`, + deps: ['injectable1'] + } + ]; + TestBed.overrideDirective(SimpleDirective, {add: {providers}}); + const el = createComponent('
    '); + expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2'); + }); + + it('should instantiate viewProviders that have dependencies', () => { + TestBed.configureTestingModule({declarations: [SimpleComponent]}); + const viewProviders = [ + {provide: 'injectable1', useValue: 'injectable1'}, { + provide: 'injectable2', + useFactory: (val: any) => `${val}-injectable2`, + deps: ['injectable1'] + } + ]; + TestBed.overrideComponent(SimpleComponent, {set: {viewProviders}}); + const el = createComponent('
    '); + expect(el.children[0].injector.get('injectable2')).toEqual('injectable1-injectable2'); + }); + + it('should instantiate components that depend on viewProviders providers', () => { + TestBed.configureTestingModule({declarations: [NeedsServiceComponent]}); + TestBed.overrideComponent( + NeedsServiceComponent, {set: {providers: [{provide: 'service', useValue: 'service'}]}}); + const el = createComponent('
    '); + expect(el.children[0].injector.get(NeedsServiceComponent).service).toEqual('service'); + }); + + it('should instantiate multi providers', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective]}); + const providers = [ + {provide: 'injectable1', useValue: 'injectable11', multi: true}, + {provide: 'injectable1', useValue: 'injectable12', multi: true} + ]; + TestBed.overrideDirective(SimpleDirective, {set: {providers}}); + const el = createComponent('
    '); + expect(el.children[0].injector.get('injectable1')).toEqual(['injectable11', 'injectable12']); + }); + + it('should instantiate providers lazily', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective]}); + + let created = false; + TestBed.overrideDirective( + SimpleDirective, + {set: {providers: [{provide: 'service', useFactory: () => created = true}]}}); + const el = createComponent('
    '); + + expect(created).toBe(false); + + el.children[0].injector.get('service'); + + expect(created).toBe(true); + }); + + it('should provide undefined', () => { + let factoryCounter = 0; + + const el = createComponent('', [{ + provide: 'token', + useFactory: () => { + factoryCounter++; + return undefined; + } + }]); + + expect(el.injector.get('token')).toBeUndefined(); + expect(el.injector.get('token')).toBeUndefined(); + expect(factoryCounter).toBe(1); + }); + + describe('injecting lazy providers into an eager provider via Injector.get', () => { + + it('should inject providers that were declared before it', () => { + @Component({ + template: '', + providers: [ + {provide: 'lazy', useFactory: () => 'lazyValue'}, + { + provide: 'eager', + useFactory: (i: Injector) => `eagerValue: ${i.get('lazy')}`, + deps: [Injector] + }, + ] + }) + class MyComp { + // Component is eager, which makes all of its deps eager + constructor(@Inject('eager') eager: any) {} + } + + const ctx = + TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); + expect(ctx.debugElement.injector.get('eager')).toBe('eagerValue: lazyValue'); + }); + + it('should inject providers that were declared after it', () => { + @Component({ + template: '', + providers: [ + { + provide: 'eager', + useFactory: (i: Injector) => `eagerValue: ${i.get('lazy')}`, + deps: [Injector] + }, + {provide: 'lazy', useFactory: () => 'lazyValue'}, + ] + }) + class MyComp { + // Component is eager, which makes all of its deps eager + constructor(@Inject('eager') eager: any) {} + } + + const ctx = + TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); + expect(ctx.debugElement.injector.get('eager')).toBe('eagerValue: lazyValue'); + }); + }); + + describe('injecting eager providers into an eager provider via Injector.get', () => { + it('should inject providers that were declared before it', () => { + @Component({ + template: '', + providers: [ + {provide: 'eager1', useFactory: () => 'v1'}, + { + provide: 'eager2', + useFactory: (i: Injector) => `v2: ${i.get('eager1')}`, + deps: [Injector] + }, + ] + }) + class MyComp { + // Component is eager, which makes all of its deps eager + constructor(@Inject('eager1') eager1: any, @Inject('eager2') eager2: any) {} + } + + const ctx = + TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); + expect(ctx.debugElement.injector.get('eager2')).toBe('v2: v1'); + }); + + it('should inject providers that were declared after it', () => { + @Component({ + template: '', + providers: [ + { + provide: 'eager1', + useFactory: (i: Injector) => `v1: ${i.get('eager2')}`, + deps: [Injector] + }, + {provide: 'eager2', useFactory: () => 'v2'}, + ] + }) + class MyComp { + // Component is eager, which makes all of its deps eager + constructor(@Inject('eager1') eager1: any, @Inject('eager2') eager2: any) {} + } + + const ctx = + TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); + expect(ctx.debugElement.injector.get('eager1')).toBe('v1: v2'); + }); + }); + + it('should allow injecting lazy providers via Injector.get from an eager provider that is declared earlier', + () => { + @Component({providers: [{provide: 'a', useFactory: () => 'aValue'}], template: ''}) + class SomeComponent { + public a: string; + constructor(injector: Injector) { this.a = injector.get('a'); } + } + + const comp = TestBed.configureTestingModule({declarations: [SomeComponent]}) + .createComponent(SomeComponent); + expect(comp.componentInstance.a).toBe('aValue'); + }); + + it('should support ngOnDestroy for lazy providers', () => { + let created = false; + let destroyed = false; + + class SomeInjectable { + constructor() { created = true; } + ngOnDestroy() { destroyed = true; } + } + + @Component({providers: [SomeInjectable], template: ''}) + class SomeComp { + } + + TestBed.configureTestingModule({declarations: [SomeComp]}); + + + let compRef = TestBed.createComponent(SomeComp).componentRef; + expect(created).toBe(false); + expect(destroyed).toBe(false); + + // no error if the provider was not yet created + compRef.destroy(); + expect(created).toBe(false); + expect(destroyed).toBe(false); + + compRef = TestBed.createComponent(SomeComp).componentRef; + compRef.injector.get(SomeInjectable); + expect(created).toBe(true); + compRef.destroy(); + expect(destroyed).toBe(true); + }); + + it('should instantiate view providers lazily', () => { + let created = false; + TestBed.configureTestingModule({declarations: [SimpleComponent]}); + TestBed.overrideComponent( + SimpleComponent, + {set: {viewProviders: [{provide: 'service', useFactory: () => created = true}]}}); + const el = createComponent('
    '); + + expect(created).toBe(false); + + el.children[0].injector.get('service'); + + expect(created).toBe(true); + }); + + it('should not instantiate other directives that depend on viewProviders providers (same element)', + () => { + TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); + TestBed.overrideComponent( + SimpleComponent, {set: {viewProviders: [{provide: 'service', useValue: 'service'}]}}); + expect(() => createComponent('
    ')) + .toThrowError(/No provider for service!/); + }); + + it('should not instantiate other directives that depend on viewProviders providers (child element)', + () => { + TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); + TestBed.overrideComponent( + SimpleComponent, {set: {viewProviders: [{provide: 'service', useValue: 'service'}]}}); + expect(() => createComponent('
    ')) + .toThrowError(/No provider for service!/); + }); + + it('should instantiate directives that depend on providers of other directives', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsService]}); + TestBed.overrideDirective( + SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}}); + + const el = createComponent('
    '); + expect(el.children[0].children[0].injector.get(NeedsService).service) + .toEqual('parentService'); + }); + + it('should instantiate directives that depend on providers in a parent view', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsService]}); + TestBed.overrideDirective( + SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}}); + const el = createComponent( + '
    '); + expect(el.children[0].children[0].injector.get(NeedsService).service) + .toEqual('parentService'); + }); + + it('should instantiate directives that depend on providers of a component', () => { + TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); + TestBed.overrideComponent( + SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); + TestBed.overrideComponent(SimpleComponent, {set: {template: '
    '}}); + const el = createComponent('
    '); + expect(el.children[0].children[0].injector.get(NeedsService).service).toEqual('hostService'); + }); + + it('should instantiate directives that depend on view providers of a component', () => { + TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); + TestBed.overrideComponent( + SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); + TestBed.overrideComponent(SimpleComponent, {set: {template: '
    '}}); + const el = createComponent('
    '); + expect(el.children[0].children[0].injector.get(NeedsService).service).toEqual('hostService'); + }); + + it('should instantiate directives in a root embedded view that depend on view providers of a component', + () => { + TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsService]}); + TestBed.overrideComponent( + SimpleComponent, {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + const el = createComponent('
    '); + expect(el.children[0].children[0].injector.get(NeedsService).service) + .toEqual('hostService'); + }); + + it('should instantiate directives that depend on instances in the app injector', () => { + TestBed.configureTestingModule({declarations: [NeedsAppService]}); + const el = createComponent('
    '); + expect(el.children[0].injector.get(NeedsAppService).service).toEqual('appService'); + }); + + obsoleteInIvy('This error is no longer generated by the compiler') + .it('should not instantiate a directive with cyclic dependencies', () => { + TestBed.configureTestingModule({declarations: [CycleDirective]}); + expect(() => createComponent('
    ')) + .toThrowError( + /Template parse errors:\nCannot instantiate cyclic dependency! CycleDirective \("\[ERROR ->\]
    <\/div>"\): .*TestComp.html@0:0/); + }); + + onlyInIvy('This error is generated by the runtime of Ivy') + .it('should not instantiate a directive with cyclic dependencies', () => { + TestBed.configureTestingModule({declarations: [CycleDirective]}); + expect(() => createComponent('
    ')) + .toThrowError('Circular dep for CycleDirective'); + }); + + obsoleteInIvy('This error is no longer generated by the compiler') + .it('should not instantiate a directive in a view that has a host dependency on providers' + + ' of the component', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleComponent, NeedsServiceFromHost]}); + TestBed.overrideComponent( + SimpleComponent, + {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + + expect(() => createComponent('
    ')) + .toThrowError( + /Template parse errors:\nNo provider for service \("\[ERROR ->\]
    "\): .*SimpleComponent.html@0:0/); + }); + + onlyInIvy('This error is generated by the runtime of Ivy') + .it('should not instantiate a directive in a view that has a host dependency on providers' + + ' of the component', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleComponent, NeedsServiceFromHost]}); + TestBed.overrideComponent( + SimpleComponent, + {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + + expect(() => createComponent('
    ')) + .toThrowError('NodeInjector: NOT_FOUND [service]'); + }); + + obsoleteInIvy('This error is no longer generated by the compiler') + .it('should not instantiate a directive in a view that has a host dependency on providers' + + ' of a decorator directive', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]}); + TestBed.overrideComponent( + SimpleComponent, + {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + + expect(() => createComponent('
    ')) + .toThrowError( + /Template parse errors:\nNo provider for service \("\[ERROR ->\]
    "\): .*SimpleComponent.html@0:0/); + }); + + onlyInIvy('This error is generated by the runtime of Ivy') + .it('should not instantiate a directive in a view that has a host dependency on providers' + + ' of a decorator directive', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleComponent, SomeOtherDirective, NeedsServiceFromHost]}); + TestBed.overrideComponent( + SimpleComponent, + {set: {providers: [{provide: 'service', useValue: 'hostService'}]}}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + + expect(() => createComponent('
    ')) + .toThrowError('NodeInjector: NOT_FOUND [service]'); + }); + + obsoleteInIvy('This error is no longer generated by the compiler') + .it('should not instantiate a directive in a view that has a self dependency on a parent directive', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleDirective, NeedsDirectiveFromSelf]}); + expect( + () => createComponent( + '
    ')) + .toThrowError( + /Template parse errors:\nNo provider for SimpleDirective \("
    \[ERROR ->\]
    <\/div><\/div>"\): .*TestComp.html@0:21/); + }); + + onlyInIvy('This error is generated by the runtime of Ivy') + .it('should not instantiate a directive in a view that has a self dependency on a parent directive', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleDirective, NeedsDirectiveFromSelf]}); + expect( + () => createComponent( + '
    ')) + .toThrowError('NodeInjector: NOT_FOUND [SimpleDirective]'); + }); + + it('should instantiate directives that depend on other directives', fakeAsync(() => { + TestBed.configureTestingModule({declarations: [SimpleDirective, NeedsDirective]}); + const el = createComponent('
    '); + const d = el.children[0].children[0].injector.get(NeedsDirective); + + expect(d).toBeAnInstanceOf(NeedsDirective); + expect(d.dependency).toBeAnInstanceOf(SimpleDirective); + })); + + it('should throw when a dependency cannot be resolved', fakeAsync(() => { + TestBed.configureTestingModule({declarations: [NeedsService]}); + + expect(() => createComponent('
    ')) + .toThrowError(/No provider for service!/); + })); + + it('should inject null when an optional dependency cannot be resolved', () => { + TestBed.configureTestingModule({declarations: [OptionallyNeedsDirective]}); + const el = createComponent('
    '); + const d = el.children[0].injector.get(OptionallyNeedsDirective); + expect(d.dependency).toBeNull(); + }); + + it('should instantiate directives that depends on the host component', () => { + TestBed.configureTestingModule({declarations: [SimpleComponent, NeedsComponentFromHost]}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + const el = createComponent('
    '); + const d = el.children[0].children[0].injector.get(NeedsComponentFromHost); + expect(d.dependency).toBeAnInstanceOf(SimpleComponent); + }); + + obsoleteInIvy('@Host() / @Self() no longer looks in module injector') + .it('should instantiate host views for components that have a @Host dependency ', () => { + TestBed.configureTestingModule({declarations: [NeedsHostAppService]}); + const el = createComponent('', [], NeedsHostAppService); + expect(el.componentInstance.service).toEqual('appService'); + }); + + obsoleteInIvy('This error is no longer generated by the compiler') + .it('should not instantiate directives that depend on other directives on the host element', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + expect(() => createComponent('
    ')) + .toThrowError( + /Template parse errors:\nNo provider for SimpleDirective \("\[ERROR ->\]
    <\/div>"\): .*SimpleComponent.html@0:0/); + }); + + onlyInIvy('This error is generated by the runtime of Ivy') + .it('should not instantiate directives that depend on other directives on the host element', + () => { + TestBed.configureTestingModule( + {declarations: [SimpleComponent, SimpleDirective, NeedsDirectiveFromHost]}); + TestBed.overrideComponent( + SimpleComponent, {set: {template: '
    '}}); + expect(() => createComponent('
    ')) + .toThrowError('NodeInjector: NOT_FOUND [SimpleDirective]'); + }); + + it('should allow to use the NgModule injector from a root ViewContainerRef.parentInjector', + () => { + @Component({template: ''}) + class MyComp { + constructor(public vc: ViewContainerRef) {} + } + + const compFixture = TestBed + .configureTestingModule({ + declarations: [MyComp], + providers: [{provide: 'someToken', useValue: 'someValue'}] + }) + .createComponent(MyComp); + + expect(compFixture.componentInstance.vc.parentInjector.get('someToken')).toBe('someValue'); + }); + }); + + describe('static attributes', () => { + it('should be injectable', () => { + TestBed.configureTestingModule({declarations: [NeedsAttribute]}); + const el = createComponent('
    '); + const needsAttribute = el.children[0].injector.get(NeedsAttribute); + + expect(needsAttribute.typeAttribute).toEqual('text'); + expect(needsAttribute.titleAttribute).toEqual(''); + expect(needsAttribute.fooAttribute).toEqual(null); + }); + + it('should be injectable without type annotation', () => { + TestBed.configureTestingModule({declarations: [NeedsAttributeNoType]}); + const el = createComponent('
    '); + const needsAttribute = el.children[0].injector.get(NeedsAttributeNoType); + + expect(needsAttribute.fooAttribute).toEqual('bar'); + }); + }); + + describe('refs', () => { + it('should inject ElementRef', () => { + TestBed.configureTestingModule({declarations: [NeedsElementRef]}); + const el = createComponent('
    '); + expect(el.children[0].injector.get(NeedsElementRef).elementRef.nativeElement) + .toBe(el.children[0].nativeElement); + }); + + it('should inject ChangeDetectorRef of the component\'s view into the component', () => { + TestBed.configureTestingModule({declarations: [PushComponentNeedsChangeDetectorRef]}); + const cf = createComponentFixture('
    '); + cf.detectChanges(); + const compEl = cf.debugElement.children[0]; + const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef); + comp.counter = 1; + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('0'); + comp.changeDetectorRef.markForCheck(); + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('1'); + }); + + it('should inject ChangeDetectorRef of the containing component into directives', () => { + TestBed.configureTestingModule( + {declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]}); + TestBed.overrideComponent(PushComponentNeedsChangeDetectorRef, { + set: { + template: + '{{counter}}
    ' + } + }); + const cf = createComponentFixture('
    '); + cf.detectChanges(); + const compEl = cf.debugElement.children[0]; + const comp: PushComponentNeedsChangeDetectorRef = + compEl.injector.get(PushComponentNeedsChangeDetectorRef); + comp.counter = 1; + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('0'); + + /** + * Compares two `ChangeDetectorRef` instances. The logic depends on the engine, as the + * implementation details of `ViewRef` vary. + */ + function _compareChangeDetectorRefs(a: ChangeDetectorRef, b: ChangeDetectorRef) { + if (!ivyEnabled) { + // View Engine case + expect(a).toEqual(b); + } else { + // Ivy case + expect((a as any)._lView).toEqual((b as any)._lView); + expect((a as any).context).toEqual((b as any).context); + } + } + + _compareChangeDetectorRefs( + compEl.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef, + comp.changeDetectorRef); + _compareChangeDetectorRefs( + compEl.children[1].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef, + comp.changeDetectorRef); + + comp.changeDetectorRef.markForCheck(); + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('1'); + }); + + it('should inject ChangeDetectorRef of a same element component into a directive', () => { + TestBed.configureTestingModule( + {declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef]}); + const cf = createComponentFixture( + '
    '); + cf.detectChanges(); + const compEl = cf.debugElement.children[0]; + const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef); + const dir = compEl.injector.get(DirectiveNeedsChangeDetectorRef); + comp.counter = 1; + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('0'); + dir.changeDetectorRef.markForCheck(); + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('1'); + }); + + it(`should not inject ChangeDetectorRef of a parent element's component into a directive`, () => { + TestBed + .configureTestingModule({ + declarations: [PushComponentNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] + }) + .overrideComponent( + PushComponentNeedsChangeDetectorRef, + {set: {template: '{{counter}}'}}); + const cf = createComponentFixture( + '
    '); + cf.detectChanges(); + const compEl = cf.debugElement.children[0]; + const comp = compEl.injector.get(PushComponentNeedsChangeDetectorRef); + const dirEl = compEl.children[0]; + const dir = dirEl.injector.get(DirectiveNeedsChangeDetectorRef); + comp.counter = 1; + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('0'); + dir.changeDetectorRef.markForCheck(); + cf.detectChanges(); + expect(compEl.nativeElement).toHaveText('0'); + }); + + it('should inject ViewContainerRef', () => { + TestBed.configureTestingModule({declarations: [NeedsViewContainerRef]}); + const el = createComponent('
    '); + expect(el.children[0].injector.get(NeedsViewContainerRef).viewContainer.element.nativeElement) + .toBe(el.children[0].nativeElement); + }); + + it('should inject ViewContainerRef', () => { + @Component({template: ''}) + class TestComp { + constructor(public vcr: ViewContainerRef) {} + } + + @NgModule({ + declarations: [TestComp], + entryComponents: [TestComp], + }) + class TestModule { + } + + const testInjector = { + get: (token: any, notFoundValue: any) => + token === 'someToken' ? 'someNewValue' : notFoundValue + }; + + const compFactory = TestBed.configureTestingModule({imports: [TestModule]}) + .get(ComponentFactoryResolver) + .resolveComponentFactory(TestComp); + const component = compFactory.create(testInjector); + expect(component.instance.vcr.parentInjector.get('someToken')).toBe('someNewValue'); + }); + + it('should inject TemplateRef', () => { + TestBed.configureTestingModule({declarations: [NeedsViewContainerRef, NeedsTemplateRef]}); + const el = + createComponent(''); + expect(el.childNodes[0].injector.get(NeedsTemplateRef).templateRef.elementRef) + .toEqual(el.childNodes[0].injector.get(NeedsViewContainerRef).viewContainer.element); + }); + + it('should throw if there is no TemplateRef', () => { + TestBed.configureTestingModule({declarations: [NeedsTemplateRef]}); + expect(() => createComponent('
    ')) + .toThrowError(/No provider for TemplateRef!/); + }); + + it('should inject null if there is no TemplateRef when the dependency is optional', () => { + TestBed.configureTestingModule({declarations: [OptionallyNeedsTemplateRef]}); + const el = createComponent('
    '); + const instance = el.children[0].injector.get(OptionallyNeedsTemplateRef); + expect(instance.templateRef).toBeNull(); + }); + }); + + describe('pipes', () => { + it('should instantiate pipes that have dependencies', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective, PipeNeedsService]}); + + const el = createComponent( + '
    ', + [{provide: 'service', useValue: 'pipeService'}]); + expect(el.children[0].injector.get(SimpleDirective).value.service).toEqual('pipeService'); + }); + + it('should overwrite pipes with later entry in the pipes array', () => { + TestBed.configureTestingModule( + {declarations: [SimpleDirective, DuplicatePipe1, DuplicatePipe2]}); + const el = createComponent('
    '); + expect(el.children[0].injector.get(SimpleDirective).value).toBeAnInstanceOf(DuplicatePipe2); + }); + + it('should inject ChangeDetectorRef into pipes', () => { + TestBed.configureTestingModule({ + declarations: + [SimpleDirective, PipeNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] + }); + const el = createComponent( + '
    '); + const cdRef = el.children[0].injector.get(DirectiveNeedsChangeDetectorRef).changeDetectorRef; + expect(el.children[0].injector.get(SimpleDirective).value.changeDetectorRef).toEqual(cdRef); + }); + + modifiedInIvy('Pure pipes are instantiated differently in view engine and ivy') + .it('should cache pure pipes', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective, PurePipe]}); + const el = createComponent( + '
    ' + + '
    '); + const purePipe1 = el.children[0].injector.get(SimpleDirective).value; + const purePipe2 = el.children[1].injector.get(SimpleDirective).value; + const purePipe3 = el.children[2].injector.get(SimpleDirective).value; + const purePipe4 = el.children[3].injector.get(SimpleDirective).value; + expect(purePipe1).toBeAnInstanceOf(PurePipe); + expect(purePipe2).toBe(purePipe1); + expect(purePipe3).toBe(purePipe1); + expect(purePipe4).toBe(purePipe1); + }); + + it('should not cache impure pipes', () => { + TestBed.configureTestingModule({declarations: [SimpleDirective, ImpurePipe]}); + const el = createComponent( + '
    ' + + '
    '); + const impurePipe1 = el.children[0].injector.get(SimpleDirective).value; + const impurePipe2 = el.children[1].injector.get(SimpleDirective).value; + const impurePipe3 = el.children[2].injector.get(SimpleDirective).value; + const impurePipe4 = el.children[3].injector.get(SimpleDirective).value; + expect(impurePipe1).toBeAnInstanceOf(ImpurePipe); + expect(impurePipe2).toBeAnInstanceOf(ImpurePipe); + expect(impurePipe2).not.toBe(impurePipe1); + expect(impurePipe3).toBeAnInstanceOf(ImpurePipe); + expect(impurePipe3).not.toBe(impurePipe1); + expect(impurePipe4).toBeAnInstanceOf(ImpurePipe); + expect(impurePipe4).not.toBe(impurePipe1); + }); + }); + + describe('view destruction', () => { + @Component({selector: 'some-component', template: ''}) + class SomeComponent { + } + + @NgModule( + {declarations: [SomeComponent], exports: [SomeComponent], entryComponents: [SomeComponent]}) + class SomeModule { + } + + @Component({selector: 'listener-and-on-destroy', template: ''}) + class ComponentThatLoadsAnotherComponentThenMovesIt { + constructor( + private viewContainerRef: ViewContainerRef, + private componentFactoryResolver: ComponentFactoryResolver) {} + + + ngOnInit() { + // Dynamically load some component. + const componentFactory = + this.componentFactoryResolver.resolveComponentFactory(SomeComponent); + const componentRef = + this.viewContainerRef.createComponent(componentFactory, this.viewContainerRef.length); + + // Manually move the loaded component to some arbitrary DOM node. + const componentRootNode = + (componentRef.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement; + document.createElement('div').appendChild(componentRootNode); + + // Destroy the component we just moved to ensure that it does not error during + // destruction. + componentRef.destroy(); + } + } + + it('should not error when destroying a component that has been moved in the DOM', () => { + TestBed.configureTestingModule({ + imports: [SomeModule], + declarations: [ComponentThatLoadsAnotherComponentThenMovesIt], + }); + const fixture = createComponentFixture(``); + fixture.detectChanges(); + + // This test will fail if the ngOnInit of ComponentThatLoadsAnotherComponentThenMovesIt + // throws an error. + }); + }); +}); class TestValue { constructor(public value: string) {} diff --git a/packages/core/test/metadata/resource_loading_spec.ts b/packages/core/test/metadata/resource_loading_spec.ts index 2c15e02a90..49d6ff5b6d 100644 --- a/packages/core/test/metadata/resource_loading_spec.ts +++ b/packages/core/test/metadata/resource_loading_spec.ts @@ -64,7 +64,6 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); compileComponent(MyComponent, metadata); await resolveComponentResources(testResolver); expect(MyComponent.ngComponentDef).toBeDefined(); - expect(metadata.templateUrl).toBe(undefined); expect(metadata.template).toBe('content'); expect(resourceFetchCount).toBe(1); }); @@ -127,7 +126,6 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); compileComponent(MyComponent, metadata); await resolveComponentResources(fetch); expect(MyComponent.ngComponentDef).toBeDefined(); - expect(metadata.templateUrl).toBe(undefined); expect(metadata.template).toBe('response for test://content'); }); }); diff --git a/packages/core/test/reflection/reflector_spec.ts b/packages/core/test/reflection/reflector_spec.ts index a8c2080e39..71f45b55eb 100644 --- a/packages/core/test/reflection/reflector_spec.ts +++ b/packages/core/test/reflection/reflector_spec.ts @@ -8,8 +8,8 @@ import {Reflector} from '@angular/core/src/reflection/reflection'; import {DELEGATE_CTOR, INHERITED_CLASS, INHERITED_CLASS_WITH_CTOR, ReflectionCapabilities} from '@angular/core/src/reflection/reflection_capabilities'; -import {global} from '@angular/core/src/util'; import {makeDecorator, makeParamDecorator, makePropDecorator} from '@angular/core/src/util/decorators'; +import {global} from '@angular/core/src/util/global'; interface ClassDecoratorFactory { (data: ClassDecorator): any; diff --git a/packages/core/test/render3/BUILD.bazel b/packages/core/test/render3/BUILD.bazel index 87237e1bb8..f57c278e75 100644 --- a/packages/core/test/render3/BUILD.bazel +++ b/packages/core/test/render3/BUILD.bazel @@ -22,6 +22,9 @@ ts_library( "//packages/common", "//packages/compiler", "//packages/core", + "//packages/core/src/di/interface", + "//packages/core/src/interface", + "//packages/core/src/util", "//packages/core/testing", "//packages/platform-browser", "//packages/platform-browser/animations", diff --git a/packages/core/test/render3/change_detection_spec.ts b/packages/core/test/render3/change_detection_spec.ts index c5fb5dd039..ee923f4baa 100644 --- a/packages/core/test/render3/change_detection_spec.ts +++ b/packages/core/test/render3/change_detection_spec.ts @@ -11,11 +11,12 @@ import {withBody} from '@angular/private/testing'; import {ChangeDetectionStrategy, ChangeDetectorRef, DoCheck, RendererType2} from '../../src/core'; import {whenRendered} from '../../src/render3/component'; -import {LifecycleHooksFeature, defineComponent, defineDirective, getRenderedText, templateRefExtractor} from '../../src/render3/index'; +import {LifecycleHooksFeature, NgOnChangesFeature, defineComponent, defineDirective, getCurrentView, getRenderedText, templateRefExtractor} from '../../src/render3/index'; import {bind, container, containerRefreshEnd, containerRefreshStart, detectChanges, directiveInject, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, listener, markDirty, reference, text, template, textBinding, tick} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {RElement, Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer'; +import {FLAGS, LViewFlags} from '../../src/render3/interfaces/view'; import {ComponentFixture, containerEl, createComponent, renderComponent, requestAnimationFrame} from './render_util'; @@ -183,41 +184,39 @@ describe('change detection', () => { myApp.name = 'Bess'; tick(myApp); + expect(comp.doCheckCount).toEqual(2); + // View should update, as changed input marks view dirty expect(getRenderedText(myApp)).toEqual('2 - Bess'); myApp.name = 'George'; tick(myApp); + // View should update, as changed input marks view dirty + expect(comp.doCheckCount).toEqual(3); expect(getRenderedText(myApp)).toEqual('3 - George'); tick(myApp); + expect(comp.doCheckCount).toEqual(4); + // View should not be updated to "4", as inputs have not changed. expect(getRenderedText(myApp)).toEqual('3 - George'); }); - it('should not check OnPush components in update mode when component events occur, unless marked dirty', - () => { - const myApp = renderComponent(MyApp); - expect(comp.doCheckCount).toEqual(1); - expect(getRenderedText(myApp)).toEqual('1 - Nancy'); + it('should check OnPush components in update mode when component events occur', () => { + const myApp = renderComponent(MyApp); + expect(comp.doCheckCount).toEqual(1); + expect(getRenderedText(myApp)).toEqual('1 - Nancy'); - const button = containerEl.querySelector('button') !; - button.click(); - requestAnimationFrame.flush(); - // No ticks should have been scheduled. - expect(comp.doCheckCount).toEqual(1); - expect(getRenderedText(myApp)).toEqual('1 - Nancy'); + const button = containerEl.querySelector('button') !; + button.click(); + requestAnimationFrame.flush(); + // No ticks should have been scheduled. + expect(comp.doCheckCount).toEqual(1); + expect(getRenderedText(myApp)).toEqual('1 - Nancy'); - tick(myApp); - // The comp should still be clean. So doCheck will run, but the view should display 1. - expect(comp.doCheckCount).toEqual(2); - expect(getRenderedText(myApp)).toEqual('1 - Nancy'); - - markDirty(comp); - requestAnimationFrame.flush(); - // Now that markDirty has been manually called, the view should be dirty and a tick - // should be scheduled to check the view. - expect(comp.doCheckCount).toEqual(3); - expect(getRenderedText(myApp)).toEqual('3 - Nancy'); - }); + tick(myApp); + // Because the onPush comp should be dirty, it should update once CD runs + expect(comp.doCheckCount).toEqual(2); + expect(getRenderedText(myApp)).toEqual('2 - Nancy'); + }); it('should not check OnPush components in update mode when parent events occur', () => { function noop() {} @@ -238,76 +237,230 @@ describe('change detection', () => { (button as HTMLButtonElement).click(); tick(buttonParent); // The comp should still be clean. So doCheck will run, but the view should display 1. + expect(comp.doCheckCount).toEqual(2); expect(getRenderedText(buttonParent)).toEqual('1 - Nancy'); }); - it('should not check parent OnPush components in update mode when child events occur, unless marked dirty', - () => { - let parent: ButtonParent; + it('should check parent OnPush components in update mode when child events occur', () => { + let parent: ButtonParent; - class ButtonParent implements DoCheck { - doCheckCount = 0; - ngDoCheck(): void { this.doCheckCount++; } + class ButtonParent implements DoCheck { + doCheckCount = 0; + ngDoCheck(): void { this.doCheckCount++; } - static ngComponentDef = defineComponent({ - type: ButtonParent, - selectors: [['button-parent']], - factory: () => parent = new ButtonParent(), - consts: 2, - vars: 1, - /** {{ doCheckCount }} - */ - template: (rf: RenderFlags, ctx: ButtonParent) => { - if (rf & RenderFlags.Create) { - text(0); - element(1, 'my-comp'); - } - if (rf & RenderFlags.Update) { - textBinding(0, interpolation1('', ctx.doCheckCount, ' - ')); - } - }, - directives: () => [MyComponent], - changeDetection: ChangeDetectionStrategy.OnPush - }); - } + static ngComponentDef = defineComponent({ + type: ButtonParent, + selectors: [['button-parent']], + factory: () => parent = new ButtonParent(), + consts: 2, + vars: 1, + /** {{ doCheckCount }} - */ + template: (rf: RenderFlags, ctx: ButtonParent) => { + if (rf & RenderFlags.Create) { + text(0); + element(1, 'my-comp'); + } + if (rf & RenderFlags.Update) { + textBinding(0, interpolation1('', ctx.doCheckCount, ' - ')); + } + }, + directives: () => [MyComponent], + changeDetection: ChangeDetectionStrategy.OnPush + }); + } - const MyButtonApp = createComponent('my-button-app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'button-parent'); + const MyButtonApp = createComponent('my-button-app', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'button-parent'); + } + }, 1, 0, [ButtonParent]); + + const myButtonApp = renderComponent(MyButtonApp); + expect(parent !.doCheckCount).toEqual(1); + expect(comp !.doCheckCount).toEqual(1); + expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); + + tick(myButtonApp); + expect(parent !.doCheckCount).toEqual(2); + // parent isn't checked, so child doCheck won't run + expect(comp !.doCheckCount).toEqual(1); + expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); + + const button = containerEl.querySelector('button'); + button !.click(); + requestAnimationFrame.flush(); + // No ticks should have been scheduled. + expect(parent !.doCheckCount).toEqual(2); + expect(comp !.doCheckCount).toEqual(1); + + tick(myButtonApp); + expect(parent !.doCheckCount).toEqual(3); + expect(comp !.doCheckCount).toEqual(2); + expect(getRenderedText(myButtonApp)).toEqual('3 - 2 - Nancy'); + }); + + describe('Manual mode', () => { + class ManualComponent implements DoCheck { + /* @Input() */ + name = 'Nancy'; + doCheckCount = 0; + + ngDoCheck(): void { this.doCheckCount++; } + + onClick() {} + + static ngComponentDef = defineComponent({ + type: ManualComponent, + selectors: [['manual-comp']], + factory: () => comp = new ManualComponent(), + consts: 2, + vars: 2, + /** + * {{ doCheckCount }} - {{ name }} + * + */ + template: (rf: RenderFlags, ctx: ManualComponent) => { + if (rf & RenderFlags.Create) { + // This is temporarily the only way to turn on manual change detection + // because public API has not yet been added. + const view = getCurrentView() as any; + view[FLAGS] |= LViewFlags.ManualOnPush; + + text(0); + elementStart(1, 'button'); + { + listener('click', () => { ctx.onClick(); }); + } + elementEnd(); + } + if (rf & RenderFlags.Update) { + textBinding(0, interpolation2('', ctx.doCheckCount, ' - ', ctx.name, '')); + } + }, + changeDetection: ChangeDetectionStrategy.OnPush, + inputs: {name: 'name'} + }); + } + + class ManualApp { + name: string = 'Nancy'; + + static ngComponentDef = defineComponent({ + type: ManualApp, + selectors: [['manual-app']], + factory: () => new ManualApp(), + consts: 1, + vars: 1, + /** */ + template: (rf: RenderFlags, ctx: ManualApp) => { + if (rf & RenderFlags.Create) { + element(0, 'manual-comp'); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'name', bind(ctx.name)); + } + + }, + directives: () => [ManualComponent] + }); + } + + + it('should not check OnPush components in update mode when component events occur, unless marked dirty', + () => { + const myApp = renderComponent(ManualApp); + expect(comp.doCheckCount).toEqual(1); + expect(getRenderedText(myApp)).toEqual('1 - Nancy'); + + const button = containerEl.querySelector('button') !; + button.click(); + requestAnimationFrame.flush(); + // No ticks should have been scheduled. + expect(comp.doCheckCount).toEqual(1); + expect(getRenderedText(myApp)).toEqual('1 - Nancy'); + + tick(myApp); + // The comp should still be clean. So doCheck will run, but the view should display 1. + expect(comp.doCheckCount).toEqual(2); + expect(getRenderedText(myApp)).toEqual('1 - Nancy'); + + markDirty(comp); + requestAnimationFrame.flush(); + // Now that markDirty has been manually called, the view should be dirty and a tick + // should be scheduled to check the view. + expect(comp.doCheckCount).toEqual(3); + expect(getRenderedText(myApp)).toEqual('3 - Nancy'); + }); + + it('should not check parent OnPush components in update mode when child events occur, unless marked dirty', + () => { + let parent: ButtonParent; + + class ButtonParent implements DoCheck { + doCheckCount = 0; + ngDoCheck(): void { this.doCheckCount++; } + + static ngComponentDef = defineComponent({ + type: ButtonParent, + selectors: [['button-parent']], + factory: () => parent = new ButtonParent(), + consts: 2, + vars: 1, + /** {{ doCheckCount }} - */ + template: (rf: RenderFlags, ctx: ButtonParent) => { + if (rf & RenderFlags.Create) { + text(0); + element(1, 'manual-comp'); + } + if (rf & RenderFlags.Update) { + textBinding(0, interpolation1('', ctx.doCheckCount, ' - ')); + } + }, + directives: () => [ManualComponent], + changeDetection: ChangeDetectionStrategy.OnPush + }); } - }, 1, 0, [ButtonParent]); - const myButtonApp = renderComponent(MyButtonApp); - expect(parent !.doCheckCount).toEqual(1); - expect(comp !.doCheckCount).toEqual(1); - expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); + const MyButtonApp = + createComponent('my-button-app', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'button-parent'); + } + }, 1, 0, [ButtonParent]); - tick(myButtonApp); - expect(parent !.doCheckCount).toEqual(2); - // parent isn't checked, so child doCheck won't run - expect(comp !.doCheckCount).toEqual(1); - expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); + const myButtonApp = renderComponent(MyButtonApp); + expect(parent !.doCheckCount).toEqual(1); + expect(comp !.doCheckCount).toEqual(1); + expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); - const button = containerEl.querySelector('button'); - button !.click(); - requestAnimationFrame.flush(); - // No ticks should have been scheduled. - expect(parent !.doCheckCount).toEqual(2); - expect(comp !.doCheckCount).toEqual(1); + tick(myButtonApp); + expect(parent !.doCheckCount).toEqual(2); + // parent isn't checked, so child doCheck won't run + expect(comp !.doCheckCount).toEqual(1); + expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); - tick(myButtonApp); - expect(parent !.doCheckCount).toEqual(3); - // parent isn't checked, so child doCheck won't run - expect(comp !.doCheckCount).toEqual(1); - expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); + const button = containerEl.querySelector('button'); + button !.click(); + requestAnimationFrame.flush(); + // No ticks should have been scheduled. + expect(parent !.doCheckCount).toEqual(2); + expect(comp !.doCheckCount).toEqual(1); - markDirty(comp); - requestAnimationFrame.flush(); - // Now that markDirty has been manually called, both views should be dirty and a tick - // should be scheduled to check the view. - expect(parent !.doCheckCount).toEqual(4); - expect(comp !.doCheckCount).toEqual(2); - expect(getRenderedText(myButtonApp)).toEqual('4 - 2 - Nancy'); - }); + tick(myButtonApp); + expect(parent !.doCheckCount).toEqual(3); + // parent isn't checked, so child doCheck won't run + expect(comp !.doCheckCount).toEqual(1); + expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); + + markDirty(comp); + requestAnimationFrame.flush(); + // Now that markDirty has been manually called, both views should be dirty and a tick + // should be scheduled to check the view. + expect(parent !.doCheckCount).toEqual(4); + expect(comp !.doCheckCount).toEqual(2); + expect(getRenderedText(myButtonApp)).toEqual('4 - 2 - Nancy'); + }); + }); }); describe('ChangeDetectorRef', () => { @@ -562,6 +715,73 @@ describe('change detection', () => { expect(getRenderedText(comp)).toEqual('1'); }); + + ['OnInit', 'AfterContentInit', 'AfterViewInit', 'OnChanges'].forEach(hook => { + it(`should not go infinite loop when recursively called from children's ng${hook}`, () => { + class ChildComp { + // @Input + inp = ''; + + count = 0; + constructor(public parentComp: ParentComp) {} + + ngOnInit() { this.check('OnInit'); } + ngAfterContentInit() { this.check('AfterContentInit'); } + ngAfterViewInit() { this.check('AfterViewInit'); } + ngOnChanges() { this.check('OnChanges'); } + + check(h: string) { + if (h === hook) { + this.count++; + if (this.count > 1) throw new Error(`ng${hook} should be called only once!`); + this.parentComp.triggerChangeDetection(); + } + } + + static ngComponentDef = defineComponent({ + type: ChildComp, + selectors: [['child-comp']], + factory: () => new ChildComp(directiveInject(ParentComp as any)), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: ChildComp) => { + if (rf & RenderFlags.Create) { + text(0, 'foo'); + } + }, + inputs: {inp: 'inp'}, + features: [NgOnChangesFeature] + }); + } + + class ParentComp { + constructor(public cdr: ChangeDetectorRef) {} + + triggerChangeDetection() { this.cdr.detectChanges(); } + + static ngComponentDef = defineComponent({ + type: ParentComp, + selectors: [['parent-comp']], + factory: () => new ParentComp(directiveInject(ChangeDetectorRef as any)), + consts: 1, + vars: 1, + /** {{ value }} */ + template: (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + element(0, 'child-comp'); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'inp', bind(true)); + } + }, + directives: [ChildComp] + }); + } + + expect(() => renderComponent(ParentComp)).not.toThrow(); + }); + }); + it('should support call in ngDoCheck', () => { class DetectChangesComp { doCheckCount = 0; @@ -946,48 +1166,50 @@ describe('change detection', () => { }); } - it('should schedule check on OnPush components', () => { - const parent = renderComponent(OnPushParent); - expect(getRenderedText(parent)).toEqual('one - one'); + it('should ensure OnPush components are checked', () => { + const fixture = new ComponentFixture(OnPushParent); + expect(fixture.hostElement.textContent).toEqual('one - one'); comp.value = 'two'; - tick(parent); - expect(getRenderedText(parent)).toEqual('one - one'); + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('one - one'); comp.cdr.markForCheck(); - requestAnimationFrame.flush(); - expect(getRenderedText(parent)).toEqual('one - two'); + + // Change detection should not have run yet, since markForCheck + // does not itself schedule change detection. + expect(fixture.hostElement.textContent).toEqual('one - one'); + + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('one - two'); }); - it('should only run change detection once with multiple calls to markForCheck', () => { - renderComponent(OnPushParent); + it('should never schedule change detection on its own', () => { + const fixture = new ComponentFixture(OnPushParent); expect(comp.doCheckCount).toEqual(1); - comp.cdr.markForCheck(); - comp.cdr.markForCheck(); - comp.cdr.markForCheck(); comp.cdr.markForCheck(); comp.cdr.markForCheck(); requestAnimationFrame.flush(); - expect(comp.doCheckCount).toEqual(2); + expect(comp.doCheckCount).toEqual(1); }); - it('should schedule check on ancestor OnPush components', () => { - const parent = renderComponent(OnPushParent); - expect(getRenderedText(parent)).toEqual('one - one'); + it('should ensure ancestor OnPush components are checked', () => { + const fixture = new ComponentFixture(OnPushParent); + expect(fixture.hostElement.textContent).toEqual('one - one'); - parent.value = 'two'; - tick(parent); - expect(getRenderedText(parent)).toEqual('one - one'); + fixture.component.value = 'two'; + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('one - one'); comp.cdr.markForCheck(); - requestAnimationFrame.flush(); - expect(getRenderedText(parent)).toEqual('two - one'); + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('two - one'); }); - it('should schedule check on OnPush components in embedded views', () => { + it('should ensure OnPush components in embedded views are checked', () => { class EmbeddedViewParent { value = 'one'; showing = true; @@ -1029,24 +1251,27 @@ describe('change detection', () => { }); } - const parent = renderComponent(EmbeddedViewParent); - expect(getRenderedText(parent)).toEqual('one - one'); + const fixture = new ComponentFixture(EmbeddedViewParent); + expect(fixture.hostElement.textContent).toEqual('one - one'); comp.value = 'two'; - tick(parent); - expect(getRenderedText(parent)).toEqual('one - one'); + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('one - one'); comp.cdr.markForCheck(); - requestAnimationFrame.flush(); - expect(getRenderedText(parent)).toEqual('one - two'); + // markForCheck should not trigger change detection on its own. + expect(fixture.hostElement.textContent).toEqual('one - one'); - parent.value = 'two'; - tick(parent); - expect(getRenderedText(parent)).toEqual('one - two'); + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('one - two'); + + fixture.component.value = 'two'; + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('one - two'); comp.cdr.markForCheck(); - requestAnimationFrame.flush(); - expect(getRenderedText(parent)).toEqual('two - two'); + tick(fixture.component); + expect(fixture.hostElement.textContent).toEqual('two - two'); }); // TODO(kara): add test for dynamic views once bug fix is in diff --git a/packages/core/test/render3/common_with_def.ts b/packages/core/test/render3/common_with_def.ts index 73cbda6bf8..c51ed2b167 100644 --- a/packages/core/test/render3/common_with_def.ts +++ b/packages/core/test/render3/common_with_def.ts @@ -40,7 +40,7 @@ NgForOf.ngDirectiveDef = defineDirective({ type: NgTemplateOutletDef, selectors: [['', 'ngTemplateOutlet', '']], factory: () => new NgTemplateOutletDef(directiveInject(ViewContainerRef as any)), - features: [NgOnChangesFeature], + features: [NgOnChangesFeature()], inputs: {ngTemplateOutlet: 'ngTemplateOutlet', ngTemplateOutletContext: 'ngTemplateOutletContext'} }); diff --git a/packages/core/test/render3/component_ref_spec.ts b/packages/core/test/render3/component_ref_spec.ts index 8b832a912e..963e7ab70c 100644 --- a/packages/core/test/render3/component_ref_spec.ts +++ b/packages/core/test/render3/component_ref_spec.ts @@ -18,7 +18,28 @@ describe('ComponentFactory', () => { const cfr = injectComponentFactoryResolver(); describe('constructor()', () => { - it('should correctly populate public properties', () => { + it('should correctly populate default properties', () => { + class TestComponent { + static ngComponentDef = defineComponent({ + type: TestComponent, + selectors: [['test', 'foo'], ['bar']], + consts: 0, + vars: 0, + template: () => undefined, + factory: () => new TestComponent(), + }); + } + + const cf = cfr.resolveComponentFactory(TestComponent); + + expect(cf.selector).toBe('test'); + expect(cf.componentType).toBe(TestComponent); + expect(cf.ngContentSelectors).toEqual([]); + expect(cf.inputs).toEqual([]); + expect(cf.outputs).toEqual([]); + }); + + it('should correctly populate defined properties', () => { class TestComponent { static ngComponentDef = defineComponent({ type: TestComponent, @@ -27,6 +48,7 @@ describe('ComponentFactory', () => { consts: 0, vars: 0, template: () => undefined, + ngContentSelectors: ['a', 'b'], factory: () => new TestComponent(), inputs: { in1: 'in1', @@ -42,7 +64,7 @@ describe('ComponentFactory', () => { const cf = cfr.resolveComponentFactory(TestComponent); expect(cf.componentType).toBe(TestComponent); - expect(cf.ngContentSelectors).toEqual([]); + expect(cf.ngContentSelectors).toEqual(['*', 'a', 'b']); expect(cf.selector).toBe('test'); expect(cf.inputs).toEqual([ diff --git a/packages/core/test/render3/component_spec.ts b/packages/core/test/render3/component_spec.ts index 743590a276..96858abf48 100644 --- a/packages/core/test/render3/component_spec.ts +++ b/packages/core/test/render3/component_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ViewEncapsulation, createInjector, defineInjectable, defineInjector} from '../../src/core'; +import {ViewEncapsulation, defineInjectable, defineInjector} from '../../src/core'; import {AttributeMarker, ComponentFactory, LifecycleHooksFeature, defineComponent, directiveInject, markDirty, template, getRenderedText} from '../../src/render3/index'; import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, nextContext, text, textBinding, tick} from '../../src/render3/instructions'; @@ -15,6 +15,7 @@ import {ComponentDef, RenderFlags} from '../../src/render3/interfaces/definition import {NgIf} from './common_with_def'; import {getRendererFactory2} from './imported_renderer2'; import {ComponentFixture, MockRendererFactory, containerEl, createComponent, renderComponent, renderToHtml, requestAnimationFrame, toHtml} from './render_util'; +import {createInjector} from '../../src/di/r3_injector'; describe('component', () => { class CounterComponent { @@ -666,3 +667,41 @@ describe('recursive components', () => { }); }); + +describe('view destruction', () => { + let wasOnDestroyCalled = false; + + class ComponentWithOnDestroy { + static ngComponentDef = defineComponent({ + selectors: [['comp-with-destroy']], + type: ComponentWithOnDestroy, + consts: 0, + vars: 0, + factory: () => new ComponentWithOnDestroy(), + template: (rf: any, ctx: any) => {}, + }); + + ngOnDestroy() { wasOnDestroyCalled = true; } + } + + it('should invoke onDestroy when directly destroying a root view', () => { + // This test asserts that the view tree is set up correctly based on the knowledge that this + // tree is used during view destruction. If the child view is not correctly attached as a + // child of the root view, then the onDestroy hook on the child view will never be called + // when the view tree is torn down following the destruction of that root view. + const ComponentWithChildOnDestroy = createComponent('test-app', (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'comp-with-destroy'); + } + }, 1, 0, [ComponentWithOnDestroy], [], null, [], []); + + const fixture = new ComponentFixture(ComponentWithChildOnDestroy); + fixture.update(); + + fixture.destroy(); + expect(wasOnDestroyCalled) + .toBe( + true, + 'Expected component onDestroy method to be called when its parent view is destroyed'); + }); +}); diff --git a/packages/core/test/render3/content_spec.ts b/packages/core/test/render3/content_spec.ts index 6625bd58ba..a4d82b307c 100644 --- a/packages/core/test/render3/content_spec.ts +++ b/packages/core/test/render3/content_spec.ts @@ -8,10 +8,12 @@ import {SelectorFlags} from '@angular/core/src/render3/interfaces/projection'; -import {AttributeMarker, detectChanges} from '../../src/render3/index'; +import {AttributeMarker, defineComponent, defineDirective, detectChanges, directiveInject, loadViewQuery, queryRefresh, reference, templateRefExtractor, viewQuery} from '../../src/render3/index'; + import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, projection, projectionDef, template, text, textBinding, interpolation1} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; +import {TemplateRef, ViewContainerRef, QueryList} from '@angular/core'; import {NgIf, NgForOf} from './common_with_def'; import {ComponentFixture, createComponent, getDirectiveOnNode, renderComponent, toHtml} from './render_util'; @@ -997,6 +999,83 @@ describe('content projection', () => { expect(fixture.html).toEqual('BBefore-
    A
    -After
    '); }); + it('should project if is in a template that has different declaration/insertion points', + () => { + let triggerDir !: Trigger; + + function NgTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + projection(0); + } + } + + /** + * + * + * + */ + const Comp = createComponent( + 'comp', + (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + projectionDef(); + template(1, NgTemplate, 1, 0, 'ng-template', null, null, templateRefExtractor); + } + }, + 2, 0, [], [], + function(rf: RenderFlags, ctx: any) { + /** @ViewChild(TemplateRef) template: TemplateRef */ + if (rf & RenderFlags.Create) { + viewQuery(TemplateRef as any, true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadViewQuery>()) && (ctx.template = tmp.first); + } + }); + + class Trigger { + // @Input() + trigger: any; + + constructor(public vcr: ViewContainerRef) {} + + open() { this.vcr.createEmbeddedView(this.trigger.template); } + + static ngComponentDef = defineDirective({ + type: Trigger, + selectors: [['', 'trigger', '']], + factory: () => triggerDir = new Trigger(directiveInject(ViewContainerRef as any)), + inputs: {trigger: 'trigger'} + }); + } + + /** + * + * + * Some content + * + */ + const App = createComponent('app', (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'button', [AttributeMarker.SelectOnly, 'trigger']); + elementStart(1, 'comp', null, ['comp', '']); + { text(3, 'Some content'); } + elementEnd(); + } + if (rf & RenderFlags.Update) { + const comp = reference(2); + elementProperty(0, 'trigger', bind(comp)); + } + }, 4, 1, [Comp, Trigger]); + + const fixture = new ComponentFixture(App); + expect(fixture.html).toEqual(``); + + triggerDir.open(); + expect(fixture.html).toEqual(`Some content`); + }); + it('should project nodes into the last ng-content', () => { /** *
    @@ -1035,7 +1114,7 @@ describe('content projection', () => { * being re-assigned from one parent to another. Proposal: have compiler * to remove all but the latest occurrence of so we generate * only one P(n, m, 0) instruction. It would make it consistent with the - * current Angular behaviour: + * current Angular behavior: * http://plnkr.co/edit/OAYkNawTDPkYBFTqovTP?p=preview */ it('should project nodes into the last available ng-content', () => { @@ -1362,6 +1441,86 @@ describe('content projection', () => { expect(toHtml(parent)).toEqual('content'); }); + it('should handle projected containers inside other containers', () => { + //
    Child content
    + const NestedComp = createComponent('nested-comp', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart(0, 'div'); + text(1, 'Child content'); + elementEnd(); + } + }, 2, 0, []); + + // + const RootComp = createComponent('root-comp', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + projectionDef(); + projection(0); + } + }, 1, 0, []); + + // + // + // + // + // + function MyApp_ng_container_1_child_comp_1_Template(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'nested-comp'); + } + } + function MyApp_ng_container_1_Template(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementContainerStart(0); + template(1, MyApp_ng_container_1_child_comp_1_Template, 1, 0, 'nested-comp', [3, 'ngIf']); + elementContainerEnd(); + } + if (rf & RenderFlags.Update) { + const last_r2 = ctx.last; + elementProperty(1, 'ngIf', bind(!last_r2)); + } + } + let myAppInstance: MyApp; + class MyApp { + items = [1, 2]; + + static ngComponentDef = defineComponent({ + type: MyApp, + selectors: [['', 'my-app', '']], + factory: () => myAppInstance = new MyApp(), + consts: 2, + vars: 1, + template: function MyApp_Template(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart(0, 'root-comp'); + template( + 1, MyApp_ng_container_1_Template, 2, 1, 'ng-container', + ['ngFor', '', 3, 'ngForOf']); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementProperty(1, 'ngForOf', bind(ctx.items)); + } + }, + directives: [NgForOf, NgIf, NestedComp, RootComp] + }); + } + const fixture = new ComponentFixture(MyApp); + fixture.update(); + + // expecting # of divs to be (items.length - 1), since last element is filtered out by *ngIf, + // this applies to all other assertions below + expect(fixture.hostElement.querySelectorAll('div').length).toBe(1); + + myAppInstance !.items = [3, 4, 5]; + fixture.update(); + expect(fixture.hostElement.querySelectorAll('div').length).toBe(2); + + myAppInstance !.items = [6, 7, 8, 9]; + fixture.update(); + expect(fixture.hostElement.querySelectorAll('div').length).toBe(3); + }); + describe('with selectors', () => { it('should project nodes using attribute selectors', () => { diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index 3ac7c644d2..0aa0c0eded 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Attribute, ChangeDetectorRef, ElementRef, Host, Inject, InjectFlags, Injector, Optional, Renderer2, Self, SkipSelf, TemplateRef, ViewContainerRef, createInjector, defineInjectable, defineInjector} from '@angular/core'; +import {Attribute, ChangeDetectorRef, ElementRef, Host, INJECTOR, Inject, InjectFlags, Injector, Optional, Renderer2, Self, SkipSelf, TemplateRef, ViewContainerRef, defineInjectable, defineInjector} from '@angular/core'; import {ComponentType, RenderFlags} from '@angular/core/src/render3/interfaces/definition'; import {defineComponent} from '../../src/render3/definition'; @@ -25,6 +25,7 @@ import {getRendererFactory2} from './imported_renderer2'; import {ComponentFixture, createComponent, createDirective, getDirectiveOnNode, renderComponent, toHtml} from './render_util'; import {NgIf} from './common_with_def'; import {TNODE} from '../../src/render3/interfaces/injector'; +import {createInjector} from '../../src/di/r3_injector'; import {LContainer, NATIVE} from '../../src/render3/interfaces/container'; describe('di', () => { @@ -36,7 +37,7 @@ describe('di', () => { type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive, - exportAs: 'dir' + exportAs: ['dir'] }); } @@ -89,7 +90,7 @@ describe('di', () => { type: DirC, selectors: [['', 'dirC', '']], factory: () => new DirC(directiveInject(DirA), directiveInject(DirB)), - exportAs: 'dirC' + exportAs: ['dirC'] }); } @@ -183,7 +184,7 @@ describe('di', () => { consts: 0, vars: 0, factory: () => new Comp(directiveInject(DirB)), - template: (ctx: any, fm: boolean) => {} + template: (rf: RenderFlags, ctx: Comp) => {} }); } @@ -427,7 +428,7 @@ describe('di', () => { type: DirA, selectors: [['', 'dirA', '']], factory: () => new DirA(directiveInject(DirB), directiveInject(ViewContainerRef as any)), - exportAs: 'dirA' + exportAs: ['dirA'] }); } @@ -1460,6 +1461,36 @@ describe('di', () => { expect(injectorDir.injector).not.toBe(otherInjectorDir.injector); }); + it('should inject INJECTOR', () => { + let injectorDir !: INJECTORDir; + let divElement !: HTMLElement; + + class INJECTORDir { + constructor(public injector: Injector) {} + + static ngDirectiveDef = defineDirective({ + type: INJECTORDir, + selectors: [['', 'injectorDir', '']], + factory: () => injectorDir = new INJECTORDir(directiveInject(INJECTOR as any)) + }); + } + + + /**
    */ + const App = createComponent('app', (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'div', ['injectorDir', '']); + } + // testing only + divElement = load(0); + }, 1, 0, [INJECTORDir]); + + const fixture = new ComponentFixture(App); + expect(injectorDir.injector.get(ElementRef).nativeElement).toBe(divElement); + expect(injectorDir.injector.get(Injector).get(ElementRef).nativeElement).toBe(divElement); + expect(injectorDir.injector.get(INJECTOR).get(ElementRef).nativeElement).toBe(divElement); + }); + }); describe('ElementRef', () => { @@ -1478,7 +1509,7 @@ describe('di', () => { type: Directive, selectors: [['', 'dir', '']], factory: () => dir = new Directive(directiveInject(ElementRef)), - exportAs: 'dir' + exportAs: ['dir'] }); } @@ -1492,7 +1523,7 @@ describe('di', () => { selectors: [['', 'dirSame', '']], factory: () => dirSameInstance = new DirectiveSameInstance( directiveInject(ElementRef), directiveInject(Directive)), - exportAs: 'dirSame' + exportAs: ['dirSame'] }); } @@ -1528,7 +1559,7 @@ describe('di', () => { type: Directive, selectors: [['', 'dir', '']], factory: () => dir = new Directive(directiveInject(ElementRef)), - exportAs: 'dir' + exportAs: ['dir'] }); } @@ -1556,7 +1587,7 @@ describe('di', () => { type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive(directiveInject(TemplateRef as any)), - exportAs: 'dir' + exportAs: ['dir'] }); } @@ -1571,7 +1602,7 @@ describe('di', () => { selectors: [['', 'dirSame', '']], factory: () => new DirectiveSameInstance( directiveInject(TemplateRef as any), directiveInject(Directive)), - exportAs: 'dirSame' + exportAs: ['dirSame'] }); } @@ -1633,7 +1664,7 @@ describe('di', () => { selectors: [['', 'dir', '']], factory: () => dir = new OptionalDirective( directiveInject(TemplateRef as any, InjectFlags.Optional)), - exportAs: 'dir' + exportAs: ['dir'] }); } @@ -1661,7 +1692,7 @@ describe('di', () => { type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive(directiveInject(ViewContainerRef as any)), - exportAs: 'dir' + exportAs: ['dir'] }); } @@ -1675,7 +1706,7 @@ describe('di', () => { selectors: [['', 'dirSame', '']], factory: () => new DirectiveSameInstance( directiveInject(ViewContainerRef as any), directiveInject(Directive)), - exportAs: 'dirSame' + exportAs: ['dirSame'] }); } @@ -1737,7 +1768,7 @@ describe('di', () => { type: Directive, selectors: [['', 'dir', '']], factory: () => dir = new Directive(directiveInject(ChangeDetectorRef as any)), - exportAs: 'dir' + exportAs: ['dir'] }); } @@ -2223,7 +2254,7 @@ describe('di', () => { type: ChildDirective, selectors: [['', 'childDir', '']], factory: () => new ChildDirective(directiveInject(ParentDirective)), - exportAs: 'childDir' + exportAs: ['childDir'] }); } @@ -2235,7 +2266,7 @@ describe('di', () => { type: Child2Directive, factory: () => new Child2Directive( directiveInject(ParentDirective), directiveInject(ChildDirective)), - exportAs: 'child2Dir' + exportAs: ['child2Dir'] }); } @@ -2289,8 +2320,8 @@ describe('di', () => { describe('getOrCreateNodeInjector', () => { it('should handle initial undefined state', () => { const contentView = createLView( - null, createTView(-1, null, 1, 0, null, null, null), null, LViewFlags.CheckAlways, - {} as any, {} as any); + null, createTView(-1, null, 1, 0, null, null, null, null), null, LViewFlags.CheckAlways, + null, null, {} as any, {} as any); const oldView = enterView(contentView, null); try { const parentTNode = createNodeAtIndex(0, TNodeType.Element, null, null, null); diff --git a/packages/core/test/render3/discovery_utils_spec.ts b/packages/core/test/render3/discovery_utils_spec.ts index f321ce6ead..8ae1366a10 100644 --- a/packages/core/test/render3/discovery_utils_spec.ts +++ b/packages/core/test/render3/discovery_utils_spec.ts @@ -5,11 +5,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {createInjector} from '@angular/core'; - import {StaticInjector} from '../../src/di/injector'; +import {createInjector} from '../../src/di/r3_injector'; import {getComponent, getContext, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getRootComponents, getViewComponent, loadLContext} from '../../src/render3/discovery_utils'; import {ProvidersFeature, RenderFlags, defineComponent, defineDirective, elementContainerEnd, elementContainerStart, getHostElement, i18n, i18nApply, i18nExp} from '../../src/render3/index'; + import {element, elementEnd, elementStart, elementStyling, elementStylingApply, template, bind, elementProperty, text, textBinding, markDirty, listener} from '../../src/render3/instructions'; import {ComponentFixture} from './render_util'; import {NgIf} from './common_with_def'; @@ -89,12 +89,12 @@ describe('discovery utils', () => { static ngDirectiveDef = defineDirective({ type: DirectiveA, selectors: [['', 'dirA', '']], - exportAs: 'dirA', + exportAs: ['dirA'], factory: () => new DirectiveA(), }); } - const MSG_DIV = `{�0�, select, + const MSG_DIV = `{�0�, select, other {ICU expression} }`; @@ -509,7 +509,7 @@ describe('discovery utils deprecated', () => { static ngDirectiveDef = defineDirective({ type: MyDir, selectors: [['', 'myDir', '']], - exportAs: 'myDir', + exportAs: ['myDir'], factory: () => new MyDir() }); } diff --git a/packages/core/test/render3/exports_spec.ts b/packages/core/test/render3/exports_spec.ts index 847ea9b30b..c8cab82482 100644 --- a/packages/core/test/render3/exports_spec.ts +++ b/packages/core/test/render3/exports_spec.ts @@ -14,140 +14,7 @@ import {NgIf} from './common_with_def'; import {ComponentFixture, createComponent, renderToHtml} from './render_util'; describe('exports', () => { - it('should support export of DOM element', () => { - - /** {{ myInput.value }} */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'input', ['value', 'one'], ['myInput', '']); - text(2); - } - if (rf & RenderFlags.Update) { - const tmp = reference(1) as any; - textBinding(2, bind(tmp.value)); - } - }, 3, 1); - - const fixture = new ComponentFixture(App); - expect(fixture.html).toEqual('one'); - }); - - it('should support basic export of component', () => { - class MyComponent { - name = 'Nancy'; - - static ngComponentDef = defineComponent({ - type: MyComponent, - selectors: [['comp']], - consts: 0, - vars: 0, - template: function() {}, - factory: () => new MyComponent - }); - } - - /** {{ myComp.name }} */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'comp', null, ['myComp', '']); - text(2); - } - if (rf & RenderFlags.Update) { - const tmp = reference(1) as any; - textBinding(2, tmp.name); - } - }, 3, 1, [MyComponent]); - - const fixture = new ComponentFixture(App); - expect(fixture.html).toEqual('Nancy'); - }); - - it('should support component instance fed into directive', () => { - - let myComponent: MyComponent; - let myDir: MyDir; - class MyComponent { - constructor() { myComponent = this; } - static ngComponentDef = defineComponent({ - type: MyComponent, - selectors: [['comp']], - consts: 0, - vars: 0, - template: function() {}, - 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'} - }); - } - - const defs = [MyComponent, MyDir]; - - /**
    */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'comp', null, ['myComp', '']); - element(2, 'div', ['myDir', '']); - } - if (rf & RenderFlags.Update) { - const tmp = reference(1) as any; - elementProperty(2, 'myDir', bind(tmp)); - } - }, 3, 1, defs); - - const fixture = new ComponentFixture(App); - expect(myDir !.myDir).toEqual(myComponent !); - }); - - it('should work with directives with exportAs set', () => { - class SomeDir { - name = 'Drew'; - static ngDirectiveDef = defineDirective({ - type: SomeDir, - selectors: [['', 'someDir', '']], - factory: () => new SomeDir, - exportAs: 'someDir' - }); - } - - /**
    {{ myDir.name }} */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'div', ['someDir', ''], ['myDir', 'someDir']); - text(2); - } - if (rf & RenderFlags.Update) { - const tmp = reference(1) as any; - textBinding(2, bind(tmp.name)); - } - }, 3, 1, [SomeDir]); - - const fixture = new ComponentFixture(App); - expect(fixture.html).toEqual('
    Drew'); - }); - - it('should throw if export name is not found', () => { - - /**
    */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - element(0, 'div', null, ['myDir', 'someDir']); - } - }, 1); - - expect(() => { - const fixture = new ComponentFixture(App); - }).toThrowError(/Export of name 'someDir' not found!/); - }); + // For basic use cases, see core/test/acceptance/exports_spec.ts. describe('forward refs', () => { it('should work with basic text bindings', () => { diff --git a/packages/core/test/render3/global_utils_spec.ts b/packages/core/test/render3/global_utils_spec.ts index 5e8d5ebf69..fe0c35994e 100644 --- a/packages/core/test/render3/global_utils_spec.ts +++ b/packages/core/test/render3/global_utils_spec.ts @@ -10,7 +10,7 @@ import {ɵmarkDirty as markDirty} from '@angular/core'; import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getRootComponents, getViewComponent} from '../../src/render3/discovery_utils'; import {GLOBAL_PUBLISH_EXPANDO_KEY, GlobalDevModeContainer, publishDefaultGlobalUtils, publishGlobalUtil} from '../../src/render3/global_utils'; import {getPlayers} from '../../src/render3/players'; -import {global} from '../../src/util'; +import {global} from '../../src/util/global'; describe('global utils', () => { describe('publishGlobalUtil', () => { diff --git a/packages/core/test/render3/host_binding_spec.ts b/packages/core/test/render3/host_binding_spec.ts index 0f1e48ddb1..2185df3317 100644 --- a/packages/core/test/render3/host_binding_spec.ts +++ b/packages/core/test/render3/host_binding_spec.ts @@ -6,13 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementRef} from '@angular/core'; +import {ElementRef, QueryList, ViewContainerRef} from '@angular/core'; -import {AttributeMarker, defineComponent, template, defineDirective, InheritDefinitionFeature, ProvidersFeature, NgOnChangesFeature, QueryList} from '../../src/render3/index'; -import {allocHostVars, bind, directiveInject, element, elementEnd, elementProperty, elementStyleProp, elementStyling, elementStylingApply, elementStart, listener, load, text, textBinding, loadQueryList, registerContentQuery, elementHostAttrs} from '../../src/render3/instructions'; -import {query, queryRefresh} from '../../src/render3/query'; +import {AttributeMarker, defineComponent, template, defineDirective, InheritDefinitionFeature, ProvidersFeature, NgOnChangesFeature} from '../../src/render3/index'; +import {allocHostVars, bind, directiveInject, element, elementAttribute, elementEnd, elementProperty, elementStyleProp, elementStyling, elementStylingApply, elementStart, listener, load, text, textBinding, elementHostAttrs} from '../../src/render3/instructions'; +import {loadContentQuery, contentQuery, queryRefresh} from '../../src/render3/query'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {pureFunction1, pureFunction2} from '../../src/render3/pure_function'; +import {sanitizeUrl, sanitizeUrlOrResourceUrl, sanitizeHtml} from '../../src/sanitization/sanitization'; +import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass'; import {ComponentFixture, TemplateFixture, createComponent, createDirective} from './render_util'; import {NgForOf} from './common_with_def'; @@ -355,7 +357,7 @@ describe('host bindings', () => { template: (rf: RenderFlags, ctx: InitHookComp) => {}, consts: 0, vars: 0, - features: [NgOnChangesFeature], + features: [NgOnChangesFeature()], hostBindings: (rf: RenderFlags, ctx: InitHookComp, elIndex: number) => { if (rf & RenderFlags.Create) { allocHostVars(1); @@ -964,7 +966,11 @@ describe('host bindings', () => { selectors: [['', 'hostAttributeDir', '']], type: HostAttributeDir, factory: () => new HostAttributeDir(), - attributes: ['role', 'listbox'] + hostBindings: function(rf, ctx, elIndex) { + if (rf & RenderFlags.Create) { + elementHostAttrs(ctx, ['role', 'listbox']); + } + } }); } @@ -1003,11 +1009,14 @@ describe('host bindings', () => { elementProperty(elIndex, 'id', bind(ctx.foos.length), null, true); } }, - contentQueries: (dirIndex) => { registerContentQuery(query(null, ['foo']), dirIndex); }, - contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { - let tmp: any; - const instance = load(dirIndex); - queryRefresh(tmp = loadQueryList(queryStartIdx)) && (instance.foos = tmp); + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo']); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.foos = tmp); + } }, template: (rf: RenderFlags, cmp: HostBindingWithContentChildren) => {} }); @@ -1126,6 +1135,58 @@ describe('host bindings', () => { expect(hostBindingEl.style.width).toEqual('5px'); }); + it('should bind to host styles on containers', () => { + let hostBindingDir !: HostBindingToStyles; + /** + * host: { + * '[style.width.px]': 'width' + * } + */ + class HostBindingToStyles { + width = 2; + + static ngDirectiveDef = defineDirective({ + type: HostBindingToStyles, + selectors: [['', 'hostStyles', '']], + factory: () => hostBindingDir = new HostBindingToStyles(), + hostBindings: (rf: RenderFlags, ctx: HostBindingToStyles, elIndex: number) => { + if (rf & RenderFlags.Create) { + elementStyling(null, ['width'], null, ctx); + } + if (rf & RenderFlags.Update) { + elementStyleProp(0, 0, ctx.width, 'px', ctx); + elementStylingApply(0, ctx); + } + } + }); + } + + class ContainerDir { + constructor(public vcr: ViewContainerRef) {} + + static ngDirectiveDef = defineDirective({ + type: ContainerDir, + selectors: [['', 'containerDir', '']], + factory: () => new ContainerDir(directiveInject(ViewContainerRef as any)), + }); + } + + /**
    */ + const App = createComponent('app', (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'div', ['containerDir', '', 'hostStyles', '']); + } + }, 1, 0, [ContainerDir, HostBindingToStyles]); + + const fixture = new ComponentFixture(App); + const hostBindingEl = fixture.hostElement.querySelector('div') as HTMLElement; + expect(hostBindingEl.style.width).toEqual('2px'); + + hostBindingDir.width = 5; + fixture.update(); + expect(hostBindingEl.style.width).toEqual('5px'); + }); + it('should apply static host classes', () => { /** * host: { @@ -1164,4 +1225,60 @@ describe('host bindings', () => { expect(hostBindingEl.className).toEqual('mat-toolbar'); }); }); + + describe('sanitization', () => { + function verify( + tag: string, prop: string, value: any, expectedSanitizedValue: any, sanitizeFn: any, + bypassFn: any, isAttribute: boolean = true) { + it('should sanitize potentially unsafe properties and attributes', () => { + let hostBindingDir: UnsafeUrlHostBindingDir; + class UnsafeUrlHostBindingDir { + // val: any = value; + static ngDirectiveDef = defineDirective({ + type: UnsafeUrlHostBindingDir, + selectors: [['', 'unsafeUrlHostBindingDir', '']], + factory: () => hostBindingDir = new UnsafeUrlHostBindingDir(), + hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => { + if (rf & RenderFlags.Create) { + allocHostVars(1); + } + if (rf & RenderFlags.Update) { + const fn = isAttribute ? elementAttribute : elementProperty; + (fn as any)(elementIndex, prop, bind(ctx[prop]), sanitizeFn, true); + } + } + }); + } + + const fixture = new TemplateFixture(() => { + element(0, tag, ['unsafeUrlHostBindingDir', '']); + }, () => {}, 1, 0, [UnsafeUrlHostBindingDir]); + + const el = fixture.hostElement.querySelector(tag) !; + const current = () => isAttribute ? el.getAttribute(prop) : (el as any)[prop]; + + (hostBindingDir !as any)[prop] = value; + fixture.update(); + expect(current()).toEqual(expectedSanitizedValue); + + (hostBindingDir !as any)[prop] = bypassFn(value); + fixture.update(); + expect(current()).toEqual(value); + }); + } + + verify( + 'a', 'href', 'javascript:alert(1)', 'unsafe:javascript:alert(1)', sanitizeUrlOrResourceUrl, + bypassSanitizationTrustUrl); + verify( + 'script', 'src', bypassSanitizationTrustResourceUrl('javascript:alert(2)'), + 'javascript:alert(2)', sanitizeUrlOrResourceUrl, bypassSanitizationTrustResourceUrl); + verify( + 'blockquote', 'cite', 'javascript:alert(3)', 'unsafe:javascript:alert(3)', sanitizeUrl, + bypassSanitizationTrustUrl); + verify( + 'b', 'innerHTML', '', + '', sanitizeHtml, bypassSanitizationTrustHtml, + /* isAttribute */ false); + }); }); diff --git a/packages/core/test/render3/i18n_spec.ts b/packages/core/test/render3/i18n_spec.ts index e64c420812..fc97c5aa04 100644 --- a/packages/core/test/render3/i18n_spec.ts +++ b/packages/core/test/render3/i18n_spec.ts @@ -8,14 +8,13 @@ import {noop} from '../../../compiler/src/render3/view/util'; import {Component as _Component} from '../../src/core'; -import {defineComponent} from '../../src/render3/definition'; +import {defineComponent, defineDirective} from '../../src/render3/definition'; import {getTranslationForTemplate, i18n, i18nApply, i18nAttributes, i18nEnd, i18nExp, i18nPostprocess, i18nStart} from '../../src/render3/i18n'; import {RenderFlags} from '../../src/render3/interfaces/definition'; +import {AttributeMarker} from '../../src/render3/interfaces/node'; import {getNativeByIndex} from '../../src/render3/util'; - import {NgIf} from './common_with_def'; - -import {element, elementEnd, elementStart, template, text, bind, elementProperty, projectionDef, projection} from '../../src/render3/instructions'; +import {allocHostVars, element, elementEnd, elementStart, template, text, nextContext, bind, elementProperty, projectionDef, projection, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nUpdateOpCode, I18nUpdateOpCodes, TI18n} from '../../src/render3/interfaces/i18n'; import {HEADER_OFFSET, LView, TVIEW} from '../../src/render3/interfaces/view'; import {ComponentFixture, TemplateFixture} from './render_util'; @@ -83,9 +82,10 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 1, - expandoStartIndex: nbConsts, - create: - ['simple text', index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild], + create: [ + 'simple text', nbConsts, + index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild + ], update: [], icus: null }); @@ -103,23 +103,27 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 5, - expandoStartIndex: nbConsts, create: [ 'Hello ', + nbConsts, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, elementIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Select, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, 'world', + nbConsts + 1, elementIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, elementIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.ElementEnd, ' and ', + nbConsts + 2, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, elementIndex2 << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Select, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, 'universe', + nbConsts + 3, elementIndex2 << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, elementIndex2 << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.ElementEnd, '!', + nbConsts + 4, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, ], update: [], @@ -135,8 +139,8 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 1, - expandoStartIndex: nbConsts, - create: ['', index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild], + create: + ['', nbConsts, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild], update: [ 0b1, // bindings mask 4, // if no update, skip 4 @@ -156,8 +160,8 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 1, - expandoStartIndex: nbConsts, - create: ['', index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild], + create: + ['', nbConsts, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild], update: [ 0b11, // bindings mask 8, // if no update, skip 8 @@ -189,13 +193,14 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 2, - expandoStartIndex: nbConsts, create: [ '', + nbConsts, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, 2 << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Select, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, '!', + nbConsts + 1, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, ], update: [ @@ -218,15 +223,16 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 2, - expandoStartIndex: nbConsts, create: [ spanElement << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Select, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, 'before', + nbConsts, spanElement << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, bElementSubTemplate << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Select, spanElement << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, 'after', + nbConsts + 1, spanElement << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, spanElement << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.ElementEnd, ], @@ -244,11 +250,11 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 1, - expandoStartIndex: nbConsts, create: [ bElement << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Select, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, 'middle', + nbConsts, bElement << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, bElement << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.ElementEnd, ], @@ -268,7 +274,7 @@ describe('Runtime i18n', () => { const opCodes = getOpCodes(() => { i18nStart(index, MSG_DIV); }, null, nbConsts, index); const tIcuIndex = 0; const icuCommentNodeIndex = index + 1; - const firstTextNode = index + 2; + const firstTextNodeIndex = index + 2; const bElementNodeIndex = index + 3; const iElementNodeIndex = index + 3; const spanElementNodeIndex = index + 3; @@ -277,9 +283,8 @@ describe('Runtime i18n', () => { expect(opCodes).toEqual({ vars: 5, - expandoStartIndex: nbConsts, create: [ - COMMENT_MARKER, 'ICU 1', + COMMENT_MARKER, 'ICU 1', icuCommentNodeIndex, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], update: [ @@ -294,55 +299,58 @@ describe('Runtime i18n', () => { icus: [{ type: 1, vars: [4, 3, 3], - expandoStartIndex: icuCommentNodeIndex + 1, childIcus: [[], [], []], cases: ['0', '1', 'other'], create: [ [ 'no ', + firstTextNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, ELEMENT_MARKER, 'b', + bElementNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, bElementNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Attr, 'title', 'none', 'emails', + innerTextNode, bElementNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, '!', + lastTextNode, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, ], [ - 'one ', + 'one ', firstTextNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, - ELEMENT_MARKER, 'i', + ELEMENT_MARKER, 'i', iElementNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, - 'email', + 'email', innerTextNode, iElementNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], [ - '', + '', firstTextNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, - ELEMENT_MARKER, 'span', + ELEMENT_MARKER, 'span', spanElementNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, - 'emails', + 'emails', innerTextNode, spanElementNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ] ], remove: [ [ - firstTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, + firstTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, innerTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, bElementNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, lastTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, ], [ - firstTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, + firstTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, innerTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, iElementNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, ], [ - firstTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, + firstTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, innerTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, spanElementNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, ] @@ -354,7 +362,7 @@ describe('Runtime i18n', () => { 3, // skip 3 if not changed -1, // binding index ' ', // text string to concatenate to the binding value - firstTextNode << I18nUpdateOpCode.SHIFT_REF | I18nUpdateOpCode.Text, + firstTextNodeIndex << I18nUpdateOpCode.SHIFT_REF | I18nUpdateOpCode.Text, 0b10, // mask for the title attribute binding 4, // skip 4 if not changed -2, // binding index @@ -380,18 +388,17 @@ describe('Runtime i18n', () => { const index = 0; const opCodes = getOpCodes(() => { i18nStart(index, MSG_DIV); }, null, nbConsts, index); const icuCommentNodeIndex = index + 1; - const firstTextNode = index + 2; + const firstTextNodeIndex = index + 2; const nestedIcuCommentNodeIndex = index + 3; - const lastTextNode = index + 4; - const nestedTextNode = index + 5; + const lastTextNodeIndex = index + 4; + const nestedTextNodeIndex = index + 5; const tIcuIndex = 1; const nestedTIcuIndex = 0; expect(opCodes).toEqual({ vars: 6, - expandoStartIndex: nbConsts, create: [ - COMMENT_MARKER, 'ICU 1', + COMMENT_MARKER, 'ICU 1', icuCommentNodeIndex, index << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], update: [ @@ -407,55 +414,56 @@ describe('Runtime i18n', () => { { type: 0, vars: [1, 1, 1], - expandoStartIndex: lastTextNode + 1, childIcus: [[], [], []], cases: ['cat', 'dog', 'other'], create: [ [ - 'cats', nestedIcuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | + 'cats', nestedTextNodeIndex, nestedIcuCommentNodeIndex + << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], [ - 'dogs', nestedIcuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | + 'dogs', nestedTextNodeIndex, nestedIcuCommentNodeIndex + << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], [ - 'animals', nestedIcuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | + 'animals', nestedTextNodeIndex, nestedIcuCommentNodeIndex + << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ] ], remove: [ - [nestedTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove], - [nestedTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove], - [nestedTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove] + [nestedTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove], + [nestedTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove], + [nestedTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove] ], update: [[], [], []] }, { type: 1, vars: [1, 4], - expandoStartIndex: icuCommentNodeIndex + 1, childIcus: [[], [0]], cases: ['0', 'other'], create: [ [ - 'zero', + 'zero', firstTextNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], [ - '', + '', firstTextNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, - COMMENT_MARKER, 'nested ICU 0', + COMMENT_MARKER, 'nested ICU 0', nestedIcuCommentNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild, - '!', + '!', lastTextNodeIndex, icuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ] ], remove: [ - [firstTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove], + [firstTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove], [ - firstTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, - lastTextNode << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, + firstTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, + lastTextNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, 0 << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.RemoveNestedIcu, nestedIcuCommentNodeIndex << I18nMutateOpCode.SHIFT_REF | I18nMutateOpCode.Remove, ] @@ -467,7 +475,7 @@ describe('Runtime i18n', () => { 3, // skip 3 if not changed -1, // binding index ' ', // text string to concatenate to the binding value - firstTextNode << I18nUpdateOpCode.SHIFT_REF | I18nUpdateOpCode.Text, + firstTextNodeIndex << I18nUpdateOpCode.SHIFT_REF | I18nUpdateOpCode.Text, 0b10, // mask for inner ICU main binding 3, // skip 3 if not changed -2, // inner ICU main binding @@ -656,6 +664,130 @@ describe('Runtime i18n', () => { expect(fixture.html).toEqual('
    '); }); + it('for multiple ICU expressions', () => { + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} + other {�0� emails} + } - {�0�, select, + other {(�0�)} + }`; + const fixture = prepareFixture(() => { + elementStart(0, 'div'); + i18n(1, MSG_DIV); + elementEnd(); + }, null, 2); + + // Template should be empty because there is no update template function + expect(fixture.html).toEqual('
    -
    '); + }); + + it('for multiple ICU expressions inside html', () => { + const MSG_DIV = `�#2�{�0�, plural, + =0 {no emails!} + =1 {one email} + other {�0� emails} + }�/#2��#3�{�0�, select, + other {(�0�)} + }�/#3�`; + const fixture = prepareFixture(() => { + elementStart(0, 'div'); + i18nStart(1, MSG_DIV); + element(2, 'span'); + element(3, 'span'); + i18nEnd(); + elementEnd(); + }, null, 4); + + // Template should be empty because there is no update template function + expect(fixture.html).toEqual('
    '); + }); + + it('for ICU expressions inside templates', () => { + const MSG_DIV = `�*2:1��#1:1�{�0:1�, plural, + =0 {no emails!} + =1 {one email} + other {�0:1� emails} + }�/#1:1��/*2:1�`; + + function subTemplate_1(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + i18nStart(0, MSG_DIV, 1); + element(1, 'span'); + i18nEnd(); + } + if (rf & RenderFlags.Update) { + const ctx = nextContext(); + i18nExp(bind(ctx.value0)); + i18nExp(bind(ctx.value1)); + i18nApply(0); + } + } + + class MyApp { + value0 = 0; + value1 = 'emails label'; + + static ngComponentDef = defineComponent({ + type: MyApp, + selectors: [['my-app']], + directives: [NgIf], + factory: () => new MyApp(), + consts: 3, + vars: 1, + template: (rf: RenderFlags, ctx: MyApp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'div'); + i18nStart(1, MSG_DIV); + template(2, subTemplate_1, 2, 2, 'span', [3, 'ngIf']); + i18nEnd(); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementProperty(2, 'ngIf', true); + } + } + }); + } + + const fixture = new ComponentFixture(MyApp); + expect(fixture.html) + .toEqual('
    no emails!
    '); + + // Update the value + fixture.component.value0 = 3; + fixture.update(); + expect(fixture.html) + .toEqual( + '
    3 emails
    '); + }); + + it('for ICU expressions inside ', () => { + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} + other {�0� emails} + }`; + const fixture = prepareFixture( + () => { + elementStart(0, 'div'); + { + elementContainerStart(1); + { i18n(2, MSG_DIV); } + elementContainerEnd(); + } + elementEnd(); + }, + () => { + i18nExp(bind(0)); + i18nExp(bind('more than one')); + i18nApply(2); + }, + 3, 2); + + expect(fixture.html).toEqual('
    no emails!
    '); + }); + it('for nested ICU expressions', () => { const MSG_DIV = `{�0�, plural, =0 {zero} @@ -929,6 +1061,118 @@ describe('Runtime i18n', () => { expect(fixture.html).toEqual('
    no emails!
    '); }); + it('for multiple ICU expressions', () => { + const MSG_DIV = `{�0�, plural, + =0 {no emails!} + =1 {one email} + other {�0� emails} + } - {�0�, select, + other {(�0�)} + }`; + const ctx = {value0: 0, value1: 'emails label'}; + + const fixture = prepareFixture( + () => { + elementStart(0, 'div'); + i18n(1, MSG_DIV); + elementEnd(); + }, + () => { + i18nExp(bind(ctx.value0)); + i18nExp(bind(ctx.value1)); + i18nApply(1); + }, + 2, 2); + expect(fixture.html) + .toEqual('
    no emails! - (0)
    '); + + // Change detection cycle, no model changes + fixture.update(); + expect(fixture.html) + .toEqual('
    no emails! - (0)
    '); + + ctx.value0 = 1; + fixture.update(); + expect(fixture.html).toEqual('
    one email - (1)
    '); + + ctx.value0 = 10; + fixture.update(); + expect(fixture.html) + .toEqual( + '
    10 emails - (10)
    '); + + ctx.value1 = '10 emails'; + fixture.update(); + expect(fixture.html) + .toEqual( + '
    10 emails - (10)
    '); + + ctx.value0 = 0; + fixture.update(); + expect(fixture.html) + .toEqual('
    no emails! - (0)
    '); + }); + + it('for multiple ICU expressions', () => { + const MSG_DIV = `�#2�{�0�, plural, + =0 {no emails!} + =1 {one email} + other {�0� emails} + }�/#2��#3�{�0�, select, + other {(�0�)} + }�/#3�`; + const ctx = {value0: 0, value1: 'emails label'}; + + const fixture = prepareFixture( + () => { + elementStart(0, 'div'); + i18nStart(1, MSG_DIV); + element(2, 'span'); + element(3, 'span'); + i18nEnd(); + elementEnd(); + }, + () => { + i18nExp(bind(ctx.value0)); + i18nExp(bind(ctx.value1)); + i18nApply(1); + }, + 4, 2); + expect(fixture.html) + .toEqual( + '
    no emails!(0)
    '); + + // Change detection cycle, no model changes + fixture.update(); + expect(fixture.html) + .toEqual( + '
    no emails!(0)
    '); + + ctx.value0 = 1; + fixture.update(); + expect(fixture.html) + .toEqual( + '
    one email(1)
    '); + + ctx.value0 = 10; + fixture.update(); + expect(fixture.html) + .toEqual( + '
    10 emails(10)
    '); + + ctx.value1 = '10 emails'; + fixture.update(); + expect(fixture.html) + .toEqual( + '
    10 emails(10)
    '); + + ctx.value0 = 0; + fixture.update(); + expect(fixture.html) + .toEqual( + '
    no emails!(0)
    '); + }); + it('for nested ICU expressions', () => { const MSG_DIV = `{�0�, plural, =0 {zero} @@ -1093,6 +1337,105 @@ describe('Runtime i18n', () => { expect(fixture.html).toEqual(`
    trad 1
    `); }); + it('should work with directives and host bindings', () => { + let directiveInstances: Directive[] = []; + + class Directive { + // @HostBinding('className') + klass = 'foo'; + + static ngDirectiveDef = defineDirective({ + type: Directive, + selectors: [['', 'dir', '']], + factory: () => { + const instance = new Directive(); + directiveInstances.push(instance); + return instance; + }, + hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => { + if (rf & RenderFlags.Create) { + allocHostVars(1); + } + if (rf & RenderFlags.Update) { + elementProperty(elementIndex, 'className', bind(ctx.klass), null, true); + } + } + }); + } + + // Translated template: + //
    + // trad {�0�, plural, + // =0 {no emails!} + // =1 {one email} + // other {�0� emails} + // } + //
    + + const MSG_DIV_1 = `trad {�0�, plural, + =0 {no emails!} + =1 {one email} + other {�0� emails} + }`; + const MSG_DIV_1_ATTR_1 = ['title', `start �1� middle �0� end`]; + + class MyApp { + exp1 = 1; + exp2 = 2; + + static ngComponentDef = defineComponent({ + type: MyApp, + selectors: [['my-app']], + factory: () => new MyApp(), + consts: 6, + vars: 5, + directives: [Directive], + template: (rf: RenderFlags, ctx: MyApp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'div', [AttributeMarker.SelectOnly, 'dir']); + { + i18nAttributes(1, MSG_DIV_1_ATTR_1); + i18nStart(2, MSG_DIV_1); + { + elementStart(3, 'b', [AttributeMarker.SelectOnly, 'dir']); // Will be removed + { i18nAttributes(4, MSG_DIV_1_ATTR_1); } + elementEnd(); + } + i18nEnd(); + } + elementEnd(); + element(5, 'div', [AttributeMarker.SelectOnly, 'dir']); + } + if (rf & RenderFlags.Update) { + i18nExp(bind(ctx.exp1)); + i18nExp(bind(ctx.exp2)); + i18nApply(1); + i18nExp(bind(ctx.exp1)); + i18nApply(2); + i18nExp(bind(ctx.exp1)); + i18nExp(bind(ctx.exp2)); + i18nApply(4); + } + } + }); + } + + const fixture = new ComponentFixture(MyApp); + // the "test" attribute should not be reflected in the DOM as it is here only for directive + // matching purposes + expect(fixture.html) + .toEqual( + `
    trad one email
    `); + + directiveInstances.forEach(instance => instance.klass = 'bar'); + fixture.component.exp1 = 2; + fixture.component.exp2 = 3; + fixture.update(); + expect(fixture.html) + .toEqual( + `
    trad 2 emails
    `); + }); + describe('projection', () => { it('should project the translations', () => { @Component({selector: 'child', template: '

    '}) @@ -1274,6 +1617,23 @@ describe('Runtime i18n', () => { expect(fixture.html) .toEqual( '

    Je suis projeté depuis Parent

    '); + + // it should be able to render a new component with the same template code + const fixture2 = new ComponentFixture(Parent); + expect(fixture2.html).toEqual(fixture.html); + + // Updating the fixture should work + fixture2.component.name = 'Parent 2'; + fixture.update(); + fixture2.update(); + expect(fixture2.html) + .toEqual( + '

    Je suis projeté depuis Parent 2

    '); + + // The first fixture should not have changed + expect(fixture.html) + .toEqual( + '

    Je suis projeté depuis Parent

    '); }); it('should re-project translations when multiple projections', () => { @@ -1411,7 +1771,7 @@ describe('Runtime i18n', () => { selectors: [['parent']], directives: [Child], factory: () => new Parent(), - consts: 2, + consts: 3, vars: 0, template: (rf: RenderFlags, cmp: Parent) => { if (rf & RenderFlags.Create) { @@ -1503,7 +1863,7 @@ describe('Runtime i18n', () => { describe('i18nPostprocess', () => { it('should handle valid cases', () => { - const arr = ['�*1:1��#2:1�', '�#4:2�', '�6:4�', '�/#2:1��/*1:1�']; + const arr = ['�*1:1��#2:1�', '�#4:1�', '�6:1�', '�/#2:1��/*1:1�']; const str = `[${arr.join('|')}]`; const cases = [ @@ -1581,6 +1941,57 @@ describe('Runtime i18n', () => { }); }); + it('should handle nested template represented by multi-value placeholders', () => { + /** + *
    + * + * Hello - 1 + * + * + * Hello - 2 + * + * Hello - 3 + * + * Hello - 4 + * + * + * + * + * Hello - 5 + * + *
    + */ + const generated = ` + [�#2�|�#4�] Bonjour - 1 [�/#2�|�/#1:3��/*2:3�|�/#1:2��/*2:2�|�/#1:1��/*3:1�|�/#4�] + [�*3:1��#1:1�|�*2:2��#1:2�|�*2:3��#1:3�] + Bonjour - 2 + [�*3:1��#1:1�|�*2:2��#1:2�|�*2:3��#1:3�] + Bonjour - 3 + [�*3:1��#1:1�|�*2:2��#1:2�|�*2:3��#1:3�] Bonjour - 4 [�/#2�|�/#1:3��/*2:3�|�/#1:2��/*2:2�|�/#1:1��/*3:1�|�/#4�] + [�/#2�|�/#1:3��/*2:3�|�/#1:2��/*2:2�|�/#1:1��/*3:1�|�/#4�] + [�/#2�|�/#1:3��/*2:3�|�/#1:2��/*2:2�|�/#1:1��/*3:1�|�/#4�] + [�#2�|�#4�] Bonjour - 5 [�/#2�|�/#1:3��/*2:3�|�/#1:2��/*2:2�|�/#1:1��/*3:1�|�/#4�] + `; + const final = ` + �#2� Bonjour - 1 �/#2� + �*3:1� + �#1:1� + Bonjour - 2 + �*2:2� + �#1:2� + Bonjour - 3 + �*2:3� + �#1:3� Bonjour - 4 �/#1:3� + �/*2:3� + �/#1:2� + �/*2:2� + �/#1:1� + �/*3:1� + �#4� Bonjour - 5 �/#4� + `; + expect(i18nPostprocess(generated.replace(/\s+/g, ''))).toEqual(final.replace(/\s+/g, '')); + }); + it('should throw in case we have invalid string', () => { const arr = ['�*1:1��#2:1�', '�#4:2�', '�6:4�', '�/#2:1��/*1:1�']; const str = `[${arr.join('|')}]`; diff --git a/packages/core/test/render3/inherit_definition_feature_spec.ts b/packages/core/test/render3/inherit_definition_feature_spec.ts index d19b58d8eb..7fa9769039 100644 --- a/packages/core/test/render3/inherit_definition_feature_spec.ts +++ b/packages/core/test/render3/inherit_definition_feature_spec.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject, InjectionToken} from '../../src/core'; -import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, allocHostVars, bind, defineBase, defineComponent, defineDirective, directiveInject, element, elementProperty, load} from '../../src/render3/index'; +import {ElementRef, Inject, InjectionToken, QueryList, ɵAttributeMarker as AttributeMarker} from '../../src/core'; +import {allocHostVars, bind, ComponentDef, contentQuery, defineBase, defineComponent, defineDirective, DirectiveDef, directiveInject, element, elementEnd, elementProperty, elementStart, InheritDefinitionFeature, load, loadContentQuery, loadViewQuery, NgOnChangesFeature, ProvidersFeature, queryRefresh, RenderFlags, viewQuery,} from '../../src/render3/index'; -import {ComponentFixture, createComponent} from './render_util'; +import {ComponentFixture, createComponent, getDirectiveOnNode} from './render_util'; describe('InheritDefinitionFeature', () => { it('should inherit lifecycle hooks', () => { @@ -363,48 +363,164 @@ describe('InheritDefinitionFeature', () => { expect(divEl.title).toEqual('new-title'); }); - it('should compose viewQuery', () => { - const log: Array<[string, RenderFlags, any]> = []; + describe('view query', () => { + const SomeComp = createComponent('some-comp', (rf: RenderFlags, ctx: any) => {}); + + /* + * class SuperComponent { + * @ViewChildren('super') superQuery; + * } + */ class SuperComponent { + superQuery?: QueryList; static ngComponentDef = defineComponent({ type: SuperComponent, template: () => {}, consts: 0, vars: 0, - selectors: [['', 'superDir', '']], - viewQuery: (rf: RenderFlags, ctx: T) => { - log.push(['super', rf, ctx]); + selectors: [['super-comp']], + viewQuery: (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + viewQuery(['super'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadViewQuery>()) && + (ctx.superQuery = tmp as QueryList); + } }, factory: () => new SuperComponent(), }); } + /** + *
    + *
    + * + * class SubComponent extends SuperComponent { + * @ViewChildren('sub') subQuery; + * } + */ class SubComponent extends SuperComponent { + subQuery?: QueryList; static ngComponentDef = defineComponent({ type: SubComponent, - template: () => {}, - consts: 0, + template: (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'div', ['id', 'sub'], ['sub', '']); + element(2, 'div', ['id', 'super'], ['super', '']); + element(4, 'some-comp'); + } + }, + consts: 5, vars: 0, - selectors: [['', 'subDir', '']], - viewQuery: (directiveIndex: number, elementIndex: number) => { - log.push(['sub', directiveIndex, elementIndex]); + selectors: [['sub-comp']], + viewQuery: (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + viewQuery(['sub'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadViewQuery>()) && + (ctx.subQuery = tmp as QueryList); + } }, factory: () => new SubComponent(), - features: [InheritDefinitionFeature] + features: [InheritDefinitionFeature], + directives: [SomeComp] }); } - const subDef = SubComponent.ngComponentDef as ComponentDef; - const context = {foo: 'bar'}; + it('should compose viewQuery (basic mechanics check)', () => { + const log: Array<[string, RenderFlags, any]> = []; - subDef.viewQuery !(1, context); + class SuperComponent { + static ngComponentDef = defineComponent({ + type: SuperComponent, + template: () => {}, + consts: 0, + vars: 0, + selectors: [['', 'superDir', '']], + viewQuery: (rf: RenderFlags, ctx: T) => { + log.push(['super', rf, ctx]); + }, + factory: () => new SuperComponent(), + }); + } + + class SubComponent extends SuperComponent { + static ngComponentDef = defineComponent({ + type: SubComponent, + template: () => {}, + consts: 0, + vars: 0, + selectors: [['', 'subDir', '']], + viewQuery: (rf: RenderFlags, ctx: SubComponent) => { + log.push(['sub', rf, ctx]); + }, + factory: () => new SubComponent(), + features: [InheritDefinitionFeature] + }); + } + + const subDef = SubComponent.ngComponentDef as ComponentDef; + + const context = {foo: 'bar'}; + + subDef.viewQuery !(RenderFlags.Create, context); + + expect(log).toEqual( + [['super', RenderFlags.Create, context], ['sub', RenderFlags.Create, context]]); + }); + + + + it('should compose viewQuery (query logic check)', () => { + const fixture = new ComponentFixture(SubComponent); + + const check = (key: string): void => { + const qList = (fixture.component as any)[`${key}Query`] as QueryList; + expect(qList.length).toBe(1); + expect(qList.first.nativeElement).toEqual(fixture.hostElement.querySelector(`#${key}`)); + expect(qList.first.nativeElement.id).toEqual(key); + }; + + check('sub'); + check('super'); + }); + + it('should work with multiple viewQuery comps', () => { + let subCompOne !: SubComponent; + let subCompTwo !: SubComponent; + + const App = createComponent('app', (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'sub-comp'); + element(1, 'sub-comp'); + } + subCompOne = getDirectiveOnNode(0); + subCompTwo = getDirectiveOnNode(1); + }, 2, 0, [SubComponent, SuperComponent]); + + const fixture = new ComponentFixture(App); + + const check = (comp: SubComponent): void => { + const qList = comp.subQuery as QueryList; + expect(qList.length).toBe(1); + expect(qList.first.nativeElement).toEqual(fixture.hostElement.querySelector('#sub')); + expect(qList.first.nativeElement.id).toEqual('sub'); + }; + + check(subCompOne); + check(subCompTwo); + }); - expect(log).toEqual([['super', 1, context], ['sub', 1, context]]); }); - it('should compose contentQueries', () => { + + it('should compose contentQueries (basic mechanics check)', () => { const log: string[] = []; class SuperDirective { @@ -428,42 +544,74 @@ describe('InheritDefinitionFeature', () => { const subDef = SubDirective.ngDirectiveDef as DirectiveDef; - subDef.contentQueries !(0); + subDef.contentQueries !(RenderFlags.Create, {}, 0); expect(log).toEqual(['super', 'sub']); }); - it('should compose contentQueriesRefresh', () => { - const log: Array<[string, number, number]> = []; - + it('should compose contentQueries (verify query sets)', () => { + let dirInstance: SubDirective; class SuperDirective { + // @ContentChildren('foo') + foos !: QueryList; + static ngDirectiveDef = defineDirective({ type: SuperDirective, - selectors: [['', 'superDir', '']], - contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => { - log.push(['super', directiveIndex, queryIndex]); - }, + selectors: [['', 'super-dir', '']], factory: () => new SuperDirective(), + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.foos = tmp); + } + } }); } class SubDirective extends SuperDirective { + // @ContentChildren('bar') + bars !: QueryList; + static ngDirectiveDef = defineDirective({ type: SubDirective, - selectors: [['', 'subDir', '']], - contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => { - log.push(['sub', directiveIndex, queryIndex]); + selectors: [['', 'sub-dir', '']], + factory: () => dirInstance = new SubDirective(), + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['bar'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.bars = tmp); + } }, - factory: () => new SubDirective(), features: [InheritDefinitionFeature] }); } - const subDef = SubDirective.ngDirectiveDef as DirectiveDef; + /** + *
    + * + * + *
    + */ + const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart(0, 'div', [AttributeMarker.SelectOnly, 'sub-dir']); + { + element(1, 'span', null, ['foo', '']); + element(3, 'span', null, ['bar', '']); + } + elementEnd(); + } + }, 5, 0, [SubDirective]); - subDef.contentQueriesRefresh !(1, 2); - - expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]); + const fixture = new ComponentFixture(AppComponent); + expect(dirInstance !.foos.length).toBe(1); + expect(dirInstance !.bars.length).toBe(1); }); it('should throw if inheriting a component from a directive', () => { @@ -488,43 +636,6 @@ describe('InheritDefinitionFeature', () => { }).toThrowError('Directives cannot inherit Components'); }); - it('should inherit ngOnChanges', () => { - const log: string[] = []; - let subDir !: SubDirective; - - class SuperDirective { - someInput = ''; - - ngOnChanges() { log.push('on changes!'); } - - static ngDirectiveDef = defineDirective({ - type: SuperDirective, - selectors: [['', 'superDir', '']], - factory: () => new SuperDirective(), - features: [NgOnChangesFeature], - inputs: {someInput: 'someInput'} - }); - } - - class SubDirective extends SuperDirective { - static ngDirectiveDef = defineDirective({ - type: SubDirective, - selectors: [['', 'subDir', '']], - factory: () => subDir = new SubDirective(), - features: [InheritDefinitionFeature], - }); - } - - const App = createComponent('app', (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - element(0, 'div', ['subDir', '']); - } - }, 1, 0, [SubDirective]); - - const fixture = new ComponentFixture(App); - expect(log).toEqual(['on changes!']); - }); - it('should NOT inherit providers', () => { let otherDir !: OtherDirective; diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index ebf4ddc476..f69ec88ee5 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -182,11 +182,12 @@ describe('instructions', () => { }); it('should not stringify non string values', () => { - const t = new TemplateFixture(createDiv, () => {}, 1); + const t = new TemplateFixture(() => { element(0, 'input'); }, () => {}, 1); - t.update(() => elementProperty(0, 'hidden', false)); - // The hidden property would be true if `false` was stringified into `"false"`. - expect((t.hostElement as HTMLElement).querySelector('div') !.hidden).toEqual(false); + // Note: don't use 'hidden' here because IE10 does not support the hidden property + t.update(() => elementProperty(0, 'required', false)); + // The required property would be true if `false` was stringified into `"false"`. + expect((t.hostElement as HTMLElement).querySelector('input') !.required).toEqual(false); expect(ngDevMode).toHaveProperties({ firstTemplatePass: 1, tNode: 2, // 1 for div, 1 for host element diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index b6fbe03438..21371db81e 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -478,8 +478,12 @@ describe('render3 integration test', () => { factory: () => new HostAttributeComp(), consts: 0, vars: 0, + hostBindings: function(rf, ctx, elIndex) { + if (rf & RenderFlags.Create) { + elementHostAttrs(ctx, ['role', 'button']); + } + }, template: (rf: RenderFlags, ctx: HostAttributeComp) => {}, - attributes: ['role', 'button'] }); } @@ -1652,6 +1656,19 @@ describe('render3 integration test', () => { set klass(value: string) { this.classesVal = value; } } + let mockStyleDirective: DirWithStyleDirective; + class DirWithStyleDirective { + static ngDirectiveDef = defineDirective({ + type: DirWithStyleDirective, + selectors: [['', 'DirWithStyle', '']], + factory: () => mockStyleDirective = new DirWithStyleDirective(), + inputs: {'style': 'style'} + }); + + public stylesVal: string = ''; + set style(value: string) { this.stylesVal = value; } + } + it('should delegate initial classes to a [class] input binding if present on a directive on the same element', () => { /** @@ -1674,6 +1691,28 @@ describe('render3 integration test', () => { expect(mockClassDirective !.classesVal).toEqual('apple orange banana'); }); + it('should delegate initial styles to a [style] input binding if present on a directive on the same element', + () => { + /** + *
    + */ + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart( + 0, 'div', + ['DirWithStyle', AttributeMarker.Styles, 'width', '100px', 'height', '200px']); + elementStyling(); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementStylingApply(0); + } + }, 1, 0, [DirWithStyleDirective]); + + const fixture = new ComponentFixture(App); + expect(mockStyleDirective !.stylesVal).toEqual('width:100px;height:200px'); + }); + it('should update `[class]` and bindings in the provided directive if the input is matched', () => { /** @@ -1695,6 +1734,27 @@ describe('render3 integration test', () => { expect(mockClassDirective !.classesVal).toEqual('cucumber grape'); }); + it('should update `[style]` and bindings in the provided directive if the input is matched', + () => { + /** + *
    + */ + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart(0, 'div', ['DirWithStyle']); + elementStyling(); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementStylingMap(0, null, {width: '200px', height: '500px'}); + elementStylingApply(0); + } + }, 1, 0, [DirWithStyleDirective]); + + const fixture = new ComponentFixture(App); + expect(mockStyleDirective !.stylesVal).toEqual('width:200px;height:500px'); + }); + it('should apply initial styling to the element that contains the directive with host styling', () => { class DirWithInitialStyling { @@ -1706,8 +1766,8 @@ describe('render3 integration test', () => { rf: RenderFlags, ctx: DirWithInitialStyling, elementIndex: number) { if (rf & RenderFlags.Create) { elementHostAttrs(ctx, [ - AttributeMarker.Classes, 'heavy', 'golden', AttributeMarker.Styles, 'color', - 'purple', 'font-weight', 'bold' + 'title', 'foo', AttributeMarker.Classes, 'heavy', 'golden', + AttributeMarker.Styles, 'color', 'purple', 'font-weight', 'bold' ]); } } @@ -1719,7 +1779,7 @@ describe('render3 integration test', () => { /** *
    + * style="color:black; font-size:200px">
    */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -1735,6 +1795,7 @@ describe('render3 integration test', () => { const classes = target.getAttribute('class') !.split(/\s+/).sort(); expect(classes).toEqual(['big', 'golden', 'heavy']); + expect(target.getAttribute('title')).toEqual('foo'); expect(target.style.getPropertyValue('color')).toEqual('black'); expect(target.style.getPropertyValue('font-size')).toEqual('200px'); expect(target.style.getPropertyValue('font-weight')).toEqual('bold'); @@ -1817,7 +1878,7 @@ describe('render3 integration test', () => { expect(target.classList.contains('xyz')).toBeTruthy(); }); - it('should properly prioritize style binding collision when they exist on multiple directives', + it('should properly prioritize single style binding collisions when they exist on multiple directives', () => { let dir1Instance: Dir1WithStyle; /** @@ -1868,7 +1929,8 @@ describe('render3 integration test', () => { } /** - *
    + * Component with the following template: + *
    */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -1911,930 +1973,1181 @@ describe('render3 integration test', () => { fixture.update(); expect(target.style.getPropertyValue('width')).toEqual('777px'); }); + + it('should properly prioritize multi style binding collisions when they exist on multiple directives', + () => { + let dir1Instance: Dir1WithStyling; + /** + * Directive with host props: + * [style] + * [class] + */ + class Dir1WithStyling { + static ngDirectiveDef = defineDirective({ + type: Dir1WithStyling, + selectors: [['', 'Dir1WithStyling', '']], + factory: () => dir1Instance = new Dir1WithStyling(), + hostBindings: function(rf: RenderFlags, ctx: Dir1WithStyling, elementIndex: number) { + if (rf & RenderFlags.Create) { + elementStyling(null, null, null, ctx); + } + if (rf & RenderFlags.Update) { + elementStylingMap(elementIndex, ctx.classesExp, ctx.stylesExp, ctx); + elementStylingApply(elementIndex, ctx); + } + } + }); + + classesExp: any = {}; + stylesExp: any = {}; + } + + let dir2Instance: Dir2WithStyling; + /** + * Directive with host props: + * [style] + * style="width:111px" + */ + class Dir2WithStyling { + static ngDirectiveDef = defineDirective({ + type: Dir2WithStyling, + selectors: [['', 'Dir2WithStyling', '']], + factory: () => dir2Instance = new Dir2WithStyling(), + hostBindings: function(rf: RenderFlags, ctx: Dir2WithStyling, elementIndex: number) { + if (rf & RenderFlags.Create) { + elementHostAttrs(ctx, [AttributeMarker.Styles, 'width', '111px']); + elementStyling(null, null, null, ctx); + } + if (rf & RenderFlags.Update) { + elementStylingMap(elementIndex, null, ctx.stylesExp, ctx); + elementStylingApply(elementIndex, ctx); + } + } + }); + + stylesExp: any = {}; + } + + /** + * Component with the following template: + *
    + */ + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'div', ['Dir1WithStyling', '', 'Dir2WithStyling', '']); + elementStyling(); + } + if (rf & RenderFlags.Update) { + elementStylingMap(0, ctx.classesExp, ctx.stylesExp); + elementStylingApply(0); + } + }, 1, 0, [Dir1WithStyling, Dir2WithStyling]); + + const fixture = new ComponentFixture(App); + const target = fixture.hostElement.querySelector('div') !; + expect(target.style.getPropertyValue('width')).toEqual('111px'); + + const compInstance = fixture.component; + compInstance.stylesExp = {width: '999px', height: null}; + compInstance.classesExp = {one: true, two: false}; + dir1Instance !.stylesExp = {width: '222px'}; + dir1Instance !.classesExp = {two: true, three: false}; + dir2Instance !.stylesExp = {width: '333px', height: '100px'}; + fixture.update(); + expect(target.style.getPropertyValue('width')).toEqual('999px'); + expect(target.style.getPropertyValue('height')).toEqual('100px'); + expect(target.classList.contains('one')).toBeTruthy(); + expect(target.classList.contains('two')).toBeFalsy(); + expect(target.classList.contains('three')).toBeFalsy(); + + compInstance.stylesExp = {}; + compInstance !.classesExp = {}; + dir1Instance !.stylesExp = {width: '222px', height: '200px'}; + fixture.update(); + expect(target.style.getPropertyValue('width')).toEqual('222px'); + expect(target.style.getPropertyValue('height')).toEqual('200px'); + expect(target.classList.contains('one')).toBeFalsy(); + expect(target.classList.contains('two')).toBeTruthy(); + expect(target.classList.contains('three')).toBeFalsy(); + + dir1Instance !.stylesExp = {}; + dir1Instance !.classesExp = {}; + fixture.update(); + expect(target.style.getPropertyValue('width')).toEqual('333px'); + expect(target.style.getPropertyValue('height')).toEqual('100px'); + expect(target.classList.contains('one')).toBeFalsy(); + expect(target.classList.contains('two')).toBeFalsy(); + expect(target.classList.contains('three')).toBeFalsy(); + + dir2Instance !.stylesExp = {}; + compInstance.stylesExp = {height: '900px'}; + fixture.update(); + expect(target.style.getPropertyValue('width')).toEqual('111px'); + expect(target.style.getPropertyValue('height')).toEqual('900px'); + + dir1Instance !.stylesExp = {width: '666px', height: '600px'}; + dir1Instance !.classesExp = {four: true, one: true}; + fixture.update(); + expect(target.style.getPropertyValue('width')).toEqual('666px'); + expect(target.style.getPropertyValue('height')).toEqual('900px'); + expect(target.classList.contains('one')).toBeTruthy(); + expect(target.classList.contains('two')).toBeFalsy(); + expect(target.classList.contains('three')).toBeFalsy(); + expect(target.classList.contains('four')).toBeTruthy(); + + compInstance.stylesExp = {width: '777px'}; + compInstance.classesExp = {four: false}; + fixture.update(); + expect(target.style.getPropertyValue('width')).toEqual('777px'); + expect(target.style.getPropertyValue('height')).toEqual('600px'); + expect(target.classList.contains('one')).toBeTruthy(); + expect(target.classList.contains('two')).toBeFalsy(); + expect(target.classList.contains('three')).toBeFalsy(); + expect(target.classList.contains('four')).toBeFalsy(); + }); }); - }); - describe('template data', () => { - - it('should re-use template data and node data', () => { - /** - * % if (condition) { - *
    - * % } - */ - function Template(rf: RenderFlags, ctx: any) { + it('should properly handle and render interpolation for class attribute bindings', () => { + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - container(0); + elementStart(0, 'div'); + elementStyling(); + elementEnd(); } if (rf & RenderFlags.Update) { - containerRefreshStart(0); - { - if (ctx.condition) { - let rf1 = embeddedViewStart(0, 1, 0); - if (rf1 & RenderFlags.Create) { - element(0, 'div'); - } - embeddedViewEnd(); - } - } - containerRefreshEnd(); + elementStylingMap(0, interpolation2('-', ctx.name, '-', ctx.age, '-')); + elementStylingApply(0); } - } + }, 1, 2); - expect((Template as any).ngPrivateData).toBeUndefined(); + const fixture = new ComponentFixture(App); + const target = fixture.hostElement.querySelector('div') !; + expect(target.classList.contains('-fred-36-')).toBeFalsy(); - renderToHtml(Template, {condition: true}, 1); + fixture.component.name = 'fred'; + fixture.component.age = '36'; + fixture.update(); - const oldTemplateData = (Template as any).ngPrivateData; - const oldContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; - const oldElementData = oldContainerData.tViews[0][HEADER_OFFSET]; - expect(oldContainerData).not.toBeNull(); - expect(oldElementData).not.toBeNull(); - - renderToHtml(Template, {condition: false}, 1); - renderToHtml(Template, {condition: true}, 1); - - const newTemplateData = (Template as any).ngPrivateData; - const newContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; - const newElementData = oldContainerData.tViews[0][HEADER_OFFSET]; - expect(newTemplateData === oldTemplateData).toBe(true); - expect(newContainerData === oldContainerData).toBe(true); - expect(newElementData === oldElementData).toBe(true); + expect(target.classList.contains('-fred-36-')).toBeTruthy(); }); - }); +}); - describe('component styles', () => { - it('should pass in the component styles directly into the underlying renderer', () => { - class StyledComp { - static ngComponentDef = defineComponent({ - type: StyledComp, - styles: ['div { color: red; }'], - consts: 1, - vars: 0, - encapsulation: 100, - selectors: [['foo']], - factory: () => new StyledComp(), - template: (rf: RenderFlags, ctx: StyledComp) => { - if (rf & RenderFlags.Create) { +describe('template data', () => { + + it('should re-use template data and node data', () => { + /** + * % if (condition) { + *
    + * % } + */ + function Template(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + container(0); + } + if (rf & RenderFlags.Update) { + containerRefreshStart(0); + { + if (ctx.condition) { + let rf1 = embeddedViewStart(0, 1, 0); + if (rf1 & RenderFlags.Create) { element(0, 'div'); } + embeddedViewEnd(); } - }); + } + containerRefreshEnd(); } - const rendererFactory = new ProxyRenderer3Factory(); - new ComponentFixture(StyledComp, {rendererFactory}); - expect(rendererFactory.lastCapturedType !.styles).toEqual(['div { color: red; }']); - expect(rendererFactory.lastCapturedType !.encapsulation).toEqual(100); - }); + } + + expect((Template as any).ngPrivateData).toBeUndefined(); + + renderToHtml(Template, {condition: true}, 1); + + const oldTemplateData = (Template as any).ngPrivateData; + const oldContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; + const oldElementData = oldContainerData.tViews[0][HEADER_OFFSET]; + expect(oldContainerData).not.toBeNull(); + expect(oldElementData).not.toBeNull(); + + renderToHtml(Template, {condition: false}, 1); + renderToHtml(Template, {condition: true}, 1); + + const newTemplateData = (Template as any).ngPrivateData; + const newContainerData = (oldTemplateData as any).data[HEADER_OFFSET]; + const newElementData = oldContainerData.tViews[0][HEADER_OFFSET]; + expect(newTemplateData === oldTemplateData).toBe(true); + expect(newContainerData === oldContainerData).toBe(true); + expect(newElementData === oldElementData).toBe(true); }); - describe('component animations', () => { - it('should pass in the component styles directly into the underlying renderer', () => { - const animA = {name: 'a'}; - const animB = {name: 'b'}; +}); - class AnimComp { - static ngComponentDef = defineComponent({ - type: AnimComp, - consts: 0, - vars: 0, - data: { - animation: [ - animA, - animB, - ], - }, - selectors: [['foo']], - factory: () => new AnimComp(), - template: (rf: RenderFlags, ctx: AnimComp) => {} - }); - } - const rendererFactory = new ProxyRenderer3Factory(); - new ComponentFixture(AnimComp, {rendererFactory}); - - const capturedAnimations = rendererFactory.lastCapturedType !.data !['animation']; - expect(Array.isArray(capturedAnimations)).toBeTruthy(); - expect(capturedAnimations.length).toEqual(2); - expect(capturedAnimations).toContain(animA); - expect(capturedAnimations).toContain(animB); - }); - - it('should include animations in the renderType data array even if the array is empty', () => { - class AnimComp { - static ngComponentDef = defineComponent({ - type: AnimComp, - consts: 0, - vars: 0, - data: { - animation: [], - }, - selectors: [['foo']], - factory: () => new AnimComp(), - template: (rf: RenderFlags, ctx: AnimComp) => {} - }); - } - const rendererFactory = new ProxyRenderer3Factory(); - new ComponentFixture(AnimComp, {rendererFactory}); - const data = rendererFactory.lastCapturedType !.data; - expect(data.animation).toEqual([]); - }); - - it('should allow [@trigger] bindings to be picked up by the underlying renderer', () => { - class AnimComp { - static ngComponentDef = defineComponent({ - type: AnimComp, - consts: 1, - vars: 1, - selectors: [['foo']], - factory: () => new AnimComp(), - template: (rf: RenderFlags, ctx: AnimComp) => { - if (rf & RenderFlags.Create) { - element(0, 'div', [AttributeMarker.SelectOnly, '@fooAnimation']); - } - if (rf & RenderFlags.Update) { - elementAttribute(0, '@fooAnimation', bind(ctx.animationValue)); - } +describe('component styles', () => { + it('should pass in the component styles directly into the underlying renderer', () => { + class StyledComp { + static ngComponentDef = defineComponent({ + type: StyledComp, + styles: ['div { color: red; }'], + consts: 1, + vars: 0, + encapsulation: 100, + selectors: [['foo']], + factory: () => new StyledComp(), + template: (rf: RenderFlags, ctx: StyledComp) => { + if (rf & RenderFlags.Create) { + element(0, 'div'); } - }); + } + }); + } + const rendererFactory = new ProxyRenderer3Factory(); + new ComponentFixture(StyledComp, {rendererFactory}); + expect(rendererFactory.lastCapturedType !.styles).toEqual(['div { color: red; }']); + expect(rendererFactory.lastCapturedType !.encapsulation).toEqual(100); + }); +}); - animationValue = '123'; - } +describe('component animations', () => { + it('should pass in the component styles directly into the underlying renderer', () => { + const animA = {name: 'a'}; + const animB = {name: 'b'}; - const rendererFactory = new MockRendererFactory(['setAttribute']); - const fixture = new ComponentFixture(AnimComp, {rendererFactory}); + class AnimComp { + static ngComponentDef = defineComponent({ + type: AnimComp, + consts: 0, + vars: 0, + data: { + animation: [ + animA, + animB, + ], + }, + selectors: [['foo']], + factory: () => new AnimComp(), + template: (rf: RenderFlags, ctx: AnimComp) => {} + }); + } + const rendererFactory = new ProxyRenderer3Factory(); + new ComponentFixture(AnimComp, {rendererFactory}); - const renderer = rendererFactory.lastRenderer !; - fixture.component.animationValue = '456'; - fixture.update(); - - const spy = renderer.spies['setAttribute']; - const [elm, attr, value] = spy.calls.mostRecent().args; - - expect(attr).toEqual('@fooAnimation'); - expect(value).toEqual('456'); - }); - - it('should allow creation-level [@trigger] properties to be picked up by the underlying renderer', - () => { - class AnimComp { - static ngComponentDef = defineComponent({ - type: AnimComp, - consts: 1, - vars: 1, - selectors: [['foo']], - factory: () => new AnimComp(), - template: (rf: RenderFlags, ctx: AnimComp) => { - if (rf & RenderFlags.Create) { - element(0, 'div', ['@fooAnimation', '']); - } - } - }); - } - - const rendererFactory = new MockRendererFactory(['setProperty']); - const fixture = new ComponentFixture(AnimComp, {rendererFactory}); - - const renderer = rendererFactory.lastRenderer !; - fixture.update(); - - const spy = renderer.spies['setProperty']; - const [elm, attr, value] = spy.calls.mostRecent().args; - expect(attr).toEqual('@fooAnimation'); - }); + const capturedAnimations = rendererFactory.lastCapturedType !.data !['animation']; + expect(Array.isArray(capturedAnimations)).toBeTruthy(); + expect(capturedAnimations.length).toEqual(2); + expect(capturedAnimations).toContain(animA); + expect(capturedAnimations).toContain(animB); }); - describe('element discovery', () => { - it('should only monkey-patch immediate child nodes in a component', () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - factory: () => new StructuredComp(), - consts: 2, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'div'); - elementStart(1, 'p'); - elementEnd(); - elementEnd(); - } - if (rf & RenderFlags.Update) { - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const host = fixture.hostElement; - const parent = host.querySelector('div') as any; - const child = host.querySelector('p') as any; - - expect(parent[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(child[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); - }); - - it('should only monkey-patch immediate child nodes in a sub component', () => { - class ChildComp { - static ngComponentDef = defineComponent({ - type: ChildComp, - selectors: [['child-comp']], - factory: () => new ChildComp(), - consts: 3, - vars: 0, - template: (rf: RenderFlags, ctx: ChildComp) => { - if (rf & RenderFlags.Create) { - element(0, 'div'); - element(1, 'div'); - element(2, 'div'); - } - } - }); - } - - class ParentComp { - static ngComponentDef = defineComponent({ - type: ParentComp, - selectors: [['parent-comp']], - directives: [ChildComp], - factory: () => new ParentComp(), - consts: 2, - vars: 0, - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'section'); - elementStart(1, 'child-comp'); - elementEnd(); - elementEnd(); - } - } - }); - } - - const fixture = new ComponentFixture(ParentComp); - fixture.update(); - - const host = fixture.hostElement; - const child = host.querySelector('child-comp') as any; - expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - - const [kid1, kid2, kid3] = Array.from(host.querySelectorAll('child-comp > *')); - expect(kid1[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(kid2[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(kid3[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - }); - - it('should only monkey-patch immediate child nodes in an embedded template container', () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - directives: [NgIf], - factory: () => new StructuredComp(), - consts: 2, - vars: 1, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'section'); - template(1, (rf, ctx) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'div'); - element(1, 'p'); - elementEnd(); - element(2, 'div'); - } - }, 3, 0, 'ng-template', ['ngIf', '']); - elementEnd(); - } - if (rf & RenderFlags.Update) { - elementProperty(1, 'ngIf', true); - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const host = fixture.hostElement; - const [section, div1, p, div2] = Array.from(host.querySelectorAll('section, div, p')); - - expect(section.nodeName.toLowerCase()).toBe('section'); - expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - - expect(div1.nodeName.toLowerCase()).toBe('div'); - expect(div1[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - - expect(p.nodeName.toLowerCase()).toBe('p'); - expect(p[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); - - expect(div2.nodeName.toLowerCase()).toBe('div'); - expect(div2[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - }); - - it('should return a context object from a given dom node', () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - directives: [NgIf], - factory: () => new StructuredComp(), - consts: 2, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - element(0, 'section'); - element(1, 'div'); - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const section = fixture.hostElement.querySelector('section') !; - const sectionContext = getLContext(section) !; - const sectionLView = sectionContext.lView !; - expect(sectionContext.nodeIndex).toEqual(HEADER_OFFSET); - expect(sectionLView.length).toBeGreaterThan(HEADER_OFFSET); - expect(sectionContext.native).toBe(section); - - const div = fixture.hostElement.querySelector('div') !; - const divContext = getLContext(div) !; - const divLView = divContext.lView !; - expect(divContext.nodeIndex).toEqual(HEADER_OFFSET + 1); - expect(divLView.length).toBeGreaterThan(HEADER_OFFSET); - expect(divContext.native).toBe(div); - - expect(divLView).toBe(sectionLView); - }); - - it('should cache the element context on a element was pre-emptively monkey-patched', () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - factory: () => new StructuredComp(), - consts: 1, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - element(0, 'section'); - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const section = fixture.hostElement.querySelector('section') !as any; - const result1 = section[MONKEY_PATCH_KEY_NAME]; - expect(Array.isArray(result1)).toBeTruthy(); - - const context = getLContext(section) !; - const result2 = section[MONKEY_PATCH_KEY_NAME]; - expect(Array.isArray(result2)).toBeFalsy(); - - expect(result2).toBe(context); - expect(result2.lView).toBe(result1); - }); - - it('should cache the element context on an intermediate element that isn\'t pre-emptively monkey-patched', - () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - factory: () => new StructuredComp(), - consts: 2, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'section'); - element(1, 'p'); - elementEnd(); - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const section = fixture.hostElement.querySelector('section') !as any; - expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - - const p = fixture.hostElement.querySelector('p') !as any; - expect(p[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); - - const pContext = getLContext(p) !; - expect(pContext.native).toBe(p); - expect(p[MONKEY_PATCH_KEY_NAME]).toBe(pContext); - }); - - it('should be able to pull in element context data even if the element is decorated using styling', - () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - factory: () => new StructuredComp(), - consts: 1, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'section'); - elementStyling(['class-foo']); - elementEnd(); - } - if (rf & RenderFlags.Update) { - elementStylingApply(0); - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const section = fixture.hostElement.querySelector('section') !as any; - const result1 = section[MONKEY_PATCH_KEY_NAME]; - expect(Array.isArray(result1)).toBeTruthy(); - - const elementResult = result1[HEADER_OFFSET]; // first element - expect(Array.isArray(elementResult)).toBeTruthy(); - expect(elementResult[StylingIndex.ElementPosition]).toBe(section); - - const context = getLContext(section) !; - const result2 = section[MONKEY_PATCH_KEY_NAME]; - expect(Array.isArray(result2)).toBeFalsy(); - - expect(context.native).toBe(section); - }); - - it('should monkey-patch immediate child nodes in a content-projected region with a reference to the parent component', - () => { - /* - -
    - - welcome -
    -

    -

    this content is projected

    - this content is projected also -

    -
    -
    -
    - */ - class ProjectorComp { - static ngComponentDef = defineComponent({ - type: ProjectorComp, - selectors: [['projector-comp']], - factory: () => new ProjectorComp(), - consts: 4, - vars: 0, - template: (rf: RenderFlags, ctx: ProjectorComp) => { - if (rf & RenderFlags.Create) { - projectionDef(); - text(0, 'welcome'); - elementStart(1, 'header'); - elementStart(2, 'h1'); - projection(3); - elementEnd(); - elementEnd(); - } - if (rf & RenderFlags.Update) { - } - } - }); - } - - class ParentComp { - static ngComponentDef = defineComponent({ - type: ParentComp, - selectors: [['parent-comp']], - directives: [ProjectorComp], - factory: () => new ParentComp(), - consts: 5, - vars: 0, - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'section'); - elementStart(1, 'projector-comp'); - elementStart(2, 'p'); - text(3, 'this content is projected'); - elementEnd(); - text(4, 'this content is projected also'); - elementEnd(); - elementEnd(); - } - } - }); - } - - const fixture = new ComponentFixture(ParentComp); - fixture.update(); - - const host = fixture.hostElement; - const textNode = host.firstChild as any; - const section = host.querySelector('section') !as any; - const projectorComp = host.querySelector('projector-comp') !as any; - const header = host.querySelector('header') !as any; - const h1 = host.querySelector('h1') !as any; - const p = host.querySelector('p') !as any; - const pText = p.firstChild as any; - const projectedTextNode = p.nextSibling; - - expect(projectorComp.children).toContain(header); - expect(h1.children).toContain(p); - - expect(textNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(projectorComp[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(header[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(h1[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); - expect(p[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - expect(pText[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); - expect(projectedTextNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - - const parentContext = getLContext(section) !; - const shadowContext = getLContext(header) !; - const projectedContext = getLContext(p) !; - - const parentComponentData = parentContext.lView; - const shadowComponentData = shadowContext.lView; - const projectedComponentData = projectedContext.lView; - - expect(projectedComponentData).toBe(parentComponentData); - expect(shadowComponentData).not.toBe(parentComponentData); - }); - - it('should return `null` when an element context is retrieved that isn\'t situated in Angular', - () => { - const elm1 = document.createElement('div'); - const context1 = getLContext(elm1); - expect(context1).toBeFalsy(); - - const elm2 = document.createElement('div'); - document.body.appendChild(elm2); - const context2 = getLContext(elm2); - expect(context2).toBeFalsy(); - }); - - it('should return `null` when an element context is retrieved that is a DOM node that was not created by Angular', - () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - factory: () => new StructuredComp(), - consts: 1, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - element(0, 'section'); - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const section = fixture.hostElement.querySelector('section') !as any; - const manuallyCreatedElement = document.createElement('div'); - section.appendChild(manuallyCreatedElement); - - const context = getLContext(manuallyCreatedElement); - expect(context).toBeFalsy(); - }); - - it('should by default monkey-patch the bootstrap component with context details', () => { - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - factory: () => new StructuredComp(), - consts: 0, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => {} - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const hostElm = fixture.hostElement; - const component = fixture.component; - - const componentLView = (component as any)[MONKEY_PATCH_KEY_NAME]; - expect(Array.isArray(componentLView)).toBeTruthy(); - - const hostLView = (hostElm as any)[MONKEY_PATCH_KEY_NAME]; - expect(hostLView).toBe(componentLView); - - const context1 = getLContext(hostElm) !; - expect(context1.lView).toBe(hostLView); - expect(context1.native).toEqual(hostElm); - - const context2 = getLContext(component) !; - expect(context2).toBe(context1); - expect(context2.lView).toBe(hostLView); - expect(context2.native).toEqual(hostElm); - }); - - it('should by default monkey-patch the directives with LView so that they can be examined', - () => { - let myDir1Instance: MyDir1|null = null; - let myDir2Instance: MyDir2|null = null; - let myDir3Instance: MyDir2|null = null; - - class MyDir1 { - static ngDirectiveDef = defineDirective({ - type: MyDir1, - selectors: [['', 'my-dir-1', '']], - factory: () => myDir1Instance = new MyDir1() - }); - } - - class MyDir2 { - static ngDirectiveDef = defineDirective({ - type: MyDir2, - selectors: [['', 'my-dir-2', '']], - factory: () => myDir2Instance = new MyDir2() - }); - } - - class MyDir3 { - static ngDirectiveDef = defineDirective({ - type: MyDir3, - selectors: [['', 'my-dir-3', '']], - factory: () => myDir3Instance = new MyDir2() - }); - } - - class StructuredComp { - static ngComponentDef = defineComponent({ - type: StructuredComp, - selectors: [['structured-comp']], - directives: [MyDir1, MyDir2, MyDir3], - factory: () => new StructuredComp(), - consts: 2, - vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - element(0, 'div', ['my-dir-1', '', 'my-dir-2', '']); - element(1, 'div', ['my-dir-3']); - } - } - }); - } - - const fixture = new ComponentFixture(StructuredComp); - fixture.update(); - - const hostElm = fixture.hostElement; - const div1 = hostElm.querySelector('div:first-child') !as any; - const div2 = hostElm.querySelector('div:last-child') !as any; - const context = getLContext(hostElm) !; - const componentView = context.lView[context.nodeIndex]; - - expect(componentView).toContain(myDir1Instance); - expect(componentView).toContain(myDir2Instance); - expect(componentView).toContain(myDir3Instance); - - expect(Array.isArray((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); - expect(Array.isArray((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); - expect(Array.isArray((myDir3Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); - - const d1Context = getLContext(myDir1Instance) !; - const d2Context = getLContext(myDir2Instance) !; - const d3Context = getLContext(myDir3Instance) !; - - expect(d1Context.lView).toEqual(componentView); - expect(d2Context.lView).toEqual(componentView); - expect(d3Context.lView).toEqual(componentView); - - expect((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d1Context); - expect((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d2Context); - expect((myDir3Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d3Context); - - expect(d1Context.nodeIndex).toEqual(HEADER_OFFSET); - expect(d1Context.native).toBe(div1); - expect(d1Context.directives as any[]).toEqual([myDir1Instance, myDir2Instance]); - - expect(d2Context.nodeIndex).toEqual(HEADER_OFFSET); - expect(d2Context.native).toBe(div1); - expect(d2Context.directives as any[]).toEqual([myDir1Instance, myDir2Instance]); - - expect(d3Context.nodeIndex).toEqual(HEADER_OFFSET + 1); - expect(d3Context.native).toBe(div2); - expect(d3Context.directives as any[]).toEqual([myDir3Instance]); - }); - - it('should monkey-patch the exact same context instance of the DOM node, component and any directives on the same element', - () => { - let myDir1Instance: MyDir1|null = null; - let myDir2Instance: MyDir2|null = null; - let childComponentInstance: ChildComp|null = null; - - class MyDir1 { - static ngDirectiveDef = defineDirective({ - type: MyDir1, - selectors: [['', 'my-dir-1', '']], - factory: () => myDir1Instance = new MyDir1() - }); - } - - class MyDir2 { - static ngDirectiveDef = defineDirective({ - type: MyDir2, - selectors: [['', 'my-dir-2', '']], - factory: () => myDir2Instance = new MyDir2() - }); - } - - class ChildComp { - static ngComponentDef = defineComponent({ - type: ChildComp, - selectors: [['child-comp']], - factory: () => childComponentInstance = new ChildComp(), - consts: 1, - vars: 0, - template: (rf: RenderFlags, ctx: ChildComp) => { - if (rf & RenderFlags.Create) { - element(0, 'div'); - } - } - }); - } - - class ParentComp { - static ngComponentDef = defineComponent({ - type: ParentComp, - selectors: [['parent-comp']], - directives: [ChildComp, MyDir1, MyDir2], - factory: () => new ParentComp(), - consts: 1, - vars: 0, - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - element(0, 'child-comp', ['my-dir-1', '', 'my-dir-2', '']); - } - } - }); - } - - const fixture = new ComponentFixture(ParentComp); - fixture.update(); - - const childCompHostElm = fixture.hostElement.querySelector('child-comp') !as any; - - const lView = childCompHostElm[MONKEY_PATCH_KEY_NAME]; - expect(Array.isArray(lView)).toBeTruthy(); - expect((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); - expect((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); - expect((childComponentInstance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); - - const childNodeContext = getLContext(childCompHostElm) !; - expect(childNodeContext.component).toBeFalsy(); - expect(childNodeContext.directives).toBeFalsy(); - assertMonkeyPatchValueIsLView(myDir1Instance); - assertMonkeyPatchValueIsLView(myDir2Instance); - assertMonkeyPatchValueIsLView(childComponentInstance); - - expect(getLContext(myDir1Instance)).toBe(childNodeContext); - expect(childNodeContext.component).toBeFalsy(); - expect(childNodeContext.directives !.length).toEqual(2); - assertMonkeyPatchValueIsLView(myDir1Instance, false); - assertMonkeyPatchValueIsLView(myDir2Instance, false); - assertMonkeyPatchValueIsLView(childComponentInstance); - - expect(getLContext(myDir2Instance)).toBe(childNodeContext); - expect(childNodeContext.component).toBeFalsy(); - expect(childNodeContext.directives !.length).toEqual(2); - assertMonkeyPatchValueIsLView(myDir1Instance, false); - assertMonkeyPatchValueIsLView(myDir2Instance, false); - assertMonkeyPatchValueIsLView(childComponentInstance); - - expect(getLContext(childComponentInstance)).toBe(childNodeContext); - expect(childNodeContext.component).toBeTruthy(); - expect(childNodeContext.directives !.length).toEqual(2); - assertMonkeyPatchValueIsLView(myDir1Instance, false); - assertMonkeyPatchValueIsLView(myDir2Instance, false); - assertMonkeyPatchValueIsLView(childComponentInstance, false); - - function assertMonkeyPatchValueIsLView(value: any, yesOrNo = true) { - expect(Array.isArray((value as any)[MONKEY_PATCH_KEY_NAME])).toBe(yesOrNo); - } - }); - - it('should monkey-patch sub components with the view data and then replace them with the context result once a lookup occurs', - () => { - class ChildComp { - static ngComponentDef = defineComponent({ - type: ChildComp, - selectors: [['child-comp']], - factory: () => new ChildComp(), - consts: 3, - vars: 0, - template: (rf: RenderFlags, ctx: ChildComp) => { - if (rf & RenderFlags.Create) { - element(0, 'div'); - element(1, 'div'); - element(2, 'div'); - } - } - }); - } - - class ParentComp { - static ngComponentDef = defineComponent({ - type: ParentComp, - selectors: [['parent-comp']], - directives: [ChildComp], - factory: () => new ParentComp(), - consts: 2, - vars: 0, - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - elementStart(0, 'section'); - elementStart(1, 'child-comp'); - elementEnd(); - elementEnd(); - } - } - }); - } - - const fixture = new ComponentFixture(ParentComp); - fixture.update(); - - const host = fixture.hostElement; - const child = host.querySelector('child-comp') as any; - expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - - const context = getLContext(child) !; - expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - - const componentData = context.lView[context.nodeIndex]; - const component = componentData[CONTEXT]; - expect(component instanceof ChildComp).toBeTruthy(); - expect(component[MONKEY_PATCH_KEY_NAME]).toBe(context.lView); - - const componentContext = getLContext(component) !; - expect(component[MONKEY_PATCH_KEY_NAME]).toBe(componentContext); - expect(componentContext.nodeIndex).toEqual(context.nodeIndex); - expect(componentContext.native).toEqual(context.native); - expect(componentContext.lView).toEqual(context.lView); - }); + it('should include animations in the renderType data array even if the array is empty', () => { + class AnimComp { + static ngComponentDef = defineComponent({ + type: AnimComp, + consts: 0, + vars: 0, + data: { + animation: [], + }, + selectors: [['foo']], + factory: () => new AnimComp(), + template: (rf: RenderFlags, ctx: AnimComp) => {} + }); + } + const rendererFactory = new ProxyRenderer3Factory(); + new ComponentFixture(AnimComp, {rendererFactory}); + const data = rendererFactory.lastCapturedType !.data; + expect(data.animation).toEqual([]); }); - describe('sanitization', () => { - it('should sanitize data using the provided sanitization interface', () => { - class SanitizationComp { - static ngComponentDef = defineComponent({ - type: SanitizationComp, - selectors: [['sanitize-this']], - factory: () => new SanitizationComp(), - consts: 1, - vars: 1, - template: (rf: RenderFlags, ctx: SanitizationComp) => { - if (rf & RenderFlags.Create) { - element(0, 'a'); - } - if (rf & RenderFlags.Update) { - elementProperty(0, 'href', bind(ctx.href), sanitizeUrl); - } + it('should allow [@trigger] bindings to be picked up by the underlying renderer', () => { + class AnimComp { + static ngComponentDef = defineComponent({ + type: AnimComp, + consts: 1, + vars: 1, + selectors: [['foo']], + factory: () => new AnimComp(), + template: (rf: RenderFlags, ctx: AnimComp) => { + if (rf & RenderFlags.Create) { + element(0, 'div', [AttributeMarker.SelectOnly, '@fooAnimation']); } - }); + if (rf & RenderFlags.Update) { + elementAttribute(0, '@fooAnimation', bind(ctx.animationValue)); + } + } + }); - private href = ''; + animationValue = '123'; + } - updateLink(href: any) { this.href = href; } - } + const rendererFactory = new MockRendererFactory(['setAttribute']); + const fixture = new ComponentFixture(AnimComp, {rendererFactory}); - const sanitizer = new LocalSanitizer((value) => { return 'http://bar'; }); + const renderer = rendererFactory.lastRenderer !; + fixture.component.animationValue = '456'; + fixture.update(); - const fixture = new ComponentFixture(SanitizationComp, {sanitizer}); - fixture.component.updateLink('http://foo'); - fixture.update(); + const spy = renderer.spies['setAttribute']; + const [elm, attr, value] = spy.calls.mostRecent().args; - const anchor = fixture.hostElement.querySelector('a') !; - expect(anchor.getAttribute('href')).toEqual('http://bar'); + expect(attr).toEqual('@fooAnimation'); + expect(value).toEqual('456'); + }); - fixture.component.updateLink(sanitizer.bypassSecurityTrustUrl('http://foo')); - fixture.update(); + it('should allow creation-level [@trigger] properties to be picked up by the underlying renderer', + () => { + class AnimComp { + static ngComponentDef = defineComponent({ + type: AnimComp, + consts: 1, + vars: 1, + selectors: [['foo']], + factory: () => new AnimComp(), + template: (rf: RenderFlags, ctx: AnimComp) => { + if (rf & RenderFlags.Create) { + element(0, 'div', ['@fooAnimation', '']); + } + } + }); + } - expect(anchor.getAttribute('href')).toEqual('http://foo'); - }); + const rendererFactory = new MockRendererFactory(['setProperty']); + const fixture = new ComponentFixture(AnimComp, {rendererFactory}); + + const renderer = rendererFactory.lastRenderer !; + fixture.update(); + + const spy = renderer.spies['setProperty']; + const [elm, attr, value] = spy.calls.mostRecent().args; + expect(attr).toEqual('@fooAnimation'); + }); + + it('should allow host binding animations to be picked up and rendered', () => { + class ChildCompWithAnim { + static ngDirectiveDef = defineDirective({ + type: ChildCompWithAnim, + factory: () => new ChildCompWithAnim(), + selectors: [['child-comp-with-anim']], + hostBindings: function(rf: RenderFlags, ctx: any, elementIndex: number): void { + if (rf & RenderFlags.Update) { + elementProperty(0, '@fooAnim', ctx.exp); + } + }, + }); + + exp = 'go'; + } + + class ParentComp { + static ngComponentDef = defineComponent({ + type: ParentComp, + consts: 1, + vars: 1, + selectors: [['foo']], + factory: () => new ParentComp(), + template: (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + element(0, 'child-comp-with-anim'); + } + }, + directives: [ChildCompWithAnim] + }); + } + + const rendererFactory = new MockRendererFactory(['setProperty']); + const fixture = new ComponentFixture(ParentComp, {rendererFactory}); + + const renderer = rendererFactory.lastRenderer !; + fixture.update(); + + const spy = renderer.spies['setProperty']; + const [elm, attr, value] = spy.calls.mostRecent().args; + expect(attr).toEqual('@fooAnim'); + }); +}); + +describe('element discovery', () => { + it('should only monkey-patch immediate child nodes in a component', () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + factory: () => new StructuredComp(), + consts: 2, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'div'); + elementStart(1, 'p'); + elementEnd(); + elementEnd(); + } + if (rf & RenderFlags.Update) { + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const host = fixture.hostElement; + const parent = host.querySelector('div') as any; + const child = host.querySelector('p') as any; + + expect(parent[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(child[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); + }); + + it('should only monkey-patch immediate child nodes in a sub component', () => { + class ChildComp { + static ngComponentDef = defineComponent({ + type: ChildComp, + selectors: [['child-comp']], + factory: () => new ChildComp(), + consts: 3, + vars: 0, + template: (rf: RenderFlags, ctx: ChildComp) => { + if (rf & RenderFlags.Create) { + element(0, 'div'); + element(1, 'div'); + element(2, 'div'); + } + } + }); + } + + class ParentComp { + static ngComponentDef = defineComponent({ + type: ParentComp, + selectors: [['parent-comp']], + directives: [ChildComp], + factory: () => new ParentComp(), + consts: 2, + vars: 0, + template: (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'section'); + elementStart(1, 'child-comp'); + elementEnd(); + elementEnd(); + } + } + }); + } + + const fixture = new ComponentFixture(ParentComp); + fixture.update(); + + const host = fixture.hostElement; + const child = host.querySelector('child-comp') as any; + expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + + const [kid1, kid2, kid3] = Array.from(host.querySelectorAll('child-comp > *')); + expect(kid1[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(kid2[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(kid3[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + }); + + it('should only monkey-patch immediate child nodes in an embedded template container', () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + directives: [NgIf], + factory: () => new StructuredComp(), + consts: 2, + vars: 1, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'section'); + template(1, (rf, ctx) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'div'); + element(1, 'p'); + elementEnd(); + element(2, 'div'); + } + }, 3, 0, 'ng-template', ['ngIf', '']); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementProperty(1, 'ngIf', true); + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const host = fixture.hostElement; + const [section, div1, p, div2] = Array.from(host.querySelectorAll('section, div, p')); + + expect(section.nodeName.toLowerCase()).toBe('section'); + expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + + expect(div1.nodeName.toLowerCase()).toBe('div'); + expect(div1[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + + expect(p.nodeName.toLowerCase()).toBe('p'); + expect(p[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); + + expect(div2.nodeName.toLowerCase()).toBe('div'); + expect(div2[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + }); + + it('should return a context object from a given dom node', () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + directives: [NgIf], + factory: () => new StructuredComp(), + consts: 2, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + element(0, 'section'); + element(1, 'div'); + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const section = fixture.hostElement.querySelector('section') !; + const sectionContext = getLContext(section) !; + const sectionLView = sectionContext.lView !; + expect(sectionContext.nodeIndex).toEqual(HEADER_OFFSET); + expect(sectionLView.length).toBeGreaterThan(HEADER_OFFSET); + expect(sectionContext.native).toBe(section); + + const div = fixture.hostElement.querySelector('div') !; + const divContext = getLContext(div) !; + const divLView = divContext.lView !; + expect(divContext.nodeIndex).toEqual(HEADER_OFFSET + 1); + expect(divLView.length).toBeGreaterThan(HEADER_OFFSET); + expect(divContext.native).toBe(div); + + expect(divLView).toBe(sectionLView); + }); + + it('should cache the element context on a element was pre-emptively monkey-patched', () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + factory: () => new StructuredComp(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + element(0, 'section'); + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const section = fixture.hostElement.querySelector('section') !as any; + const result1 = section[MONKEY_PATCH_KEY_NAME]; + expect(Array.isArray(result1)).toBeTruthy(); + + const context = getLContext(section) !; + const result2 = section[MONKEY_PATCH_KEY_NAME]; + expect(Array.isArray(result2)).toBeFalsy(); + + expect(result2).toBe(context); + expect(result2.lView).toBe(result1); + }); + + it('should cache the element context on an intermediate element that isn\'t pre-emptively monkey-patched', + () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + factory: () => new StructuredComp(), + consts: 2, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'section'); + element(1, 'p'); + elementEnd(); + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const section = fixture.hostElement.querySelector('section') !as any; + expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + + const p = fixture.hostElement.querySelector('p') !as any; + expect(p[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); + + const pContext = getLContext(p) !; + expect(pContext.native).toBe(p); + expect(p[MONKEY_PATCH_KEY_NAME]).toBe(pContext); + }); + + it('should be able to pull in element context data even if the element is decorated using styling', + () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + factory: () => new StructuredComp(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'section'); + elementStyling(['class-foo']); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementStylingApply(0); + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const section = fixture.hostElement.querySelector('section') !as any; + const result1 = section[MONKEY_PATCH_KEY_NAME]; + expect(Array.isArray(result1)).toBeTruthy(); + + const elementResult = result1[HEADER_OFFSET]; // first element + expect(Array.isArray(elementResult)).toBeTruthy(); + expect(elementResult[StylingIndex.ElementPosition]).toBe(section); + + const context = getLContext(section) !; + const result2 = section[MONKEY_PATCH_KEY_NAME]; + expect(Array.isArray(result2)).toBeFalsy(); + + expect(context.native).toBe(section); + }); + + it('should monkey-patch immediate child nodes in a content-projected region with a reference to the parent component', + () => { + /* + +
    + + welcome +
    +

    +

    this content is projected

    + this content is projected also +

    +
    +
    +
    + */ + class ProjectorComp { + static ngComponentDef = defineComponent({ + type: ProjectorComp, + selectors: [['projector-comp']], + factory: () => new ProjectorComp(), + consts: 4, + vars: 0, + template: (rf: RenderFlags, ctx: ProjectorComp) => { + if (rf & RenderFlags.Create) { + projectionDef(); + text(0, 'welcome'); + elementStart(1, 'header'); + elementStart(2, 'h1'); + projection(3); + elementEnd(); + elementEnd(); + } + if (rf & RenderFlags.Update) { + } + } + }); + } + + class ParentComp { + static ngComponentDef = defineComponent({ + type: ParentComp, + selectors: [['parent-comp']], + directives: [ProjectorComp], + factory: () => new ParentComp(), + consts: 5, + vars: 0, + template: (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'section'); + elementStart(1, 'projector-comp'); + elementStart(2, 'p'); + text(3, 'this content is projected'); + elementEnd(); + text(4, 'this content is projected also'); + elementEnd(); + elementEnd(); + } + } + }); + } + + const fixture = new ComponentFixture(ParentComp); + fixture.update(); + + const host = fixture.hostElement; + const textNode = host.firstChild as any; + const section = host.querySelector('section') !as any; + const projectorComp = host.querySelector('projector-comp') !as any; + const header = host.querySelector('header') !as any; + const h1 = host.querySelector('h1') !as any; + const p = host.querySelector('p') !as any; + const pText = p.firstChild as any; + const projectedTextNode = p.nextSibling; + + expect(projectorComp.children).toContain(header); + expect(h1.children).toContain(p); + + expect(textNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(projectorComp[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(header[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(h1[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); + expect(p[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + expect(pText[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); + expect(projectedTextNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + + const parentContext = getLContext(section) !; + const shadowContext = getLContext(header) !; + const projectedContext = getLContext(p) !; + + const parentComponentData = parentContext.lView; + const shadowComponentData = shadowContext.lView; + const projectedComponentData = projectedContext.lView; + + expect(projectedComponentData).toBe(parentComponentData); + expect(shadowComponentData).not.toBe(parentComponentData); + }); + + it('should return `null` when an element context is retrieved that isn\'t situated in Angular', + () => { + const elm1 = document.createElement('div'); + const context1 = getLContext(elm1); + expect(context1).toBeFalsy(); + + const elm2 = document.createElement('div'); + document.body.appendChild(elm2); + const context2 = getLContext(elm2); + expect(context2).toBeFalsy(); + }); + + it('should return `null` when an element context is retrieved that is a DOM node that was not created by Angular', + () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + factory: () => new StructuredComp(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + element(0, 'section'); + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const section = fixture.hostElement.querySelector('section') !as any; + const manuallyCreatedElement = document.createElement('div'); + section.appendChild(manuallyCreatedElement); + + const context = getLContext(manuallyCreatedElement); + expect(context).toBeFalsy(); + }); + + it('should by default monkey-patch the bootstrap component with context details', () => { + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + factory: () => new StructuredComp(), + consts: 0, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => {} + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const hostElm = fixture.hostElement; + const component = fixture.component; + + const componentLView = (component as any)[MONKEY_PATCH_KEY_NAME]; + expect(Array.isArray(componentLView)).toBeTruthy(); + + const hostLView = (hostElm as any)[MONKEY_PATCH_KEY_NAME]; + expect(hostLView).toBe(componentLView); + + const context1 = getLContext(hostElm) !; + expect(context1.lView).toBe(hostLView); + expect(context1.native).toEqual(hostElm); + + const context2 = getLContext(component) !; + expect(context2).toBe(context1); + expect(context2.lView).toBe(hostLView); + expect(context2.native).toEqual(hostElm); + }); + + it('should by default monkey-patch the directives with LView so that they can be examined', + () => { + let myDir1Instance: MyDir1|null = null; + let myDir2Instance: MyDir2|null = null; + let myDir3Instance: MyDir2|null = null; + + class MyDir1 { + static ngDirectiveDef = defineDirective({ + type: MyDir1, + selectors: [['', 'my-dir-1', '']], + factory: () => myDir1Instance = new MyDir1() + }); + } + + class MyDir2 { + static ngDirectiveDef = defineDirective({ + type: MyDir2, + selectors: [['', 'my-dir-2', '']], + factory: () => myDir2Instance = new MyDir2() + }); + } + + class MyDir3 { + static ngDirectiveDef = defineDirective({ + type: MyDir3, + selectors: [['', 'my-dir-3', '']], + factory: () => myDir3Instance = new MyDir2() + }); + } + + class StructuredComp { + static ngComponentDef = defineComponent({ + type: StructuredComp, + selectors: [['structured-comp']], + directives: [MyDir1, MyDir2, MyDir3], + factory: () => new StructuredComp(), + consts: 2, + vars: 0, + template: (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + element(0, 'div', ['my-dir-1', '', 'my-dir-2', '']); + element(1, 'div', ['my-dir-3']); + } + } + }); + } + + const fixture = new ComponentFixture(StructuredComp); + fixture.update(); + + const hostElm = fixture.hostElement; + const div1 = hostElm.querySelector('div:first-child') !as any; + const div2 = hostElm.querySelector('div:last-child') !as any; + const context = getLContext(hostElm) !; + const componentView = context.lView[context.nodeIndex]; + + expect(componentView).toContain(myDir1Instance); + expect(componentView).toContain(myDir2Instance); + expect(componentView).toContain(myDir3Instance); + + expect(Array.isArray((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); + expect(Array.isArray((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); + expect(Array.isArray((myDir3Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); + + const d1Context = getLContext(myDir1Instance) !; + const d2Context = getLContext(myDir2Instance) !; + const d3Context = getLContext(myDir3Instance) !; + + expect(d1Context.lView).toEqual(componentView); + expect(d2Context.lView).toEqual(componentView); + expect(d3Context.lView).toEqual(componentView); + + expect((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d1Context); + expect((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d2Context); + expect((myDir3Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(d3Context); + + expect(d1Context.nodeIndex).toEqual(HEADER_OFFSET); + expect(d1Context.native).toBe(div1); + expect(d1Context.directives as any[]).toEqual([myDir1Instance, myDir2Instance]); + + expect(d2Context.nodeIndex).toEqual(HEADER_OFFSET); + expect(d2Context.native).toBe(div1); + expect(d2Context.directives as any[]).toEqual([myDir1Instance, myDir2Instance]); + + expect(d3Context.nodeIndex).toEqual(HEADER_OFFSET + 1); + expect(d3Context.native).toBe(div2); + expect(d3Context.directives as any[]).toEqual([myDir3Instance]); + }); + + it('should monkey-patch the exact same context instance of the DOM node, component and any directives on the same element', + () => { + let myDir1Instance: MyDir1|null = null; + let myDir2Instance: MyDir2|null = null; + let childComponentInstance: ChildComp|null = null; + + class MyDir1 { + static ngDirectiveDef = defineDirective({ + type: MyDir1, + selectors: [['', 'my-dir-1', '']], + factory: () => myDir1Instance = new MyDir1() + }); + } + + class MyDir2 { + static ngDirectiveDef = defineDirective({ + type: MyDir2, + selectors: [['', 'my-dir-2', '']], + factory: () => myDir2Instance = new MyDir2() + }); + } + + class ChildComp { + static ngComponentDef = defineComponent({ + type: ChildComp, + selectors: [['child-comp']], + factory: () => childComponentInstance = new ChildComp(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: ChildComp) => { + if (rf & RenderFlags.Create) { + element(0, 'div'); + } + } + }); + } + + class ParentComp { + static ngComponentDef = defineComponent({ + type: ParentComp, + selectors: [['parent-comp']], + directives: [ChildComp, MyDir1, MyDir2], + factory: () => new ParentComp(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + element(0, 'child-comp', ['my-dir-1', '', 'my-dir-2', '']); + } + } + }); + } + + const fixture = new ComponentFixture(ParentComp); + fixture.update(); + + const childCompHostElm = fixture.hostElement.querySelector('child-comp') !as any; + + const lView = childCompHostElm[MONKEY_PATCH_KEY_NAME]; + expect(Array.isArray(lView)).toBeTruthy(); + expect((myDir1Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); + expect((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); + expect((childComponentInstance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); + + const childNodeContext = getLContext(childCompHostElm) !; + expect(childNodeContext.component).toBeFalsy(); + expect(childNodeContext.directives).toBeFalsy(); + assertMonkeyPatchValueIsLView(myDir1Instance); + assertMonkeyPatchValueIsLView(myDir2Instance); + assertMonkeyPatchValueIsLView(childComponentInstance); + + expect(getLContext(myDir1Instance)).toBe(childNodeContext); + expect(childNodeContext.component).toBeFalsy(); + expect(childNodeContext.directives !.length).toEqual(2); + assertMonkeyPatchValueIsLView(myDir1Instance, false); + assertMonkeyPatchValueIsLView(myDir2Instance, false); + assertMonkeyPatchValueIsLView(childComponentInstance); + + expect(getLContext(myDir2Instance)).toBe(childNodeContext); + expect(childNodeContext.component).toBeFalsy(); + expect(childNodeContext.directives !.length).toEqual(2); + assertMonkeyPatchValueIsLView(myDir1Instance, false); + assertMonkeyPatchValueIsLView(myDir2Instance, false); + assertMonkeyPatchValueIsLView(childComponentInstance); + + expect(getLContext(childComponentInstance)).toBe(childNodeContext); + expect(childNodeContext.component).toBeTruthy(); + expect(childNodeContext.directives !.length).toEqual(2); + assertMonkeyPatchValueIsLView(myDir1Instance, false); + assertMonkeyPatchValueIsLView(myDir2Instance, false); + assertMonkeyPatchValueIsLView(childComponentInstance, false); + + function assertMonkeyPatchValueIsLView(value: any, yesOrNo = true) { + expect(Array.isArray((value as any)[MONKEY_PATCH_KEY_NAME])).toBe(yesOrNo); + } + }); + + it('should monkey-patch sub components with the view data and then replace them with the context result once a lookup occurs', + () => { + class ChildComp { + static ngComponentDef = defineComponent({ + type: ChildComp, + selectors: [['child-comp']], + factory: () => new ChildComp(), + consts: 3, + vars: 0, + template: (rf: RenderFlags, ctx: ChildComp) => { + if (rf & RenderFlags.Create) { + element(0, 'div'); + element(1, 'div'); + element(2, 'div'); + } + } + }); + } + + class ParentComp { + static ngComponentDef = defineComponent({ + type: ParentComp, + selectors: [['parent-comp']], + directives: [ChildComp], + factory: () => new ParentComp(), + consts: 2, + vars: 0, + template: (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'section'); + elementStart(1, 'child-comp'); + elementEnd(); + elementEnd(); + } + } + }); + } + + const fixture = new ComponentFixture(ParentComp); + fixture.update(); + + const host = fixture.hostElement; + const child = host.querySelector('child-comp') as any; + expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + + const context = getLContext(child) !; + expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); + + const componentData = context.lView[context.nodeIndex]; + const component = componentData[CONTEXT]; + expect(component instanceof ChildComp).toBeTruthy(); + expect(component[MONKEY_PATCH_KEY_NAME]).toBe(context.lView); + + const componentContext = getLContext(component) !; + expect(component[MONKEY_PATCH_KEY_NAME]).toBe(componentContext); + expect(componentContext.nodeIndex).toEqual(context.nodeIndex); + expect(componentContext.native).toEqual(context.native); + expect(componentContext.lView).toEqual(context.lView); + }); +}); + +describe('sanitization', () => { + it('should sanitize data using the provided sanitization interface', () => { + class SanitizationComp { + static ngComponentDef = defineComponent({ + type: SanitizationComp, + selectors: [['sanitize-this']], + factory: () => new SanitizationComp(), + consts: 1, + vars: 1, + template: (rf: RenderFlags, ctx: SanitizationComp) => { + if (rf & RenderFlags.Create) { + element(0, 'a'); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'href', bind(ctx.href), sanitizeUrl); + } + } + }); + + private href = ''; + + updateLink(href: any) { this.href = href; } + } + + const sanitizer = new LocalSanitizer((value) => { return 'http://bar'; }); + + const fixture = new ComponentFixture(SanitizationComp, {sanitizer}); + fixture.component.updateLink('http://foo'); + fixture.update(); + + const anchor = fixture.hostElement.querySelector('a') !; + expect(anchor.getAttribute('href')).toEqual('http://bar'); + + fixture.component.updateLink(sanitizer.bypassSecurityTrustUrl('http://foo')); + fixture.update(); + + expect(anchor.getAttribute('href')).toEqual('http://foo'); + }); + + it('should sanitize HostBindings data using provided sanitization interface', () => { + let hostBindingDir: UnsafeUrlHostBindingDir; + class UnsafeUrlHostBindingDir { + // @HostBinding() + cite: any = 'http://cite-dir-value'; + + static ngDirectiveDef = defineDirective({ + type: UnsafeUrlHostBindingDir, + selectors: [['', 'unsafeUrlHostBindingDir', '']], + factory: () => hostBindingDir = new UnsafeUrlHostBindingDir(), + hostBindings: (rf: RenderFlags, ctx: any, elementIndex: number) => { + if (rf & RenderFlags.Create) { + allocHostVars(1); + } + if (rf & RenderFlags.Update) { + elementProperty(elementIndex, 'cite', bind(ctx.cite), sanitizeUrl, true); + } + } + }); + } + + class SimpleComp { + static ngComponentDef = defineComponent({ + type: SimpleComp, + selectors: [['sanitize-this']], + factory: () => new SimpleComp(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: SimpleComp) => { + if (rf & RenderFlags.Create) { + element(0, 'blockquote', ['unsafeUrlHostBindingDir', '']); + } + }, + directives: [UnsafeUrlHostBindingDir] + }); + } + + const sanitizer = new LocalSanitizer((value) => 'http://bar'); + + const fixture = new ComponentFixture(SimpleComp, {sanitizer}); + hostBindingDir !.cite = 'http://foo'; + fixture.update(); + + const anchor = fixture.hostElement.querySelector('blockquote') !; + expect(anchor.getAttribute('cite')).toEqual('http://bar'); + + hostBindingDir !.cite = sanitizer.bypassSecurityTrustUrl('http://foo'); + fixture.update(); + + expect(anchor.getAttribute('cite')).toEqual('http://foo'); }); }); diff --git a/packages/core/test/render3/ivy/BUILD.bazel b/packages/core/test/render3/ivy/BUILD.bazel index 9f89287a01..efd2b58d8e 100644 --- a/packages/core/test/render3/ivy/BUILD.bazel +++ b/packages/core/test/render3/ivy/BUILD.bazel @@ -9,6 +9,7 @@ ts_library( deps = [ "//packages:types", "//packages/core", + "//packages/core/src/di/interface", ], ) diff --git a/packages/core/test/render3/ivy/jit_spec.ts b/packages/core/test/render3/ivy/jit_spec.ts index fe6f0fcff6..0e8e3c399c 100644 --- a/packages/core/test/render3/ivy/jit_spec.ts +++ b/packages/core/test/render3/ivy/jit_spec.ts @@ -7,10 +7,10 @@ */ import 'reflect-metadata'; -import {ElementRef, QueryList} from '@angular/core'; -import {InjectorDef, defineInjectable} from '@angular/core/src/di/defs'; +import {ElementRef, QueryList, ɵsetComponentScope as setComponentScope} from '@angular/core'; import {Injectable} from '@angular/core/src/di/injectable'; import {inject, setCurrentInjector} from '@angular/core/src/di/injector_compatibility'; +import {InjectorDef, defineInjectable} from '@angular/core/src/di/interface/defs'; import {ivyEnabled} from '@angular/core/src/ivy_switch'; import {ContentChild, ContentChildren, ViewChild, ViewChildren} from '@angular/core/src/metadata/di'; import {Component, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata/directives'; @@ -313,7 +313,6 @@ ivyEnabled && describe('render3 jit', () => { } expect((TestDirective as any).ngDirectiveDef.contentQueries).not.toBeNull(); - expect((TestDirective as any).ngDirectiveDef.contentQueriesRefresh).not.toBeNull(); }); it('should compile ContentChild query with string predicate on a directive', () => { @@ -323,7 +322,6 @@ ivyEnabled && describe('render3 jit', () => { } expect((TestDirective as any).ngDirectiveDef.contentQueries).not.toBeNull(); - expect((TestDirective as any).ngDirectiveDef.contentQueriesRefresh).not.toBeNull(); }); it('should compile ContentChildren query with type predicate on a directive', () => { @@ -335,7 +333,6 @@ ivyEnabled && describe('render3 jit', () => { } expect((TestDirective as any).ngDirectiveDef.contentQueries).not.toBeNull(); - expect((TestDirective as any).ngDirectiveDef.contentQueriesRefresh).not.toBeNull(); }); it('should compile ContentChild query with type predicate on a directive', () => { @@ -347,7 +344,6 @@ ivyEnabled && describe('render3 jit', () => { } expect((TestDirective as any).ngDirectiveDef.contentQueries).not.toBeNull(); - expect((TestDirective as any).ngDirectiveDef.contentQueriesRefresh).not.toBeNull(); }); it('should not pick up view queries from directives', () => { diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index b501cb0847..c721ff6613 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ComponentFactoryResolver, OnDestroy, SimpleChanges, ViewContainerRef} from '../../src/core'; +import {ComponentFactoryResolver, OnDestroy, SimpleChange, SimpleChanges, ViewContainerRef} from '../../src/core'; import {AttributeMarker, ComponentTemplate, LifecycleHooksFeature, NO_CHANGE, NgOnChangesFeature, defineComponent, defineDirective, injectComponentFactoryResolver} from '../../src/render3/index'; import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, listener, markDirty, projection, projectionDef, store, template, text} from '../../src/render3/instructions'; @@ -14,6 +14,7 @@ import {RenderFlags} from '../../src/render3/interfaces/definition'; import {NgIf} from './common_with_def'; import {ComponentFixture, containerEl, createComponent, renderComponent, renderToHtml, requestAnimationFrame} from './render_util'; +import {fixmeIvy} from '@angular/private/testing'; describe('lifecycles', () => { @@ -442,7 +443,8 @@ describe('lifecycles', () => { factory: () => new Component(), template, consts: consts, vars: vars, - directives: directives + directives: directives, + inputs: {val: 'val'} }); }; } @@ -1941,10 +1943,15 @@ describe('lifecycles', () => { }); describe('onChanges', () => { - let events: string[]; + let events: ({type: string, name: string, [key: string]: any})[]; beforeEach(() => { events = []; }); + /** + *
    + * + *
    + */ const Comp = createOnChangesComponent('comp', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { projectionDef(); @@ -1953,15 +1960,20 @@ describe('lifecycles', () => { elementEnd(); } }, 2); + + /** + * + */ const Parent = createOnChangesComponent('parent', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { element(0, 'comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(ctx.a)); - elementProperty(0, 'publicName', bind(ctx.b)); + elementProperty(0, 'publicVal2', bind(ctx.b)); } }, 1, 2, [Comp]); + const ProjectedComp = createOnChangesComponent('projected', (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { text(0, 'content'); @@ -1974,72 +1986,95 @@ describe('lifecycles', () => { directives: any[] = []) { return class Component { // @Input() val1: string; - // @Input('publicName') val2: string; + // @Input('publicVal2') val2: string; a: string = 'wasVal1BeforeMinification'; b: string = 'wasVal2BeforeMinification'; - ngOnChanges(simpleChanges: SimpleChanges) { - events.push( - `comp=${name} val1=${this.a} val2=${this.b} - changed=[${Object.getOwnPropertyNames(simpleChanges).join(',')}]`); + ngOnChanges(changes: SimpleChanges) { + if (changes.a && this.a !== changes.a.currentValue) { + throw Error( + `SimpleChanges invalid expected this.a ${this.a} to equal currentValue ${changes.a.currentValue}`); + } + if (changes.b && this.b !== changes.b.currentValue) { + throw Error( + `SimpleChanges invalid expected this.b ${this.b} to equal currentValue ${changes.b.currentValue}`); + } + events.push({type: 'onChanges', name: 'comp - ' + name, changes}); } static ngComponentDef = defineComponent({ type: Component, selectors: [[name]], factory: () => new Component(), - features: [NgOnChangesFeature], consts: consts, vars: vars, - inputs: {a: 'val1', b: ['publicName', 'val2']}, template, - directives: directives + inputs: {a: 'val1', b: ['publicVal2', 'val2']}, template, + directives: directives, + features: [NgOnChangesFeature()], }); }; } class Directive { // @Input() val1: string; - // @Input('publicName') val2: string; + // @Input('publicVal2') val2: string; a: string = 'wasVal1BeforeMinification'; b: string = 'wasVal2BeforeMinification'; - ngOnChanges(simpleChanges: SimpleChanges) { - events.push( - `dir - val1=${this.a} val2=${this.b} - changed=[${Object.getOwnPropertyNames(simpleChanges).join(',')}]`); + ngOnChanges(changes: SimpleChanges) { + events.push({type: 'onChanges', name: 'dir - dir', changes}); } static ngDirectiveDef = defineDirective({ type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive(), - features: [NgOnChangesFeature], - inputs: {a: 'val1', b: ['publicName', 'val2']} + inputs: {a: 'val1', b: ['publicVal2', 'val2']}, + features: [NgOnChangesFeature()], }); } const defs = [Comp, Parent, Directive, ProjectedComp]; it('should call onChanges method after inputs are set in creation and update mode', () => { - /** */ + /** */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp'); } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(ctx.val1)); - elementProperty(0, 'publicName', bind(ctx.val2)); + elementProperty(0, 'publicVal2', bind(ctx.val2)); } }, 1, 2, defs); + // First changes happen here. const fixture = new ComponentFixture(App); + events = []; fixture.component.val1 = '1'; fixture.component.val2 = 'a'; fixture.update(); - expect(events).toEqual(['comp=comp val1=1 val2=a - changed=[val1,val2]']); + expect(events).toEqual([{ + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange( + undefined, '1', false), // we cleared `events` above, this is the second change + 'val2': new SimpleChange(undefined, 'a', false), + } + }]); events = []; fixture.component.val1 = '2'; fixture.component.val2 = 'b'; fixture.update(); - expect(events).toEqual(['comp=comp val1=2 val2=b - changed=[val1,val2]']); + expect(events).toEqual([{ + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange('1', '2', false), + 'val2': new SimpleChange('a', 'b', false), + } + }]); }); it('should call parent onChanges before child onChanges', () => { @@ -2053,28 +2088,42 @@ describe('lifecycles', () => { } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(ctx.val1)); - elementProperty(0, 'publicName', bind(ctx.val2)); + elementProperty(0, 'publicVal2', bind(ctx.val2)); } }, 1, 2, defs); const fixture = new ComponentFixture(App); + + // We're clearing events after the first change here events = []; fixture.component.val1 = '1'; fixture.component.val2 = 'a'; fixture.update(); expect(events).toEqual([ - 'comp=parent val1=1 val2=a - changed=[val1,val2]', - 'comp=comp val1=1 val2=a - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, '1', false), + 'val2': new SimpleChange(undefined, 'a', false), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, '1', false), + 'val2': new SimpleChange(undefined, 'a', false), + } + }, ]); }); it('should call all parent onChanges across view before calling children onChanges', () => { /** - * - * - * - * parent temp: + * + * */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { @@ -2084,18 +2133,46 @@ describe('lifecycles', () => { } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); elementProperty(1, 'val1', bind(2)); - elementProperty(1, 'publicName', bind(2)); + elementProperty(1, 'publicVal2', bind(2)); } }, 2, 4, defs); const fixture = new ComponentFixture(App); expect(events).toEqual([ - 'comp=parent val1=1 val2=1 - changed=[val1,val2]', - 'comp=parent val1=2 val2=2 - changed=[val1,val2]', - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', - 'comp=comp val1=2 val2=2 - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, 2, true), + 'val2': new SimpleChange(undefined, 2, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 2, true), + 'val2': new SimpleChange(undefined, 2, true), + } + }, ]); }); @@ -2121,7 +2198,7 @@ describe('lifecycles', () => { } if (rf1 & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); } embeddedViewEnd(); } @@ -2131,19 +2208,51 @@ describe('lifecycles', () => { }, 1, 0, defs); const fixture = new ComponentFixture(App); + + // Show the `comp` component, causing it to initialize. (first change is true) fixture.component.condition = true; fixture.update(); - expect(events).toEqual(['comp=comp val1=1 val2=1 - changed=[val1,val2]']); + expect(events).toEqual([{ + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }]); + // Hide the `comp` component, no onChanges should fire fixture.component.condition = false; fixture.update(); - expect(events).toEqual(['comp=comp val1=1 val2=1 - changed=[val1,val2]']); + expect(events).toEqual([{ + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }]); + // Show the `comp` component, it initializes again. (first change is true) fixture.component.condition = true; fixture.update(); expect(events).toEqual([ - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', - 'comp=comp val1=1 val2=1 - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + } ]); }); @@ -2161,26 +2270,40 @@ describe('lifecycles', () => { } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); elementProperty(1, 'val1', bind(2)); - elementProperty(1, 'publicName', bind(2)); + elementProperty(1, 'publicVal2', bind(2)); } }, 2, 4, defs); const fixture = new ComponentFixture(App); expect(events).toEqual([ - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', - 'comp=projected val1=2 val2=2 - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - projected', + changes: { + 'val1': new SimpleChange(undefined, 2, true), + 'val2': new SimpleChange(undefined, 2, true), + } + }, ]); }); it('should call onChanges in host and its content children before next host', () => { /** - * - * + * + * * - * - * + * + * * */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { @@ -2194,75 +2317,130 @@ describe('lifecycles', () => { } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); elementProperty(1, 'val1', bind(2)); - elementProperty(1, 'publicName', bind(2)); + elementProperty(1, 'publicVal2', bind(2)); elementProperty(2, 'val1', bind(3)); - elementProperty(2, 'publicName', bind(3)); + elementProperty(2, 'publicVal2', bind(3)); elementProperty(3, 'val1', bind(4)); - elementProperty(3, 'publicName', bind(4)); + elementProperty(3, 'publicVal2', bind(4)); } }, 4, 8, defs); const fixture = new ComponentFixture(App); expect(events).toEqual([ - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', - 'comp=projected val1=2 val2=2 - changed=[val1,val2]', - 'comp=comp val1=3 val2=3 - changed=[val1,val2]', - 'comp=projected val1=4 val2=4 - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - projected', + changes: { + 'val1': new SimpleChange(undefined, 2, true), + 'val2': new SimpleChange(undefined, 2, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 3, true), + 'val2': new SimpleChange(undefined, 3, true), + } + }, + { + type: 'onChanges', + name: 'comp - projected', + changes: { + 'val1': new SimpleChange(undefined, 4, true), + 'val2': new SimpleChange(undefined, 4, true), + } + }, ]); }); it('should be called on directives after component', () => { - /** */ + /** + * + */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'comp', ['dir', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); } }, 1, 2, defs); const fixture = new ComponentFixture(App); expect(events).toEqual([ - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', 'dir - val1=1 val2=1 - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'dir - dir', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, ]); + // Update causes no changes to be fired, since the bindings didn't change. + events = []; fixture.update(); - expect(events).toEqual([ - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', 'dir - val1=1 val2=1 - changed=[val1,val2]' - ]); + expect(events).toEqual([]); }); it('should be called on directives on an element', () => { - /**
    */ + /** + *
    + */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { element(0, 'div', ['dir', '']); } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); } }, 1, 2, defs); const fixture = new ComponentFixture(App); - expect(events).toEqual(['dir - val1=1 val2=1 - changed=[val1,val2]']); + expect(events).toEqual([{ + type: 'onChanges', + name: 'dir - dir', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }]); + events = []; fixture.update(); - expect(events).toEqual(['dir - val1=1 val2=1 - changed=[val1,val2]']); + expect(events).toEqual([]); }); it('should call onChanges properly in for loop', () => { /** - * + * * % for (let j = 2; j < 5; j++) { - * + * * % } - * + * */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { @@ -2273,9 +2451,9 @@ describe('lifecycles', () => { } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); elementProperty(2, 'val1', bind(5)); - elementProperty(2, 'publicName', bind(5)); + elementProperty(2, 'publicVal2', bind(5)); containerRefreshStart(1); { for (let j = 2; j < 5; j++) { @@ -2285,7 +2463,7 @@ describe('lifecycles', () => { } if (rf1 & RenderFlags.Update) { elementProperty(0, 'val1', bind(j)); - elementProperty(0, 'publicName', bind(j)); + elementProperty(0, 'publicVal2', bind(j)); } embeddedViewEnd(); } @@ -2299,21 +2477,56 @@ describe('lifecycles', () => { // onChanges is called top to bottom, so top level comps (1 and 5) are called // before the comps inside the for loop's embedded view (2, 3, and 4) expect(events).toEqual([ - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', - 'comp=comp val1=5 val2=5 - changed=[val1,val2]', - 'comp=comp val1=2 val2=2 - changed=[val1,val2]', - 'comp=comp val1=3 val2=3 - changed=[val1,val2]', - 'comp=comp val1=4 val2=4 - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 5, true), + 'val2': new SimpleChange(undefined, 5, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 2, true), + 'val2': new SimpleChange(undefined, 2, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 3, true), + 'val2': new SimpleChange(undefined, 3, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 4, true), + 'val2': new SimpleChange(undefined, 4, true), + } + }, ]); }); it('should call onChanges properly in for loop with children', () => { /** - * + * * % for (let j = 2; j < 5; j++) { - * + * * % } - * + * */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { @@ -2324,9 +2537,9 @@ describe('lifecycles', () => { } if (rf & RenderFlags.Update) { elementProperty(0, 'val1', bind(1)); - elementProperty(0, 'publicName', bind(1)); + elementProperty(0, 'publicVal2', bind(1)); elementProperty(2, 'val1', bind(5)); - elementProperty(2, 'publicName', bind(5)); + elementProperty(2, 'publicVal2', bind(5)); containerRefreshStart(1); { for (let j = 2; j < 5; j++) { @@ -2336,7 +2549,7 @@ describe('lifecycles', () => { } if (rf1 & RenderFlags.Update) { elementProperty(0, 'val1', bind(j)); - elementProperty(0, 'publicName', bind(j)); + elementProperty(0, 'publicVal2', bind(j)); } embeddedViewEnd(); } @@ -2350,19 +2563,144 @@ describe('lifecycles', () => { // onChanges is called top to bottom, so top level comps (1 and 5) are called // before the comps inside the for loop's embedded view (2, 3, and 4) expect(events).toEqual([ - 'comp=parent val1=1 val2=1 - changed=[val1,val2]', - 'comp=parent val1=5 val2=5 - changed=[val1,val2]', - 'comp=parent val1=2 val2=2 - changed=[val1,val2]', - 'comp=comp val1=2 val2=2 - changed=[val1,val2]', - 'comp=parent val1=3 val2=3 - changed=[val1,val2]', - 'comp=comp val1=3 val2=3 - changed=[val1,val2]', - 'comp=parent val1=4 val2=4 - changed=[val1,val2]', - 'comp=comp val1=4 val2=4 - changed=[val1,val2]', - 'comp=comp val1=1 val2=1 - changed=[val1,val2]', - 'comp=comp val1=5 val2=5 - changed=[val1,val2]' + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, 5, true), + 'val2': new SimpleChange(undefined, 5, true), + } + }, + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, 2, true), + 'val2': new SimpleChange(undefined, 2, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 2, true), + 'val2': new SimpleChange(undefined, 2, true), + } + }, + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, 3, true), + 'val2': new SimpleChange(undefined, 3, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 3, true), + 'val2': new SimpleChange(undefined, 3, true), + } + }, + { + type: 'onChanges', + name: 'comp - parent', + changes: { + 'val1': new SimpleChange(undefined, 4, true), + 'val2': new SimpleChange(undefined, 4, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 4, true), + 'val2': new SimpleChange(undefined, 4, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 1, true), + 'val2': new SimpleChange(undefined, 1, true), + } + }, + { + type: 'onChanges', + name: 'comp - comp', + changes: { + 'val1': new SimpleChange(undefined, 5, true), + 'val2': new SimpleChange(undefined, 5, true), + } + }, ]); }); + it('should not call onChanges if props are set directly', () => { + let events: SimpleChanges[] = []; + let compInstance: MyComp; + class MyComp { + value = 0; + + ngOnChanges(changes: SimpleChanges) { events.push(changes); } + + static ngComponentDef = defineComponent({ + type: MyComp, + factory: () => { + // Capture the instance so we can test setting the property directly + compInstance = new MyComp(); + return compInstance; + }, + template: (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'div'); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'id', bind(ctx.a)); + } + }, + selectors: [['my-comp']], + inputs: { + value: 'value', + }, + consts: 1, + vars: 1, + }); + } + + /** + * + */ + + const App = createComponent('app', function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + element(0, 'my-comp'); + } + if (rf & RenderFlags.Update) { + elementProperty(0, 'value', bind(1)); + } + }, 1, 1, [MyComp]); + + const fixture = new ComponentFixture(App); + events = []; + + // Try setting the property directly + compInstance !.value = 2; + + fixture.update(); + expect(events).toEqual([]); + }); + }); describe('hook order', () => { @@ -2394,8 +2732,8 @@ describe('lifecycles', () => { consts: consts, vars: vars, inputs: {val: 'val'}, template, - features: [NgOnChangesFeature], - directives: directives + directives: directives, + features: [NgOnChangesFeature()], }); }; } @@ -2412,6 +2750,11 @@ describe('lifecycles', () => { element(0, 'comp'); element(1, 'comp'); } + // This template function is a little weird in that the `elementProperty` calls + // below are directly setting values `1` and `2`, where normally there would be + // a call to `bind()` that would do the work of seeing if something changed. + // This means when `fixture.update()` is called below, ngOnChanges should fire, + // even though the *value* itself never changed. if (rf & RenderFlags.Update) { elementProperty(0, 'val', 1); elementProperty(1, 'val', 2); @@ -2426,7 +2769,7 @@ describe('lifecycles', () => { ]); events = []; - fixture.update(); + fixture.update(); // Changes are made due to lack of `bind()` call in template fn. expect(events).toEqual([ 'changes comp1', 'check comp1', 'changes comp2', 'check comp2', 'contentCheck comp1', 'contentCheck comp2', 'viewCheck comp1', 'viewCheck comp2' diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index fd1473cf2b..c063d242a9 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -6,17 +6,21 @@ * found in the LICENSE file at https://angular.io/license */ -import {bind, defineComponent, defineDirective, markDirty, reference, textBinding} from '../../src/render3/index'; +import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'; + +import {bind, defineComponent, defineDirective, markDirty, reference, resolveBody, resolveDocument, textBinding} from '../../src/render3/index'; import {container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, getCurrentView, listener, text} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; +import {GlobalTargetResolver} from '../../src/render3/interfaces/renderer'; import {restoreView} from '../../src/render3/state'; import {getRendererFactory2} from './imported_renderer2'; -import {ComponentFixture, containerEl, createComponent, getDirectiveOnNode, renderToHtml, requestAnimationFrame} from './render_util'; +import {ComponentFixture, TemplateFixture, containerEl, createComponent, getDirectiveOnNode, renderToHtml, requestAnimationFrame} from './render_util'; describe('event listeners', () => { - let comps: MyComp[] = []; + let comps: any[] = []; + let events: any[] = []; class MyComp { showing = true; @@ -48,6 +52,67 @@ describe('event listeners', () => { }); } + class MyCompWithGlobalListeners { + /* @HostListener('document:custom') */ + onDocumentCustomEvent() { events.push('component - document:custom'); } + + /* @HostListener('body:click') */ + onBodyClick() { events.push('component - body:click'); } + + static ngComponentDef = defineComponent({ + type: MyCompWithGlobalListeners, + selectors: [['comp']], + consts: 1, + vars: 0, + template: function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + text(0, 'Some text'); + } + }, + factory: () => { + let comp = new MyCompWithGlobalListeners(); + comps.push(comp); + return comp; + }, + hostBindings: function HostListenerDir_HostBindings( + rf: RenderFlags, ctx: any, elIndex: number) { + if (rf & RenderFlags.Create) { + listener('custom', function() { + return ctx.onDocumentCustomEvent(); + }, false, resolveDocument as GlobalTargetResolver); + listener('click', function() { + return ctx.onBodyClick(); + }, false, resolveBody as GlobalTargetResolver); + } + } + }); + } + + class GlobalHostListenerDir { + /* @HostListener('document:custom') */ + onDocumentCustomEvent() { events.push('directive - document:custom'); } + + /* @HostListener('body:click') */ + onBodyClick() { events.push('directive - body:click'); } + + static ngDirectiveDef = defineDirective({ + type: GlobalHostListenerDir, + selectors: [['', 'hostListenerDir', '']], + factory: function HostListenerDir_Factory() { return new GlobalHostListenerDir(); }, + hostBindings: function HostListenerDir_HostBindings( + rf: RenderFlags, ctx: any, elIndex: number) { + if (rf & RenderFlags.Create) { + listener('custom', function() { + return ctx.onDocumentCustomEvent(); + }, false, resolveDocument as GlobalTargetResolver); + listener('click', function() { + return ctx.onBodyClick(); + }, false, resolveBody as GlobalTargetResolver); + } + } + }); + } + class PreventDefaultComp { handlerReturnValue: any = true; // TODO(issue/24571): remove '!'. @@ -84,7 +149,10 @@ describe('event listeners', () => { }); } - beforeEach(() => { comps = []; }); + beforeEach(() => { + comps = []; + events = []; + }); it('should call function on event emit', () => { const fixture = new ComponentFixture(MyComp); @@ -477,6 +545,7 @@ describe('event listeners', () => { const fixture = new ComponentFixture(MyComp); const host = fixture.hostElement; + host.click(); expect(events).toEqual(['click!']); @@ -484,6 +553,20 @@ describe('event listeners', () => { expect(events).toEqual(['click!', 'click!']); }); + it('should support global host listeners on components', () => { + const fixture = new ComponentFixture(MyCompWithGlobalListeners); + const doc = fixture.hostElement.ownerDocument !; + + dispatchEvent(doc, 'custom'); + expect(events).toEqual(['component - document:custom']); + + dispatchEvent(doc.body, 'click'); + expect(events).toEqual(['component - document:custom', 'component - body:click']); + + // invoke destroy for this fixture to cleanup all listeners setup for global objects + fixture.destroy(); + }); + it('should support host listeners on directives', () => { let events: string[] = []; @@ -504,16 +587,14 @@ describe('event listeners', () => { }); } - function Template(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - elementStart(0, 'button', ['hostListenerDir', '']); - text(1, 'Click'); - elementEnd(); - } - } + const fixture = new TemplateFixture(() => { + elementStart(0, 'button', ['hostListenerDir', '']); + text(1, 'Click'); + elementEnd(); + }, () => {}, 2, 0, [HostListenerDir]); + + const button = fixture.hostElement.querySelector('button') !; - renderToHtml(Template, {}, 2, 0, [HostListenerDir]); - const button = containerEl.querySelector('button') !; button.click(); expect(events).toEqual(['click!']); @@ -521,6 +602,23 @@ describe('event listeners', () => { expect(events).toEqual(['click!', 'click!']); }); + it('should support global host listeners on directives', () => { + const fixture = new TemplateFixture(() => { + element(0, 'div', ['hostListenerDir', '']); + }, () => {}, 1, 0, [GlobalHostListenerDir]); + + const doc = fixture.hostElement.ownerDocument !; + + dispatchEvent(doc, 'custom'); + expect(events).toEqual(['directive - document:custom']); + + dispatchEvent(doc.body, 'click'); + expect(events).toEqual(['directive - document:custom', 'directive - body:click']); + + // invoke destroy for this fixture to cleanup all listeners setup for global objects + fixture.destroy(); + }); + it('should support listeners with specified set of args', () => { class MyComp { counter = 0; @@ -673,6 +771,40 @@ describe('event listeners', () => { expect(comps[1] !.counter).toEqual(1); }); + it('should destroy global listeners in component views', () => { + const ctx = {showing: true}; + + const fixture = new TemplateFixture( + () => { container(0); }, + () => { + containerRefreshStart(0); + { + if (ctx.showing) { + let rf1 = embeddedViewStart(0, 1, 0); + if (rf1 & RenderFlags.Create) { + element(0, 'comp'); + } + embeddedViewEnd(); + } + } + containerRefreshEnd(); + }, + 1, 0, [MyCompWithGlobalListeners]); + + const body = fixture.hostElement.ownerDocument !.body; + + body.click(); + expect(events).toEqual(['component - body:click']); + + // the child view listener should be removed when the parent view is removed + ctx.showing = false; + fixture.update(); + + body.click(); + // expecting no changes in events array + expect(events).toEqual(['component - body:click']); + }); + it('should support listeners with sibling nested containers', () => { /** * % if (condition) { diff --git a/packages/core/test/render3/metadata_spec.ts b/packages/core/test/render3/metadata_spec.ts index 26494a6e37..7a124d9ee1 100644 --- a/packages/core/test/render3/metadata_spec.ts +++ b/packages/core/test/render3/metadata_spec.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +import {Type} from '../../src/interface/type'; import {setClassMetadata} from '../../src/render3/metadata'; -import {Type} from '../../src/type'; interface Decorator { type: any; diff --git a/packages/core/test/render3/ng_on_changes_feature_spec.ts b/packages/core/test/render3/ng_on_changes_feature_spec.ts deleted file mode 100644 index 69e8012c79..0000000000 --- a/packages/core/test/render3/ng_on_changes_feature_spec.ts +++ /dev/null @@ -1,325 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {DoCheck, EventEmitter, Input, OnChanges, Output, SimpleChange, SimpleChanges} from '../../src/core'; -import {InheritDefinitionFeature} from '../../src/render3/features/inherit_definition_feature'; -import {DirectiveDef, NgOnChangesFeature, defineComponent, defineDirective} from '../../src/render3/index'; - -describe('NgOnChangesFeature', () => { - it('should patch class', () => { - class MyDirective implements OnChanges, DoCheck { - public log: Array = []; - public valA: string = 'initValue'; - public set valB(value: string) { this.log.push(value); } - - public get valB() { return 'works'; } - - ngDoCheck(): void { this.log.push('ngDoCheck'); } - ngOnChanges(changes: SimpleChanges): void { - this.log.push('ngOnChanges'); - this.log.push('valA', changes['valA']); - this.log.push('valB', changes['valB']); - } - - static ngDirectiveDef = defineDirective({ - type: MyDirective, - selectors: [['', 'myDir', '']], - factory: () => new MyDirective(), - features: [NgOnChangesFeature], - inputs: {valA: 'valA', valB: 'valB'} - }); - } - - const myDir = - (MyDirective.ngDirectiveDef as DirectiveDef).factory(null) as MyDirective; - myDir.valA = 'first'; - expect(myDir.valA).toEqual('first'); - myDir.valB = 'second'; - expect(myDir.log).toEqual(['second']); - expect(myDir.valB).toEqual('works'); - myDir.log.length = 0; - (MyDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeA = new SimpleChange(undefined, 'first', true); - const changeB = new SimpleChange(undefined, 'second', true); - expect(myDir.log).toEqual(['ngOnChanges', 'valA', changeA, 'valB', changeB, 'ngDoCheck']); - }); - - it('should inherit the behavior from super class', () => { - const log: any[] = []; - - class SuperDirective implements OnChanges, DoCheck { - valA = 'initValue'; - - set valB(value: string) { log.push(value); } - - get valB() { return 'works'; } - - ngDoCheck(): void { log.push('ngDoCheck'); } - ngOnChanges(changes: SimpleChanges): void { - log.push('ngOnChanges'); - log.push('valA', changes['valA']); - log.push('valB', changes['valB']); - log.push('valC', changes['valC']); - } - - static ngDirectiveDef = defineDirective({ - type: SuperDirective, - selectors: [['', 'superDir', '']], - factory: () => new SuperDirective(), - features: [NgOnChangesFeature], - inputs: {valA: 'valA', valB: 'valB'}, - }); - } - - class SubDirective extends SuperDirective { - valC = 'initValue'; - - static ngDirectiveDef = defineDirective({ - type: SubDirective, - selectors: [['', 'subDir', '']], - factory: () => new SubDirective(), - features: [InheritDefinitionFeature], - inputs: {valC: 'valC'}, - }); - } - - const myDir = - (SubDirective.ngDirectiveDef as DirectiveDef).factory(null) as SubDirective; - myDir.valA = 'first'; - expect(myDir.valA).toEqual('first'); - - myDir.valB = 'second'; - expect(myDir.valB).toEqual('works'); - - myDir.valC = 'third'; - expect(myDir.valC).toEqual('third'); - - log.length = 0; - (SubDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeA = new SimpleChange(undefined, 'first', true); - const changeB = new SimpleChange(undefined, 'second', true); - const changeC = new SimpleChange(undefined, 'third', true); - - expect(log).toEqual( - ['ngOnChanges', 'valA', changeA, 'valB', changeB, 'valC', changeC, 'ngDoCheck']); - }); - - it('should not run the parent doCheck if it is not called explicitly on super class', () => { - const log: any[] = []; - - class SuperDirective implements OnChanges, DoCheck { - valA = 'initValue'; - - ngDoCheck(): void { log.push('ERROR: Child overrides it without super call'); } - ngOnChanges(changes: SimpleChanges): void { log.push(changes.valA, changes.valB); } - - static ngDirectiveDef = defineDirective({ - type: SuperDirective, - selectors: [['', 'superDir', '']], - factory: () => new SuperDirective(), - features: [NgOnChangesFeature], - inputs: {valA: 'valA'}, - }); - } - - class SubDirective extends SuperDirective implements DoCheck { - valB = 'initValue'; - - ngDoCheck(): void { log.push('sub ngDoCheck'); } - - static ngDirectiveDef = defineDirective({ - type: SubDirective, - selectors: [['', 'subDir', '']], - factory: () => new SubDirective(), - features: [InheritDefinitionFeature], - inputs: {valB: 'valB'}, - }); - } - - const myDir = - (SubDirective.ngDirectiveDef as DirectiveDef).factory(null) as SubDirective; - myDir.valA = 'first'; - myDir.valB = 'second'; - - (SubDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeA = new SimpleChange(undefined, 'first', true); - const changeB = new SimpleChange(undefined, 'second', true); - expect(log).toEqual([changeA, changeB, 'sub ngDoCheck']); - }); - - it('should run the parent doCheck if it is inherited from super class', () => { - const log: any[] = []; - - class SuperDirective implements OnChanges, DoCheck { - valA = 'initValue'; - - ngDoCheck(): void { log.push('super ngDoCheck'); } - ngOnChanges(changes: SimpleChanges): void { log.push(changes.valA, changes.valB); } - - static ngDirectiveDef = defineDirective({ - type: SuperDirective, - selectors: [['', 'superDir', '']], - factory: () => new SuperDirective(), - features: [NgOnChangesFeature], - inputs: {valA: 'valA'}, - }); - } - - class SubDirective extends SuperDirective implements DoCheck { - valB = 'initValue'; - - static ngDirectiveDef = defineDirective({ - type: SubDirective, - selectors: [['', 'subDir', '']], - factory: () => new SubDirective(), - features: [InheritDefinitionFeature], - inputs: {valB: 'valB'}, - }); - } - - const myDir = - (SubDirective.ngDirectiveDef as DirectiveDef).factory(null) as SubDirective; - myDir.valA = 'first'; - myDir.valB = 'second'; - - (SubDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeA = new SimpleChange(undefined, 'first', true); - const changeB = new SimpleChange(undefined, 'second', true); - expect(log).toEqual([changeA, changeB, 'super ngDoCheck']); - }); - - it('should apply the feature to inherited properties if on sub class', () => { - const log: any[] = []; - - class SuperDirective { - valC = 'initValue'; - - static ngDirectiveDef = defineDirective({ - type: SuperDirective, - selectors: [['', 'subDir', '']], - factory: () => new SuperDirective(), - features: [], - inputs: {valC: 'valC'}, - }); - } - - class SubDirective extends SuperDirective implements OnChanges, DoCheck { - valA = 'initValue'; - - set valB(value: string) { log.push(value); } - - get valB() { return 'works'; } - - ngDoCheck(): void { log.push('ngDoCheck'); } - ngOnChanges(changes: SimpleChanges): void { - log.push('ngOnChanges'); - log.push('valA', changes['valA']); - log.push('valB', changes['valB']); - log.push('valC', changes['valC']); - } - - static ngDirectiveDef = defineDirective({ - type: SubDirective, - selectors: [['', 'superDir', '']], - factory: () => new SubDirective(), - // Inheritance must always be before OnChanges feature. - features: [ - InheritDefinitionFeature, - NgOnChangesFeature, - ], - inputs: {valA: 'valA', valB: 'valB'} - }); - } - - const myDir = - (SubDirective.ngDirectiveDef as DirectiveDef).factory(null) as SubDirective; - myDir.valA = 'first'; - expect(myDir.valA).toEqual('first'); - - myDir.valB = 'second'; - expect(log).toEqual(['second']); - expect(myDir.valB).toEqual('works'); - - myDir.valC = 'third'; - expect(myDir.valC).toEqual('third'); - - log.length = 0; - (SubDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeA = new SimpleChange(undefined, 'first', true); - const changeB = new SimpleChange(undefined, 'second', true); - const changeC = new SimpleChange(undefined, 'third', true); - expect(log).toEqual( - ['ngOnChanges', 'valA', changeA, 'valB', changeB, 'valC', changeC, 'ngDoCheck']); - }); - - it('correctly computes firstChange', () => { - class MyDirective implements OnChanges { - public log: Array = []; - public valA: string = 'initValue'; - // TODO(issue/24571): remove '!'. - public valB !: string; - - ngOnChanges(changes: SimpleChanges): void { - this.log.push('valA', changes['valA']); - this.log.push('valB', changes['valB']); - } - - static ngDirectiveDef = defineDirective({ - type: MyDirective, - selectors: [['', 'myDir', '']], - factory: () => new MyDirective(), - features: [NgOnChangesFeature], - inputs: {valA: 'valA', valB: 'valB'} - }); - } - - const myDir = - (MyDirective.ngDirectiveDef as DirectiveDef).factory(null) as MyDirective; - myDir.valA = 'first'; - myDir.valB = 'second'; - (MyDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeA1 = new SimpleChange(undefined, 'first', true); - const changeB1 = new SimpleChange(undefined, 'second', true); - expect(myDir.log).toEqual(['valA', changeA1, 'valB', changeB1]); - - myDir.log.length = 0; - myDir.valA = 'third'; - (MyDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeA2 = new SimpleChange('first', 'third', false); - expect(myDir.log).toEqual(['valA', changeA2, 'valB', undefined]); - }); - - it('should not create a getter when only a setter is originally defined', () => { - class MyDirective implements OnChanges { - public log: Array = []; - - public set onlySetter(value: string) { this.log.push(value); } - - ngOnChanges(changes: SimpleChanges): void { - this.log.push('ngOnChanges'); - this.log.push('onlySetter', changes['onlySetter']); - } - - static ngDirectiveDef = defineDirective({ - type: MyDirective, - selectors: [['', 'myDir', '']], - factory: () => new MyDirective(), - features: [NgOnChangesFeature], - inputs: {onlySetter: 'onlySetter'} - }); - } - - const myDir = - (MyDirective.ngDirectiveDef as DirectiveDef).factory(null) as MyDirective; - myDir.onlySetter = 'someValue'; - expect(myDir.onlySetter).toBeUndefined(); - (MyDirective.ngDirectiveDef as DirectiveDef).doCheck !.call(myDir); - const changeSetter = new SimpleChange(undefined, 'someValue', true); - expect(myDir.log).toEqual(['someValue', 'ngOnChanges', 'onlySetter', changeSetter]); - }); -}); diff --git a/packages/core/test/render3/node_selector_matcher_spec.ts b/packages/core/test/render3/node_selector_matcher_spec.ts index 5974dd4391..9a62268fd1 100644 --- a/packages/core/test/render3/node_selector_matcher_spec.ts +++ b/packages/core/test/render3/node_selector_matcher_spec.ts @@ -10,17 +10,20 @@ import {AttributeMarker, TAttributes, TNode, TNodeType} from '../../src/render3/ import {CssSelector, CssSelectorList, NG_PROJECT_AS_ATTR_NAME, SelectorFlags,} from '../../src/render3/interfaces/projection'; import {getProjectAsAttrValue, isNodeMatchingSelectorList, isNodeMatchingSelector} from '../../src/render3/node_selector_matcher'; +import {initializeStaticContext} from '../../src/render3/styling/class_and_style_bindings'; import {createTNode} from '@angular/core/src/render3/instructions'; -import {getLView} from '@angular/core/src/render3/state'; function testLStaticData(tagName: string, attrs: TAttributes | null): TNode { - return createTNode(getLView(), TNodeType.Element, 0, tagName, attrs, null); + return createTNode(null, TNodeType.Element, 0, tagName, attrs); } describe('css selector matching', () => { - function isMatching(tagName: string, attrs: TAttributes | null, selector: CssSelector): boolean { - return isNodeMatchingSelector( - createTNode(getLView(), TNodeType.Element, 0, tagName, attrs, null), selector, false); + function isMatching( + tagName: string, attrsOrTNode: TAttributes | TNode | null, selector: CssSelector): boolean { + const tNode = (!attrsOrTNode || Array.isArray(attrsOrTNode)) ? + createTNode(null, TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes) : + (attrsOrTNode as TNode); + return isNodeMatchingSelector(tNode, selector, false); } describe('isNodeMatchingSimpleSelector', () => { @@ -298,6 +301,26 @@ describe('css selector matching', () => { //
    expect(isMatching('div', ['class', 'foo'], selector)).toBeFalsy(); }); + + it('should match against a class value before and after the styling context is created', + () => { + // selector: 'div.abc' + const selector = ['div', SelectorFlags.CLASS, 'abc']; + const tNode = createTNode(null, TNodeType.Element, 0, 'div', []); + + //
    (without attrs or styling context) + expect(isMatching('div', tNode, selector)).toBeFalsy(); + + //
    (with attrs but without styling context) + tNode.attrs = ['class', 'abc']; + tNode.stylingTemplate = null; + expect(isMatching('div', tNode, selector)).toBeTruthy(); + + //
    (with styling context but without attrs) + tNode.stylingTemplate = initializeStaticContext([AttributeMarker.Classes, 'abc']); + tNode.attrs = null; + expect(isMatching('div', tNode, selector)).toBeTruthy(); + }); }); }); diff --git a/packages/core/test/render3/perfCounter_spec.ts b/packages/core/test/render3/perfCounter_spec.ts index b98b54ff3b..48f42784d0 100644 --- a/packages/core/test/render3/perfCounter_spec.ts +++ b/packages/core/test/render3/perfCounter_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ngDevModeResetPerfCounters} from '../../src/render3/ng_dev_mode'; +import {ngDevModeResetPerfCounters} from '../../src/util/ng_dev_mode'; beforeEach(ngDevModeResetPerfCounters); beforeEach(() => { diff --git a/packages/core/test/render3/pipe_spec.ts b/packages/core/test/render3/pipe_spec.ts index c63c473bda..a2a9050d42 100644 --- a/packages/core/test/render3/pipe_spec.ts +++ b/packages/core/test/render3/pipe_spec.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive as _Directive, InjectionToken, OnChanges, OnDestroy, Pipe as _Pipe, PipeTransform, WrappedValue, createInjector, defineInjectable, defineInjector, ɵNgModuleDef as NgModuleDef, ɵdefineComponent as defineComponent, ɵdirectiveInject as directiveInject} from '@angular/core'; +import {Directive as _Directive, InjectionToken, OnChanges, OnDestroy, Pipe as _Pipe, PipeTransform, WrappedValue, defineInjectable, defineInjector, ɵNgModuleDef as NgModuleDef, ɵdefineComponent as defineComponent, ɵdirectiveInject as directiveInject} from '@angular/core'; import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {createInjector} from '../../src/di/r3_injector'; import {defineDirective, definePipe} from '../../src/render3/definition'; import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, text, textBinding} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; @@ -39,7 +40,8 @@ describe('pipe', () => { person = new Person(); }); - const pipes = () => [CountingPipe, MultiArgPipe, CountingImpurePipe]; + const pipes = + () => [CountingPipe, MultiArgPipe, CountingImpurePipe, DuplicatePipe1, DuplicatePipe2]; it('should support interpolation', () => { function Template(rf: RenderFlags, person: Person) { @@ -168,18 +170,33 @@ describe('pipe', () => { elementEnd(); } if (rf & RenderFlags.Update) { - elementProperty(0, 'someProp', bind(pipeBind1(1, 1, 'Megatron'))); + elementProperty(0, 'id', bind(pipeBind1(1, 1, 'Megatron'))); } } renderToHtml(Template, person, 2, 3, null, [IdentityPipe], rendererFactory2); - expect(renderLog.log).toEqual(['someProp=Megatron']); + expect(renderLog.log).toEqual(['id=Megatron']); renderLog.clear(); renderToHtml(Template, person, 2, 3, null, pipes, rendererFactory2); expect(renderLog.log).toEqual([]); }); + it('should support duplicates by using the later entry', () => { + function Template(rf: RenderFlags, person: Person) { + if (rf & RenderFlags.Create) { + text(0); + pipe(1, 'duplicatePipe'); + } + if (rf & RenderFlags.Update) { + textBinding(0, interpolation1('', pipeBind1(1, 1, person.name), '')); + } + } + + person.init('bob', null); + expect(renderToHtml(Template, person, 2, 3, null, pipes)).toEqual('bob from duplicate 2'); + }); + describe('pure', () => { it('should call pure pipes only if the arguments change', () => { function Template(rf: RenderFlags, person: Person) { @@ -238,8 +255,8 @@ describe('pipe', () => { container(4); } if (rf & RenderFlags.Update) { - elementProperty(0, 'someProp', bind(pipeBind1(1, 2, true))); - elementProperty(2, 'someProp', bind(pipeBind1(3, 4, true))); + elementProperty(0, 'id', bind(pipeBind1(1, 2, true))); + elementProperty(2, 'id', bind(pipeBind1(3, 4, true))); pipeInstances.push(load(1), load(3)); containerRefreshStart(4); { @@ -252,7 +269,7 @@ describe('pipe', () => { elementEnd(); } if (rf1 & RenderFlags.Update) { - elementProperty(0, 'someProp', bind(pipeBind1(1, 1, true))); + elementProperty(0, 'id', bind(pipeBind1(1, 1, true))); pipeInstances.push(load(1)); } } @@ -497,6 +514,28 @@ class MultiArgPipe implements PipeTransform { }); } +@Pipe({name: 'duplicatePipe'}) +class DuplicatePipe1 implements PipeTransform { + transform(value: any) { return `${value} from duplicate 1`; } + + static ngPipeDef = definePipe({ + name: 'duplicatePipe', + type: DuplicatePipe1, + factory: function DuplicatePipe1_Factory() { return new DuplicatePipe1(); }, + }); +} + +@Pipe({name: 'duplicatePipe'}) +class DuplicatePipe2 implements PipeTransform { + transform(value: any) { return `${value} from duplicate 2`; } + + static ngPipeDef = definePipe({ + name: 'duplicatePipe', + type: DuplicatePipe2, + factory: function DuplicatePipe2_Factory() { return new DuplicatePipe2(); }, + }); +} + class Person { // TODO(issue/24571): remove '!'. age !: number; diff --git a/packages/core/test/render3/properties_spec.ts b/packages/core/test/render3/properties_spec.ts index 8a13ec371a..808901d036 100644 --- a/packages/core/test/render3/properties_spec.ts +++ b/packages/core/test/render3/properties_spec.ts @@ -382,7 +382,7 @@ describe('elementProperty', () => { factory: () => myDir = new MyDir(), inputs: {role: 'role', direction: 'dir'}, outputs: {changeStream: 'change'}, - exportAs: 'myDir' + exportAs: ['myDir'] }); } diff --git a/packages/core/test/render3/providers_spec.ts b/packages/core/test/render3/providers_spec.ts index b5cedd99c4..4b6732dacf 100644 --- a/packages/core/test/render3/providers_spec.ts +++ b/packages/core/test/render3/providers_spec.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component as _Component, ComponentFactoryResolver, ElementRef, InjectFlags, Injectable as _Injectable, InjectionToken, InjectorType, Provider, RendererFactory2, ViewContainerRef, createInjector, defineInjectable, defineInjector, inject, ɵNgModuleDef as NgModuleDef} from '../../src/core'; +import {Component as _Component, ComponentFactoryResolver, ElementRef, InjectFlags, Injectable as _Injectable, InjectionToken, InjectorType, Provider, RendererFactory2, ViewContainerRef, defineInjectable, defineInjector, inject, ɵNgModuleDef as NgModuleDef} from '../../src/core'; import {forwardRef} from '../../src/di/forward_ref'; +import {createInjector} from '../../src/di/r3_injector'; import {getInjector} from '../../src/render3/discovery_utils'; import {ProvidersFeature, defineComponent, defineDirective, directiveInject, injectComponentFactoryResolver} from '../../src/render3/index'; import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, text, textBinding} from '../../src/render3/instructions'; @@ -1188,7 +1189,11 @@ describe('providers', () => { static ngInjectableDef = defineInjectable({factory: () => new SomeInj(inject(String))}); } - @Component({template: `

    `, providers: [{provide: String, useValue: 'From my component'}]}) + @Component({ + template: `

    `, + providers: [{provide: String, useValue: 'From my component'}], + viewProviders: [{provide: Number, useValue: 123}] + }) class MyComponent { constructor() {} @@ -1204,7 +1209,9 @@ describe('providers', () => { } }, features: [ - ProvidersFeature([{provide: String, useValue: 'From my component'}]), + ProvidersFeature( + [{provide: String, useValue: 'From my component'}], + [{provide: Number, useValue: 123}]), ], }); } @@ -1237,15 +1244,117 @@ describe('providers', () => { }); } - it('should work', () => { + it('should work from within the template', () => { const fixture = new ComponentFixture(AppComponent); expect(fixture.html).toEqual('

    '); const p = fixture.hostElement.querySelector('p'); const injector = getInjector(p as any); + expect(injector.get(Number)).toEqual(123); expect(injector.get(String)).toEqual('From my component'); expect(injector.get(Some).location).toEqual('From app component'); }); + + it('should work from the host of the component', () => { + const fixture = new ComponentFixture(AppComponent); + expect(fixture.html).toEqual('

    '); + + const myCmp = fixture.hostElement.querySelector('my-cmp'); + const injector = getInjector(myCmp as any); + expect(injector.get(Number)).toEqual(123); + expect(injector.get(String)).toEqual('From my component'); + expect(injector.get(Some).location).toEqual('From app component'); + }); + }); + + describe('lifecycles', () => { + it('should execute ngOnDestroy hooks on providers (and only this one)', () => { + const logs: string[] = []; + + @Injectable() + class InjectableWithLifeCycleHooks { + ngOnChanges() { logs.push('Injectable OnChanges'); } + ngOnInit() { logs.push('Injectable OnInit'); } + ngDoCheck() { logs.push('Injectable DoCheck'); } + ngAfterContentInit() { logs.push('Injectable AfterContentInit'); } + ngAfterContentChecked() { logs.push('Injectable AfterContentChecked'); } + ngAfterViewInit() { logs.push('Injectable AfterViewInit'); } + ngAfterViewChecked() { logs.push('Injectable gAfterViewChecked'); } + ngOnDestroy() { logs.push('Injectable OnDestroy'); } + } + + @Component({template: ``, providers: [InjectableWithLifeCycleHooks]}) + class MyComponent { + constructor(foo: InjectableWithLifeCycleHooks) {} + + static ngComponentDef = defineComponent({ + type: MyComponent, + selectors: [['my-comp']], + factory: () => new MyComponent(directiveInject(InjectableWithLifeCycleHooks)), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: MyComponent) => { + if (rf & RenderFlags.Create) { + element(0, 'span'); + } + }, + features: [ProvidersFeature([InjectableWithLifeCycleHooks])] + }); + } + + @Component({ + template: ` +
    + % if (ctx.condition) { + + % } +
    + `, + }) + class App { + public condition = true; + + static ngComponentDef = defineComponent({ + type: App, + selectors: [['app-cmp']], + factory: () => new App(), + consts: 2, + vars: 0, + template: (rf: RenderFlags, ctx: App) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'div'); + { container(1); } + elementEnd(); + } + if (rf & RenderFlags.Update) { + containerRefreshStart(1); + { + if (ctx.condition) { + let rf1 = embeddedViewStart(1, 2, 1); + { + if (rf1 & RenderFlags.Create) { + element(0, 'my-comp'); + } + } + embeddedViewEnd(); + } + } + containerRefreshEnd(); + } + }, + directives: [MyComponent] + }); + } + + const fixture = new ComponentFixture(App); + fixture.update(); + expect(fixture.html).toEqual('
    '); + + fixture.component.condition = false; + fixture.update(); + expect(fixture.html).toEqual('
    '); + expect(logs).toEqual(['Injectable OnDestroy']); + }); }); }); interface ComponentTest { diff --git a/packages/core/test/render3/query_list_spec.ts b/packages/core/test/render3/query_list_spec.ts deleted file mode 100644 index 59e3973047..0000000000 --- a/packages/core/test/render3/query_list_spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {QueryList} from '../../src/render3/query'; - -describe('QueryList', () => { - let q: QueryList; - - beforeEach(() => { q = new QueryList(); }); - - describe('dirty and reset', () => { - - it('should be dirty and empty initially', () => { - expect(q.dirty).toBeTruthy(); - expect(q.length).toBe(0); - }); - - it('should be not dirty after reset', () => { - expect(q.dirty).toBeTruthy(); - q.reset([1, 2, 3]); - expect(q.dirty).toBeFalsy(); - expect(q.length).toBe(3); - }); - - }); - - describe('elements access', () => { - - it('should give access to the first / last element', () => { - q.reset([1, 2, 3]); - expect(q.length).toBe(3); - expect(q.first).toBe(1); - expect(q.last).toBe(3); - }); - - it('should return copy of matched elements as an array', () => { - q.reset([1, 2, 3]); - - const result = q.toArray(); - expect(result).toEqual([1, 2, 3]); - - // mutate returned result to make sure that oryginal values in query are not mutated - result.push(4); - expect(q.toArray()).toEqual([1, 2, 3]); - }); - - }); - - describe('array-like methods', () => { - - it('should support map method', () => { - q.reset([1, 2, 3]); - expect(q.map((item: number, idx: number) => { - return item + idx; - })).toEqual([1, 3, 5]); - }); - - it('should support filter method', () => { - q.reset([1, 2, 3]); - expect(q.filter((item: number, idx: number) => { return item > 2; })).toEqual([3]); - }); - - it('should support find method', () => { - q.reset([1, 2, 3]); - expect(q.find((item: number, idx: number) => { return item > 0; })).toBe(1); - }); - - it('should support reduce method', () => { - q.reset([1, 2, 3]); - expect(q.reduce((prevValue: number, curValue: number, curIndex: number) => { - return prevValue + curValue + curIndex; - }, 0)).toBe(9); - }); - - it('should support forEach method', () => { - let itemIdxSum = 0; - q.reset([1, 2, 3]); - q.forEach((item: number, idx: number) => { itemIdxSum += item + idx; }); - expect(itemIdxSum).toBe(9); - }); - - it('should support some method', () => { - q.reset([1, 2, 3]); - expect(q.some((item: number, idx: number) => { return item > 0; })).toBe(true); - }); - - }); - - describe('destroy', () => { - it('should close all subscriptions', () => { - let completed = false; - q.changes.subscribe(() => {}, () => {}, () => { completed = true; }); - q.destroy(); - expect(completed).toBeTruthy(); - }); - }); -}); diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index ba1c172e27..8f769b4b3f 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -7,15 +7,15 @@ */ import {NgForOfContext} from '@angular/common'; -import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core'; +import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core'; import {EventEmitter} from '../..'; -import {AttributeMarker, ProvidersFeature, QueryList, defineComponent, defineDirective, detectChanges} from '../../src/render3/index'; +import {AttributeMarker, ProvidersFeature, defineComponent, defineDirective, detectChanges} from '../../src/render3/index'; import {getNativeByIndex} from '../../src/render3/util'; -import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadQueryList, reference, registerContentQuery, template, text} from '../../src/render3/instructions'; +import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, reference, template, text} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; -import {query, queryRefresh} from '../../src/render3/query'; +import {queryRefresh, viewQuery, loadViewQuery, contentQuery, loadContentQuery} from '../../src/render3/query'; import {getLView} from '../../src/render3/state'; import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound'; @@ -71,25 +71,27 @@ describe('query', () => { * } */ if (rf & RenderFlags.Create) { - elementStart(2, 'child'); - { element(3, 'child'); } + elementStart(0, 'child'); + { element(1, 'child'); } elementEnd(); } if (rf & RenderFlags.Update) { - child1 = getDirectiveOnNode(2); - child2 = getDirectiveOnNode(3); + child1 = getDirectiveOnNode(0); + child2 = getDirectiveOnNode(1); } }, - 4, 0, [Child], [], + 2, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, Child, false); - query(1, Child, true); + viewQuery(Child, false); + viewQuery(Child, true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query0 = tmp as QueryList); - queryRefresh(tmp = load>(1)) && (ctx.query1 = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query0 = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query1 = tmp as QueryList); } }); @@ -114,18 +116,19 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', '']); - elToQuery = getNativeByIndex(1, getLView()); + element(0, 'div', ['child', '']); + elToQuery = getNativeByIndex(0, getLView()); } }, - 2, 0, [Child], [], + 1, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, Child, false, ElementRef); + viewQuery(Child, false, ElementRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -150,19 +153,20 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - elementStart(1, 'div', ['child', '', 'otherChild', '']); - { otherChildInstance = getDirectiveOnNode(1, 1); } + elementStart(0, 'div', ['child', '', 'otherChild', '']); + { otherChildInstance = getDirectiveOnNode(0, 1); } elementEnd(); } }, - 2, 0, [Child, OtherChild], [], + 1, 0, [Child, OtherChild], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, Child, false, OtherChild); + viewQuery(Child, false, OtherChild); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -185,17 +189,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', '']); + element(0, 'div', ['child', '']); } }, - 2, 0, [Child, OtherChild], [], + 1, 0, [Child, OtherChild], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, Child, false, OtherChild); + viewQuery(Child, false, OtherChild); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -246,25 +251,25 @@ describe('query', () => { static ngComponentDef = defineComponent({ type: App, selectors: [['app']], - consts: 4, + consts: 1, vars: 0, factory: function App_Factory() { return new App(); }, template: function App_Template(rf: RenderFlags, ctx: App) { if (rf & RenderFlags.Create) { - element(3, 'div', ['myDir']); + element(0, 'div', ['myDir']); } }, viewQuery: function(rf: RenderFlags, ctx: App) { - let tmp: any; if (rf & RenderFlags.Create) { - query(0, MyDirective, false); - query(1, Service, false); - query(2, Alias, false); + viewQuery(MyDirective, false); + viewQuery(Service, false); + viewQuery(Alias, false); } if (rf & RenderFlags.Update) { - queryRefresh(tmp = load>(0)) && (ctx.directive = tmp.first); - queryRefresh(tmp = load>(1)) && (ctx.service = tmp.first); - queryRefresh(tmp = load>(2)) && (ctx.alias = tmp.first); + let tmp: any; + queryRefresh(tmp = loadViewQuery>()) && (ctx.directive = tmp.first); + queryRefresh(tmp = loadViewQuery>()) && (ctx.service = tmp.first); + queryRefresh(tmp = loadViewQuery>()) && (ctx.alias = tmp.first); } }, directives: [MyDirective] @@ -291,21 +296,21 @@ describe('query', () => { static ngComponentDef = defineComponent({ type: App, selectors: [['app']], - consts: 2, + consts: 1, vars: 0, factory: function App_Factory() { return new App(); }, template: function App_Template(rf: RenderFlags, ctx: App) { if (rf & RenderFlags.Create) { - element(1, 'div', ['myDir']); + element(0, 'div', ['myDir']); } }, viewQuery: function(rf: RenderFlags, ctx: App) { let tmp: any; if (rf & RenderFlags.Create) { - query(0, MyDirective, false, Alias); + viewQuery(MyDirective, false, Alias); } if (rf & RenderFlags.Update) { - queryRefresh(tmp = load>(0)) && (ctx.service = tmp.first); + queryRefresh(tmp = loadViewQuery>()) && (ctx.service = tmp.first); } }, directives: [MyDirective] @@ -334,19 +339,20 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', null, ['foo', '']); - elToQuery = getNativeByIndex(1, getLView()); - element(3, 'div'); + element(0, 'div', null, ['foo', '']); + elToQuery = getNativeByIndex(0, getLView()); + element(2, 'div'); } }, - 4, 0, [], [], + 3, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false); + viewQuery(['foo'], false); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -371,22 +377,22 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(2, 'div', null, ['foo', '', 'bar', '']); - elToQuery = getNativeByIndex(2, getLView()); - element(5, 'div'); + element(0, 'div', null, ['foo', '', 'bar', '']); + elToQuery = getNativeByIndex(0, getLView()); + element(3, 'div'); } }, - 6, 0, [], [], + 4, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false); - query(1, ['bar'], false); + viewQuery(['foo'], false); + viewQuery(['bar'], false); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.fooQuery = tmp as QueryList); - queryRefresh(tmp = load>(1)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.barQuery = tmp as QueryList); } }); @@ -418,21 +424,22 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', null, ['foo', '']); - el1ToQuery = getNativeByIndex(1, getLView()); - element(3, 'div'); - element(4, 'div', null, ['bar', '']); - el2ToQuery = getNativeByIndex(4, getLView()); + element(0, 'div', null, ['foo', '']); + el1ToQuery = getNativeByIndex(0, getLView()); + element(2, 'div'); + element(3, 'div', null, ['bar', '']); + el2ToQuery = getNativeByIndex(3, getLView()); } }, - 6, 0, [], [], + 5, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo', 'bar'], undefined); + viewQuery(['foo', 'bar'], undefined); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -457,19 +464,20 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', null, ['foo', '']); - elToQuery = getNativeByIndex(1, getLView()); - element(3, 'div'); + element(0, 'div', null, ['foo', '']); + elToQuery = getNativeByIndex(0, getLView()); + element(2, 'div'); } }, - 4, 0, [], [], + 3, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false); + viewQuery(['foo'], false); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -493,19 +501,19 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - elementContainerStart(1, null, ['foo', '']); - elToQuery = getNativeByIndex(1, getLView()); + elementContainerStart(0, null, ['foo', '']); + elToQuery = getNativeByIndex(0, getLView()); elementContainerEnd(); } }, - 3, 0, [], [], + 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false, ElementRef); + viewQuery(['foo'], false, ElementRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.query = tmp as QueryList); } }); @@ -529,19 +537,20 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - elementContainerStart(1, null, ['foo', '']); - elToQuery = getNativeByIndex(1, getLView()); + elementContainerStart(0, null, ['foo', '']); + elToQuery = getNativeByIndex(0, getLView()); elementContainerEnd(); } }, - 3, 0, [], [], + 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -553,13 +562,13 @@ describe('query', () => { }); /** - * BREAKING CHANGE: this tests asserts different behaviour as compared to Renderer2 when it + * BREAKING CHANGE: this tests asserts different behavior as compared to Renderer2 when it * comes to descendants: false option and . * - * Previous behaviour: queries with descendants: false would descend into . - * New behaviour: queries with descendants: false would NOT descend into . + * Previous behavior: queries with descendants: false would descend into . + * New behavior: queries with descendants: false would NOT descend into . * - * Reasoning: the Renderer2 behaviour is inconsistent and hard to explain to users when it + * Reasoning: the Renderer2 behavior is inconsistent and hard to explain to users when it * comes to descendants: false interpretation (see * https://github.com/angular/angular/issues/14769#issuecomment-356609267) so we are changing * it in ngIvy. @@ -590,24 +599,25 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - elementContainerStart(2); + elementContainerStart(0); { - element(3, 'div', null, ['foo', '']); + element(1, 'div', null, ['foo', '']); elToQuery = getNativeByIndex(3, getLView()); } elementContainerEnd(); } }, - 5, 0, [], [], + 3, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true, ElementRef); - query(1, ['foo'], false, ElementRef); + viewQuery(['foo'], true, ElementRef); + viewQuery(['foo'], false, ElementRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.deep = tmp as QueryList); - queryRefresh(tmp = load>(1)) && + queryRefresh(tmp = loadViewQuery>()) && + (ctx.deep = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && (ctx.shallow = tmp as QueryList); } }); @@ -630,17 +640,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', null, ['foo', '']); + element(0, 'div', null, ['foo', '']); } }, - 3, 0, [], [], + 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false, ViewContainerRef); + viewQuery(['foo'], false, ViewContainerRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -661,17 +672,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, 0, 0, 'ng-template', null, ['foo', '']); + template(0, null, 0, 0, 'ng-template', null, ['foo', '']); } }, - 3, 0, [], [], + 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false, ViewContainerRef); + viewQuery(['foo'], false, ViewContainerRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -693,18 +705,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, 0, 0, 'ng-template', null, ['foo', '']); + template(0, null, 0, 0, 'ng-template', null, ['foo', '']); } }, - 3, 0, [], [], + 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false, ElementRef); + viewQuery(['foo'], false, ElementRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.query = tmp as QueryList); } }); @@ -728,17 +740,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, 0, 0, 'ng-template', null, ['foo', '']); + template(0, null, 0, 0, 'ng-template', null, ['foo', '']); } }, - 3, 0, [], [], + 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], undefined); + viewQuery(['foo'], undefined); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -760,17 +773,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, null, 0, 0, 'ng-template', null, ['foo', '']); + template(0, null, 0, 0, 'ng-template', null, ['foo', '']); } }, - 3, 0, [], [], + 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false, TemplateRef); + viewQuery(['foo'], false, TemplateRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -794,20 +808,21 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'child', null, ['foo', '']); + element(0, 'child', null, ['foo', '']); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(1); + childInstance = getDirectiveOnNode(0); } }, - 3, 0, [Child], [], + 2, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -828,7 +843,7 @@ describe('query', () => { consts: 0, vars: 0, template: (rf: RenderFlags, ctx: Child) => {}, - exportAs: 'child' + exportAs: ['child'] }); } @@ -842,17 +857,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'child', null, ['foo', 'child']); + element(0, 'child', null, ['foo', 'child']); } }, - 3, 0, [Child], [], + 2, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -864,7 +880,7 @@ describe('query', () => { it('should read directive instance if element queried for has an exported directive with a matching name', () => { - const Child = createDirective('child', {exportAs: 'child'}); + const Child = createDirective('child', {exportAs: ['child']}); let childInstance; /** @@ -877,20 +893,20 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', ''], ['foo', 'child']); + element(0, 'div', ['child', ''], ['foo', 'child']); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(1); + childInstance = getDirectiveOnNode(0); } }, - 3, 0, [Child], [], + 2, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.query = tmp as QueryList); } }); @@ -902,8 +918,8 @@ describe('query', () => { }); it('should read all matching directive instances from a given element', () => { - const Child1 = createDirective('child1', {exportAs: 'child1'}); - const Child2 = createDirective('child2', {exportAs: 'child2'}); + const Child1 = createDirective('child1', {exportAs: ['child1']}); + const Child2 = createDirective('child2', {exportAs: ['child2']}); let child1Instance, child2Instance; /** @@ -916,21 +932,22 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child1', '', 'child2', ''], ['foo', 'child1', 'bar', 'child2']); + element(0, 'div', ['child1', '', 'child2', ''], ['foo', 'child1', 'bar', 'child2']); } if (rf & RenderFlags.Update) { - child1Instance = getDirectiveOnNode(1, 0); - child2Instance = getDirectiveOnNode(1, 1); + child1Instance = getDirectiveOnNode(0, 0); + child2Instance = getDirectiveOnNode(0, 1); } }, - 4, 0, [Child1, Child2], [], + 3, 0, [Child1, Child2], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo', 'bar'], true); + viewQuery(['foo', 'bar'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -942,7 +959,7 @@ describe('query', () => { }); it('should read multiple locals exporting the same directive from a given element', () => { - const Child = createDirective('child', {exportAs: 'child'}); + const Child = createDirective('child', {exportAs: ['child']}); let childInstance; /** @@ -956,23 +973,23 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(2, 'div', ['child', ''], ['foo', 'child', 'bar', 'child']); + element(0, 'div', ['child', ''], ['foo', 'child', 'bar', 'child']); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(2); + childInstance = getDirectiveOnNode(0); } }, - 5, 0, [Child], [], + 3, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); - query(1, ['bar'], true); + viewQuery(['foo'], true); + viewQuery(['bar'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.fooQuery = tmp as QueryList); - queryRefresh(tmp = load>(1)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.barQuery = tmp as QueryList); } }); @@ -989,7 +1006,7 @@ describe('query', () => { }); it('should match on exported directive name and read a requested token', () => { - const Child = createDirective('child', {exportAs: 'child'}); + const Child = createDirective('child', {exportAs: ['child']}); let div; /** @@ -1002,18 +1019,19 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', ''], ['foo', 'child']); - div = getNativeByIndex(1, getLView()); + element(0, 'div', ['child', ''], ['foo', 'child']); + div = getNativeByIndex(0, getLView()); } }, - 3, 0, [Child], [], + 2, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], undefined, ElementRef); + viewQuery(['foo'], undefined, ElementRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1024,7 +1042,7 @@ describe('query', () => { }); it('should support reading a mix of ElementRef and directive instances', () => { - const Child = createDirective('child', {exportAs: 'child'}); + const Child = createDirective('child', {exportAs: ['child']}); let childInstance, div; /** @@ -1037,21 +1055,22 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', ''], ['foo', '', 'bar', 'child']); - div = getNativeByIndex(1, getLView()); + element(0, 'div', ['child', ''], ['foo', '', 'bar', 'child']); + div = getNativeByIndex(0, getLView()); } if (rf & RenderFlags.Update) { - childInstance = getDirectiveOnNode(1); + childInstance = getDirectiveOnNode(0); } }, - 4, 0, [Child], [], + 3, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo', 'bar'], undefined); + viewQuery(['foo', 'bar'], undefined); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1075,17 +1094,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['foo', '']); + element(0, 'div', ['foo', '']); } }, - 3, 0, [Child], [], + 2, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false, Child); + viewQuery(['foo'], false, Child); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1108,17 +1128,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', '']); + element(0, 'div', ['child', '']); } }, - 2, 0, [Child, OtherChild], [], + 1, 0, [Child, OtherChild], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, Child, false, OtherChild); + viewQuery(Child, false, OtherChild); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1141,17 +1162,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', '']); + element(0, 'div', ['child', '']); } }, - 2, 0, [Child, OtherChild], [], + 1, 0, [Child, OtherChild], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, OtherChild, false, Child); + viewQuery(OtherChild, false, Child); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1171,17 +1193,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div'); + element(0, 'div'); } }, - 2, 0, [], [], + 1, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, TemplateRef as any, false, ElementRef); + viewQuery(TemplateRef as any, false, ElementRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1203,17 +1226,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', ''], ['foo', '']); + element(0, 'div', ['child', ''], ['foo', '']); } }, - 3, 0, [Child], [], + 2, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false, Child); + viewQuery(['foo'], false, Child); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1236,17 +1260,18 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', ['child', '']); + element(0, 'div', ['child', '']); } }, - 2, 0, [Child], [], + 1, 0, [Child], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, TemplateRef as any, false); + viewQuery(TemplateRef as any, false); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1277,27 +1302,27 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { template( - 2, Cmpt_Template_1, 2, 0, 'ng-template', null, ['foo', ''], + 0, Cmpt_Template_1, 2, 0, 'ng-template', null, ['foo', ''], templateRefExtractor); template( - 3, Cmpt_Template_1, 2, 0, 'ng-template', null, ['bar', ''], + 2, Cmpt_Template_1, 2, 0, 'ng-template', null, ['bar', ''], templateRefExtractor); template( 4, Cmpt_Template_1, 2, 0, 'ng-template', null, ['baz', ''], templateRefExtractor); } }, - 5, 0, [], [], + 6, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, TemplateRef as any, false); - query(1, TemplateRef as any, false, ElementRef); + viewQuery(TemplateRef as any, false); + viewQuery(TemplateRef as any, false, ElementRef); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.tmplQuery = tmp as QueryList); - queryRefresh(tmp = load>(1)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.elemQuery = tmp as QueryList); } }); @@ -1367,20 +1392,21 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, Cmpt_Template_1, 2, 0, 'ng-template', ['ngIf', '']); + template(0, Cmpt_Template_1, 2, 0, 'ng-template', ['ngIf', '']); } if (rf & RenderFlags.Update) { - elementProperty(1, 'ngIf', bind(ctx.value)); + elementProperty(0, 'ngIf', bind(ctx.value)); } }, - 3, 1, [NgIf], [], + 2, 1, [NgIf], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1424,23 +1450,24 @@ describe('query', () => { type: Cmpt, factory: () => new Cmpt(), selectors: [['my-app']], - consts: 3, + consts: 2, vars: 1, template: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - template(1, Cmpt_Template_1, 2, 1, 'ng-template', ['ngForOf', '']); + template(0, Cmpt_Template_1, 2, 1, 'ng-template', ['ngForOf', '']); } if (rf & RenderFlags.Update) { - elementProperty(1, 'ngForOf', bind(ctx.value)); + elementProperty(0, 'ngForOf', bind(ctx.value)); } }, viewQuery: function(rf: RenderFlags, ctx: Cmpt) { let tmp: any; if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }, directives: () => [NgForOf] @@ -1507,29 +1534,29 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { template( - 1, Cmpt_Template_1, 2, 1, 'ng-template', null, ['tpl1', ''], + 0, Cmpt_Template_1, 2, 1, 'ng-template', null, ['tpl1', ''], templateRefExtractor); - element(3, 'div', ['id', 'middle'], ['foo', '']); + element(2, 'div', ['id', 'middle'], ['foo', '']); template( - 5, Cmpt_Template_5, 2, 1, 'ng-template', null, ['tpl2', ''], + 4, Cmpt_Template_5, 2, 1, 'ng-template', null, ['tpl2', ''], templateRefExtractor); - template(7, null, 0, 0, 'ng-template', [AttributeMarker.SelectOnly, 'vc']); + template(6, null, 0, 0, 'ng-template', [AttributeMarker.SelectOnly, 'vc']); } if (rf & RenderFlags.Update) { - tpl1 = reference(2); - tpl2 = reference(6); + tpl1 = reference(1); + tpl2 = reference(5); } }, - 9, 0, [ViewContainerManipulatorDirective], [], + 8, 0, [ViewContainerManipulatorDirective], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.query = tmp as QueryList); } }); @@ -1602,30 +1629,30 @@ describe('query', () => { type: Cmpt, factory: () => new Cmpt(), selectors: [['my-app']], - consts: 5, + consts: 4, vars: 0, template: function(rf: RenderFlags, ctx: any) { let tmp: any; if (rf & RenderFlags.Create) { template( - 1, Cmpt_Template_1, 2, 1, 'ng-template', [], ['tpl', ''], + 0, Cmpt_Template_1, 2, 1, 'ng-template', [], ['tpl', ''], templateRefExtractor); + template(2, null, 0, 0, 'ng-template', [AttributeMarker.SelectOnly, 'vc']); template(3, null, 0, 0, 'ng-template', [AttributeMarker.SelectOnly, 'vc']); - template(4, null, 0, 0, 'ng-template', [AttributeMarker.SelectOnly, 'vc']); } if (rf & RenderFlags.Update) { - tpl = reference(2); + tpl = reference(1); } }, viewQuery: (rf: RenderFlags, cmpt: Cmpt) => { let tmp: any; if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (cmpt.query = tmp as QueryList); } }, @@ -1672,7 +1699,7 @@ describe('query', () => { type: MyApp, factory: () => new MyApp(), selectors: [['my-app']], - consts: 5, + consts: 4, vars: 1, /** * @@ -1681,24 +1708,24 @@ describe('query', () => { template: (rf: RenderFlags, myApp: MyApp) => { if (rf & RenderFlags.Create) { template( - 1, MyApp_Template_1, 2, 0, 'ng-template', undefined, ['tpl', ''], + 0, MyApp_Template_1, 2, 0, 'ng-template', undefined, ['tpl', ''], templateRefExtractor); template( - 3, null, 0, 0, 'ng-template', [AttributeMarker.SelectOnly, 'ngTemplateOutlet']); + 2, null, 0, 0, 'ng-template', [AttributeMarker.SelectOnly, 'ngTemplateOutlet']); } if (rf & RenderFlags.Update) { - const tplRef = reference(2); - elementProperty(3, 'ngTemplateOutlet', bind(myApp.show ? tplRef : null)); + const tplRef = reference(1); + elementProperty(2, 'ngTemplateOutlet', bind(myApp.show ? tplRef : null)); } }, directives: () => [NgTemplateOutlet], viewQuery: (rf: RenderFlags, myApp: MyApp) => { let tmp: any; if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (myApp.query = tmp as QueryList); } } @@ -1738,10 +1765,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - container(1); + container(0); } if (rf & RenderFlags.Update) { - containerRefreshStart(1); + containerRefreshStart(0); { if (ctx.exp) { let rf1 = embeddedViewStart(1, 2, 0); @@ -1757,14 +1784,15 @@ describe('query', () => { containerRefreshEnd(); } }, - 2, 0, [], [], + 1, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1799,14 +1827,14 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'span', null, ['foo', '']); - firstEl = getNativeByIndex(1, getLView()); - container(3); - element(4, 'span', null, ['foo', '']); - lastEl = getNativeByIndex(4, getLView()); + element(0, 'span', null, ['foo', '']); + firstEl = getNativeByIndex(0, getLView()); + container(2); + element(3, 'span', null, ['foo', '']); + lastEl = getNativeByIndex(3, getLView()); } if (rf & RenderFlags.Update) { - containerRefreshStart(3); + containerRefreshStart(2); { if (ctx.exp) { let rf1 = embeddedViewStart(1, 2, 0); @@ -1822,14 +1850,14 @@ describe('query', () => { containerRefreshEnd(); } }, - 6, 0, [], [], + 5, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.query = tmp as QueryList); } }); @@ -1870,10 +1898,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - container(1); + container(0); } if (rf & RenderFlags.Update) { - containerRefreshStart(1); + containerRefreshStart(0); { if (ctx.exp1) { let rf0 = embeddedViewStart(0, 2, 0); @@ -1899,14 +1927,15 @@ describe('query', () => { containerRefreshEnd(); } }, - 2, 0, [], [], + 1, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -1943,10 +1972,10 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - container(1); + container(0); } if (rf & RenderFlags.Update) { - containerRefreshStart(1); + containerRefreshStart(0); { if (ctx.exp1) { let rf0 = embeddedViewStart(0, 3, 0); @@ -1979,14 +2008,15 @@ describe('query', () => { containerRefreshEnd(); } }, - 2, 0, [], [], + 1, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -2027,11 +2057,11 @@ describe('query', () => { 'cmpt', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - container(2); - element(3, 'span', null, ['foo', '']); + container(0); + element(1, 'span', null, ['foo', '']); } if (rf & RenderFlags.Update) { - containerRefreshStart(2); + containerRefreshStart(0); { if (ctx.exp) { let rf0 = embeddedViewStart(0, 4, 0); @@ -2048,16 +2078,17 @@ describe('query', () => { containerRefreshEnd(); } }, - 5, 0, [], [], + 3, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); - query(1, ['foo'], false); + viewQuery(['foo'], true); + viewQuery(['foo'], false); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.deep = tmp as QueryList); - queryRefresh(tmp = load>(1)) && + queryRefresh(tmp = loadViewQuery>()) && + (ctx.deep = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && (ctx.shallow = tmp as QueryList); } }); @@ -2126,17 +2157,17 @@ describe('query', () => { 'some-component-with-query', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - element(1, 'div', null, ['foo', '']); + element(0, 'div', null, ['foo', '']); } }, 2, 0, [], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], false); + viewQuery(['foo'], false); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && + queryRefresh(tmp = loadViewQuery>()) && (ctx.query = queryInstance = tmp as QueryList); } }); @@ -2206,18 +2237,19 @@ describe('query', () => { function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { template( - 1, AppComponent_Template_1, 1, 0, 'div', [AttributeMarker.SelectOnly, 'someDir']); - element(2, 'div', null, ['foo', '']); + 0, AppComponent_Template_1, 1, 0, 'div', [AttributeMarker.SelectOnly, 'someDir']); + element(1, 'div', null, ['foo', '']); } }, - 4, 0, [SomeDir], [], + 3, 0, [SomeDir], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.query = tmp as QueryList); } }); @@ -2249,14 +2281,15 @@ describe('query', () => { static ngDirectiveDef = defineDirective({ type: WithContentDirective, selectors: [['', 'with-content', '']], - factory: () => new WithContentDirective(), - contentQueries: - (dirIndex) => { registerContentQuery(query(null, ['foo'], true), dirIndex); }, - contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { - let tmp: any; - withContentInstance = load(dirIndex); - queryRefresh(tmp = loadQueryList(queryStartIdx)) && - (withContentInstance.foos = tmp); + factory: () => withContentInstance = new WithContentDirective(), + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.foos = tmp); + } } }); } @@ -2268,17 +2301,18 @@ describe('query', () => { static ngComponentDef = defineComponent({ type: ShallowComp, selectors: [['shallow-comp']], - factory: () => new ShallowComp(), + factory: () => shallowCompInstance = new ShallowComp(), template: function(rf: RenderFlags, ctx: any) {}, consts: 0, vars: 0, - contentQueries: - (dirIndex) => { registerContentQuery(query(null, ['foo'], false), dirIndex); }, - contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { - let tmp: any; - shallowCompInstance = load(dirIndex); - queryRefresh(tmp = loadQueryList(queryStartIdx)) && - (shallowCompInstance.foos = tmp); + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.foos = tmp); + } } }); } @@ -2357,7 +2391,7 @@ describe('query', () => { `Expected content query results to be available when ngAfterContentChecked was called.`); }); - it('should support content query matches on directive hosts', () => { + it('should not match directive host with content queries', () => { /** *
    *
    @@ -2370,7 +2404,7 @@ describe('query', () => { const fixture = new ComponentFixture(AppComponent); expect(withContentInstance !.foos.length) - .toBe(1, `Expected content query to match
    .`); + .toBe(0, `Expected content query not to match
    .`); }); it('should match shallow content queries in views inserted / removed by ngIf', () => { @@ -2425,20 +2459,21 @@ describe('query', () => { 'app-component', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - elementStart(1, 'div', ['with-content', '']); - { element(2, 'div', null, ['foo', '']); } + elementStart(0, 'div', ['with-content', '']); + { element(1, 'div', null, ['foo', '']); } elementEnd(); - element(4, 'div', ['id', 'after'], ['bar', '']); + element(3, 'div', ['id', 'after'], ['bar', '']); } }, - 6, 0, [WithContentDirective], [], + 5, 0, [WithContentDirective], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo', 'bar'], true); + viewQuery(['foo', 'bar'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.foos = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.foos = tmp as QueryList); } }); @@ -2465,20 +2500,21 @@ describe('query', () => { 'app-component', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - elementStart(1, 'div', ['with-content', '']); - { element(2, 'div', ['id', 'yes'], ['foo', '']); } + elementStart(0, 'div', ['with-content', '']); + { element(1, 'div', ['id', 'yes'], ['foo', '']); } elementEnd(); - element(4, 'div', null, ['foo', '']); + element(3, 'div', null, ['foo', '']); } }, - 6, 0, [WithContentDirective], [], + 5, 0, [WithContentDirective], [], function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['bar'], true); + viewQuery(['bar'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.bars = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.bars = tmp as QueryList); } }); @@ -2493,19 +2529,19 @@ describe('query', () => { static ngDirectiveDef = defineDirective({ type: QueryDirective, selectors: [['', 'query', '']], - exportAs: 'query', + exportAs: ['query'], factory: () => new QueryDirective(), - contentQueries: (dirIndex) => { - // @ContentChildren('foo, bar, baz', {descendants: true}) fooBars: - // QueryList; - registerContentQuery(query(null, ['foo', 'bar', 'baz'], true), dirIndex); - }, - contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { - let tmp: any; - const instance = load(dirIndex); - queryRefresh(tmp = loadQueryList(queryStartIdx)) && - (instance.fooBars = tmp); - }, + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo, bar, baz', {descendants: true}) + // fooBars: QueryList; + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo', 'bar', 'baz'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.fooBars = tmp); + } + } }); } @@ -2557,19 +2593,19 @@ describe('query', () => { static ngDirectiveDef = defineDirective({ type: QueryDirective, selectors: [['', 'query', '']], - exportAs: 'query', + exportAs: ['query'], factory: () => new QueryDirective(), - contentQueries: (dirIndex) => { - // @ContentChildren('foo, bar, baz', {descendants: true}) fooBars: - // QueryList; - registerContentQuery(query(null, ['foo'], false), dirIndex); - }, - contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { - let tmp: any; - const instance = load(dirIndex); - queryRefresh(tmp = loadQueryList(queryStartIdx)) && - (instance.fooBars = tmp); - }, + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: true}) + // fooBars: QueryList; + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.fooBars = tmp); + } + } }); } @@ -2601,7 +2637,69 @@ describe('query', () => { const fixture = new ComponentFixture(AppComponent); expect(outInstance !.fooBars.length).toBe(1); - expect(inInstance !.fooBars.length).toBe(2); + expect(inInstance !.fooBars.length).toBe(1); + }); + + it('should support nested shallow content queries across multiple component instances', () => { + let outInstance: QueryDirective; + let inInstance: QueryDirective; + + class QueryDirective { + fooBars: any; + static ngDirectiveDef = defineDirective({ + type: QueryDirective, + selectors: [['', 'query', '']], + exportAs: ['query'], + factory: () => new QueryDirective(), + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: true}) + // fooBars: QueryList; + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.fooBars = tmp); + } + } + }); + } + + const AppComponent = createComponent( + 'app-component', + /** + *
    + *
    + * + *
    + *
    + */ + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart(0, 'div', ['query', ''], ['out', 'query']); + { + elementStart(2, 'div', ['query', ''], ['in', 'query', 'foo', '']); + { element(5, 'span', ['id', 'bar'], ['foo', '']); } + elementEnd(); + } + elementEnd(); + } + if (rf & RenderFlags.Update) { + outInstance = load(1); + inInstance = load(3); + } + }, + 7, 0, [QueryDirective]); + + const fixture1 = new ComponentFixture(AppComponent); + expect(outInstance !.fooBars.length).toBe(1); + expect(inInstance !.fooBars.length).toBe(1); + + outInstance = inInstance = null !; + + const fixture2 = new ComponentFixture(AppComponent); + expect(outInstance !.fooBars.length).toBe(1); + expect(inInstance !.fooBars.length).toBe(1); }); it('should respect shallow flag on content queries when mixing deep and shallow queries', @@ -2611,18 +2709,19 @@ describe('query', () => { static ngDirectiveDef = defineDirective({ type: ShallowQueryDirective, selectors: [['', 'shallow-query', '']], - exportAs: 'shallow-query', + exportAs: ['shallow-query'], factory: () => new ShallowQueryDirective(), - contentQueries: (dirIndex) => { - // @ContentChildren('foo', {descendants: false}) foos: QueryList; - registerContentQuery(query(null, ['foo'], false), dirIndex); - }, - contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { - let tmp: any; - const instance = load(dirIndex); - queryRefresh(tmp = loadQueryList(queryStartIdx)) && - (instance.foos = tmp); - }, + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: false}) + // foos: QueryList; + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.foos = tmp); + } + } }); } @@ -2631,18 +2730,19 @@ describe('query', () => { static ngDirectiveDef = defineDirective({ type: DeepQueryDirective, selectors: [['', 'deep-query', '']], - exportAs: 'deep-query', + exportAs: ['deep-query'], factory: () => new DeepQueryDirective(), - contentQueries: (dirIndex) => { - // @ContentChildren('foo', {descendants: false}) foos: QueryList; - registerContentQuery(query(null, ['foo'], true), dirIndex); - }, - contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => { - let tmp: any; - const instance = load(dirIndex); - queryRefresh(tmp = loadQueryList(queryStartIdx)) && - (instance.foos = tmp); - }, + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: true}) + // foos: QueryList; + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, ['foo'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.foos = tmp); + } + } }); } @@ -2684,4 +2784,127 @@ describe('query', () => { expect(deepInstance !.foos.length).toBe(2); }); }); + + describe('order', () => { + class TextDirective { + value !: string; + + static ngDirectiveDef = defineDirective({ + type: TextDirective, + selectors: [['', 'text', '']], + factory: () => new TextDirective(), + inputs: {value: 'text'} + }); + } + + it('should register content matches from top to bottom', () => { + let contentQueryDirective: ContentQueryDirective; + + class ContentQueryDirective { + // @ContentChildren(TextDirective) + texts !: QueryList; + + static ngComponentDef = defineDirective({ + type: ContentQueryDirective, + selectors: [['', 'content-query', '']], + factory: () => contentQueryDirective = new ContentQueryDirective(), + contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren(TextDirective, {descendants: true}) + // texts: QueryList; + if (rf & RenderFlags.Create) { + contentQuery(dirIndex, TextDirective, true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + queryRefresh(tmp = loadContentQuery()) && (ctx.texts = tmp); + } + } + }); + } + + const AppComponent = createComponent( + 'app-component', + /** + *
    + * + *
    + * + * + * + *
    + * + *
    + */ + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart(0, 'div', ['content-query']); + { + element(1, 'span', ['text', 'A']); + elementStart(2, 'div', ['text', 'B']); + elementStart(3, 'span', ['text', 'C']); + { element(4, 'span', ['text', 'D']); } + elementEnd(); + elementEnd(); + element(5, 'span', ['text', 'E']); + } + elementEnd(); + } + }, + 6, 0, [TextDirective, ContentQueryDirective]); + + new ComponentFixture(AppComponent); + expect(contentQueryDirective !.texts.map(item => item.value)).toEqual([ + 'A', 'B', 'C', 'D', 'E' + ]); + }); + + it('should register view matches from top to bottom', () => { + /** + * + *
    + * + * + * + *
    + * + */ + class ViewQueryComponent { + // @ViewChildren(TextDirective) + texts !: QueryList; + + static ngComponentDef = defineComponent({ + type: ViewQueryComponent, + selectors: [['view-query']], + factory: () => new ViewQueryComponent(), + template: function(rf: RenderFlags, ctx: ViewQueryComponent) { + if (rf & RenderFlags.Create) { + element(0, 'span', ['text', 'A']); + elementStart(1, 'div', ['text', 'B']); + elementStart(2, 'span', ['text', 'C']); + { element(3, 'span', ['text', 'D']); } + elementEnd(); + elementEnd(); + element(4, 'span', ['text', 'E']); + } + }, + consts: 5, + vars: 0, + viewQuery: function(rf: RenderFlags, ctx: ViewQueryComponent) { + let tmp: any; + if (rf & RenderFlags.Create) { + viewQuery(TextDirective, true); + } + if (rf & RenderFlags.Update) { + queryRefresh(tmp = loadViewQuery>()) && + (ctx.texts = tmp as QueryList); + } + }, + directives: [TextDirective] + }); + } + + const fixture = new ComponentFixture(ViewQueryComponent); + expect(fixture.component.texts.map(item => item.value)).toEqual(['A', 'B', 'C', 'D', 'E']); + }); + }); }); diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 2ec2ecfb50..ac3b3aea76 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -7,7 +7,7 @@ */ import {ChangeDetectorRef} from '@angular/core/src/change_detection/change_detector_ref'; -import {Provider} from '@angular/core/src/di/provider'; +import {Provider} from '@angular/core/src/di/interface/provider'; import {ElementRef} from '@angular/core/src/linker/element_ref'; import {TemplateRef} from '@angular/core/src/linker/template_ref'; import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref'; @@ -16,7 +16,8 @@ import {getLView} from '@angular/core/src/render3/state'; import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util'; import {SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as R3_CHANGE_DETECTOR_REF_FACTORY} from '../../src/change_detection/change_detector_ref'; -import {Injector, SWITCH_INJECTOR_FACTORY__POST_R3__ as R3_INJECTOR_FACTORY} from '../../src/di/injector'; +import {Injector} from '../../src/di/injector'; +import {Type} from '../../src/interface/type'; import {SWITCH_ELEMENT_REF_FACTORY__POST_R3__ as R3_ELEMENT_REF_FACTORY} from '../../src/linker/element_ref'; import {SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ as R3_TEMPLATE_REF_FACTORY} from '../../src/linker/template_ref'; import {SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ as R3_VIEW_CONTAINER_REF_FACTORY} from '../../src/linker/view_container_ref'; @@ -27,12 +28,13 @@ import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition' import {NG_ELEMENT_ID} from '../../src/render3/fields'; import {ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, ProvidersFeature, RenderFlags, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index'; import {renderTemplate} from '../../src/render3/instructions'; -import {DirectiveDefList, DirectiveTypesOrFactory, PipeDef, PipeDefList, PipeTypesOrFactory} from '../../src/render3/interfaces/definition'; +import {DirectiveDefList, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeDefList, PipeTypesOrFactory} from '../../src/render3/interfaces/definition'; import {PlayerHandler} from '../../src/render3/interfaces/player'; import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; import {HEADER_OFFSET, LView} from '../../src/render3/interfaces/view'; +import {destroyLView} from '../../src/render3/node_manipulation'; +import {getRootView} from '../../src/render3/util'; import {Sanitizer} from '../../src/sanitization/security'; -import {Type} from '../../src/type'; import {getRendererFactory2} from './imported_renderer2'; @@ -130,6 +132,11 @@ export class TemplateFixture extends BaseFixture { this.hostElement, updateBlock || this.updateBlock, 0, this.vars, null !, this._rendererFactory, this.hostView, this._directiveDefs, this._pipeDefs, this._sanitizer); } + + destroy(): void { + this.containerElement.removeChild(this.hostElement); + destroyLView(this.hostView); + } } @@ -171,6 +178,16 @@ export class ComponentFixture extends BaseFixture { tick(this.component); this.requestAnimationFrame.flush(); } + + destroy(): void { + // Skip removing the DOM element if it has already been removed (the view has already + // been destroyed). + if (this.hostElement.parentNode === this.containerElement) { + this.containerElement.removeChild(this.hostElement); + } + + destroyLView(getRootView(this.component)); + } } /////////////////////////////////////////////////////////////////////////////////// @@ -297,7 +314,7 @@ export function createComponent( name: string, template: ComponentTemplate, consts: number = 0, vars: number = 0, directives: DirectiveTypesOrFactory = [], pipes: PipeTypesOrFactory = [], viewQuery: ComponentTemplate| null = null, providers: Provider[] = [], - viewProviders: Provider[] = []): ComponentType { + viewProviders: Provider[] = [], hostBindings?: HostBindingsFunction): ComponentType { return class Component { value: any; static ngComponentDef = defineComponent({ @@ -308,7 +325,7 @@ export function createComponent( factory: () => new Component, template: template, viewQuery: viewQuery, - directives: directives, + directives: directives, hostBindings, pipes: pipes, features: (providers.length > 0 || viewProviders.length > 0)? [ProvidersFeature(providers || [], viewProviders || [])]: [] @@ -317,7 +334,7 @@ export function createComponent( } export function createDirective( - name: string, {exportAs}: {exportAs?: string} = {}): DirectiveType { + name: string, {exportAs}: {exportAs?: string[]} = {}): DirectiveType { return class Directive { static ngDirectiveDef = defineDirective({ type: Directive, @@ -356,7 +373,6 @@ export function enableIvyInjectableFactories() { R3_VIEW_CONTAINER_REF_FACTORY(ViewContainerRef, ElementRef); (ChangeDetectorRef as any)[NG_ELEMENT_ID] = () => R3_CHANGE_DETECTOR_REF_FACTORY(); (Renderer2 as any)[NG_ELEMENT_ID] = () => R3_RENDERER2_FACTORY(); - (Injector as any)[NG_ELEMENT_ID] = () => R3_INJECTOR_FACTORY(); } export class MockRendererFactory implements RendererFactory3 { @@ -383,7 +399,7 @@ class MockRenderer implements ProceduralRenderer3 { destroy(): void {} createComment(value: string): RComment { return document.createComment(value); } createElement(name: string, namespace?: string|null): RElement { - return document.createElement(name); + return namespace ? document.createElementNS(namespace, name) : document.createElement(name); } createText(value: string): RText { return document.createTextNode(value); } appendChild(parent: RElement, newChild: RNode): void { parent.appendChild(newChild); } @@ -418,4 +434,4 @@ class MockRenderer implements ProceduralRenderer3 { listen(target: RNode, eventName: string, callback: (event: any) => boolean | void): () => void { return () => {}; } -} \ No newline at end of file +} diff --git a/packages/core/test/render3/renderer_factory_spec.ts b/packages/core/test/render3/renderer_factory_spec.ts index 3fdd05170e..b32da94ffa 100644 --- a/packages/core/test/render3/renderer_factory_spec.ts +++ b/packages/core/test/render3/renderer_factory_spec.ts @@ -13,7 +13,6 @@ import {RendererType2, ViewEncapsulation} from '../../src/core'; import {defineComponent} from '../../src/render3/index'; import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, listener, text, tick} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; -import {createRendererType2} from '../../src/view/index'; import {getAnimationRendererFactory2, getRendererFactory2} from './imported_renderer2'; import {TemplateFixture, containerEl, document, renderComponent, renderToHtml, toHtml} from './render_util'; @@ -105,7 +104,7 @@ describe('renderer factory lifecycle', () => { it('should work with a template', () => { renderToHtml(Template, {}, 1, 0, null, null, rendererFactory); - expect(logs).toEqual(['create', 'begin', 'function create', 'function update', 'end']); + expect(logs).toEqual(['create', 'function create', 'function update']); logs = []; renderToHtml(Template, {}); @@ -115,8 +114,8 @@ describe('renderer factory lifecycle', () => { it('should work with a template which contains a component', () => { renderToHtml(TemplateWithComponent, {}, 2, 0, directives, null, rendererFactory); expect(logs).toEqual([ - 'create', 'begin', 'function_with_component create', 'create', 'component create', - 'function_with_component update', 'component update', 'end' + 'create', 'function_with_component create', 'create', 'component create', + 'function_with_component update', 'component update' ]); logs = []; diff --git a/packages/core/test/render3/styling/class_and_style_bindings_spec.ts b/packages/core/test/render3/styling/class_and_style_bindings_spec.ts index de3a76ee7c..d109d8ec73 100644 --- a/packages/core/test/render3/styling/class_and_style_bindings_spec.ts +++ b/packages/core/test/render3/styling/class_and_style_bindings_spec.ts @@ -34,8 +34,8 @@ describe('style and class based bindings', () => { const rootContext = createRootContext(requestAnimationFrame.bind(window), playerHandler || null); const lView = createLView( - null, createTView(-1, null, 1, 0, null, null, null), rootContext, LViewFlags.IsRoot, - domRendererFactory3, domRendererFactory3.createRenderer(element, null)); + null, createTView(-1, null, 1, 0, null, null, null, null), rootContext, LViewFlags.IsRoot, + null, null, domRendererFactory3, domRendererFactory3.createRenderer(element, null)); return lView; } @@ -70,7 +70,7 @@ describe('style and class based bindings', () => { attrs.push(AttributeMarker.Styles); attrs.push(...styles); } - patchContextWithStaticAttrs(context, attrs, directiveRef || null); + patchContextWithStaticAttrs(context, attrs, 0, directiveRef || null); } function getRootContextInternal(lView: LView) { return lView[CONTEXT] as RootContext; } @@ -202,12 +202,12 @@ describe('style and class based bindings', () => { assertContext(template, [ masterConfig(9), [null, 2, false, null], - [null], - [null], + [null, null], + [null, null], [0, 0, 0, 0], element, - null, - null, + [0, 0, 9, null, 0], + [0, 0, 9, null, 0], null, ]); }); @@ -217,12 +217,12 @@ describe('style and class based bindings', () => { assertContext(template, [ masterConfig(9), [null, 2, false, null], - [null, 'color', 'red', 'width', '10px'], - [null, 'foo', true, 'bar', true], + [null, null, 'color', 'red', 'width', '10px'], + [null, null, 'foo', true, 'bar', true], [0, 0, 0, 0], element, - null, - null, + [0, 0, 9, null, 0], + [0, 0, 9, null, 0], null, ]); }); @@ -231,11 +231,13 @@ describe('style and class based bindings', () => { () => { const template = initContext(['color', 'red'], null, ['foo']); expect(template[StylingIndex.InitialStyleValuesPosition]).toEqual([ + null, null, 'color', 'red', ]); expect(template[StylingIndex.InitialClassValuesPosition]).toEqual([ + null, null, 'foo', true, @@ -243,21 +245,23 @@ describe('style and class based bindings', () => { patchContext(template, ['color', 'black', 'height', '200px'], ['bar', 'foo'], '1'); expect(template[StylingIndex.InitialStyleValuesPosition]).toEqual([ - null, 'color', 'red', 'height', '200px' + null, null, 'color', 'red', 'height', '200px' ]); expect(template[StylingIndex.InitialClassValuesPosition]).toEqual([ - null, 'foo', true, 'bar', true + null, null, 'foo', true, 'bar', true ]); }); it('should only populate static styles for a given directive once', () => { const template = initContext(['color', 'red'], null, ['foo']); expect(template[StylingIndex.InitialStyleValuesPosition]).toEqual([ + null, null, 'color', 'red', ]); expect(template[StylingIndex.InitialClassValuesPosition]).toEqual([ + null, null, 'foo', true, @@ -265,11 +269,13 @@ describe('style and class based bindings', () => { patchContext(template, ['color', 'black', 'height', '200px'], ['bar', 'foo']); expect(template[StylingIndex.InitialStyleValuesPosition]).toEqual([ + null, null, 'color', 'red', ]); expect(template[StylingIndex.InitialClassValuesPosition]).toEqual([ + null, null, 'foo', true, @@ -278,17 +284,6 @@ describe('style and class based bindings', () => { patchContext(template, ['color', 'black', 'height', '200px'], ['bar', 'foo'], '1'); expect(template[StylingIndex.InitialStyleValuesPosition]).toEqual([ null, - 'color', - 'red', - 'height', - '200px', - ]); - expect(template[StylingIndex.InitialClassValuesPosition]).toEqual([ - null, 'foo', true, 'bar', true - ]); - - patchContext(template, ['color', 'black', 'height', '200px'], ['bar', 'foo'], '1'); - expect(template[StylingIndex.InitialStyleValuesPosition]).toEqual([ null, 'color', 'red', @@ -296,6 +291,20 @@ describe('style and class based bindings', () => { '200px', ]); expect(template[StylingIndex.InitialClassValuesPosition]).toEqual([ + null, null, 'foo', true, 'bar', true + ]); + + patchContext(template, ['color', 'black', 'height', '200px'], ['bar', 'foo'], '1'); + expect(template[StylingIndex.InitialStyleValuesPosition]).toEqual([ + null, + null, + 'color', + 'red', + 'height', + '200px', + ]); + expect(template[StylingIndex.InitialClassValuesPosition]).toEqual([ + null, null, 'foo', true, @@ -380,6 +389,45 @@ describe('style and class based bindings', () => { .toEqual( ''); }); + + it('should support binding to camelCased and hyphenated style properties', () => { + //
    + class Comp { + borderWidth: string = '3px'; + borderColor: string = 'red'; + + static ngComponentDef = defineComponent({ + type: Comp, + selectors: [['comp']], + factory: () => new Comp(), + consts: 1, + vars: 0, + template: (rf: RenderFlags, ctx: Comp) => { + if (rf & RenderFlags.Create) { + elementStart(0, 'div'); + elementStyling(null, ['borderWidth', 'border-color']); + elementEnd(); + } + if (rf & RenderFlags.Update) { + elementStyleProp(0, 0, ctx.borderWidth); + elementStyleProp(0, 1, ctx.borderColor); + elementStylingApply(0); + } + } + }); + } + + const fixture = new ComponentFixture(Comp); + fixture.update(); + + const target = fixture.hostElement.querySelector('div') !as any; + + expect(target.style.borderWidth).toEqual('3px'); + expect(target.style.borderColor).toEqual('red'); + expect(fixture.html).toContain('border-width: 3px'); + expect(fixture.html).toContain('border-color: red'); + }); + }); describe('dynamic styling properties within a styling context', () => { @@ -391,34 +439,34 @@ describe('style and class based bindings', () => { assertContext(ctx, [ masterConfig(17, false, false), // [null, 2, false, null], - [null, 'width', null], - [null, 'foo', false], + [null, null, 'width', null], + [null, null, 'foo', false], [1, 1, 1, 1, 9, 13], null, - null, - null, + [1, 0, 21, null, 1], + [1, 0, 17, null, 1], null, // #9 - cleanStyle(2, 17), + cleanStyle(3, 17), 'width', null, 0, // #13 - cleanClass(2, 21), + cleanClass(3, 21), 'foo', null, 0, // #17 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', null, 0, // #21 - cleanClass(2, 13), + cleanClass(3, 13), 'foo', null, 0, @@ -429,58 +477,58 @@ describe('style and class based bindings', () => { assertContext(ctx, [ masterConfig(25, false, false), // [null, 2, false, null, 'SOME DIRECTIVE', 6, false, null], - [null, 'width', null, 'height', null], - [null, 'foo', false, 'bar', false], + [null, null, 'width', null, 'height', null], + [null, null, 'foo', false, 'bar', false], [2, 2, 1, 1, 9, 17, 2, 1, 9, 13, 21], null, - null, - null, + [2, 0, 33, null, 1, 0, 37, null, 1], + [2, 0, 25, null, 1, 0, 29, null, 1], null, // #9 - cleanStyle(2, 25), + cleanStyle(3, 25), 'width', null, 0, // #13 - cleanStyle(4, 29), + cleanStyle(5, 29), 'height', null, 1, // #17 - cleanClass(2, 33), + cleanClass(3, 33), 'foo', null, 0, // #21 - cleanClass(4, 37), + cleanClass(5, 37), 'bar', null, 1, // #25 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', null, 0, // #29 - cleanStyle(4, 13), + cleanStyle(5, 13), 'height', null, 1, // #33 - cleanClass(2, 17), + cleanClass(3, 17), 'foo', null, 0, // #37 - cleanClass(4, 21), + cleanClass(5, 21), 'bar', null, 1, @@ -495,82 +543,82 @@ describe('style and class based bindings', () => { null, 2, false, null, 'SOME DIRECTIVE', 6, false, null, 'SOME DIRECTIVE 2', 11, false, null ], - [null, 'width', null, 'height', null, 'opacity', null], - [null, 'foo', false, 'bar', false, 'baz', false], + [null, null, 'width', null, 'height', null, 'opacity', null], + [null, null, 'foo', false, 'bar', false, 'baz', false], [3, 3, 1, 1, 9, 21, 2, 1, 9, 13, 25, 3, 3, 17, 9, 13, 29, 25, 21], null, - null, - null, + [3, 0, 45, null, 1, 0, 49, null, 1, 0, 53, null, 1], + [3, 0, 33, null, 1, 0, 37, null, 1, 0, 41, null, 1], null, // #9 - cleanStyle(2, 33), + cleanStyle(3, 33), 'width', null, 0, // #13 - cleanStyle(4, 37), + cleanStyle(5, 37), 'height', null, 1, // #17 - cleanStyle(6, 41), + cleanStyle(7, 41), 'opacity', null, 2, // #21 - cleanClass(2, 45), + cleanClass(3, 45), 'foo', null, 0, // #25 - cleanClass(4, 49), + cleanClass(5, 49), 'bar', null, 1, // #29 - cleanClass(6, 53), + cleanClass(7, 53), 'baz', null, 2, // #33 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', null, 0, // #37 - cleanStyle(4, 13), + cleanStyle(5, 13), 'height', null, 1, // #41 - cleanStyle(6, 17), + cleanStyle(7, 17), 'opacity', null, 2, // #45 - cleanClass(2, 21), + cleanClass(3, 21), 'foo', null, 0, // #49 - cleanClass(4, 25), + cleanClass(5, 25), 'bar', null, 1, // #53 - cleanClass(6, 29), + cleanClass(7, 29), 'baz', null, 2, @@ -722,25 +770,25 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - cleanStyle(2, 17), + cleanStyle(3, 17), 'width', null, 0, // #13 - cleanStyle(4, 21), + cleanStyle(5, 21), 'height', null, 0, // #17 - dirtyStyle(2, 9), + dirtyStyle(3, 9), 'width', '100px', 0, // #21 - dirtyStyle(4, 13), + dirtyStyle(5, 13), 'height', '100px', 0, @@ -751,19 +799,19 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - cleanStyle(2, 17), + cleanStyle(3, 17), 'width', null, 0, // #13 - cleanStyle(4, 25), + cleanStyle(5, 25), 'height', null, 0, // #17 - dirtyStyle(2, 9), + dirtyStyle(3, 9), 'width', '200px', 0, @@ -775,7 +823,7 @@ describe('style and class based bindings', () => { 0, // #25 - dirtyStyle(4, 13), + dirtyStyle(5, 13), 'height', null, 0, @@ -784,19 +832,19 @@ describe('style and class based bindings', () => { getStyles(stylingContext); assertContextOnlyValues(stylingContext, [ // #9 - cleanStyle(2, 17), + cleanStyle(3, 17), 'width', null, 0, // #13 - cleanStyle(4, 25), + cleanStyle(5, 25), 'height', null, 0, // #17 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', '200px', 0, @@ -808,7 +856,7 @@ describe('style and class based bindings', () => { 0, // #23 - cleanStyle(4, 13), + cleanStyle(5, 13), 'height', null, 0, @@ -819,19 +867,19 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - dirtyStyle(2, 17), + dirtyStyle(3, 17), 'width', '300px', 0, // #13 - cleanStyle(4, 25), + cleanStyle(5, 25), 'height', null, 0, // #17 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', null, 0, @@ -843,7 +891,7 @@ describe('style and class based bindings', () => { 0, // #23 - cleanStyle(4, 13), + cleanStyle(5, 13), 'height', null, 0, @@ -854,19 +902,19 @@ describe('style and class based bindings', () => { updateStyleProp(stylingContext, 0, null); assertContextOnlyValues(stylingContext, [ // #9 - dirtyStyle(2, 17), + dirtyStyle(3, 17), 'width', null, 0, // #13 - cleanStyle(4, 25), + cleanStyle(5, 25), 'height', null, 0, // #17 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', null, 0, @@ -878,7 +926,7 @@ describe('style and class based bindings', () => { 0, // #23 - cleanStyle(4, 13), + cleanStyle(5, 13), 'height', null, 0, @@ -887,15 +935,15 @@ describe('style and class based bindings', () => { it('should find the next available space in the context when data is added after being removed before', () => { - const stylingContext = initContext(null, ['lineHeight']); + const stylingContext = initContext(null, ['line-height']); const getStyles = trackStylesFactory(); updateStyles(stylingContext, {width: '100px', height: '100px', opacity: '0.5'}); assertContextOnlyValues(stylingContext, [ // #9 - cleanStyle(2, 25), - 'lineHeight', + cleanStyle(3, 25), + 'line-height', null, 0, @@ -918,8 +966,8 @@ describe('style and class based bindings', () => { 0, // #23 - cleanStyle(2, 9), - 'lineHeight', + cleanStyle(3, 9), + 'line-height', null, 0, ]); @@ -929,8 +977,8 @@ describe('style and class based bindings', () => { updateStyles(stylingContext, {}); assertContextOnlyValues(stylingContext, [ // #9 - cleanStyle(2, 25), - 'lineHeight', + cleanStyle(3, 25), + 'line-height', null, 0, @@ -953,27 +1001,25 @@ describe('style and class based bindings', () => { 0, // #23 - cleanStyle(2, 9), - 'lineHeight', + cleanStyle(3, 9), + 'line-height', null, 0, ]); getStyles(stylingContext); - updateStyles(stylingContext, { - borderWidth: '5px', - }); + updateStyles(stylingContext, {borderWidth: '5px'}); assertContextOnlyValues(stylingContext, [ // #9 - cleanStyle(2, 29), - 'lineHeight', + cleanStyle(3, 29), + 'line-height', null, 0, // #13 dirtyStyle(), - 'borderWidth', + 'border-width', '5px', 0, @@ -996,8 +1042,8 @@ describe('style and class based bindings', () => { 0, // #29 - cleanStyle(2, 9), - 'lineHeight', + cleanStyle(3, 9), + 'line-height', null, 0, ]); @@ -1006,14 +1052,14 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - dirtyStyle(2, 29), - 'lineHeight', + dirtyStyle(3, 29), + 'line-height', '200px', 0, // #13 dirtyStyle(), - 'borderWidth', + 'border-width', '5px', 0, @@ -1036,8 +1082,8 @@ describe('style and class based bindings', () => { 0, // #29 - cleanStyle(2, 9), - 'lineHeight', + cleanStyle(3, 9), + 'line-height', null, 0, ]); @@ -1046,20 +1092,20 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - dirtyStyle(2, 33), - 'lineHeight', + dirtyStyle(3, 33), + 'line-height', '200px', 0, // #13 dirtyStyle(), - 'borderWidth', + 'border-width', '15px', 0, // #17 dirtyStyle(), - 'borderColor', + 'border-color', 'red', 0, @@ -1082,8 +1128,8 @@ describe('style and class based bindings', () => { 0, // #33 - cleanStyle(2, 9), - 'lineHeight', + cleanStyle(3, 9), + 'line-height', null, 0, ]); @@ -1093,22 +1139,24 @@ describe('style and class based bindings', () => { const getStyles = trackStylesFactory(); const stylingContext = initContext(null, ['height']); - updateStyles(stylingContext, {width: '100px'}); + const cachedStyleValue = {width: '100px'}; + + updateStyles(stylingContext, cachedStyleValue); updateStyleProp(stylingContext, 0, '200px'); assertContext(stylingContext, [ masterConfig(13, true), // [null, 2, true, null], - [null, 'height', null], - [null], + [null, null, 'height', null], + [null, null], [1, 0, 1, 0, 9], element, - null, - {width: '100px'}, + [0, 0, 21, null, 0], + [1, 0, 13, cachedStyleValue, 1], null, // #9 - dirtyStyle(2, 17), + dirtyStyle(3, 17), 'height', '200px', 0, @@ -1120,7 +1168,7 @@ describe('style and class based bindings', () => { 0, // #17 - cleanStyle(2, 9), + cleanStyle(3, 9), 'height', null, 0, @@ -1131,16 +1179,16 @@ describe('style and class based bindings', () => { assertContext(stylingContext, [ masterConfig(13, false), // [null, 2, false, null], - [null, 'height', null], - [null], + [null, null, 'height', null], + [null, null], [1, 0, 1, 0, 9], element, - null, - {width: '100px'}, + [0, 0, 21, null, 0], + [1, 0, 13, cachedStyleValue, 1], null, // #9 - cleanStyle(2, 17), + cleanStyle(3, 17), 'height', '200px', 0, @@ -1152,7 +1200,7 @@ describe('style and class based bindings', () => { 0, // #17 - cleanStyle(2, 9), + cleanStyle(3, 9), 'height', null, 0, @@ -1171,25 +1219,25 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - dirtyStyleWithSanitization(2, 17), + dirtyStyleWithSanitization(3, 17), 'border-image', 'url(foo.jpg)', 0, // #13 - dirtyStyle(4, 21), + dirtyStyle(5, 21), 'border-width', '100px', 0, // #17 - cleanStyleWithSanitization(2, 9), + cleanStyleWithSanitization(3, 9), 'border-image', null, 0, // #21 - cleanStyle(4, 13), + cleanStyle(5, 13), 'border-width', null, 0, @@ -1199,13 +1247,13 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - dirtyStyleWithSanitization(2, 21), + dirtyStyleWithSanitization(3, 21), 'border-image', 'url(foo.jpg)', 0, // #13 - dirtyStyle(4, 25), + dirtyStyle(5, 25), 'border-width', '100px', 0, @@ -1217,13 +1265,13 @@ describe('style and class based bindings', () => { 0, // #21 - cleanStyleWithSanitization(2, 9), + cleanStyleWithSanitization(3, 9), 'border-image', null, 0, // #23 - cleanStyle(4, 13), + cleanStyle(5, 13), 'border-width', null, 0, @@ -1233,13 +1281,13 @@ describe('style and class based bindings', () => { assertContextOnlyValues(stylingContext, [ // #9 - cleanStyleWithSanitization(2, 21), + cleanStyleWithSanitization(3, 21), 'border-image', 'url(foo.jpg)', 0, // #13 - cleanStyle(4, 25), + cleanStyle(5, 25), 'border-width', '100px', 0, @@ -1251,20 +1299,20 @@ describe('style and class based bindings', () => { 0, // #21 - cleanStyleWithSanitization(2, 9), + cleanStyleWithSanitization(3, 9), 'border-image', null, 0, // #23 - cleanStyle(4, 13), + cleanStyle(5, 13), 'border-width', null, 0, ]); }); - it('should only update styling values for successive directives if null in a former directive', + it('should only update single styling values for successive directives if null in a former directive', () => { const template = createEmptyStylingContext(); @@ -1304,6 +1352,347 @@ describe('style and class based bindings', () => { expect(getDirectiveIndexFromEntry(ctx, colorIndex)).toEqual(3); }); + it('should allow single style values to override a previous entry if a flag is passed in', + () => { + const template = createEmptyStylingContext(); + + const dir1 = {}; + const dir2 = {}; + const dir3 = {}; + + updateContextWithBindings(template, dir1, null, ['width', 'height']); + updateContextWithBindings(template, dir2, null, ['width', 'color']); + updateContextWithBindings(template, dir3, null, ['height', 'opacity']); + + const ctx = allocStylingContext(element, template); + + // styles 0 = width, 1 = height, 2 = color within the context + const widthIndex = StylingIndex.SingleStylesStartPosition + StylingIndex.Size * 0; + const heightIndex = StylingIndex.SingleStylesStartPosition + StylingIndex.Size * 1; + + updateStyleProp(ctx, 0, '100px', dir1); + updateStyleProp(ctx, 1, '100px', dir1); + expect(ctx[widthIndex + StylingIndex.ValueOffset]).toEqual('100px'); + expect(ctx[heightIndex + StylingIndex.ValueOffset]).toEqual('100px'); + expect(getDirectiveIndexFromEntry(ctx, widthIndex)).toEqual(1); + expect(getDirectiveIndexFromEntry(ctx, heightIndex)).toEqual(1); + + updateStyleProp(ctx, 0, '300px', dir1); + updateStyleProp(ctx, 1, '300px', dir1); + + updateStyleProp(ctx, 0, '900px', dir2); + updateStyleProp(ctx, 0, '900px', dir3, true); + + expect(ctx[widthIndex + StylingIndex.ValueOffset]).toEqual('300px'); + expect(ctx[heightIndex + StylingIndex.ValueOffset]).toEqual('900px'); + expect(getDirectiveIndexFromEntry(ctx, widthIndex)).toEqual(1); + expect(getDirectiveIndexFromEntry(ctx, heightIndex)).toEqual(3); + + updateStyleProp(ctx, 0, '400px', dir1); + updateStyleProp(ctx, 1, '400px', dir1); + + expect(ctx[widthIndex + StylingIndex.ValueOffset]).toEqual('400px'); + expect(ctx[heightIndex + StylingIndex.ValueOffset]).toEqual('400px'); + expect(getDirectiveIndexFromEntry(ctx, widthIndex)).toEqual(1); + expect(getDirectiveIndexFromEntry(ctx, heightIndex)).toEqual(1); + }); + + it('should only update missing multi styling values for successive directives if null in a former directive', + () => { + const template = createEmptyStylingContext(); + updateContextWithBindings(template, null); + + const dir1 = {}; + const dir2 = {}; + const dir3 = {}; + updateContextWithBindings(template, dir1, null, ['width', 'height']); + updateContextWithBindings(template, dir2); + updateContextWithBindings(template, dir3); + + const ctx = allocStylingContext(element, template); + let s1, s2, s3; + updateStylingMap(ctx, null, s1 = {width: '100px', height: '99px'}, dir1); + updateStylingMap(ctx, null, s2 = {width: '200px', opacity: '0.5'}, dir2); + updateStylingMap(ctx, null, s3 = {width: '300px', height: '999px'}, dir3); + + expect(ctx[StylingIndex.CachedMultiStyles]).toEqual([ + 3, 0, 17, null, 0, 0, 17, s1, 2, 0, 25, s2, 1, 0, 29, s3, 0 + ]); + + assertContextOnlyValues(ctx, [ + // #9 + cleanStyle(3, 17), + 'width', + null, + 1, + + // #13 + cleanStyle(5, 21), + 'height', + null, + 1, + + // #17 + dirtyStyle(3, 9), + 'width', + '100px', + 1, + + // #21 + dirtyStyle(5, 13), + 'height', + '99px', + 1, + + // #25 + dirtyStyle(0, 0), + 'opacity', + '0.5', + 2, + ]); + + updateStylingMap(ctx, null, {opacity: '0', width: null}, dir1); + updateStylingMap(ctx, null, {width: '200px', opacity: '0.5'}, dir2); + updateStylingMap(ctx, null, {width: '300px', height: '999px'}, dir3); + + assertContextOnlyValues(ctx, [ + // #9 + cleanStyle(3, 21), + 'width', + null, + 1, + + // #13 + cleanStyle(5, 25), + 'height', + null, + 1, + + // #17 + dirtyStyle(0, 0), + 'opacity', + '0', + 1, + + // #21 + dirtyStyle(3, 9), + 'width', + '200px', + 2, + + // #25 + dirtyStyle(5, 13), + 'height', + '999px', + 3, + ]); + + updateStylingMap(ctx, null, null, dir1); + updateStylingMap(ctx, null, {width: '500px', opacity: '0.2'}, dir2); + updateStylingMap(ctx, null, {width: '300px', height: '999px', color: 'red'}, dir3); + + assertContextOnlyValues(ctx, [ + // #9 + cleanStyle(3, 17), + 'width', + null, + 1, + + // #13 + cleanStyle(5, 25), + 'height', + null, + 1, + + // #17 + dirtyStyle(3, 9), + 'width', + '500px', + 2, + + // #21 + dirtyStyle(0, 0), + 'opacity', + '0.2', + 2, + + // #25 + dirtyStyle(5, 13), + 'height', + '999px', + 3, + + // #29 + dirtyStyle(0, 0), + 'color', + 'red', + 3, + ]); + }); + + it('should only update missing multi class values for successive directives if null in a former directive', + () => { + const template = createEmptyStylingContext(); + updateContextWithBindings(template, null); + + const dir1 = {}; + const dir2 = {}; + const dir3 = {}; + updateContextWithBindings(template, dir1, ['red', 'green']); + updateContextWithBindings(template, dir2); + updateContextWithBindings(template, dir3); + + const ctx = allocStylingContext(element, template); + let c1, c2, c3; + updateStylingMap(ctx, c1 = {red: true, orange: true}, null, dir1); + updateStylingMap(ctx, c2 = 'black red', null, dir2); + updateStylingMap(ctx, c3 = 'silver green', null, dir3); + + expect(ctx[StylingIndex.CachedMultiClasses]).toEqual([ + 5, 0, 17, null, 0, 0, 17, c1, 2, 0, 25, c2, 1, 0, 29, c3, 2 + ]); + + assertContextOnlyValues(ctx, [ + // #9 + cleanClass(3, 17), + 'red', + null, + 1, + + // #13 + cleanClass(5, 33), + 'green', + null, + 1, + + // #17 + dirtyClass(3, 9), + 'red', + true, + 1, + + // #21 + dirtyClass(0, 0), + 'orange', + true, + 1, + + // #25 + dirtyClass(0, 0), + 'black', + true, + 2, + + // #29 + dirtyClass(0, 0), + 'silver', + true, + 3, + + // #33 + dirtyClass(5, 13), + 'green', + true, + 3, + ]); + + updateStylingMap(ctx, c1 = {orange: true}, null, dir1); + updateStylingMap(ctx, c2 = 'black red', null, dir2); + updateStylingMap(ctx, c3 = 'green', null, dir3); + + assertContextOnlyValues(ctx, [ + // #9 + cleanClass(3, 25), + 'red', + null, + 1, + + // #13 + cleanClass(5, 29), + 'green', + null, + 1, + + // #17 + dirtyClass(0, 0), + 'orange', + true, + 1, + + // #21 + dirtyClass(0, 0), + 'black', + true, + 2, + + // #25 + dirtyClass(3, 9), + 'red', + true, + 2, + + // #29 + dirtyClass(5, 13), + 'green', + true, + 3, + + // #33 + dirtyClass(0, 0), + 'silver', + null, + 1, + ]); + + updateStylingMap(ctx, c1 = 'green', null, dir1); + updateStylingMap(ctx, c2 = null, null, dir2); + updateStylingMap(ctx, c3 = 'red', null, dir3); + + assertContextOnlyValues(ctx, [ + // #9 + cleanClass(3, 21), + 'red', + null, + 1, + + // #13 + cleanClass(5, 17), + 'green', + null, + 1, + + // #17 + dirtyClass(5, 13), + 'green', + true, + 1, + + // #21 + dirtyClass(3, 9), + 'red', + true, + 3, + + // #25 + dirtyClass(0, 0), + 'black', + null, + 1, + + // #29 + dirtyClass(0, 0), + 'orange', + null, + 1, + + // #33 + dirtyClass(0, 0), + 'silver', + null, + 1, + ]); + }); + it('should throw an error if a directive is provided that isn\'t registered', () => { const template = createEmptyStylingContext(); const knownDir = {}; @@ -1385,27 +1774,27 @@ describe('style and class based bindings', () => { const getStyles = trackStylesFactory(store); const otherDirective = {}; - let styles: any = {fontSize: ''}; + let styles: any = {'font-size': ''}; updateStyleProp(stylingContext, 0, ''); updateStylingMap(stylingContext, null, styles); - patchContextWithStaticAttrs(stylingContext, [], otherDirective); + patchContextWithStaticAttrs(stylingContext, [], 0, otherDirective); getStyles(stylingContext, otherDirective); expect(store.getValues()).toEqual({}); - styles = {fontSize: '20px'}; + styles = {'font-size': '20px'}; updateStyleProp(stylingContext, 0, 'red'); updateStylingMap(stylingContext, null, styles); getStyles(stylingContext); - expect(store.getValues()).toEqual({fontSize: '20px', color: 'red'}); + expect(store.getValues()).toEqual({'font-size': '20px', color: 'red'}); styles = {}; updateStyleProp(stylingContext, 0, ''); updateStylingMap(stylingContext, null, styles); getStyles(stylingContext); - expect(store.getValues()).toEqual({fontSize: null, color: ''}); + expect(store.getValues()).toEqual({'font-size': null, color: ''}); }); }); @@ -1415,34 +1804,34 @@ describe('style and class based bindings', () => { assertContext(template, [ masterConfig(17, false), // [null, 2, false, null], - [null], - [null, 'one', false, 'two', false], + [null, null], + [null, null, 'one', false, 'two', false], [0, 2, 0, 2, 9, 13], element, - null, - null, + [2, 0, 17, null, 2], + [0, 0, 17, null, 0], null, // #9 - cleanClass(2, 17), + cleanClass(3, 17), 'one', null, 0, // #13 - cleanClass(4, 21), + cleanClass(5, 21), 'two', null, 0, // #17 - cleanClass(2, 9), + cleanClass(3, 9), 'one', null, 0, // #21 - cleanClass(4, 13), + cleanClass(5, 13), 'two', null, 0, @@ -1496,58 +1885,58 @@ describe('style and class based bindings', () => { assertContext(stylingContext, [ masterConfig(25, false), // [null, 2, false, null], - [null, 'width', '100px', 'height', null], - [null, 'wide', true, 'tall', false], + [null, null, 'width', '100px', 'height', null], + [null, null, 'wide', true, 'tall', false], [2, 2, 2, 2, 9, 13, 17, 21], element, - null, - null, + [2, 0, 33, null, 2], + [2, 0, 25, null, 2], null, // #9 - cleanStyle(2, 25), + cleanStyle(3, 25), 'width', null, 0, // #13 - cleanStyle(4, 29), + cleanStyle(5, 29), 'height', null, 0, // #17 - cleanClass(2, 33), + cleanClass(3, 33), 'wide', null, 0, // #21 - cleanClass(4, 37), + cleanClass(5, 37), 'tall', null, 0, // #25 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', null, 0, // #29 - cleanStyle(4, 13), + cleanStyle(5, 13), 'height', null, 0, // #33 - cleanClass(2, 17), + cleanClass(3, 17), 'wide', null, 0, // #37 - cleanClass(4, 21), + cleanClass(5, 21), 'tall', null, 0, @@ -1555,44 +1944,45 @@ describe('style and class based bindings', () => { expect(getStylesAndClasses(stylingContext)).toEqual([{}, {}]); - updateStylingMap(stylingContext, 'tall round', {width: '200px', opacity: '0.5'}); + let cachedStyleMap: any = {width: '200px', opacity: '0.5'}; + updateStylingMap(stylingContext, 'tall round', cachedStyleMap); assertContext(stylingContext, [ masterConfig(25, true), // [null, 2, true, null], - [null, 'width', '100px', 'height', null], - [null, 'wide', true, 'tall', false], + [null, null, 'width', '100px', 'height', null], + [null, null, 'wide', true, 'tall', false], [2, 2, 2, 2, 9, 13, 17, 21], element, - 'tall round', - {width: '200px', opacity: '0.5'}, + [2, 0, 37, 'tall round', 2], + [2, 0, 25, cachedStyleMap, 2], null, // #9 - cleanStyle(2, 25), + cleanStyle(3, 25), 'width', null, 0, // #13 - cleanStyle(4, 45), + cleanStyle(5, 33), 'height', null, 0, // #17 - cleanClass(2, 41), + cleanClass(3, 45), 'wide', null, 0, // #21 - cleanClass(4, 33), + cleanClass(5, 37), 'tall', null, 0, - // #23 - dirtyStyle(2, 9), + // #25 + dirtyStyle(3, 9), 'width', '200px', 0, @@ -1604,26 +1994,26 @@ describe('style and class based bindings', () => { 0, // #33 - dirtyClass(4, 21), + cleanStyle(5, 13), + 'height', + null, + 0, + + // #37 + dirtyClass(5, 21), 'tall', true, 0, - // #37 + // #41 dirtyClass(0, 0), 'round', true, 0, - // #41 - cleanClass(2, 17), - 'wide', - null, - 0, - // #45 - cleanStyle(4, 13), - 'height', + cleanClass(3, 17), + 'wide', null, 0, ]); @@ -1633,79 +2023,81 @@ describe('style and class based bindings', () => { {width: '200px', opacity: '0.5'}, ]); - updateStylingMap(stylingContext, {tall: true, wide: true}, {width: '500px'}); + let cachedClassMap = {tall: true, wide: true}; + cachedStyleMap = {width: '500px'}; + updateStylingMap(stylingContext, cachedClassMap, cachedStyleMap); updateStyleProp(stylingContext, 0, '300px'); assertContext(stylingContext, [ masterConfig(25, true), // [null, 2, true, null], - [null, 'width', '100px', 'height', null], - [null, 'wide', true, 'tall', false], + [null, null, 'width', '100px', 'height', null], + [null, null, 'wide', true, 'tall', false], [2, 2, 2, 2, 9, 13, 17, 21], element, - {tall: true, wide: true}, - {width: '500px'}, + [2, 0, 37, cachedClassMap, 2], + [1, 0, 25, cachedStyleMap, 1], null, // #9 - dirtyStyle(2, 25), + dirtyStyle(3, 25), 'width', '300px', 0, // #13 - cleanStyle(4, 45), + cleanStyle(5, 33), 'height', null, 0, // #17 - cleanClass(2, 33), + cleanClass(3, 41), 'wide', null, 0, // #21 - cleanClass(4, 29), + cleanClass(5, 37), 'tall', null, 0, // #25 - cleanStyle(2, 9), + cleanStyle(3, 9), 'width', '500px', 0, // #29 - cleanClass(4, 21), - 'tall', - true, - 0, - - // #33 - cleanClass(2, 17), - 'wide', - true, - 0, - - // #37 - dirtyClass(0, 0), - 'round', - null, - 0, - - // #41 dirtyStyle(0, 0), 'opacity', null, 0, - // #45 - cleanStyle(4, 13), + // #33 + cleanStyle(5, 13), 'height', null, 0, + + // #37 + cleanClass(5, 21), + 'tall', + true, + 0, + + // #41 + cleanClass(3, 17), + 'wide', + true, + 0, + + // #45 + dirtyClass(0, 0), + 'round', + null, + 0, ]); expect(getStylesAndClasses(stylingContext)).toEqual([ @@ -1733,15 +2125,15 @@ describe('style and class based bindings', () => { getStylesAndClasses(stylingContext); assertContext(stylingContext, [ - masterConfig(9, false), // - [null, 2, false, null], // - [null], // - [null], // - [0, 0, 0, 0], // - element, // - {foo: true}, // - {width: '200px'}, // - null, // + masterConfig(9, false), // + [null, 2, false, null], // + [null, null], // + [null, null], // + [0, 0, 0, 0], // + element, // + [1, 0, 13, classesMap, 1], // + [1, 0, 9, stylesMap, 1], // + null, // // #9 cleanStyle(0, 0), 'width', '200px', 0, @@ -1759,15 +2151,15 @@ describe('style and class based bindings', () => { getStylesAndClasses(stylingContext); assertContext(stylingContext, [ - masterConfig(9, false), // - [null, 2, false, null], // - [null], // - [null], // - [0, 0, 0, 0], // - element, // - {foo: false}, // - {width: '300px'}, // - null, // + masterConfig(9, false), // + [null, 2, false, null], // + [null, null], // + [null, null], // + [0, 0, 0, 0], // + element, // + [1, 0, 13, classesMap, 1], // + [1, 0, 9, stylesMap, 1], // + null, // // #9 cleanStyle(0, 0), 'width', '200px', 0, @@ -1790,12 +2182,12 @@ describe('style and class based bindings', () => { assertContext(stylingContext, [ masterConfig(9, false), // [null, 2, false, null], - [null], - [null], + [null, null], + [null, null], [0, 0, 0, 0], element, - 'apple orange banana', - null, + [3, 0, 9, 'apple orange banana', 3], + [0, 0, 9, null, 0], null, // #9 @@ -1817,12 +2209,8 @@ describe('style and class based bindings', () => { 0, ]); - stylingContext - [StylingIndex.SingleStylesStartPosition + 1 * StylingIndex.Size + - StylingIndex.ValueOffset] = false; // no orange - stylingContext - [StylingIndex.SingleStylesStartPosition + 2 * StylingIndex.Size + - StylingIndex.ValueOffset] = false; // no banana + stylingContext[13 + StylingIndex.ValueOffset] = false; + stylingContext[17 + StylingIndex.ValueOffset] = false; updateStylingMap(stylingContext, classes); // apply the styles @@ -2158,43 +2546,45 @@ describe('style and class based bindings', () => { }; assertContext(context, [ - masterConfig(17, false), // - [null, 2, false, null], // - [null, 'color', null], // - [null, 'foo', false], // - [1, 1, 1, 1, 9, 13], // - element, // - null, // - null, // - null, // + masterConfig(17, false), // + [null, 2, false, null], // + [null, null, 'color', null], // + [null, null, 'foo', false], // + [1, 1, 1, 1, 9, 13], // + element, // + [1, 0, 21, null, 1], // + [1, 0, 17, null, 1], // + null, // // #9 - cleanStyle(2, 17), + cleanStyle(3, 17), 'color', null, 0, // #13 - cleanClass(2, 21), + cleanClass(3, 21), 'foo', null, 0, // #17 - cleanStyle(2, 9), + cleanStyle(3, 9), 'color', null, 0, // #21 - cleanClass(2, 13), + cleanClass(3, 13), 'foo', null, 0, ]); - const styleMapWithPlayerFactory = bindPlayerFactory(buildStyleFn, {opacity: '1'}); - const classMapWithPlayerFactory = bindPlayerFactory(buildClassFn, {map: true}); + const cachedClassMap = {map: true}; + const cachedStyleMap = {opacity: '1'}; + const styleMapWithPlayerFactory = bindPlayerFactory(buildStyleFn, cachedStyleMap); + const classMapWithPlayerFactory = bindPlayerFactory(buildClassFn, cachedClassMap); const styleMapPlayerBuilder = makePlayerBuilder(styleMapWithPlayerFactory, false); const classMapPlayerBuilder = makePlayerBuilder(classMapWithPlayerFactory, true); updateStylingMap(context, classMapWithPlayerFactory, styleMapWithPlayerFactory); @@ -2219,24 +2609,24 @@ describe('style and class based bindings', () => { ] as PlayerContext); assertContext(context, [ - masterConfig(17, false), // - [null, 2, false, null], // - [null, 'color', null], // - [null, 'foo', false], // - [1, 1, 1, 1, 9, 13], // - element, // - {map: true}, // - {opacity: '1'}, // + masterConfig(17, false), // + [null, 2, false, null], // + [null, null, 'color', null], // + [null, null, 'foo', false], // + [1, 1, 1, 1, 9, 13], // + element, // + [1, 0, 25, classMapWithPlayerFactory, 1], // + [1, 0, 17, styleMapWithPlayerFactory, 1], // playerContext, // #9 - cleanStyle(2, 25), + cleanStyle(3, 21), 'color', 'red', directiveOwnerPointers(0, 5), // #13 - cleanClass(2, 29), + cleanClass(3, 29), 'foo', true, directiveOwnerPointers(0, 7), @@ -2248,27 +2638,25 @@ describe('style and class based bindings', () => { directiveOwnerPointers(0, 3), // #21 + cleanStyle(3, 9), + 'color', + null, + 0, + + // #25 cleanClass(0, 0), 'map', true, directiveOwnerPointers(0, 1), - // #23 - cleanStyle(2, 9), - 'color', - null, - 0, - // #29 - cleanClass(2, 13), + cleanClass(3, 13), 'foo', null, 0, ]); - const styleMapWithoutPlayerFactory = {opacity: '1'}; - const classMapWithoutPlayerFactory = {map: true}; - updateStylingMap(context, classMapWithoutPlayerFactory, styleMapWithoutPlayerFactory); + updateStylingMap(context, cachedClassMap, cachedStyleMap); const colorWithoutPlayerFactory = 'blue'; const fooWithoutPlayerFactory = false; @@ -2282,24 +2670,24 @@ describe('style and class based bindings', () => { ] as PlayerContext); assertContext(context, [ - masterConfig(17, false), // - [null, 2, false, null], // - [null, 'color', null], // - [null, 'foo', false], // - [1, 1, 1, 1, 9, 13], // - element, // - {map: true}, // - {opacity: '1'}, // + masterConfig(17, false), // + [null, 2, false, null], // + [null, null, 'color', null], // + [null, null, 'foo', false], // + [1, 1, 1, 1, 9, 13], // + element, // + [1, 0, 25, cachedClassMap, 1], // + [1, 0, 17, cachedStyleMap, 1], // playerContext, // #9 - cleanStyle(2, 25), + cleanStyle(3, 21), 'color', 'blue', 0, // #13 - cleanClass(2, 29), + cleanClass(3, 29), 'foo', false, 0, @@ -2311,19 +2699,19 @@ describe('style and class based bindings', () => { 0, // #21 + cleanStyle(3, 9), + 'color', + null, + 0, + + // #25 cleanClass(0, 0), 'map', true, 0, - // #23 - cleanStyle(2, 9), - 'color', - null, - 0, - // #29 - cleanClass(2, 13), + cleanClass(3, 13), 'foo', null, 0, @@ -2347,9 +2735,8 @@ describe('style and class based bindings', () => { return new MockPlayer(); }; - const styleFactory = - bindPlayerFactory(buildStyleFn, {opacity: '1'}) as BoundPlayerFactory; - const classFactory = bindPlayerFactory(buildClassFn, 'bar') as BoundPlayerFactory; + let styleFactory = bindPlayerFactory(buildStyleFn, {opacity: '1'}) as BoundPlayerFactory; + let classFactory = bindPlayerFactory(buildClassFn, 'bar') as BoundPlayerFactory; updateStylingMap(context, classFactory, styleFactory); expect(styleCalls).toEqual(0); expect(classCalls).toEqual(0); @@ -2362,13 +2749,13 @@ describe('style and class based bindings', () => { expect(styleCalls).toEqual(1); expect(classCalls).toEqual(1); - styleFactory.value = {opacity: '0.5'}; + styleFactory = bindPlayerFactory(buildStyleFn, {opacity: '0.5'}) as BoundPlayerFactory; updateStylingMap(context, classFactory, styleFactory); renderStyles(context, false, undefined, lView); expect(styleCalls).toEqual(2); expect(classCalls).toEqual(1); - classFactory.value = 'foo'; + classFactory = bindPlayerFactory(buildClassFn, 'foo') as BoundPlayerFactory; updateStylingMap(context, classFactory, styleFactory); renderStyles(context, false, undefined, lView); expect(styleCalls).toEqual(2); @@ -2666,11 +3053,11 @@ describe('style and class based bindings', () => { return new MockPlayer(); }; - const styleMapFactory = + let styleMapFactory = bindPlayerFactory(buildFn, {height: '200px'}) as BoundPlayerFactory; - const classMapFactory = bindPlayerFactory(buildFn, {bar: true}) as BoundPlayerFactory; - const widthFactory = bindPlayerFactory(buildFn, '100px') as BoundPlayerFactory; - const fooFactory = bindPlayerFactory(buildFn, true) as BoundPlayerFactory; + let classMapFactory = bindPlayerFactory(buildFn, {bar: true}) as BoundPlayerFactory; + let widthFactory = bindPlayerFactory(buildFn, '100px') as BoundPlayerFactory; + let fooFactory = bindPlayerFactory(buildFn, true) as BoundPlayerFactory; class Comp { static ngComponentDef = defineComponent({ @@ -2711,6 +3098,11 @@ describe('style and class based bindings', () => { widthFactory.value = '50px'; fooFactory.value = false; + styleMapFactory = bindPlayerFactory(buildFn, {height: '100px'}) as BoundPlayerFactory; + classMapFactory = bindPlayerFactory(buildFn, {bar: false}) as BoundPlayerFactory; + widthFactory = bindPlayerFactory(buildFn, '50px') as BoundPlayerFactory; + fooFactory = bindPlayerFactory(buildFn, false) as BoundPlayerFactory; + fixture.update(); expect(firstRenderCaptures.length).toEqual(0); @@ -2868,11 +3260,19 @@ function assertContext(actual: StylingContext, target: StylingContext, startInde null; fieldName = 'Element Position'; break; - case StylingIndex.CachedClassValueOrInitialClassString: - case StylingIndex.CachedStyleValue: - valueIsTheSame = stringMapEqualsStringMap(actualValue, targetValue); - stringError = - !valueIsTheSame ? generateValueCompareError(actualValue, targetValue) : null; + case StylingIndex.CachedMultiClasses: + case StylingIndex.CachedMultiStyles: + valueIsTheSame = Array.isArray(actualValue) ? + valueEqualsValue(actualValue, targetValue) : + stringMapEqualsStringMap(actualValue, targetValue); + if (!valueIsTheSame) { + stringError = '\n\n ' + generateValueCompareError(actualValue, targetValue); + if (Array.isArray(actualValue)) { + stringError += '\n ....'; + stringError += + generateArrayCompareError(actualValue as any[], targetValue as any[], ' '); + } + } fieldName = 'Cached Style/Class Value'; break; default: @@ -2897,11 +3297,12 @@ function assertContext(actual: StylingContext, target: StylingContext, startInde function generateArrayCompareError(a: any[], b: any[], tab: string) { const values: string[] = []; - for (let i = 0; i < a.length; i++) { - if (a[i] !== b[i]) { - values.push(`${tab}a[${i}] !== b[${i}]`); + const length = Math.max(a.length, b.length); + for (let i = 0; i < length; i++) { + if (a[i] === b[i]) { + values.push(`${tab}a[${i}] === b[${i}] (${a[i]} === ${b[i]})`); } else { - values.push(`${tab}a[${i}] === b[${i}]`); + values.push(`${tab}a[${i}] !== b[${i}] (${a[i]} !== ${b[i]})`); } } return values.length ? '\n' + values.join('\n') : null; diff --git a/packages/core/test/render3/styling/players_spec.ts b/packages/core/test/render3/styling/players_spec.ts index 13029c149d..2f77e83943 100644 --- a/packages/core/test/render3/styling/players_spec.ts +++ b/packages/core/test/render3/styling/players_spec.ts @@ -5,14 +5,15 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {QueryList} from '@angular/core'; import {RenderFlags} from '@angular/core/src/render3'; -import {defineComponent, getHostElement} from '../../../src/render3/index'; -import {element, elementEnd, elementStart, elementStyling, elementStylingApply, load, markDirty} from '../../../src/render3/instructions'; +import {defineComponent, getHostElement, loadViewQuery, viewQuery} from '../../../src/render3/index'; +import {element, elementEnd, elementStart, elementStyling, elementStylingApply, markDirty} from '../../../src/render3/instructions'; import {PlayState, Player, PlayerHandler} from '../../../src/render3/interfaces/player'; import {RElement} from '../../../src/render3/interfaces/renderer'; import {addPlayer, getPlayers} from '../../../src/render3/players'; -import {QueryList, query, queryRefresh} from '../../../src/render3/query'; +import {queryRefresh} from '../../../src/render3/query'; import {getOrCreatePlayerContext} from '../../../src/render3/styling/util'; import {ComponentFixture} from '../render_util'; @@ -229,7 +230,7 @@ function buildElementWithStyling() { class Comp { static ngComponentDef = defineComponent({ type: Comp, - exportAs: 'child', + exportAs: ['child'], selectors: [['child-comp']], factory: () => new Comp(), consts: 1, @@ -249,7 +250,7 @@ class Comp { class CompWithStyling { static ngComponentDef = defineComponent({ type: CompWithStyling, - exportAs: 'child-styled', + exportAs: ['child-styled'], selectors: [['child-styled-comp']], factory: () => new CompWithStyling(), consts: 1, @@ -278,18 +279,18 @@ class SuperComp { vars: 0, template: (rf: RenderFlags, ctx: SuperComp) => { if (rf & RenderFlags.Create) { - elementStart(1, 'div'); - element(2, 'child-comp', ['child', ''], ['child', 'child']); + elementStart(0, 'div'); + element(1, 'child-comp', ['child', ''], ['child', 'child']); elementEnd(); } }, viewQuery: function(rf: RenderFlags, ctx: SuperComp) { if (rf & RenderFlags.Create) { - query(0, ['child'], true); + viewQuery(['child'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.query = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && (ctx.query = tmp as QueryList); } }, directives: [Comp] diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index 6efbdcd38c..c3ad8f260c 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -6,22 +6,23 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectorRef, Component as _Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, QueryList, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core'; +import {ChangeDetectorRef, Component as _Component, ComponentFactoryResolver, ComponentRef, defineInjector, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, QueryList, RendererFactory2, TemplateRef, ViewContainerRef, ViewRef, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef,} from '../../src/core'; +import {createInjector} from '../../src/di/r3_injector'; import {ViewEncapsulation} from '../../src/metadata'; -import {AttributeMarker, NO_CHANGE, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, load, query, queryRefresh} from '../../src/render3/index'; +import {AttributeMarker, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, listener, loadViewQuery, NgOnChangesFeature, queryRefresh, viewQuery,} from '../../src/render3/index'; -import {allocHostVars, bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, nextContext, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions'; +import {allocHostVars, bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementEnd, elementHostAttrs, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, nextContext, projection, projectionDef, reference, template, text, textBinding,} from '../../src/render3/instructions'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {RElement} from '../../src/render3/interfaces/renderer'; -import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound'; import {NgModuleFactory} from '../../src/render3/ng_module_ref'; import {pipe, pipeBind1} from '../../src/render3/pipe'; import {getLView} from '../../src/render3/state'; import {getNativeByIndex} from '../../src/render3/util'; +import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound'; import {NgForOf} from '../../test/render3/common_with_def'; import {getRendererFactory2} from './imported_renderer2'; -import {ComponentFixture, TemplateFixture, createComponent, getDirectiveOnNode} from './render_util'; +import {ComponentFixture, createComponent, getDirectiveOnNode, TemplateFixture,} from './render_util'; const Component: typeof _Component = function(...args: any[]): any { // In test we use @Component for documentation only so it's safe to mock out the implementation. @@ -41,12 +42,14 @@ describe('ViewContainerRef', () => { factory: () => directiveInstance = new DirectiveWithVCRef( directiveInject(ViewContainerRef as any), injectComponentFactoryResolver()), - inputs: {tplRef: 'tplRef'} + inputs: {tplRef: 'tplRef', name: 'name'} }); // TODO(issue/24571): remove '!'. tplRef !: TemplateRef<{}>; + name: string = ''; + // injecting a ViewContainerRef to create a dynamic container in which embedded views will be // created constructor(public vcref: ViewContainerRef, public cfr: ComponentFactoryResolver) {} @@ -1631,7 +1634,7 @@ describe('ViewContainerRef', () => { textBinding(0, interpolation1('', cmp.name, '')); } }, - features: [NgOnChangesFeature], + features: [NgOnChangesFeature()], inputs: {name: 'name'} }); } @@ -1677,7 +1680,8 @@ describe('ViewContainerRef', () => { elementProperty(3, 'name', bind('B')); } }, - directives: [ComponentWithHooks, DirectiveWithVCRef] + directives: [ComponentWithHooks, DirectiveWithVCRef], + features: [NgOnChangesFeature()], }); } @@ -1769,7 +1773,8 @@ describe('ViewContainerRef', () => { elementProperty(1, 'name', bind('B')); } }, - directives: [ComponentWithHooks, DirectiveWithVCRef] + directives: [ComponentWithHooks, DirectiveWithVCRef], + features: [NgOnChangesFeature()], }); } @@ -1801,7 +1806,7 @@ describe('ViewContainerRef', () => { fixture.update(); expect(fixture.html).toEqual('ADB'); expect(log).toEqual([ - 'doCheck-A', 'doCheck-B', 'onChanges-D', 'onInit-D', 'doCheck-D', 'afterContentInit-D', + 'doCheck-A', 'doCheck-B', 'onInit-D', 'doCheck-D', 'afterContentInit-D', 'afterContentChecked-D', 'afterViewInit-D', 'afterViewChecked-D', 'afterContentChecked-A', 'afterContentChecked-B', 'afterViewChecked-A', 'afterViewChecked-B' ]); @@ -1855,9 +1860,9 @@ describe('ViewContainerRef', () => { consts: 0, vars: 0, template: (rf: RenderFlags, cmp: HostBindingCmpt) => {}, - attributes: ['id', 'attribute'], hostBindings: function(rf: RenderFlags, ctx: HostBindingCmpt, elIndex: number) { if (rf & RenderFlags.Create) { + elementHostAttrs(ctx, ['id', 'attribute']); allocHostVars(1); } if (rf & RenderFlags.Update) { @@ -1926,6 +1931,8 @@ describe('ViewContainerRef', () => { } clear() { this._vcRef.clear(); } + + getVCRefParentInjector() { return this._vcRef.parentInjector; } } // https://stackblitz.com/edit/angular-xxpffd?file=src%2Findex.html @@ -1952,6 +1959,21 @@ describe('ViewContainerRef', () => { expect(fixture.outerHtml).toBe('
    '); }); + it('should allow getting the parentInjector of the VCRef which was injected into the root (bootstrapped) component', + () => { + const fixture = new ComponentFixture(AppCmpt, { + injector: { + get: (token: any) => { + if (token === 'foo') return 'bar'; + } + } + }); + expect(fixture.outerHtml).toBe('
    '); + + const parentInjector = fixture.component.getVCRefParentInjector(); + expect(parentInjector.get('foo')).toEqual('bar'); + }); + it('should check bindings for components dynamically created by root component', () => { class DynamicCompWithBindings { checkCount = 0; @@ -2041,18 +2063,19 @@ describe('ViewContainerRef', () => { vars: 0, template: (rf: RenderFlags, ctx: DynamicCompWithViewQueries) => { if (rf & RenderFlags.Create) { - element(1, 'div', ['bar', ''], ['foo', '']); + element(0, 'div', ['bar', ''], ['foo', '']); } // testing only - fooEl = getNativeByIndex(1, getLView()); + fooEl = getNativeByIndex(0, getLView()); }, viewQuery: function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { - query(0, ['foo'], true); + viewQuery(['foo'], true); } if (rf & RenderFlags.Update) { let tmp: any; - queryRefresh(tmp = load>(0)) && (ctx.foo = tmp as QueryList); + queryRefresh(tmp = loadViewQuery>()) && + (ctx.foo = tmp as QueryList); } } }); @@ -2067,4 +2090,56 @@ describe('ViewContainerRef', () => { }); }); + + describe('view destruction', () => { + class CompWithListenerThatDestroysItself { + constructor(private viewRef: ViewRef) {} + + onClick() {} + + ngOnDestroy() { this.viewRef.destroy(); } + + static ngComponentDef = defineComponent({ + type: CompWithListenerThatDestroysItself, + selectors: [['comp-with-listener-and-on-destroy']], + consts: 2, + vars: 0, + /** */ + template: function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + elementStart(0, 'button'); + { + listener('click', function() { return ctx.onClick(); }); + text(1, 'Click me'); + } + elementEnd(); + } + }, + // We want the ViewRef, so we rely on the knowledge that `ViewRef` is actually given + // when injecting `ChangeDetectorRef`. + factory: + () => new CompWithListenerThatDestroysItself(directiveInject(ChangeDetectorRef as any)), + }); + } + + + it('should not error when destroying a view with listeners twice', () => { + const CompWithChildListener = createComponent('test-app', (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Create) { + element(0, 'comp-with-listener-and-on-destroy'); + } + }, 1, 0, [CompWithListenerThatDestroysItself]); + + const fixture = new ComponentFixture(CompWithChildListener); + fixture.update(); + + // Destroying the parent view will also destroy all of its children views and call their + // onDestroy hooks. Here, our child view attempts to destroy itself *again* in its onDestroy. + // This test exists to verify that no errors are thrown when doing this. We want the test + // component to destroy its own view in onDestroy because the destroy hooks happen as a + // *part of* view destruction. We also ensure that the test component has at least one + // listener so that it runs the event listener cleanup code path. + fixture.destroy(); + }); + }); }); diff --git a/packages/core/test/sanitization/sanatization_spec.ts b/packages/core/test/sanitization/sanatization_spec.ts index db61da433d..5d538b6305 100644 --- a/packages/core/test/sanitization/sanatization_spec.ts +++ b/packages/core/test/sanitization/sanatization_spec.ts @@ -7,10 +7,12 @@ * found in the LICENSE file at https://angular.io/license */ +import {SECURITY_SCHEMA} from '@angular/compiler/src/schema/dom_security_schema'; import {setTNodeAndViewData} from '@angular/core/src/render3/state'; import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl} from '../../src/sanitization/bypass'; -import {sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization'; +import {getUrlSanitizer, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl, sanitizeUrlOrResourceUrl} from '../../src/sanitization/sanitization'; +import {SecurityContext} from '../../src/sanitization/security'; describe('sanitization', () => { beforeEach(() => setTNodeAndViewData(null !, [] as any)); @@ -69,4 +71,54 @@ describe('sanitization', () => { expect(() => sanitizeScript(bypassSanitizationTrustHtml('true'))).toThrowError(ERROR); expect(sanitizeScript(bypassSanitizationTrustScript('true'))).toEqual('true'); }); + + it('should select correct sanitizer for URL props', () => { + // making sure security schema we have on compiler side is in sync with the `getUrlSanitizer` + // runtime function definition + const schema = SECURITY_SCHEMA(); + const contextsByProp: Map> = new Map(); + const sanitizerNameByContext: Map = new Map([ + [SecurityContext.URL, 'sanitizeUrl'], [SecurityContext.RESOURCE_URL, 'sanitizeResourceUrl'] + ]); + Object.keys(schema).forEach(key => { + const context = schema[key]; + if (context === SecurityContext.URL || SecurityContext.RESOURCE_URL) { + const [tag, prop] = key.split('|'); + const contexts = contextsByProp.get(prop) || new Set(); + contexts.add(context); + contextsByProp.set(prop, contexts); + // check only in case a prop can be a part of both URL contexts + if (contexts.size === 2) { + expect(getUrlSanitizer(tag, prop).name).toEqual(sanitizerNameByContext.get(context) !); + } + } + }); + }); + + it('should sanitize resourceUrls via sanitizeUrlOrResourceUrl', () => { + const ERROR = 'unsafe value used in a resource URL context (see http://g.co/ng/security#xss)'; + expect(() => sanitizeUrlOrResourceUrl('http://server', 'iframe', 'src')).toThrowError(ERROR); + expect(() => sanitizeUrlOrResourceUrl('javascript:true', 'iframe', 'src')).toThrowError(ERROR); + expect( + () => sanitizeUrlOrResourceUrl( + bypassSanitizationTrustHtml('javascript:true'), 'iframe', 'src')) + .toThrowError(ERROR); + expect(sanitizeUrlOrResourceUrl( + bypassSanitizationTrustResourceUrl('javascript:true'), 'iframe', 'src')) + .toEqual('javascript:true'); + }); + + it('should sanitize urls via sanitizeUrlOrResourceUrl', () => { + expect(sanitizeUrlOrResourceUrl('http://server', 'a', 'href')).toEqual('http://server'); + expect(sanitizeUrlOrResourceUrl(new Wrap('http://server'), 'a', 'href')) + .toEqual('http://server'); + expect(sanitizeUrlOrResourceUrl('javascript:true', 'a', 'href')) + .toEqual('unsafe:javascript:true'); + expect(sanitizeUrlOrResourceUrl(new Wrap('javascript:true'), 'a', 'href')) + .toEqual('unsafe:javascript:true'); + expect(sanitizeUrlOrResourceUrl(bypassSanitizationTrustHtml('javascript:true'), 'a', 'href')) + .toEqual('unsafe:javascript:true'); + expect(sanitizeUrlOrResourceUrl(bypassSanitizationTrustUrl('javascript:true'), 'a', 'href')) + .toEqual('javascript:true'); + }); }); diff --git a/packages/core/test/strict_types/BUILD.bazel b/packages/core/test/strict_types/BUILD.bazel new file mode 100644 index 0000000000..d33360a60e --- /dev/null +++ b/packages/core/test/strict_types/BUILD.bazel @@ -0,0 +1,23 @@ +package(default_visibility = ["//visibility:private"]) + +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "strict_types_lib", + testonly = True, + srcs = glob( + ["**/*.ts"], + ), + tsconfig = ":tsconfig.json", + deps = [ + "//packages/core", + ], +) + +jasmine_node_test( + name = "strict_types", + deps = [ + ":strict_types_lib", + "//tools/testing:node", + ], +) diff --git a/packages/core/test/strict_types/inheritance_spec.ts b/packages/core/test/strict_types/inheritance_spec.ts new file mode 100644 index 0000000000..4600737d38 --- /dev/null +++ b/packages/core/test/strict_types/inheritance_spec.ts @@ -0,0 +1,37 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ɵComponentDefWithMeta as ComponentDefWithMeta, ɵPipeDefWithMeta as PipeDefWithMeta} from '@angular/core'; + +declare class SuperComponent { + static ngComponentDef: ComponentDefWithMeta; +} + +declare class SubComponent extends SuperComponent { + // Declaring a field in the subtype makes its structure incompatible with that of the + // supertype. Special care needs to be taken in Ivy's definition types, or TypeScript + // would produce type errors when the "strictFunctionTypes" option is enabled. + onlyInSubtype: string; + + static ngComponentDef: ComponentDefWithMeta; +} + +declare class SuperPipe { static ngPipeDef: PipeDefWithMeta; } + +declare class SubPipe extends SuperPipe { + onlyInSubtype: string; + + static ngPipeDef: PipeDefWithMeta; +} + +describe('inheritance strict type checking', () => { + // Verify that Ivy definition fields in declaration files conform to TypeScript's strict + // type checking constraints in the case of inheritance across directives/components/pipes. + // https://github.com/angular/angular/issues/28079 + it('should compile without errors', () => {}); +}); diff --git a/packages/core/test/strict_types/tsconfig.json b/packages/core/test/strict_types/tsconfig.json new file mode 100644 index 0000000000..67ecb66037 --- /dev/null +++ b/packages/core/test/strict_types/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../../tsconfig-test.json", + "compilerOptions": { + "strict": true + } +} diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 666617c6f6..07e2445fe4 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Inject, InjectionToken, NgModule, Optional} from '@angular/core'; +import {Component, Directive, Inject, InjectionToken, NgModule, Optional, Pipe} from '@angular/core'; import {TestBed, getTestBed} from '@angular/core/testing/src/test_bed'; import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {onlyInIvy} from '@angular/private/testing'; const NAME = new InjectionToken('name'); @@ -47,8 +48,46 @@ export class SimpleCmp { export class WithRefsCmp { } +@Component({selector: 'inherited-cmp', template: 'inherited'}) +export class InheritedCmp extends SimpleCmp { +} + +@Directive({selector: '[hostBindingDir]', host: {'[id]': 'id'}}) +export class HostBindingDir { + id = 'one'; +} + +@Component({ + selector: 'component-with-prop-bindings', + template: ` +
    +

    +

    + ` +}) +export class ComponentWithPropBindings { + title = 'some title'; + label = 'some label'; +} + +@Component({ + selector: 'simple-app', + template: ` + - + ` +}) +export class SimpleApp { +} + +@Component({selector: 'inline-template', template: '

    Hello

    '}) +export class ComponentWithInlineTemplate { +} + @NgModule({ - declarations: [HelloWorld, SimpleCmp, WithRefsCmp], + declarations: [ + HelloWorld, SimpleCmp, WithRefsCmp, InheritedCmp, SimpleApp, ComponentWithPropBindings, + HostBindingDir + ], imports: [GreetingModule], providers: [ {provide: NAME, useValue: 'World!'}, @@ -98,6 +137,23 @@ describe('TestBed', () => { expect(greetingByCss.nativeElement).toHaveText('Hello TestBed!'); }); + it('should give the ability to access property bindings on a node', () => { + const fixture = TestBed.createComponent(ComponentWithPropBindings); + fixture.detectChanges(); + + const divElement = fixture.debugElement.query(By.css('div')); + expect(divElement.properties).toEqual({id: 'one', title: 'some title'}); + }); + + it('should give the ability to access interpolated properties on a node', () => { + const fixture = TestBed.createComponent(ComponentWithPropBindings); + fixture.detectChanges(); + + const paragraphEl = fixture.debugElement.query(By.css('p')); + expect(paragraphEl.properties) + .toEqual({title: '( some label - some title )', id: '[ some label ] [ some title ]'}); + }); + it('should give access to the node injector', () => { const fixture = TestBed.createComponent(HelloWorld); fixture.detectChanges(); @@ -172,4 +228,96 @@ describe('TestBed', () => { hello.detectChanges(); expect(hello.nativeElement).toHaveText('Hello injected World !'); }); + + it('should resolve components that are extended by other components', () => { + // SimpleApp uses SimpleCmp in its template, which is extended by InheritedCmp + const simpleApp = TestBed.createComponent(SimpleApp); + simpleApp.detectChanges(); + expect(simpleApp.nativeElement).toHaveText('simple - inherited'); + }); + + it('should resolve components without async resources synchronously', (done) => { + TestBed + .configureTestingModule({ + declarations: [ComponentWithInlineTemplate], + }) + .compileComponents() + .then(done) + .catch(error => { + // This should not throw any errors. If an error is thrown, the test will fail. + // Specifically use `catch` here to mark the test as done and *then* throw the error + // so that the test isn't treated as a timeout. + done(); + throw error; + }); + + // Intentionally call `createComponent` before `compileComponents` is resolved. We want this to + // work for components that don't have any async resources (templateUrl, styleUrls). + TestBed.createComponent(ComponentWithInlineTemplate); + }); + + onlyInIvy('patched ng defs should be removed after resetting TestingModule') + .describe('resetting ng defs', () => { + it('should restore ng defs to their initial states', () => { + @Pipe({name: 'somePipe', pure: true}) + class SomePipe { + transform(value: string): string { return `transformed ${value}`; } + } + + @Directive({selector: 'someDirective'}) + class SomeDirective { + someProp = 'hello'; + } + + @Component({selector: 'comp', template: 'someText'}) + class SomeComponent { + } + + @NgModule({declarations: [SomeComponent]}) + class SomeModule { + } + + TestBed.configureTestingModule({imports: [SomeModule]}); + + // adding Pipe and Directive via metadata override + TestBed.overrideModule( + SomeModule, {set: {declarations: [SomeComponent, SomePipe, SomeDirective]}}); + TestBed.overrideComponent( + SomeComponent, + {set: {template: `{{'hello' | somePipe}}`}}); + TestBed.createComponent(SomeComponent); + + const defBeforeReset = (SomeComponent as any).ngComponentDef; + expect(defBeforeReset.pipeDefs().length).toEqual(1); + expect(defBeforeReset.directiveDefs().length).toEqual(2); // directive + component + + TestBed.resetTestingModule(); + + const defAfterReset = (SomeComponent as any).ngComponentDef; + expect(defAfterReset.pipeDefs().length).toEqual(0); + expect(defAfterReset.directiveDefs().length).toEqual(1); // component + }); + + it('should cleanup ng defs for classes with no ng annotations (in case of inheritance)', + () => { + @Component({selector: 'someDirective', template: '...'}) + class SomeComponent { + } + + class ComponentWithNoAnnotations extends SomeComponent {} + + TestBed.configureTestingModule({declarations: [ComponentWithNoAnnotations]}); + TestBed.createComponent(ComponentWithNoAnnotations); + + expect(ComponentWithNoAnnotations.hasOwnProperty('ngComponentDef')).toBeTruthy(); + expect(SomeComponent.hasOwnProperty('ngComponentDef')).toBeTruthy(); + + TestBed.resetTestingModule(); + + expect(ComponentWithNoAnnotations.hasOwnProperty('ngComponentDef')).toBeFalsy(); + + // ngComponentDef should be preserved on super component + expect(SomeComponent.hasOwnProperty('ngComponentDef')).toBeTruthy(); + }); + }); }); diff --git a/packages/core/test/testability/testability_spec.ts b/packages/core/test/testability/testability_spec.ts index 6acd7884f3..7eb7a09303 100644 --- a/packages/core/test/testability/testability_spec.ts +++ b/packages/core/test/testability/testability_spec.ts @@ -13,7 +13,7 @@ import {NgZone} from '@angular/core/src/zone/ng_zone'; import {async, fakeAsync, flush, tick} from '@angular/core/testing'; import {SpyObject, beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal'; -import {scheduleMicroTask} from '../../src/util'; +import {scheduleMicroTask} from '../../src/util/microtask'; // Schedules a microtasks (using a resolved promise .then()) function microTask(fn: Function): void { diff --git a/packages/core/test/util/global_spec.ts b/packages/core/test/util/global_spec.ts new file mode 100644 index 0000000000..c74e33ea69 --- /dev/null +++ b/packages/core/test/util/global_spec.ts @@ -0,0 +1,25 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {global} from '../../src/util/global'; + +// Not yet available in TypeScript: https://github.com/Microsoft/TypeScript/pull/29332 +declare var globalThis: any /** TODO #9100 */; + +{ + describe('global', () => { + it('should be global this value', () => { + const _global = new Function('return this')(); + expect(global).toBe(_global); + }); + + if (typeof globalThis !== 'undefined') { + it('should use globalThis as global reference', () => { expect(global).toBe(globalThis); }); + } + }); +} diff --git a/packages/core/test/util_spec.ts b/packages/core/test/util_spec.ts index cd11cbd9ed..2c31deb7f1 100644 --- a/packages/core/test/util_spec.ts +++ b/packages/core/test/util_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {stringify} from '../src/util'; +import {stringify} from '../src/util/stringify'; { describe('stringify', () => { diff --git a/packages/core/test/view/BUILD.bazel b/packages/core/test/view/BUILD.bazel index 31f50eb1cf..e4b7fb7200 100644 --- a/packages/core/test/view/BUILD.bazel +++ b/packages/core/test/view/BUILD.bazel @@ -10,6 +10,9 @@ ts_library( ), deps = [ "//packages/core", + "//packages/core/src/di/interface", + "//packages/core/src/interface", + "//packages/core/src/util", "//packages/core/testing", "//packages/platform-browser", "//packages/private/testing", diff --git a/packages/core/test/view/ng_module_spec.ts b/packages/core/test/view/ng_module_spec.ts index 53f8a464f7..67bb917b0c 100644 --- a/packages/core/test/view/ng_module_spec.ts +++ b/packages/core/test/view/ng_module_spec.ts @@ -7,14 +7,14 @@ */ import {NgModuleRef} from '@angular/core'; -import {InjectableDef, defineInjectable} from '@angular/core/src/di/defs'; +import {InjectFlags, inject} from '@angular/core/src/di'; import {INJECTOR, Injector} from '@angular/core/src/di/injector'; -import {InjectFlags, inject} from '@angular/core/src/di/injector_compatibility'; -import {makePropDecorator} from '@angular/core/src/util/decorators'; +import {InjectableDef, defineInjectable} from '@angular/core/src/di/interface/defs'; import {NgModuleDefinition, NgModuleProviderDef, NodeFlags} from '@angular/core/src/view'; -import {moduleDef, moduleProvideDef, resolveNgModuleDep} from '@angular/core/src/view/ng_module'; +import {moduleDef} from '@angular/core/src/view/ng_module'; import {createNgModuleRef} from '@angular/core/src/view/refs'; import {tokenKey} from '@angular/core/src/view/util'; + import {APP_ROOT} from '../../src/di/scope'; class Foo {} diff --git a/packages/core/test/view/provider_spec.ts b/packages/core/test/view/provider_spec.ts index 3d3bcd88c7..098d87907b 100644 --- a/packages/core/test/view/provider_spec.ts +++ b/packages/core/test/view/provider_spec.ts @@ -11,6 +11,7 @@ import {getDebugContext} from '@angular/core/src/errors'; import {ArgumentType, DepFlags, NodeFlags, Services, anchorDef, asElementData, directiveDef, elementDef, providerDef, textDef} from '@angular/core/src/view/index'; import {TestBed, withModule} from '@angular/core/testing'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; +import {ivyEnabled} from '@angular/private/testing'; import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetRootNodes, compViewDef, compViewDefFactory} from './helper'; @@ -147,7 +148,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR expect(() => createAndGetRootNodes(compViewDef(rootElNodes))) .toThrowError( - 'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' + + `${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` + ' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' + ' NullInjectorError: No provider for Dep!'); @@ -161,7 +162,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes))) .toThrowError( - 'StaticInjectorError(DynamicTestModule)[SomeService -> Dep]: \n' + + `${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` + ' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' + ' NullInjectorError: No provider for Dep!'); }); @@ -186,7 +187,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep']) ]))) .toThrowError( - 'StaticInjectorError(DynamicTestModule)[nonExistingDep]: \n' + + `${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[nonExistingDep]: \n` + ' StaticInjectorError(Platform: core)[nonExistingDep]: \n' + ' NullInjectorError: No provider for nonExistingDep!'); }); diff --git a/packages/core/test/zone/ng_zone_spec.ts b/packages/core/test/zone/ng_zone_spec.ts index 10307a5bbd..5ed7c61ea9 100644 --- a/packages/core/test/zone/ng_zone_spec.ts +++ b/packages/core/test/zone/ng_zone_spec.ts @@ -10,7 +10,7 @@ import {EventEmitter, NgZone} from '@angular/core'; import {async, fakeAsync, flushMicrotasks} from '@angular/core/testing'; import {AsyncTestCompleter, Log, beforeEach, describe, expect, inject, it, xit} from '@angular/core/testing/src/testing_internal'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; -import {scheduleMicroTask} from '../../src/util'; +import {scheduleMicroTask} from '../../src/util/microtask'; import {NoopNgZone} from '../../src/zone/ng_zone'; const needsLongerTimers = browserDetection.isSlow || browserDetection.isEdge; diff --git a/packages/core/testing/BUILD.bazel b/packages/core/testing/BUILD.bazel index 5dcecb5300..8e20a93e78 100644 --- a/packages/core/testing/BUILD.bazel +++ b/packages/core/testing/BUILD.bazel @@ -9,9 +9,9 @@ ng_module( srcs = glob( ["**/*.ts"], ), - module_name = "@angular/core/testing", deps = [ "//packages:types", + "//packages/compiler", "//packages/core", "@ngdeps//@types/jasmine", "@ngdeps//zone.js", diff --git a/packages/core/testing/rollup.config.js b/packages/core/testing/rollup.config.js deleted file mode 100644 index 7166f4aa49..0000000000 --- a/packages/core/testing/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/compiler': 'ng.compiler', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../../dist/packages-dist/core/fesm5/testing.js', - dest: '../../../dist/packages-dist/core/bundles/core-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/core/testing'}, - moduleName: 'ng.core.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/core/testing/src/r3_test_bed.ts b/packages/core/testing/src/r3_test_bed.ts index 115609747e..7b61642387 100644 --- a/packages/core/testing/src/r3_test_bed.ts +++ b/packages/core/testing/src/r3_test_bed.ts @@ -6,8 +6,56 @@ * found in the LICENSE file at https://angular.io/license */ -import {ApplicationInitStatus, Component, Directive, Injector, NgModule, NgZone, Pipe, PlatformRef, Provider, SchemaMetadata, Type, ɵInjectableDef as InjectableDef, ɵNgModuleDef as NgModuleDef, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵNgModuleType as NgModuleType, ɵRender3ComponentFactory as ComponentFactory, ɵRender3NgModuleRef as NgModuleRef, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵgetInjectableDef as getInjectableDef, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵresetCompiledComponents as resetCompiledComponents, ɵstringify as stringify} from '@angular/core'; +// The formatter and CI disagree on how this import statement should be formatted. Both try to keep +// it on one line, too, which has gotten very hard to read & manage. So disable the formatter for +// this statement only. +// clang-format off +import { + ApplicationInitStatus, + Compiler, + Component, + Directive, + ErrorHandler, + Injector, + ModuleWithComponentFactories, + NgModule, + NgModuleFactory, + NgZone, + Pipe, + PlatformRef, + Provider, + SchemaMetadata, + Type, + resolveForwardRef, + ɵInjectableDef as InjectableDef, + ɵNG_COMPONENT_DEF as NG_COMPONENT_DEF, + ɵNG_DIRECTIVE_DEF as NG_DIRECTIVE_DEF, + ɵNG_INJECTOR_DEF as NG_INJECTOR_DEF, + ɵNG_MODULE_DEF as NG_MODULE_DEF, + ɵNG_PIPE_DEF as NG_PIPE_DEF, + ɵNgModuleDef as NgModuleDef, + ɵNgModuleFactory as R3NgModuleFactory, + ɵNgModuleType as NgModuleType, + ɵRender3ComponentFactory as ComponentFactory, + ɵRender3NgModuleRef as NgModuleRef, + ɵcompileComponent as compileComponent, + ɵcompileDirective as compileDirective, + ɵcompileNgModuleDefs as compileNgModuleDefs, + ɵcompilePipe as compilePipe, + ɵgetInjectableDef as getInjectableDef, + ɵflushModuleScopingQueueAsMuchAsPossible as flushModuleScopingQueueAsMuchAsPossible, + ɵpatchComponentDefWithScope as patchComponentDefWithScope, + ɵresetCompiledComponents as resetCompiledComponents, + ɵstringify as stringify, + ɵtransitiveScopesFor as transitiveScopesFor, + CompilerOptions, + StaticProvider, + COMPILER_OPTIONS, +} from '@angular/core'; +// clang-format on +import {ResourceLoader} from '@angular/compiler'; +import {clearResolutionOfComponentResourcesQueue, componentNeedsResolution, resolveComponentResources} from '../../src/metadata/resource_loading'; import {ComponentFixture} from './component_fixture'; import {MetadataOverride} from './metadata_override'; import {ComponentResolver, DirectiveResolver, NgModuleResolver, PipeResolver, Resolver} from './resolvers'; @@ -18,6 +66,8 @@ let _nextRootElementId = 0; const EMPTY_ARRAY: Type[] = []; +const UNDEFINED: Symbol = Symbol('UNDEFINED'); + // Resolvers for Angular decorators type Resolvers = { module: Resolver, @@ -124,7 +174,11 @@ export class TestBedRender3 implements Injector, TestBed { } overrideTemplateUsingTestingModule(component: Type, template: string): void { - throw new Error('Render3TestBed.overrideTemplateUsingTestingModule is not implemented yet'); + if (this._instantiated) { + throw new Error( + 'Cannot override template when the test module has already been instantiated'); + } + this._templateOverrides.set(component, template); } static overrideProvider(token: any, provider: { @@ -183,20 +237,32 @@ export class TestBedRender3 implements Injector, TestBed { private _directiveOverrides: [Type, MetadataOverride][] = []; private _pipeOverrides: [Type, MetadataOverride][] = []; private _providerOverrides: Provider[] = []; + private _compilerProviders: StaticProvider[] = []; private _rootProviderOverrides: Provider[] = []; private _providerOverridesByToken: Map = new Map(); + private _templateOverrides: Map, string> = new Map(); + private _resolvers: Resolvers = null !; // test module configuration private _providers: Provider[] = []; + private _compilerOptions: CompilerOptions[] = []; private _declarations: Array|any[]|any> = []; private _imports: Array|any[]|any> = []; private _schemas: Array = []; private _activeFixtures: ComponentFixture[] = []; + private _compilerInjector: Injector = null !; private _moduleRef: NgModuleRef = null !; + private _testModuleType: NgModuleType = null !; private _instantiated: boolean = false; + private _globalCompilationChecked = false; + + // Map that keeps initial version of component/directive/pipe defs in case + // we compile a Type again, thus overriding respective static fields. This is + // required to make sure we restore defs to their initial states between test runs + private _initiaNgDefs: Map, [string, PropertyDescriptor|undefined]> = new Map(); /** * Initialize the environment for testing with a compiler factory, a PlatformRef, and an @@ -232,6 +298,7 @@ export class TestBedRender3 implements Injector, TestBed { } resetTestingModule(): void { + this._checkGlobalCompilationFinished(); resetCompiledComponents(); // reset metadata overrides this._moduleOverrides = []; @@ -241,14 +308,20 @@ export class TestBedRender3 implements Injector, TestBed { this._providerOverrides = []; this._rootProviderOverrides = []; this._providerOverridesByToken.clear(); + this._templateOverrides.clear(); + this._resolvers = null !; // reset test module config this._providers = []; + this._compilerOptions = []; + this._compilerProviders = []; this._declarations = []; this._imports = []; this._schemas = []; this._moduleRef = null !; + this._testModuleType = null !; + this._compilerInjector = null !; this._instantiated = false; this._activeFixtures.forEach((fixture) => { try { @@ -261,6 +334,24 @@ export class TestBedRender3 implements Injector, TestBed { } }); this._activeFixtures = []; + + // restore initial component/directive/pipe defs + this._initiaNgDefs.forEach((value: [string, PropertyDescriptor], type: Type) => { + const [prop, descriptor] = value; + if (!descriptor) { + // Delete operations are generally undesirable since they have performance implications on + // objects they were applied to. In this particular case, situations where this code is + // invoked should be quite rare to cause any noticable impact, since it's applied only to + // some test cases (for example when class with no annotations extends some @Component) when + // we need to clear 'ngComponentDef' field on a given class to restore its original state + // (before applying overrides and running tests). + delete (type as any)[prop]; + } else { + Object.defineProperty(type, prop, descriptor); + } + }); + this._initiaNgDefs.clear(); + clearResolutionOfComponentResourcesQueue(); } configureCompiler(config: {providers?: any[]; useJit?: boolean;}): void { @@ -270,6 +361,7 @@ export class TestBedRender3 implements Injector, TestBed { if (config.providers) { this._providerOverrides.push(...config.providers); + this._compilerProviders.push(...config.providers); } } @@ -290,9 +382,48 @@ export class TestBedRender3 implements Injector, TestBed { } compileComponents(): Promise { - // assume for now that components don't use templateUrl / stylesUrl to unblock further testing - // TODO(pk): plug into the ivy's resource fetching pipeline - return Promise.resolve(); + const resolvers = this._getResolvers(); + const declarations: Type[] = flatten(this._declarations || EMPTY_ARRAY, resolveForwardRef); + + const componentOverrides: [Type, Component][] = []; + let hasAsyncResources = false; + + // Compile the components declared by this module + declarations.forEach(declaration => { + const component = resolvers.component.resolve(declaration); + if (component) { + // We make a copy of the metadata to ensure that we don't mutate the original metadata + const metadata = {...component}; + compileComponent(declaration, metadata); + componentOverrides.push([declaration, metadata]); + hasAsyncResources = hasAsyncResources || componentNeedsResolution(component); + } + }); + + const overrideComponents = () => { + componentOverrides.forEach((override: [Type, Component]) => { + // Override the existing metadata, ensuring that the resolved resources + // are only available until the next TestBed reset (when `resetTestingModule` is called) + this.overrideComponent(override[0], {set: override[1]}); + }); + }; + + // If the component has no async resources (templateUrl, styleUrls), we can finish + // synchronously. This is important so that users who mistakenly treat `compileComponents` + // as synchronous don't encounter an error, as ViewEngine was tolerant of this. + if (!hasAsyncResources) { + overrideComponents(); + return Promise.resolve(); + } else { + let resourceLoader: ResourceLoader; + return resolveComponentResources(url => { + if (!resourceLoader) { + resourceLoader = this.compilerInjector.get(ResourceLoader); + } + return Promise.resolve(resourceLoader.get(url)); + }) + .then(overrideComponents); + } } get(token: any, notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any { @@ -300,7 +431,8 @@ export class TestBedRender3 implements Injector, TestBed { if (token === TestBedRender3) { return this; } - return this._moduleRef.injector.get(token, notFoundValue); + const result = this._moduleRef.injector.get(token, UNDEFINED); + return result === UNDEFINED ? this.compilerInjector.get(token, notFoundValue) : result; } execute(tokens: any[], fn: Function, context?: any): any { @@ -397,16 +529,17 @@ export class TestBedRender3 implements Injector, TestBed { // internal methods private _initIfNeeded(): void { + this._checkGlobalCompilationFinished(); if (this._instantiated) { return; } - const resolvers = this._getResolvers(); - const testModuleType = this._createTestModule(); - this._compileNgModule(testModuleType, resolvers); + this._resolvers = this._getResolvers(); + this._testModuleType = this._createTestModule(); + this._compileNgModule(this._testModuleType); const parentInjector = this.platform.injector; - this._moduleRef = new NgModuleRef(testModuleType, parentInjector); + this._moduleRef = new NgModuleRef(this._testModuleType, parentInjector); // ApplicationInitStatus.runInitializers() is marked @internal // to core. Cast it to any before accessing it. @@ -414,9 +547,16 @@ export class TestBedRender3 implements Injector, TestBed { this._instantiated = true; } + private _storeNgDef(prop: string, type: Type) { + if (!this._initiaNgDefs.has(type)) { + const currentDef = Object.getOwnPropertyDescriptor(type, prop); + this._initiaNgDefs.set(type, [prop, currentDef]); + } + } + // get overrides for a specific provider (if any) private _getProviderOverrides(provider: any) { - const token = typeof provider === 'object' && provider.hasOwnProperty('provide') ? + const token = provider && typeof provider === 'object' && provider.hasOwnProperty('provide') ? provider.provide : provider; return this._providerOverridesByToken.get(token) || []; @@ -458,8 +598,13 @@ export class TestBedRender3 implements Injector, TestBed { } const ngZone = new NgZone({enableLongStackTrace: true}); - const providers = - [{provide: NgZone, useValue: ngZone}, ...this._providers, ...this._providerOverrides]; + const providers = [ + {provide: NgZone, useValue: ngZone}, + {provide: Compiler, useFactory: () => new R3TestCompiler(this)}, + {provide: ErrorHandler, useClass: R3TestErrorHandler}, + ...this._providers, + ...this._providerOverrides, + ]; const declarations = this._declarations; const imports = [RootScopeModule, this.ngModule, this._imports]; @@ -472,148 +617,147 @@ export class TestBedRender3 implements Injector, TestBed { return DynamicTestModule as NgModuleType; } - private _getMetaWithOverrides(meta: Component|Directive|NgModule) { - if (meta.providers && meta.providers.length) { - const overrides = - flatten(meta.providers, (provider: any) => this._getProviderOverrides(provider)); - if (overrides.length) { - return {...meta, providers: [...meta.providers, ...overrides]}; - } + get compilerInjector(): Injector { + if (this._compilerInjector !== null) { + return this._compilerInjector; } - return meta; + + const providers: StaticProvider[] = []; + const compilerOptions = this.platform.injector.get(COMPILER_OPTIONS); + compilerOptions.forEach(opts => { + if (opts.providers) { + providers.push(opts.providers); + } + }); + providers.push(...this._compilerProviders); + + // TODO(ocombe): make this work with an Injector directly instead of creating a module for it + @NgModule({providers}) + class CompilerModule { + } + + const CompilerModuleFactory = new R3NgModuleFactory(CompilerModule); + this._compilerInjector = CompilerModuleFactory.create(this.platform.injector).injector; + return this._compilerInjector; } - private _compileNgModule(moduleType: NgModuleType, resolvers: Resolvers): void { - const ngModule = resolvers.module.resolve(moduleType); + private _getMetaWithOverrides(meta: Component|Directive|NgModule, type?: Type) { + const overrides: {providers?: any[], template?: string} = {}; + if (meta.providers && meta.providers.length) { + // There are two flattening operations here. The inner flatten() operates on the metadata's + // providers and applies a mapping function which retrieves overrides for each incoming + // provider. The outer flatten() then flattens the produced overrides array. If this is not + // done, the array can contain other empty arrays (e.g. `[[], []]`) which leak into the + // providers array and contaminate any error messages that might be generated. + const providerOverrides = + flatten(flatten(meta.providers, (provider: any) => this._getProviderOverrides(provider))); + if (providerOverrides.length) { + overrides.providers = [...meta.providers, ...providerOverrides]; + } + } + const hasTemplateOverride = !!type && this._templateOverrides.has(type); + if (hasTemplateOverride) { + overrides.template = this._templateOverrides.get(type !); + } + return Object.keys(overrides).length ? {...meta, ...overrides} : meta; + } + + /** + * @internal + */ + _getModuleResolver() { return this._resolvers.module; } + + /** + * @internal + */ + _compileNgModule(moduleType: NgModuleType): void { + const ngModule = this._resolvers.module.resolve(moduleType); if (ngModule === null) { - throw new Error(`${stringify(moduleType)} has not @NgModule annotation`); + throw new Error(`${stringify(moduleType)} has no @NgModule annotation`); } + this._storeNgDef(NG_MODULE_DEF, moduleType); + this._storeNgDef(NG_INJECTOR_DEF, moduleType); const metadata = this._getMetaWithOverrides(ngModule); compileNgModuleDefs(moduleType, metadata); - const declarations: Type[] = flatten(ngModule.declarations || EMPTY_ARRAY); + const declarations: Type[] = + flatten(ngModule.declarations || EMPTY_ARRAY, resolveForwardRef); const compiledComponents: Type[] = []; // Compile the components, directives and pipes declared by this module declarations.forEach(declaration => { - const component = resolvers.component.resolve(declaration); + const component = this._resolvers.component.resolve(declaration); if (component) { - const metadata = this._getMetaWithOverrides(component); + this._storeNgDef(NG_COMPONENT_DEF, declaration); + const metadata = this._getMetaWithOverrides(component, declaration); compileComponent(declaration, metadata); compiledComponents.push(declaration); return; } - const directive = resolvers.directive.resolve(declaration); + const directive = this._resolvers.directive.resolve(declaration); if (directive) { + this._storeNgDef(NG_DIRECTIVE_DEF, declaration); const metadata = this._getMetaWithOverrides(directive); compileDirective(declaration, metadata); return; } - const pipe = resolvers.pipe.resolve(declaration); + const pipe = this._resolvers.pipe.resolve(declaration); if (pipe) { + this._storeNgDef(NG_PIPE_DEF, declaration); compilePipe(declaration, pipe); return; } }); // Compile transitive modules, components, directives and pipes - const transitiveScope = this._transitiveScopesFor(moduleType, resolvers); - compiledComponents.forEach( - cmp => patchComponentDefWithScope((cmp as any).ngComponentDef, transitiveScope)); + const calcTransitiveScopesFor = (moduleType: NgModuleType) => transitiveScopesFor( + moduleType, (ngModule: NgModuleType) => this._compileNgModule(ngModule)); + const transitiveScope = calcTransitiveScopesFor(moduleType); + compiledComponents.forEach(cmp => { + const scope = this._templateOverrides.has(cmp) ? + // if we have template override via `TestBed.overrideTemplateUsingTestingModule` - + // define Component scope as TestingModule scope, instead of the scope of NgModule + // where this Component was declared + calcTransitiveScopesFor(this._testModuleType) : + transitiveScope; + patchComponentDefWithScope((cmp as any).ngComponentDef, scope); + }); } /** - * Compute the pair of transitive scopes (compilation scope and exported scope) for a given - * module. - * - * This operation is memoized and the result is cached on the module's definition. It can be - * called on modules with components that have not fully compiled yet, but the result should not - * be used until they have. + * @internal */ - private _transitiveScopesFor(moduleType: Type, resolvers: Resolvers): - NgModuleTransitiveScopes { - if (!isNgModule(moduleType)) { - throw new Error(`${moduleType.name} does not have an ngModuleDef`); + _getComponentFactories(moduleType: NgModuleType): ComponentFactory[] { + return moduleType.ngModuleDef.declarations.reduce((factories, declaration) => { + const componentDef = (declaration as any).ngComponentDef; + componentDef && factories.push(new ComponentFactory(componentDef, this._moduleRef)); + return factories; + }, [] as ComponentFactory[]); + } + + /** + * Check whether the module scoping queue should be flushed, and flush it if needed. + * + * When the TestBed is reset, it clears the JIT module compilation queue, cancelling any + * in-progress module compilation. This creates a potential hazard - the very first time the + * TestBed is initialized (or if it's reset without being initialized), there may be pending + * compilations of modules declared in global scope. These compilations should be finished. + * + * To ensure that globally declared modules have their components scoped properly, this function + * is called whenever TestBed is initialized or reset. The _first_ time that this happens, prior + * to any other operations, the scoping queue is flushed. + */ + private _checkGlobalCompilationFinished(): void { + // !this._instantiated should not be necessary, but is left in as an additional guard that + // compilations queued in tests (after instantiation) are never flushed accidentally. + if (!this._globalCompilationChecked && !this._instantiated) { + flushModuleScopingQueueAsMuchAsPossible(); } - const def = moduleType.ngModuleDef; - - if (def.transitiveCompileScopes !== null) { - return def.transitiveCompileScopes; - } - - const scopes: NgModuleTransitiveScopes = { - compilation: { - directives: new Set(), - pipes: new Set(), - }, - exported: { - directives: new Set(), - pipes: new Set(), - }, - }; - - def.declarations.forEach(declared => { - const declaredWithDefs = declared as Type& { ngPipeDef?: any; }; - - if (declaredWithDefs.ngPipeDef !== undefined) { - scopes.compilation.pipes.add(declared); - } else { - scopes.compilation.directives.add(declared); - } - }); - - def.imports.forEach((imported: NgModuleType) => { - const ngModule = resolvers.module.resolve(imported); - - if (ngModule === null) { - throw new Error(`Importing ${imported.name} which does not have an @ngModule`); - } else { - this._compileNgModule(imported, resolvers); - } - - // When this module imports another, the imported module's exported directives and pipes are - // added to the compilation scope of this module. - const importedScope = this._transitiveScopesFor(imported, resolvers); - importedScope.exported.directives.forEach(entry => scopes.compilation.directives.add(entry)); - importedScope.exported.pipes.forEach(entry => scopes.compilation.pipes.add(entry)); - }); - - def.exports.forEach((exported: Type) => { - const exportedTyped = exported as Type& { - // Components, Directives, NgModules, and Pipes can all be exported. - ngComponentDef?: any; - ngDirectiveDef?: any; - ngModuleDef?: NgModuleDef; - ngPipeDef?: any; - }; - - // Either the type is a module, a pipe, or a component/directive (which may not have an - // ngComponentDef as it might be compiled asynchronously). - if (isNgModule(exportedTyped)) { - // When this module exports another, the exported module's exported directives and pipes are - // added to both the compilation and exported scopes of this module. - const exportedScope = this._transitiveScopesFor(exportedTyped, resolvers); - exportedScope.exported.directives.forEach(entry => { - scopes.compilation.directives.add(entry); - scopes.exported.directives.add(entry); - }); - exportedScope.exported.pipes.forEach(entry => { - scopes.compilation.pipes.add(entry); - scopes.exported.pipes.add(entry); - }); - } else if (exportedTyped.ngPipeDef !== undefined) { - scopes.exported.pipes.add(exportedTyped); - } else { - scopes.exported.directives.add(exportedTyped); - } - }); - - def.transitiveCompileScopes = scopes; - return scopes; + this._globalCompilationChecked = true; } } @@ -623,19 +767,6 @@ export function _getTestBedRender3(): TestBedRender3 { return testBed = testBed || new TestBedRender3(); } -const OWNER_MODULE = '__NG_MODULE__'; -/** - * This function clears the OWNER_MODULE property from the Types. This is set in - * r3/jit/modules.ts. It is common for the same Type to be compiled in different tests. If we don't - * clear this we will get errors which will complain that the same Component/Directive is in more - * than one NgModule. - */ -function clearNgModules(type: Type) { - if (type.hasOwnProperty(OWNER_MODULE)) { - (type as any)[OWNER_MODULE] = undefined; - } -} - function flatten(values: any[], mapFn?: (value: T) => any): T[] { const out: T[] = []; values.forEach(value => { @@ -651,3 +782,41 @@ function flatten(values: any[], mapFn?: (value: T) => any): T[] { function isNgModule(value: Type): value is Type&{ngModuleDef: NgModuleDef} { return (value as{ngModuleDef?: NgModuleDef}).ngModuleDef !== undefined; } + +class R3TestCompiler implements Compiler { + constructor(private testBed: TestBedRender3) {} + + compileModuleSync(moduleType: Type): NgModuleFactory { + this.testBed._compileNgModule(moduleType as NgModuleType); + return new R3NgModuleFactory(moduleType); + } + + compileModuleAsync(moduleType: Type): Promise> { + return Promise.resolve(this.compileModuleSync(moduleType)); + } + + compileModuleAndAllComponentsSync(moduleType: Type): ModuleWithComponentFactories { + const ngModuleFactory = this.compileModuleSync(moduleType); + const componentFactories = this.testBed._getComponentFactories(moduleType as NgModuleType); + return new ModuleWithComponentFactories(ngModuleFactory, componentFactories); + } + + compileModuleAndAllComponentsAsync(moduleType: Type): + Promise> { + return Promise.resolve(this.compileModuleAndAllComponentsSync(moduleType)); + } + + clearCache(): void {} + + clearCacheFor(type: Type): void {} + + getModuleId(moduleType: Type): string|undefined { + const meta = this.testBed._getModuleResolver().resolve(moduleType); + return meta && meta.id || undefined; + } +} + +/** Error handler used for tests. Rethrows errors rather than logging them out. */ +class R3TestErrorHandler extends ErrorHandler { + handleError(error: any) { throw error; } +} diff --git a/packages/core/testing/src/resolvers.ts b/packages/core/testing/src/resolvers.ts index 2a15dd7bc5..027929078e 100644 --- a/packages/core/testing/src/resolvers.ts +++ b/packages/core/testing/src/resolvers.ts @@ -37,7 +37,21 @@ abstract class OverrideResolver implements Resolver { } getAnnotation(type: Type): T|null { - return reflection.annotations(type).find(a => a instanceof this.type) || null; + const annotations = reflection.annotations(type); + // Try to find the nearest known Type annotation and make sure that this annotation is an + // instance of the type we are looking for, so we can use it for resolution. Note: there might + // be multiple known annotations found due to the fact that Components can extend Directives (so + // both Directive and Component annotations would be present), so we always check if the known + // annotation has the right type. + for (let i = annotations.length - 1; i >= 0; i--) { + const annotation = annotations[i]; + const isKnownType = annotation instanceof Directive || annotation instanceof Component || + annotation instanceof Pipe || annotation instanceof NgModule; + if (isKnownType) { + return annotation instanceof this.type ? annotation : null; + } + } + return null; } resolve(type: Type): T|null { diff --git a/packages/core/testing/src/testing_internal.ts b/packages/core/testing/src/testing_internal.ts index 670dbf8a26..1620e2d718 100644 --- a/packages/core/testing/src/testing_internal.ts +++ b/packages/core/testing/src/testing_internal.ts @@ -7,7 +7,7 @@ */ import {ɵisPromise as isPromise} from '@angular/core'; -import {global} from '@angular/core/src/util'; +import {global} from '@angular/core/src/util/global'; import {AsyncTestCompleter} from './async_test_completer'; import {getTestBed, inject} from './test_bed'; @@ -169,7 +169,7 @@ export class SpyObject { let m: any = null; try { m = type.prototype[prop]; - } catch (e) { + } catch { // As we are creating spys for abstract classes, // these classes might have getters that throw when they are accessed. // As we are only auto creating spys for methods, this diff --git a/packages/elements/BUILD.bazel b/packages/elements/BUILD.bazel index c3a939128e..5e39ef5bab 100644 --- a/packages/elements/BUILD.bazel +++ b/packages/elements/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/elements", deps = [ "//packages/core", "//packages/platform-browser", diff --git a/packages/elements/rollup.config.js b/packages/elements/rollup.config.js deleted file mode 100644 index 477863d15e..0000000000 --- a/packages/elements/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/platform-browser': 'ng.platformBrowser', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators' -}; - -module.exports = { - entry: '../../dist/packages-dist/elements/fesm5/elements.js', - dest: '../../dist/packages-dist/elements/bundles/elements.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/elements'}, - moduleName: 'ng.elements', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/elements/schematics/ng-add/index.ts b/packages/elements/schematics/ng-add/index.ts index 6928e36383..cfae88cc3a 100644 --- a/packages/elements/schematics/ng-add/index.ts +++ b/packages/elements/schematics/ng-add/index.ts @@ -64,7 +64,7 @@ function addScript(options: Schema) { scripts.push({input: script}); host.overwrite('angular.json', JSON.stringify(json, null, 2)); } - } catch (e) { + } catch { context.logger.log( 'warn', 'Failed to add the polyfill document-register-element.js to scripts'); } diff --git a/packages/es6-subset.d.ts b/packages/es6-subset.d.ts deleted file mode 100644 index 2f16198223..0000000000 --- a/packages/es6-subset.d.ts +++ /dev/null @@ -1,65 +0,0 @@ - -/** - * Subset of lib.es2015.core.d.ts typings. - * Angular should not require use of ES6 runtime but some API usages are already present. - * See https://github.com/angular/angular/issues/5242 - * TODO(alexeagle): remove methods below which may not be present in targeted browser - */ - -interface String { - /** - * Returns true if the sequence of elements of searchString converted to a String is the - * same as the corresponding elements of this object (converted to a String) starting at - * position. Otherwise returns false. - */ - startsWith(searchString: string, position?: number): boolean; - - /** - * Returns true if the sequence of elements of searchString converted to a String is the - * same as the corresponding elements of this object (converted to a String) starting at - * endPosition – length(this). Otherwise returns false. - */ - endsWith(searchString: string, endPosition?: number): boolean; -} - -interface Array { - /** - * Returns the value of the first element in the array where predicate is true, and undefined - * otherwise. - * @param predicate find calls predicate once for each element of the array, in ascending - * order, until it finds one where predicate returns true. If such an element is found, find - * immediately returns that element value. Otherwise, find returns undefined. - * @param thisArg If provided, it will be used as the this value for each invocation of - * predicate. If it is not provided, undefined is used instead. - */ - find(predicate: (value: T, index: number, obj: Array) => boolean, thisArg?: any): T|undefined; - /** - * Returns the this object after filling the section identified by start and end with value - * @param value value to fill array section with - * @param start index to start filling the array at. If start is negative, it is treated as - * length+start where length is the length of the array. - * @param end index to stop filling the array at. If end is negative, it is treated as - * length+end. - */ - fill(value: T, start?: number, end?: number): T[]; -} - -interface NumberConstructor { - /** - * Returns true if the value passed is an integer, false otherwise. - * @param number A numeric value. - */ - isInteger(number: number): boolean; -} - -// Workaround https://github.com/Microsoft/TypeScript/issues/9193 -interface PromiseConstructor { - all(values: (T|PromiseLike)[]): Promise; -} - -interface Function { - /** - * Returns the name of the function. Function names are read-only and can not be changed. - */ - readonly name: string; -} diff --git a/packages/examples/BUILD.bazel b/packages/examples/BUILD.bazel new file mode 100644 index 0000000000..70b5855669 --- /dev/null +++ b/packages/examples/BUILD.bazel @@ -0,0 +1,4 @@ +exports_files([ + "index.html", + "tsconfig-e2e.json", +]) diff --git a/packages/examples/README.md b/packages/examples/README.md index 2e3269f41f..c472095b25 100644 --- a/packages/examples/README.md +++ b/packages/examples/README.md @@ -7,28 +7,15 @@ behavior) just like an Angular application developer would write. # Running the examples ``` -# # execute the following command only when framework code changes -./build.sh +# Serving individual examples (e.g. common) +yarn bazel run //packages/examples/common:devserver -# run when test change -./packages/examples/build.sh - -# start server -$(npm bin)/gulp serve-examples +# "core" examples +yarn bazel run //packages/examples/core:devserver ``` -navigate to [http://localhost:8001](http://localhost:8001) - # Running the tests ``` - # run only when framework code changes -./build.sh - -# run to compile tests and run them -./packages/examples/test.sh -``` - -NOTE: sometimes the http server does not exit properly and it retains the `8001` port. - in such a case you can use `lsof -i:8001` to see which process it is and then use `kill` - to remove it. (Or in single command: `lsof -i:8001 -t | xargs kill`) \ No newline at end of file +yarn bazel test //packages/examples/... +``` \ No newline at end of file diff --git a/packages/examples/_common/bootstrap.ts b/packages/examples/_common/bootstrap.ts deleted file mode 100644 index 24bad23979..0000000000 --- a/packages/examples/_common/bootstrap.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -(function(global: any) { - writeScriptTag('/vendor/zone.js'); - writeScriptTag('/vendor/task-tracking.js'); - writeScriptTag('/vendor/system.js'); - writeScriptTag('/vendor/Reflect.js'); - writeScriptTag('/_common/system-config.js'); - if (location.pathname.indexOf('/upgrade/') != -1) { - writeScriptTag('/vendor/angular.js'); - } - - function writeScriptTag(scriptUrl: string, onload: string = '') { - document.write(''); - } -}(window)); diff --git a/packages/examples/_common/e2e_util.ts b/packages/examples/_common/e2e_util.ts deleted file mode 100644 index 4ca6732c1e..0000000000 --- a/packages/examples/_common/e2e_util.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/* tslint:disable:no-console */ -import * as webdriver from 'selenium-webdriver'; -declare var browser: any; -declare var expect: any; - -// TODO (juliemr): remove this method once this becomes a protractor plugin -export function verifyNoBrowserErrors() { - browser.manage().logs().get('browser').then(function(browserLog: any[]) { - const errors: any[] = []; - browserLog.filter(logEntry => { - const msg = logEntry.message; - console.log('>> ' + msg); - if (logEntry.level.value >= webdriver.logging.Level.INFO.value) { - errors.push(msg); - } - }); - expect(errors).toEqual([]); - }); -} diff --git a/packages/examples/_common/index.html b/packages/examples/_common/index.html deleted file mode 100644 index 645ad3416f..0000000000 --- a/packages/examples/_common/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - loading... - - - diff --git a/packages/examples/_common/module.d.ts b/packages/examples/_common/module.d.ts deleted file mode 100644 index 9038a8f4ac..0000000000 --- a/packages/examples/_common/module.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/* - -DO NOT DELETE THIS FILE -======================= - -The purpose of this file is to allow `main-dynamic.ts` to be tsc-compiled -BEFORE it is copied over to each of the associated example directories -within `dist/examples`. - - */ -export class AppModule {}; diff --git a/packages/examples/_common/system-config.ts b/packages/examples/_common/system-config.ts deleted file mode 100644 index 2ad12456a6..0000000000 --- a/packages/examples/_common/system-config.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -System.config({ - defaultJSExtensions: true, - map: { - '@angular/common': '/vendor/@angular/common/bundles/common.umd.js', - '@angular/compiler': '/vendor/@angular/compiler/bundles/compiler.umd.js', - '@angular/animations': '/vendor/@angular/animations/bundles/animations.umd.js', - '@angular/animations/browser': '/vendor/@angular/animations/bundles/animations-browser.umd.js', - '@angular/platform-browser/animations': - '/vendor/@angular/platform-browser/bundles/platform-browser-animations.umd.js', - '@angular/core': '/vendor/@angular/core/bundles/core.umd.js', - '@angular/forms': '/vendor/@angular/forms/bundles/forms.umd.js', - '@angular/http': '/vendor/@angular/forms/bundles/http.umd.js', - '@angular/platform-browser': - '/vendor/@angular/platform-browser/bundles/platform-browser.umd.js', - '@angular/platform-browser-dynamic': - '/vendor/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', - '@angular/router': '/vendor/@angular/router/bundles/router.umd.js', - '@angular/upgrade': '/vendor/@angular/upgrade/bundles/upgrade.umd.js', - '@angular/upgrade/static': '/vendor/@angular/upgrade/bundles/upgrade-static.umd.js', - 'rxjs': '/vendor/rxjs' - }, - packages: { - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - }, -}); diff --git a/packages/examples/build.sh b/packages/examples/build.sh deleted file mode 100755 index ce521af07a..0000000000 --- a/packages/examples/build.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# -# This script is used to compile and copy the contents for each of -# example directories over to the dist/examples directory so that they -# can be tested with karma and protractor. The `gulp serve-examples` command -# can be used to run each of the examples in isolation via http as well. -# - -( - cd `dirname $0` - - DIST="../../dist/examples"; - rm -rf -- $DIST - $(npm bin)/tsc -p ./tsconfig-build.json --importHelpers false - - mkdir $DIST/vendor/ - - ln -s ../../../dist/packages-dist/ $DIST/vendor/@angular - - for FILE in \ - ../../../node_modules/angular/angular.js \ - ../../../node_modules/zone.js/dist/zone.js \ - ../../../node_modules/zone.js/dist/task-tracking.js \ - ../../../node_modules/systemjs/dist/system.js \ - ../../../node_modules/reflect-metadata/Reflect.js \ - ../../../node_modules/rxjs - do - ln -s $FILE $DIST/vendor/`basename $FILE` - done - - for MODULE in `find . -name module.ts`; do - FINAL_DIR_PATH=$DIST/`dirname $MODULE` - - echo "==== $MODULE" - cp _common/*.html $FINAL_DIR_PATH - cp $DIST/_common/*.js $FINAL_DIR_PATH - cp $DIST/_common/*.js.map $FINAL_DIR_PATH - - find `dirname $MODULE` -name \*.css -exec cp {} $FINAL_DIR_PATH \; - done -) diff --git a/packages/examples/common/BUILD.bazel b/packages/examples/common/BUILD.bazel new file mode 100644 index 0000000000..5b7ce353f2 --- /dev/null +++ b/packages/examples/common/BUILD.bazel @@ -0,0 +1,63 @@ +package(default_visibility = ["//visibility:public"]) + +load("//packages/bazel:index.bzl", "protractor_web_test_suite") +load("//tools:defaults.bzl", "ng_module", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +ng_module( + name = "common_examples", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*_spec.ts"], + ), + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/common", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + "//packages/router", + "@rxjs", + ], +) + +ts_library( + name = "common_tests_lib", + testonly = True, + srcs = glob(["**/*_spec.ts"]), + tsconfig = "//packages/examples:tsconfig-e2e.json", + deps = [ + "//packages/examples/test-utils", + "//packages/private/testing", + "@ngdeps//@types/jasminewd2", + "@ngdeps//protractor", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "@angular/examples/common/main", + index_html = "//packages/examples:index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + # This is needed because the "ngComponentOutlet" test uses the JIT compiler + # and needs to be able to read metadata at runtime. + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + deps = [":common_examples"], +) + +protractor_web_test_suite( + name = "protractor_tests", + data = ["//packages/bazel/src/protractor/utils"], + on_prepare = ":start-server.js", + server = ":devserver", + deps = [ + ":common_tests_lib", + "@ngdeps//protractor", + "@ngdeps//selenium-webdriver", + ], +) diff --git a/packages/examples/common/location/ts/e2e_test/location_component_spec.ts b/packages/examples/common/location/ts/e2e_test/location_component_spec.ts index 20e790a3c1..917b3f43c1 100644 --- a/packages/examples/common/location/ts/e2e_test/location_component_spec.ts +++ b/packages/examples/common/location/ts/e2e_test/location_component_spec.ts @@ -8,7 +8,7 @@ import {$, browser, by, element, protractor} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { @@ -21,10 +21,9 @@ describe('Location', () => { afterEach(verifyNoBrowserErrors); it('should verify paths', () => { - browser.get('/common/location/ts/#/bar/baz'); + browser.get('/location/#/bar/baz'); waitForElement('hash-location'); - expect(element.all(by.css('path-location code')).get(0).getText()) - .toEqual('/common/location/ts'); + expect(element.all(by.css('path-location code')).get(0).getText()).toEqual('/location'); expect(element.all(by.css('hash-location code')).get(0).getText()).toEqual('/bar/baz'); }); }); diff --git a/packages/examples/common/location/ts/module.ts b/packages/examples/common/location/ts/module.ts index 10b064e54d..76a902de2a 100644 --- a/packages/examples/common/location/ts/module.ts +++ b/packages/examples/common/location/ts/module.ts @@ -17,14 +17,13 @@ import {PathLocationComponent} from './path_location_component'; selector: 'example-app', template: `` }) -export class ExampleAppComponent { +export class AppComponent { } @NgModule({ - declarations: [ExampleAppComponent, PathLocationComponent, HashLocationComponent], + declarations: [AppComponent, PathLocationComponent, HashLocationComponent], providers: [{provide: APP_BASE_HREF, useValue: '/'}], imports: [BrowserModule], - bootstrap: [ExampleAppComponent] }) export class AppModule { } diff --git a/packages/examples/_common/main-dynamic.ts b/packages/examples/common/main.ts similarity index 66% rename from packages/examples/_common/main-dynamic.ts rename to packages/examples/common/main.ts index e30f1c076b..b5ec0fb33e 100644 --- a/packages/examples/_common/main-dynamic.ts +++ b/packages/examples/common/main.ts @@ -5,9 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import * as mod from './module'; -if (mod.AppModule) { - platformBrowserDynamic().bootstrapModule(mod.AppModule); -} +import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; +import {TestsAppModuleNgFactory} from './test_module.ngfactory'; + +platformBrowserDynamic().bootstrapModuleFactory(TestsAppModuleNgFactory); diff --git a/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts b/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts index fd6110a4b5..f04cd582b2 100644 --- a/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts +++ b/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import {fixmeIvy, modifiedInIvy} from '@angular/private/testing'; import {$, ExpectedConditions, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; + +import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { const EC = ExpectedConditions; @@ -15,29 +17,33 @@ function waitForElement(selector: string) { browser.wait(EC.presenceOf($(selector)), 20000); } -describe('ngComponentOutlet', () => { - const URL = 'common/ngComponentOutlet/ts/'; - afterEach(verifyNoBrowserErrors); +fixmeIvy('FW-1022: JitCompilerFactory creates incorrect compiler instance') + .describe('ngComponentOutlet', () => { + const URL = '/ngComponentOutlet'; + afterEach(verifyNoBrowserErrors); - describe('ng-component-outlet-example', () => { - it('should render simple', () => { - browser.get(URL); - waitForElement('ng-component-outlet-simple-example'); - expect(element.all(by.css('hello-world')).getText()).toEqual(['Hello World!']); - }); + describe('ng-component-outlet-example', () => { + it('should render simple', () => { + browser.get(URL); + waitForElement('ng-component-outlet-simple-example'); + expect(element.all(by.css('hello-world')).getText()).toEqual(['Hello World!']); + }); - it('should render complete', () => { - browser.get(URL); - waitForElement('ng-component-outlet-complete-example'); - expect(element.all(by.css('complete-component')).getText()).toEqual(['Complete: AhojSvet!']); - }); + modifiedInIvy('Different behavior for projectableNodes in ViewContainerRef.createComponent') + .it('should render complete', () => { + browser.get(URL); + waitForElement('ng-component-outlet-complete-example'); + expect(element.all(by.css('complete-component')).getText()).toEqual([ + 'Complete: AhojSvet!' + ]); + }); - it('should render other module', () => { - browser.get(URL); - waitForElement('ng-component-outlet-other-module-example'); - expect(element.all(by.css('other-module-component')).getText()).toEqual([ - 'Other Module Component!' - ]); + it('should render other module', () => { + browser.get(URL); + waitForElement('ng-component-outlet-other-module-example'); + expect(element.all(by.css('other-module-component')).getText()).toEqual([ + 'Other Module Component!' + ]); + }); + }); }); - }); -}); diff --git a/packages/examples/common/ngComponentOutlet/ts/module.ts b/packages/examples/common/ngComponentOutlet/ts/module.ts index e56f528cea..a351268186 100644 --- a/packages/examples/common/ngComponentOutlet/ts/module.ts +++ b/packages/examples/common/ngComponentOutlet/ts/module.ts @@ -7,21 +7,22 @@ */ import {CommonModule} from '@angular/common'; -import {Compiler, Component, Injectable, Injector, NgModule, NgModuleFactory, ReflectiveInjector} from '@angular/core'; +import {COMPILER_OPTIONS, Compiler, CompilerFactory, Component, Injectable, Injector, NgModule, NgModuleFactory} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; +import {JitCompilerFactory} from '@angular/platform-browser-dynamic'; // #docregion SimpleExample @Component({selector: 'hello-world', template: 'Hello World!'}) -class HelloWorld { +export class HelloWorld { } @Component({ selector: 'ng-component-outlet-simple-example', template: `` }) -class NgTemplateOutletSimpleExample { +export class NgTemplateOutletSimpleExample { // This field is necessary to expose HelloWorld to the template. HelloWorld = HelloWorld; } @@ -29,7 +30,7 @@ class NgTemplateOutletSimpleExample { // #docregion CompleteExample @Injectable() -class Greeter { +export class Greeter { suffix = '!'; } @@ -37,7 +38,7 @@ class Greeter { selector: 'complete-component', template: `Complete: {{ greeter.suffix }}` }) -class CompleteComponent { +export class CompleteComponent { constructor(public greeter: Greeter) {} } @@ -48,7 +49,7 @@ class CompleteComponent { injector: myInjector; content: myContent">` }) -class NgTemplateOutletCompleteExample { +export class NgTemplateOutletCompleteExample { // This field is necessary to expose CompleteComponent to the template. CompleteComponent = CompleteComponent; myInjector: Injector; @@ -56,14 +57,15 @@ class NgTemplateOutletCompleteExample { myContent = [[document.createTextNode('Ahoj')], [document.createTextNode('Svet')]]; constructor(injector: Injector) { - this.myInjector = ReflectiveInjector.resolveAndCreate([Greeter], injector); + this.myInjector = + Injector.create({providers: [{provide: Greeter, deps: []}], parent: injector}); } } // #enddocregion // #docregion NgModuleFactoryExample @Component({selector: 'other-module-component', template: `Other Module Component!`}) -class OtherModuleComponent { +export class OtherModuleComponent { } @Component({ @@ -72,7 +74,7 @@ class OtherModuleComponent { ` }) -class NgTemplateOutletOtherModuleExample { +export class NgTemplateOutletOtherModuleExample { // This field is necessary to expose OtherModuleComponent to the template. OtherModuleComponent = OtherModuleComponent; myModule: NgModuleFactory; @@ -90,19 +92,7 @@ class NgTemplateOutletOtherModuleExample {
    ` }) -class ExampleApp { -} - -@NgModule({ - imports: [BrowserModule], - declarations: [ - ExampleApp, NgTemplateOutletSimpleExample, NgTemplateOutletCompleteExample, - NgTemplateOutletOtherModuleExample, HelloWorld, CompleteComponent - ], - entryComponents: [HelloWorld, CompleteComponent], - bootstrap: [ExampleApp] -}) -export class AppModule { +export class AppComponent { } @NgModule({ @@ -111,4 +101,27 @@ export class AppModule { entryComponents: [OtherModuleComponent] }) export class OtherModule { -} \ No newline at end of file +} + +export function createCompiler(compilerFactory: CompilerFactory) { + return compilerFactory.createCompiler(); +} + +@NgModule({ + imports: [BrowserModule], + declarations: [ + AppComponent, NgTemplateOutletSimpleExample, NgTemplateOutletCompleteExample, + NgTemplateOutletOtherModuleExample, HelloWorld, CompleteComponent + ], + entryComponents: [HelloWorld, CompleteComponent], + providers: [ + // Setup the JIT compiler that is not set up by default because the examples + // are bootstrapped using their NgModule factory. Since this example uses the + // JIT compiler, we manually set it up for this module. + {provide: COMPILER_OPTIONS, useValue: {}, multi: true}, + {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]}, + {provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory]} + ] +}) +export class AppModule { +} diff --git a/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts b/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts index b0ba5c41c6..833479edfa 100644 --- a/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts +++ b/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +import {modifiedInIvy} from '@angular/private/testing'; import {$, ExpectedConditions, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { const EC = ExpectedConditions; @@ -16,7 +17,7 @@ function waitForElement(selector: string) { } describe('ngIf', () => { - const URL = 'common/ngIf/ts/'; + const URL = '/ngIf'; afterEach(verifyNoBrowserErrors); describe('ng-if-simple', () => { @@ -44,18 +45,21 @@ describe('ngIf', () => { describe('ng-if-then-else', () => { let comp = 'ng-if-then-else'; - it('should hide/show content', () => { - browser.get(URL); - waitForElement(comp); - expect(element.all(by.css(comp)).get(0).getText()) - .toEqual('hideSwitch Primary show = true\nPrimary text to show'); - element.all(by.css(comp + ' button')).get(1).click(); - expect(element.all(by.css(comp)).get(0).getText()) - .toEqual('hideSwitch Primary show = true\nSecondary text to show'); - element.all(by.css(comp + ' button')).get(0).click(); - expect(element.all(by.css(comp)).get(0).getText()) - .toEqual('showSwitch Primary show = false\nAlternate text while primary text is hidden'); - }); + + modifiedInIvy('FW-1019: Design new API to replace static queries') + .it('should hide/show content', () => { + browser.get(URL); + waitForElement(comp); + expect(element.all(by.css(comp)).get(0).getText()) + .toEqual('hideSwitch Primary show = true\nPrimary text to show'); + element.all(by.css(comp + ' button')).get(1).click(); + expect(element.all(by.css(comp)).get(0).getText()) + .toEqual('hideSwitch Primary show = true\nSecondary text to show'); + element.all(by.css(comp + ' button')).get(0).click(); + expect(element.all(by.css(comp)).get(0).getText()) + .toEqual( + 'showSwitch Primary show = false\nAlternate text while primary text is hidden'); + }); }); describe('ng-if-let', () => { diff --git a/packages/examples/common/ngIf/ts/module.ts b/packages/examples/common/ngIf/ts/module.ts index 902ea6e528..51df5ed019 100644 --- a/packages/examples/common/ngIf/ts/module.ts +++ b/packages/examples/common/ngIf/ts/module.ts @@ -21,7 +21,7 @@ import {Subject} from 'rxjs';
    Text to show
    ` }) -class NgIfSimple { +export class NgIfSimple { show: boolean = true; } // #enddocregion @@ -37,7 +37,7 @@ class NgIfSimple { Alternate text while primary text is hidden ` }) -class NgIfElse { +export class NgIfElse { show: boolean = true; } // #enddocregion @@ -56,7 +56,7 @@ class NgIfElse { Alternate text while primary text is hidden ` }) -class NgIfThenElse implements OnInit { +export class NgIfThenElse implements OnInit { thenBlock: TemplateRef|null = null; show: boolean = true; @@ -85,7 +85,7 @@ class NgIfThenElse implements OnInit { Waiting... (user is {{user|json}}) ` }) -class NgIfAs { +export class NgIfAs { userObservable = new Subject<{first: string, last: string}>(); first = ['John', 'Mike', 'Mary', 'Bob']; firstIndex = 0; @@ -116,13 +116,12 @@ class NgIfAs {
    ` }) -class ExampleApp { +export class AppComponent { } @NgModule({ imports: [BrowserModule], - declarations: [ExampleApp, NgIfSimple, NgIfElse, NgIfThenElse, NgIfAs], - bootstrap: [ExampleApp] + declarations: [AppComponent, NgIfSimple, NgIfElse, NgIfThenElse, NgIfAs], }) export class AppModule { } diff --git a/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts b/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts index a57ea4fc9f..508a68b01e 100644 --- a/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts +++ b/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts @@ -7,7 +7,7 @@ */ import {$, ExpectedConditions, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { const EC = ExpectedConditions; @@ -16,7 +16,7 @@ function waitForElement(selector: string) { } describe('ngTemplateOutlet', () => { - const URL = 'common/ngTemplateOutlet/ts/'; + const URL = '/ngTemplateOutlet'; afterEach(verifyNoBrowserErrors); describe('ng-template-outlet-example', () => { diff --git a/packages/examples/common/ngTemplateOutlet/ts/module.ts b/packages/examples/common/ngTemplateOutlet/ts/module.ts index dc14eb17be..22e371a38b 100644 --- a/packages/examples/common/ngTemplateOutlet/ts/module.ts +++ b/packages/examples/common/ngTemplateOutlet/ts/module.ts @@ -26,7 +26,7 @@ import {BrowserModule} from '@angular/platform-browser'; Ahoj {{person}}! ` }) -class NgTemplateOutletExample { +export class NgTemplateOutletExample { myContext = {$implicit: 'World', localSk: 'Svet'}; } // #enddocregion @@ -36,13 +36,12 @@ class NgTemplateOutletExample { selector: 'example-app', template: `` }) -class ExampleApp { +export class AppComponent { } @NgModule({ imports: [BrowserModule], - declarations: [ExampleApp, NgTemplateOutletExample], - bootstrap: [ExampleApp] + declarations: [AppComponent, NgTemplateOutletExample], }) export class AppModule { } diff --git a/packages/examples/common/pipes/ts/async_pipe.ts b/packages/examples/common/pipes/ts/async_pipe.ts index 31fa366d10..50eb38ae01 100644 --- a/packages/examples/common/pipes/ts/async_pipe.ts +++ b/packages/examples/common/pipes/ts/async_pipe.ts @@ -58,7 +58,7 @@ export class AsyncObservablePipeComponent { // protractor will not see us. Also we want to have this outside the docregion so as not to confuse // the reader. function setInterval(fn: Function, delay: number) { - const zone = Zone.current; + const zone = (window as any)['Zone'].current; let rootZone = zone; while (rootZone.parent) { rootZone = rootZone.parent; diff --git a/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts b/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts index 10551fcfb1..def858d4a6 100644 --- a/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts +++ b/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts @@ -7,7 +7,7 @@ */ import {$, ExpectedConditions, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { const EC = ExpectedConditions; @@ -17,7 +17,7 @@ function waitForElement(selector: string) { describe('pipe', () => { afterEach(verifyNoBrowserErrors); - const URL = '/common/pipes/ts/'; + const URL = '/pipes'; describe('async', () => { it('should resolve and display promise', () => { diff --git a/packages/examples/common/pipes/ts/module.ts b/packages/examples/common/pipes/ts/module.ts index f21d3af8b1..5600dda996 100644 --- a/packages/examples/common/pipes/ts/module.ts +++ b/packages/examples/common/pipes/ts/module.ts @@ -59,19 +59,19 @@ import {TitleCasePipeComponent} from './titlecase_pipe'; ` }) -export class ExampleAppComponent { +export class AppComponent { } @NgModule({ declarations: [ - AsyncPromisePipeComponent, AsyncObservablePipeComponent, ExampleAppComponent, JsonPipeComponent, + AsyncPromisePipeComponent, AsyncObservablePipeComponent, AppComponent, JsonPipeComponent, DatePipeComponent, DeprecatedDatePipeComponent, LowerUpperPipeComponent, TitleCasePipeComponent, - NumberPipeComponent, PercentPipeComponent, DeprecatedPercentPipeComponent, - CurrencyPipeComponent, DeprecatedCurrencyPipeComponent, SlicePipeStringComponent, - SlicePipeListComponent, I18nPluralPipeComponent, I18nSelectPipeComponent, KeyValuePipeComponent + NumberPipeComponent, DeprecatedNumberPipeComponent, PercentPipeComponent, + DeprecatedPercentPipeComponent, CurrencyPipeComponent, DeprecatedCurrencyPipeComponent, + SlicePipeStringComponent, SlicePipeListComponent, I18nPluralPipeComponent, + I18nSelectPipeComponent, KeyValuePipeComponent ], imports: [BrowserModule], - bootstrap: [ExampleAppComponent] }) export class AppModule { } diff --git a/packages/examples/common/start-server.js b/packages/examples/common/start-server.js new file mode 100644 index 0000000000..e7d432281a --- /dev/null +++ b/packages/examples/common/start-server.js @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const protractorUtils = require('@angular/bazel/protractor-utils'); +const protractor = require('protractor'); + +module.exports = async function(config) { + const {port} = await protractorUtils.runServer(config.workspace, config.server, '-port', []); + const serverUrl = `http://localhost:${port}`; + + protractor.browser.baseUrl = serverUrl; +}; diff --git a/packages/examples/common/test_module.ts b/packages/examples/common/test_module.ts new file mode 100644 index 0000000000..03e78df027 --- /dev/null +++ b/packages/examples/common/test_module.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, NgModule} from '@angular/core'; +import {RouterModule} from '@angular/router'; + +import * as locationExample from './location/ts/module'; +import * as ngComponentOutletExample from './ngComponentOutlet/ts/module'; +import * as ngIfExample from './ngIf/ts/module'; +import * as ngTemplateOutletExample from './ngTemplateOutlet/ts/module'; +import * as pipesExample from './pipes/ts/module'; + +@Component({selector: 'example-app', template: ''}) +export class TestsAppComponent { +} + +@NgModule({ + imports: [ + locationExample.AppModule, ngComponentOutletExample.AppModule, ngIfExample.AppModule, + ngTemplateOutletExample.AppModule, pipesExample.AppModule, + + // Router configuration so that the individual e2e tests can load their + // app components. + RouterModule.forRoot([ + {path: 'location', component: locationExample.AppComponent}, + {path: 'ngComponentOutlet', component: ngComponentOutletExample.AppComponent}, + {path: 'ngIf', component: ngIfExample.AppComponent}, + {path: 'ngTemplateOutlet', component: ngTemplateOutletExample.AppComponent}, + {path: 'pipes', component: pipesExample.AppComponent}, + ]) + ], + declarations: [TestsAppComponent], + bootstrap: [TestsAppComponent] +}) +export class TestsAppModule { +} diff --git a/packages/examples/compiler/BUILD.bazel b/packages/examples/compiler/BUILD.bazel new file mode 100644 index 0000000000..0ca85ef155 --- /dev/null +++ b/packages/examples/compiler/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ng_module") + +ng_module( + name = "compiler_examples", + srcs = glob(["**/*.ts"]), + deps = [ + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) diff --git a/packages/examples/compiler/ts/url_resolver/url_resolver.ts b/packages/examples/compiler/ts/url_resolver/url_resolver.ts index aac9552714..4519132045 100644 --- a/packages/examples/compiler/ts/url_resolver/url_resolver.ts +++ b/packages/examples/compiler/ts/url_resolver/url_resolver.ts @@ -7,11 +7,13 @@ */ import {UrlResolver} from '@angular/compiler'; -import {NgModule} from '@angular/core'; +import {Component, NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -let MyApp: any; +@Component({selector: 'my-app', template: 'empty'}) +class MyApp { +} // #docregion url_resolver class MyUrlResolver extends UrlResolver { diff --git a/packages/examples/core/BUILD.bazel b/packages/examples/core/BUILD.bazel new file mode 100644 index 0000000000..0c25642b88 --- /dev/null +++ b/packages/examples/core/BUILD.bazel @@ -0,0 +1,63 @@ +package(default_visibility = ["//visibility:public"]) + +load("//packages/bazel:index.bzl", "protractor_web_test_suite") +load("//tools:defaults.bzl", "ng_module", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +ng_module( + name = "core_examples", + srcs = glob( + ["**/*.ts"], + exclude = [ + "**/*_spec.ts", + "**/*_howto.ts", + ], + ), + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/animations", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + "//packages/platform-browser/animations", + "//packages/router", + ], +) + +ts_library( + name = "core_e2e_tests_lib", + testonly = True, + srcs = glob(["**/e2e_test/*_spec.ts"]), + tsconfig = "//packages/examples:tsconfig-e2e.json", + deps = [ + "//packages/examples/test-utils", + "@ngdeps//@types/jasminewd2", + "@ngdeps//protractor", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "@angular/examples/core/main", + index_html = "//packages/examples:index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/zone.js:dist/task-tracking.js", + ], + deps = [":core_examples"], +) + +protractor_web_test_suite( + name = "protractor_tests", + data = ["//packages/bazel/src/protractor/utils"], + on_prepare = ":start-server.js", + server = ":devserver", + deps = [ + ":core_e2e_tests_lib", + "@ngdeps//protractor", + "@ngdeps//selenium-webdriver", + ], +) diff --git a/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts b/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts index 11ff8acfb5..550af8d2a5 100644 --- a/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts +++ b/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts @@ -7,7 +7,7 @@ */ import {$, ExpectedConditions, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; function waitForElement(selector: string) { const EC = ExpectedConditions; @@ -19,7 +19,7 @@ describe('animation example', () => { afterEach(verifyNoBrowserErrors); describe('index view', () => { - const URL = '/core/animation/ts/dsl/'; + const URL = '/animation/dsl/'; it('should list out the current collection of items', () => { browser.get(URL); diff --git a/packages/examples/core/animation/ts/dsl/module.ts b/packages/examples/core/animation/ts/dsl/module.ts index 6420007c73..b98014f470 100644 --- a/packages/examples/core/animation/ts/dsl/module.ts +++ b/packages/examples/core/animation/ts/dsl/module.ts @@ -5,4 +5,5 @@ * 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 */ -export {AppModule} from './animation_example'; + +export {AppModule, MyExpandoCmp as AppComponent} from './animation_example'; diff --git a/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts b/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts index 3d18b2e6c4..8c88393838 100644 --- a/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts +++ b/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts @@ -7,7 +7,7 @@ */ import {ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('contentChild example', () => { afterEach(verifyNoBrowserErrors); @@ -15,7 +15,7 @@ describe('contentChild example', () => { let result: ElementFinder; beforeEach(() => { - browser.get('/core/di/ts/contentChild/index.html'); + browser.get('/di/contentChild'); button = element(by.css('button')); result = element(by.css('div')); }); diff --git a/packages/examples/core/di/ts/contentChild/module.ts b/packages/examples/core/di/ts/contentChild/module.ts index d64982d351..57a4d9378c 100644 --- a/packages/examples/core/di/ts/contentChild/module.ts +++ b/packages/examples/core/di/ts/contentChild/module.ts @@ -17,3 +17,5 @@ import {ContentChildComp, Pane, Tab} from './content_child_example'; }) export class AppModule { } + +export {ContentChildComp as AppComponent}; diff --git a/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts b/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts index 1f061af5fe..068e457704 100644 --- a/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts +++ b/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts @@ -7,7 +7,7 @@ */ import {ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('contentChildren example', () => { afterEach(verifyNoBrowserErrors); @@ -16,7 +16,7 @@ describe('contentChildren example', () => { let resultNested: ElementFinder; beforeEach(() => { - browser.get('/core/di/ts/contentChildren/index.html'); + browser.get('/di/contentChildren'); button = element(by.css('button')); resultTopLevel = element(by.css('.top-level')); resultNested = element(by.css('.nested')); diff --git a/packages/examples/core/di/ts/contentChildren/module.ts b/packages/examples/core/di/ts/contentChildren/module.ts index 18e50ea60c..1182507812 100644 --- a/packages/examples/core/di/ts/contentChildren/module.ts +++ b/packages/examples/core/di/ts/contentChildren/module.ts @@ -17,3 +17,5 @@ import {ContentChildrenComp, Pane, Tab} from './content_children_example'; }) export class AppModule { } + +export {ContentChildrenComp as AppComponent}; diff --git a/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts b/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts index 5d58b46a5b..295cd1dbf1 100644 --- a/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts +++ b/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts @@ -7,7 +7,7 @@ */ import {ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('viewChild example', () => { afterEach(verifyNoBrowserErrors); @@ -15,7 +15,7 @@ describe('viewChild example', () => { let result: ElementFinder; beforeEach(() => { - browser.get('/core/di/ts/viewChild/index.html'); + browser.get('/di/viewChild'); button = element(by.css('button')); result = element(by.css('div')); }); diff --git a/packages/examples/core/di/ts/viewChild/module.ts b/packages/examples/core/di/ts/viewChild/module.ts index 0ea1c25ec6..de45d067f3 100644 --- a/packages/examples/core/di/ts/viewChild/module.ts +++ b/packages/examples/core/di/ts/viewChild/module.ts @@ -15,3 +15,5 @@ import {Pane, ViewChildComp} from './view_child_example'; {imports: [BrowserModule], declarations: [ViewChildComp, Pane], bootstrap: [ViewChildComp]}) export class AppModule { } + +export {ViewChildComp as AppComponent}; diff --git a/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts b/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts index a61d8e1ed3..701e8cc389 100644 --- a/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts +++ b/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts @@ -8,7 +8,7 @@ import {ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('viewChildren example', () => { afterEach(verifyNoBrowserErrors); @@ -16,7 +16,7 @@ describe('viewChildren example', () => { let result: ElementFinder; beforeEach(() => { - browser.get('/core/di/ts/viewChildren/index.html'); + browser.get('/di/viewChildren'); button = element(by.css('button')); result = element(by.css('div')); }); diff --git a/packages/examples/core/di/ts/viewChildren/module.ts b/packages/examples/core/di/ts/viewChildren/module.ts index 1783203c2b..59c07ea88d 100644 --- a/packages/examples/core/di/ts/viewChildren/module.ts +++ b/packages/examples/core/di/ts/viewChildren/module.ts @@ -18,3 +18,5 @@ import {Pane, ViewChildrenComp} from './view_children_example'; }) export class AppModule { } + +export {ViewChildrenComp as AppComponent}; diff --git a/packages/examples/core/main.ts b/packages/examples/core/main.ts new file mode 100644 index 0000000000..b5ec0fb33e --- /dev/null +++ b/packages/examples/core/main.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; +import {TestsAppModuleNgFactory} from './test_module.ngfactory'; + +platformBrowserDynamic().bootstrapModuleFactory(TestsAppModuleNgFactory); diff --git a/packages/examples/core/start-server.js b/packages/examples/core/start-server.js new file mode 100644 index 0000000000..e7d432281a --- /dev/null +++ b/packages/examples/core/start-server.js @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const protractorUtils = require('@angular/bazel/protractor-utils'); +const protractor = require('protractor'); + +module.exports = async function(config) { + const {port} = await protractorUtils.runServer(config.workspace, config.server, '-port', []); + const serverUrl = `http://localhost:${port}`; + + protractor.browser.baseUrl = serverUrl; +}; diff --git a/packages/examples/core/test_module.ts b/packages/examples/core/test_module.ts new file mode 100644 index 0000000000..933ed95b81 --- /dev/null +++ b/packages/examples/core/test_module.ts @@ -0,0 +1,44 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, NgModule} from '@angular/core'; +import {RouterModule} from '@angular/router'; + +import * as animationDslExample from './animation/ts/dsl/module'; +import * as diContentChildExample from './di/ts/contentChild/module'; +import * as diContentChildrenExample from './di/ts/contentChildren/module'; +import * as diViewChildExample from './di/ts/viewChild/module'; +import * as diViewChildrenExample from './di/ts/viewChildren/module'; +import * as testabilityWhenStableExample from './testability/ts/whenStable/module'; + +@Component({selector: 'example-app', template: ''}) +export class TestsAppComponent { +} + +@NgModule({ + imports: [ + animationDslExample.AppModule, diContentChildExample.AppModule, + diContentChildrenExample.AppModule, diViewChildExample.AppModule, + diViewChildrenExample.AppModule, testabilityWhenStableExample.AppModule, + + // Router configuration so that the individual e2e tests can load their + // app components. + RouterModule.forRoot([ + {path: 'animation/dsl', component: animationDslExample.AppComponent}, + {path: 'di/contentChild', component: diContentChildExample.AppComponent}, + {path: 'di/contentChildren', component: diContentChildrenExample.AppComponent}, + {path: 'di/viewChild', component: diViewChildExample.AppComponent}, + {path: 'di/viewChildren', component: diViewChildrenExample.AppComponent}, + {path: 'testability/whenStable', component: testabilityWhenStableExample.AppComponent}, + ]) + ], + declarations: [TestsAppComponent], + bootstrap: [TestsAppComponent] +}) +export class TestsAppModule { +} diff --git a/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts b/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts index 544914552b..9ffc27a774 100644 --- a/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts +++ b/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts @@ -7,13 +7,19 @@ */ import {browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; + +// Declare the global "window" and "document" constant since we don't want to add the "dom" +// TypeScript lib for the e2e specs that execute code in the browser and reference such +// global constants. +declare const window: any; +declare const document: any; describe('testability example', () => { afterEach(verifyNoBrowserErrors); describe('using task tracking', () => { - const URL = '/core/testability/ts/whenStable/'; + const URL = '/testability/whenStable/'; it('times out with a list of tasks', done => { browser.get(URL); @@ -22,7 +28,7 @@ describe('testability example', () => { // Script that runs in the browser and calls whenStable with a timeout. let waitWithResultScript = function(done: any) { let rootEl = document.querySelector('example-app'); - let testability = (window as any).getAngularTestability(rootEl); + let testability = window.getAngularTestability(rootEl); testability.whenStable((didWork: boolean, tasks: any) => { done(tasks); }, 1000); }; diff --git a/packages/examples/core/testability/ts/whenStable/module.ts b/packages/examples/core/testability/ts/whenStable/module.ts index a8f49caec7..51fe049302 100644 --- a/packages/examples/core/testability/ts/whenStable/module.ts +++ b/packages/examples/core/testability/ts/whenStable/module.ts @@ -5,4 +5,4 @@ * 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 */ -export {AppModule} from './testability_example'; +export {AppModule, StableTestCmp as AppComponent} from './testability_example'; diff --git a/packages/examples/core/testing/ts/BUILD.bazel b/packages/examples/core/testing/ts/BUILD.bazel new file mode 100644 index 0000000000..2fe7a63b68 --- /dev/null +++ b/packages/examples/core/testing/ts/BUILD.bazel @@ -0,0 +1,23 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +ts_library( + name = "fake_async_lib", + srcs = [ + "example_spec.ts", + "fake_async.ts", + ], + deps = [ + "//packages/core/testing", + "@ngdeps//@types/jasmine", + "@ngdeps//@types/node", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["angular/tools/testing/init_node_spec.js"], + deps = [ + ":fake_async_lib", + "//tools/testing:node", + ], +) diff --git a/packages/examples/core/testing/ts/example_spec.ts b/packages/examples/core/testing/ts/example_spec.ts new file mode 100644 index 0000000000..880c5f975a --- /dev/null +++ b/packages/examples/core/testing/ts/example_spec.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// Import the "fake_async" example that registers tests which are shown as examples. These need +// to be valid tests, so we run them here. Note that we need to add this layer of abstraction here +// because the "jasmine_node_test" rule only picks up test files with the "_spec.ts" file suffix. +import './fake_async'; diff --git a/packages/examples/core/ts/metadata/directives.ts b/packages/examples/core/ts/metadata/directives.ts index d1fa0b28aa..49aa0ea6b1 100644 --- a/packages/examples/core/ts/metadata/directives.ts +++ b/packages/examples/core/ts/metadata/directives.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ /* tslint:disable:no-console */ -import {Component, Directive, EventEmitter} from '@angular/core'; +import {Component, Directive, EventEmitter, NgModule} from '@angular/core'; // #docregion component-input @Component({ @@ -63,4 +63,10 @@ export class MyOutputComponent { onEverySecond() { console.log('second'); } onEveryFiveSeconds() { console.log('five seconds'); } } -// #enddocregion component-output-interval \ No newline at end of file +// #enddocregion component-output-interval + +@NgModule({ + declarations: [BankAccountComponent, MyInputComponent, IntervalDirComponent, MyOutputComponent] +}) +export class AppModule { +} diff --git a/packages/examples/core/ts/prod_mode/prod_mode_example.ts b/packages/examples/core/ts/prod_mode/prod_mode_example.ts index 4dcb7a55e2..34cc039b4e 100644 --- a/packages/examples/core/ts/prod_mode/prod_mode_example.ts +++ b/packages/examples/core/ts/prod_mode/prod_mode_example.ts @@ -13,8 +13,10 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {MyComponent} from './my_component'; enableProdMode(); -@NgModule({imports: [BrowserModule], bootstrap: [MyComponent]}) -class AppModule { + +@NgModule({imports: [BrowserModule], declarations: [MyComponent], bootstrap: [MyComponent]}) +export class AppModule { } + platformBrowserDynamic().bootstrapModule(AppModule); // #enddocregion diff --git a/packages/examples/forms/BUILD.bazel b/packages/examples/forms/BUILD.bazel new file mode 100644 index 0000000000..3b82221b41 --- /dev/null +++ b/packages/examples/forms/BUILD.bazel @@ -0,0 +1,59 @@ +package(default_visibility = ["//visibility:public"]) + +load("//packages/bazel:index.bzl", "protractor_web_test_suite") +load("//tools:defaults.bzl", "ng_module", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +ng_module( + name = "forms_examples", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*_spec.ts"], + ), + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "//packages/core", + "//packages/forms", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + "//packages/router", + ], +) + +ts_library( + name = "forms_e2e_tests_lib", + testonly = True, + srcs = glob(["**/e2e_test/*_spec.ts"]), + tsconfig = "//packages/examples:tsconfig-e2e.json", + deps = [ + "//packages/examples/test-utils", + "//packages/private/testing", + "@ngdeps//@types/jasminewd2", + "@ngdeps//protractor", + ], +) + +ts_devserver( + name = "devserver", + entry_module = "@angular/examples/forms/main", + index_html = "//packages/examples:index.html", + port = 4200, + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + ], + deps = [":forms_examples"], +) + +protractor_web_test_suite( + name = "protractor_tests", + data = ["//packages/bazel/src/protractor/utils"], + on_prepare = ":start-server.js", + server = ":devserver", + deps = [ + ":forms_e2e_tests_lib", + "@ngdeps//protractor", + "@ngdeps//selenium-webdriver", + ], +) diff --git a/packages/examples/forms/main.ts b/packages/examples/forms/main.ts new file mode 100644 index 0000000000..b5ec0fb33e --- /dev/null +++ b/packages/examples/forms/main.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; +import {TestsAppModuleNgFactory} from './test_module.ngfactory'; + +platformBrowserDynamic().bootstrapModuleFactory(TestsAppModuleNgFactory); diff --git a/packages/examples/forms/start-server.js b/packages/examples/forms/start-server.js new file mode 100644 index 0000000000..e7d432281a --- /dev/null +++ b/packages/examples/forms/start-server.js @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const protractorUtils = require('@angular/bazel/protractor-utils'); +const protractor = require('protractor'); + +module.exports = async function(config) { + const {port} = await protractorUtils.runServer(config.workspace, config.server, '-port', []); + const serverUrl = `http://localhost:${port}`; + + protractor.browser.baseUrl = serverUrl; +}; diff --git a/packages/examples/forms/test_module.ts b/packages/examples/forms/test_module.ts new file mode 100644 index 0000000000..95d02990f2 --- /dev/null +++ b/packages/examples/forms/test_module.ts @@ -0,0 +1,58 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, NgModule} from '@angular/core'; +import {RouterModule} from '@angular/router'; + +import * as formBuilderExample from './ts/formBuilder/module'; +import * as nestedFormArrayExample from './ts/nestedFormArray/module'; +import * as nestedFormGroupExample from './ts/nestedFormGroup/module'; +import * as ngModelGroupExample from './ts/ngModelGroup/module'; +import * as radioButtonsExample from './ts/radioButtons/module'; +import * as reactiveRadioButtonsExample from './ts/reactiveRadioButtons/module'; +import * as reactiveSelectControlExample from './ts/reactiveSelectControl/module'; +import * as selectControlExample from './ts/selectControl/module'; +import * as simpleFormExample from './ts/simpleForm/module'; +import * as simpleFormControlExample from './ts/simpleFormControl/module'; +import * as simpleFormGroupExample from './ts/simpleFormGroup/module'; +import * as simpleNgModelExample from './ts/simpleNgModel/module'; + +@Component({selector: 'example-app', template: ''}) +export class TestsAppComponent { +} + +@NgModule({ + imports: [ + formBuilderExample.AppModule, nestedFormArrayExample.AppModule, + nestedFormGroupExample.AppModule, ngModelGroupExample.AppModule, radioButtonsExample.AppModule, + reactiveRadioButtonsExample.AppModule, reactiveSelectControlExample.AppModule, + selectControlExample.AppModule, simpleFormExample.AppModule, simpleFormControlExample.AppModule, + simpleFormGroupExample.AppModule, simpleNgModelExample.AppModule, + + // Router configuration so that the individual e2e tests can load their + // app components. + RouterModule.forRoot([ + {path: 'formBuilder', component: formBuilderExample.AppComponent}, + {path: 'nestedFormArray', component: nestedFormArrayExample.AppComponent}, + {path: 'nestedFormGroup', component: nestedFormGroupExample.AppComponent}, + {path: 'ngModelGroup', component: ngModelGroupExample.AppComponent}, + {path: 'radioButtons', component: radioButtonsExample.AppComponent}, + {path: 'reactiveRadioButtons', component: reactiveRadioButtonsExample.AppComponent}, + {path: 'reactiveSelectControl', component: reactiveSelectControlExample.AppComponent}, + {path: 'selectControl', component: selectControlExample.AppComponent}, + {path: 'simpleForm', component: simpleFormExample.AppComponent}, + {path: 'simpleFormControl', component: simpleFormControlExample.AppComponent}, + {path: 'simpleFormGroup', component: simpleFormGroupExample.AppComponent}, + {path: 'simpleNgModel', component: simpleNgModelExample.AppComponent} + ]) + ], + declarations: [TestsAppComponent], + bootstrap: [TestsAppComponent] +}) +export class TestsAppModule { +} diff --git a/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts b/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts index 55d4a43a55..03c964d0c6 100644 --- a/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts +++ b/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts @@ -7,7 +7,7 @@ */ import {ElementArrayFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('formBuilder example', () => { afterEach(verifyNoBrowserErrors); @@ -15,7 +15,7 @@ describe('formBuilder example', () => { let paragraphs: ElementArrayFinder; beforeEach(() => { - browser.get('/forms/ts/formBuilder/index.html'); + browser.get('/formBuilder'); inputs = element.all(by.css('input')); paragraphs = element.all(by.css('p')); }); diff --git a/packages/examples/forms/ts/formBuilder/module.ts b/packages/examples/forms/ts/formBuilder/module.ts index d34292d1d3..7e94ea650a 100644 --- a/packages/examples/forms/ts/formBuilder/module.ts +++ b/packages/examples/forms/ts/formBuilder/module.ts @@ -9,12 +9,14 @@ import {NgModule} from '@angular/core'; import {ReactiveFormsModule} from '@angular/forms'; import {BrowserModule} from '@angular/platform-browser'; -import {FormBuilderComp} from './form_builder_example'; +import {DisabledFormControlComponent, FormBuilderComp} from './form_builder_example'; @NgModule({ imports: [BrowserModule, ReactiveFormsModule], - declarations: [FormBuilderComp], + declarations: [FormBuilderComp, DisabledFormControlComponent], bootstrap: [FormBuilderComp] }) export class AppModule { } + +export {FormBuilderComp as AppComponent}; diff --git a/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts b/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts index e594b27290..9baaac992c 100644 --- a/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts +++ b/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts @@ -7,7 +7,7 @@ */ import {ElementArrayFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('nestedFormArray example', () => { afterEach(verifyNoBrowserErrors); @@ -15,7 +15,7 @@ describe('nestedFormArray example', () => { let buttons: ElementArrayFinder; beforeEach(() => { - browser.get('/forms/ts/nestedFormArray/index.html'); + browser.get('/nestedFormArray'); inputs = element.all(by.css('input')); buttons = element.all(by.css('button')); }); diff --git a/packages/examples/forms/ts/nestedFormArray/module.ts b/packages/examples/forms/ts/nestedFormArray/module.ts index eb2478a6e4..0d1d9b2f61 100644 --- a/packages/examples/forms/ts/nestedFormArray/module.ts +++ b/packages/examples/forms/ts/nestedFormArray/module.ts @@ -18,3 +18,5 @@ import {NestedFormArray} from './nested_form_array_example'; }) export class AppModule { } + +export {NestedFormArray as AppComponent}; diff --git a/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts b/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts index 6de78dfe09..a3fb76047c 100644 --- a/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts +++ b/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts @@ -7,7 +7,7 @@ */ import {ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('nestedFormGroup example', () => { afterEach(verifyNoBrowserErrors); @@ -16,7 +16,7 @@ describe('nestedFormGroup example', () => { let button: ElementFinder; beforeEach(() => { - browser.get('/forms/ts/nestedFormGroup/index.html'); + browser.get('/nestedFormGroup'); firstInput = element(by.css('[formControlName="first"]')); lastInput = element(by.css('[formControlName="last"]')); button = element(by.css('button:not([type="submit"])')); diff --git a/packages/examples/forms/ts/nestedFormGroup/module.ts b/packages/examples/forms/ts/nestedFormGroup/module.ts index 5773d5281f..0d5503f1ae 100644 --- a/packages/examples/forms/ts/nestedFormGroup/module.ts +++ b/packages/examples/forms/ts/nestedFormGroup/module.ts @@ -18,3 +18,5 @@ import {NestedFormGroupComp} from './nested_form_group_example'; }) export class AppModule { } + +export {NestedFormGroupComp as AppComponent}; diff --git a/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts b/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts index 176a4eb8ae..6d700e69ee 100644 --- a/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts +++ b/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts @@ -7,7 +7,7 @@ */ import {ElementArrayFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('ngModelGroup example', () => { afterEach(verifyNoBrowserErrors); @@ -15,7 +15,7 @@ describe('ngModelGroup example', () => { let buttons: ElementArrayFinder; beforeEach(() => { - browser.get('/forms/ts/ngModelGroup/index.html'); + browser.get('/ngModelGroup'); inputs = element.all(by.css('input')); buttons = element.all(by.css('button')); }); diff --git a/packages/examples/forms/ts/ngModelGroup/module.ts b/packages/examples/forms/ts/ngModelGroup/module.ts index ce06883c67..692f6edb46 100644 --- a/packages/examples/forms/ts/ngModelGroup/module.ts +++ b/packages/examples/forms/ts/ngModelGroup/module.ts @@ -18,3 +18,5 @@ import {NgModelGroupComp} from './ng_model_group_example'; }) export class AppModule { } + +export {NgModelGroupComp as AppComponent}; diff --git a/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts b/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts index 04b0ddd715..56f668ec14 100644 --- a/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts +++ b/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts @@ -7,7 +7,7 @@ */ import {ElementArrayFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('radioButtons example', () => { afterEach(verifyNoBrowserErrors); @@ -15,7 +15,7 @@ describe('radioButtons example', () => { let paragraphs: ElementArrayFinder; beforeEach(() => { - browser.get('/forms/ts/radioButtons/index.html'); + browser.get('/radioButtons'); inputs = element.all(by.css('input')); paragraphs = element.all(by.css('p')); }); diff --git a/packages/examples/forms/ts/radioButtons/module.ts b/packages/examples/forms/ts/radioButtons/module.ts index 6a8151e88e..4a146db88f 100644 --- a/packages/examples/forms/ts/radioButtons/module.ts +++ b/packages/examples/forms/ts/radioButtons/module.ts @@ -18,3 +18,5 @@ import {RadioButtonComp} from './radio_button_example'; }) export class AppModule { } + +export {RadioButtonComp as AppComponent}; diff --git a/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts b/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts index d4286d5199..4b23a8ffd5 100644 --- a/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts +++ b/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts @@ -7,14 +7,14 @@ */ import {ElementArrayFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('radioButtons example', () => { afterEach(verifyNoBrowserErrors); let inputs: ElementArrayFinder; beforeEach(() => { - browser.get('/forms/ts/reactiveRadioButtons/index.html'); + browser.get('/reactiveRadioButtons'); inputs = element.all(by.css('input')); }); diff --git a/packages/examples/forms/ts/reactiveRadioButtons/module.ts b/packages/examples/forms/ts/reactiveRadioButtons/module.ts index 17f67b430b..acf2040f9e 100644 --- a/packages/examples/forms/ts/reactiveRadioButtons/module.ts +++ b/packages/examples/forms/ts/reactiveRadioButtons/module.ts @@ -18,3 +18,5 @@ import {ReactiveRadioButtonComp} from './reactive_radio_button_example'; }) export class AppModule { } + +export {ReactiveRadioButtonComp as AppComponent}; diff --git a/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts b/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts index 5d2b338804..1da4d5eff0 100644 --- a/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts +++ b/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts @@ -7,7 +7,7 @@ */ import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('reactiveSelectControl example', () => { afterEach(verifyNoBrowserErrors); @@ -16,7 +16,7 @@ describe('reactiveSelectControl example', () => { let p: ElementFinder; beforeEach(() => { - browser.get('/forms/ts/reactiveSelectControl/index.html'); + browser.get('/reactiveSelectControl'); select = element(by.css('select')); options = element.all(by.css('option')); p = element(by.css('p')); diff --git a/packages/examples/forms/ts/reactiveSelectControl/module.ts b/packages/examples/forms/ts/reactiveSelectControl/module.ts index 47c53b3fe7..eace263e9b 100644 --- a/packages/examples/forms/ts/reactiveSelectControl/module.ts +++ b/packages/examples/forms/ts/reactiveSelectControl/module.ts @@ -18,3 +18,5 @@ import {ReactiveSelectComp} from './reactive_select_control_example'; }) export class AppModule { } + +export {ReactiveSelectComp as AppComponent}; diff --git a/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts b/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts index f79efa27bb..2fbbc22fd3 100644 --- a/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts +++ b/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts @@ -7,7 +7,7 @@ */ import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('selectControl example', () => { afterEach(verifyNoBrowserErrors); @@ -16,7 +16,7 @@ describe('selectControl example', () => { let p: ElementFinder; beforeEach(() => { - browser.get('/forms/ts/selectControl/index.html'); + browser.get('/selectControl'); select = element(by.css('select')); options = element.all(by.css('option')); p = element(by.css('p')); diff --git a/packages/examples/forms/ts/selectControl/module.ts b/packages/examples/forms/ts/selectControl/module.ts index f2adc86335..722f3baf43 100644 --- a/packages/examples/forms/ts/selectControl/module.ts +++ b/packages/examples/forms/ts/selectControl/module.ts @@ -18,3 +18,5 @@ import {SelectControlComp} from './select_control_example'; }) export class AppModule { } + +export {SelectControlComp as AppComponent}; diff --git a/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts b/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts index 6f176ca56a..0588a5882d 100644 --- a/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts +++ b/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts @@ -7,7 +7,7 @@ */ import {ElementArrayFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('simpleForm example', () => { afterEach(verifyNoBrowserErrors); @@ -15,7 +15,7 @@ describe('simpleForm example', () => { let paragraphs: ElementArrayFinder; beforeEach(() => { - browser.get('/forms/ts/simpleForm/index.html'); + browser.get('/simpleForm'); inputs = element.all(by.css('input')); paragraphs = element.all(by.css('p')); }); diff --git a/packages/examples/forms/ts/simpleForm/module.ts b/packages/examples/forms/ts/simpleForm/module.ts index 12037114e4..5b004e6ffe 100644 --- a/packages/examples/forms/ts/simpleForm/module.ts +++ b/packages/examples/forms/ts/simpleForm/module.ts @@ -18,3 +18,5 @@ import {SimpleFormComp} from './simple_form_example'; }) export class AppModule { } + +export {SimpleFormComp as AppComponent}; diff --git a/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts b/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts index 5436952a63..810064705c 100644 --- a/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts +++ b/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts @@ -7,7 +7,7 @@ */ import {ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('simpleFormControl example', () => { afterEach(verifyNoBrowserErrors); @@ -18,7 +18,7 @@ describe('simpleFormControl example', () => { let statusP: ElementFinder; beforeEach(() => { - browser.get('/forms/ts/simpleFormControl/index.html'); + browser.get('/simpleFormControl'); input = element(by.css('input')); valueP = element(by.css('p:first-of-type')); statusP = element(by.css('p:last-of-type')); diff --git a/packages/examples/forms/ts/simpleFormControl/module.ts b/packages/examples/forms/ts/simpleFormControl/module.ts index a16a1f4369..860756856e 100644 --- a/packages/examples/forms/ts/simpleFormControl/module.ts +++ b/packages/examples/forms/ts/simpleFormControl/module.ts @@ -18,3 +18,5 @@ import {SimpleFormControl} from './simple_form_control_example'; }) export class AppModule { } + +export {SimpleFormControl as AppComponent}; diff --git a/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts b/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts index 5e2b3c8fdf..76fdf8e7c6 100644 --- a/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts +++ b/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts @@ -7,7 +7,7 @@ */ import {ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('formControlName example', () => { afterEach(verifyNoBrowserErrors); @@ -17,7 +17,7 @@ describe('formControlName example', () => { let lastInput: ElementFinder; beforeEach(() => { - browser.get('/forms/ts/simpleFormGroup/index.html'); + browser.get('/simpleFormGroup'); firstInput = element(by.css('[formControlName="first"]')); lastInput = element(by.css('[formControlName="last"]')); }); diff --git a/packages/examples/forms/ts/simpleFormGroup/module.ts b/packages/examples/forms/ts/simpleFormGroup/module.ts index cbafcdd503..e5749d0d56 100644 --- a/packages/examples/forms/ts/simpleFormGroup/module.ts +++ b/packages/examples/forms/ts/simpleFormGroup/module.ts @@ -18,3 +18,5 @@ import {SimpleFormGroup} from './simple_form_group_example'; }) export class AppModule { } + +export {SimpleFormGroup as AppComponent}; diff --git a/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts b/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts index a54faabaa2..1036b9161a 100644 --- a/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts +++ b/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts @@ -6,40 +6,43 @@ * found in the LICENSE file at https://angular.io/license */ +import {fixmeIvy} from '@angular/private/testing'; import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; -describe('simpleNgModel example', () => { - afterEach(verifyNoBrowserErrors); - let input: ElementFinder; - let paragraphs: ElementArrayFinder; - let button: ElementFinder; +import {verifyNoBrowserErrors} from '../../../../test-utils'; - beforeEach(() => { - browser.get('/forms/ts/simpleNgModel/index.html'); - input = element(by.css('input')); - paragraphs = element.all(by.css('p')); - button = element(by.css('button')); - }); +fixmeIvy('FW-1051: Directives are updated after the execution of the template function') + .describe('simpleNgModel example', () => { + afterEach(verifyNoBrowserErrors); + let input: ElementFinder; + let paragraphs: ElementArrayFinder; + let button: ElementFinder; - it('should update the domain model as you type', () => { - input.click(); - input.sendKeys('Carson'); + beforeEach(() => { + browser.get('/simpleNgModel'); + input = element(by.css('input')); + paragraphs = element.all(by.css('p')); + button = element(by.css('button')); + }); - expect(paragraphs.get(0).getText()).toEqual('Value: Carson'); - }); + it('should update the domain model as you type', () => { + input.click(); + input.sendKeys('Carson'); - it('should report the validity correctly', () => { - expect(paragraphs.get(1).getText()).toEqual('Valid: false'); - input.click(); - input.sendKeys('a'); + expect(paragraphs.get(0).getText()).toEqual('Value: Carson'); + }); - expect(paragraphs.get(1).getText()).toEqual('Valid: true'); - }); + it('should report the validity correctly', () => { + expect(paragraphs.get(1).getText()).toEqual('Valid: false'); + input.click(); + input.sendKeys('a'); - it('should set the value by changing the domain model', () => { - button.click(); - expect(input.getAttribute('value')).toEqual('Nancy'); - }); + expect(paragraphs.get(1).getText()).toEqual('Valid: true'); + }); -}); + it('should set the value by changing the domain model', () => { + button.click(); + expect(input.getAttribute('value')).toEqual('Nancy'); + }); + + }); diff --git a/packages/examples/forms/ts/simpleNgModel/module.ts b/packages/examples/forms/ts/simpleNgModel/module.ts index 9f0872c544..86e1e7d726 100644 --- a/packages/examples/forms/ts/simpleNgModel/module.ts +++ b/packages/examples/forms/ts/simpleNgModel/module.ts @@ -18,3 +18,5 @@ import {SimpleNgModelComp} from './simple_ng_model_example'; }) export class AppModule { } + +export {SimpleNgModelComp as AppComponent}; diff --git a/packages/examples/http/BUILD.bazel b/packages/examples/http/BUILD.bazel new file mode 100644 index 0000000000..ffd0fb0cdc --- /dev/null +++ b/packages/examples/http/BUILD.bazel @@ -0,0 +1 @@ +package(default_visibility = ["//visibility:public"]) diff --git a/packages/examples/index.html b/packages/examples/index.html new file mode 100644 index 0000000000..7f405e44b9 --- /dev/null +++ b/packages/examples/index.html @@ -0,0 +1,15 @@ + + + + + Angular Examples + + + + + + + Loading... + + diff --git a/packages/examples/platform-browser/BUILD.bazel b/packages/examples/platform-browser/BUILD.bazel new file mode 100644 index 0000000000..9298acbc99 --- /dev/null +++ b/packages/examples/platform-browser/BUILD.bazel @@ -0,0 +1,14 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ng_module") + +ng_module( + name = "platform_browser_examples", + srcs = glob(["**/*.ts"]), + deps = [ + "//packages/compiler", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + ], +) diff --git a/packages/examples/platform-browser/dom/debug/ts/debug_element_view_listener/providers.ts b/packages/examples/platform-browser/dom/debug/ts/debug_element_view_listener/providers.ts index 0e47ad0b6f..1e4c53dea6 100644 --- a/packages/examples/platform-browser/dom/debug/ts/debug_element_view_listener/providers.ts +++ b/packages/examples/platform-browser/dom/debug/ts/debug_element_view_listener/providers.ts @@ -11,7 +11,7 @@ import {Component, NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -@Component({selector: 'my-component'}) +@Component({selector: 'my-component', template: 'text'}) class MyAppComponent { } diff --git a/packages/examples/test-utils/BUILD.bazel b/packages/examples/test-utils/BUILD.bazel new file mode 100644 index 0000000000..be2496ecae --- /dev/null +++ b/packages/examples/test-utils/BUILD.bazel @@ -0,0 +1,11 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "test-utils", + srcs = ["index.ts"], + deps = [ + "@ngdeps//@types/selenium-webdriver", + ], +) diff --git a/packages/examples/test-utils/index.ts b/packages/examples/test-utils/index.ts new file mode 100644 index 0000000000..4bf0dd2b5d --- /dev/null +++ b/packages/examples/test-utils/index.ts @@ -0,0 +1,43 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/* tslint:disable:no-console */ +import {WebDriver, logging} from 'selenium-webdriver'; + +declare var browser: WebDriver; +declare var expect: any; + +// TODO (juliemr): remove this method once this becomes a protractor plugin +export async function verifyNoBrowserErrors() { + const browserLog = await browser.manage().logs().get('browser'); + const collectedErrors: any[] = []; + + browserLog.forEach(logEntry => { + const msg = logEntry.message; + + // Since we currently use the `ts_devserver` from the Bazel TypeScript rules, which does + // fallback to the "index.html" file for HTML5 pushState routing but does always serve the + // expected fallback with a 404 status code, the browser will print a message about the 404, + // while the page loaded properly. Ideally the "ts_devserver" would allow us to opt-in for + // just returning a 200 status code, but the devserver is intended to be kept manually, so + // we manually filter this error before ensuring there are no console errors. + // TODO: This is a current limitation of using the "ts_devserver" with Angular routing. + // Tracked with: TOOL-629 + if (msg.includes( + `Failed to load resource: the server responded with a status of 404 (Not Found)`)) { + return; + } + + console.log('>> ' + msg, logEntry); + + if (logEntry.level.value >= logging.Level.INFO.value) { + collectedErrors.push(msg); + } + }); + + expect(collectedErrors).toEqual([]); +} diff --git a/packages/examples/test.sh b/packages/examples/test.sh deleted file mode 100755 index c8827305a8..0000000000 --- a/packages/examples/test.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -( - cd `dirname $0` - ./build.sh - - gulp serve-examples & - trap "kill $!" EXIT - - ( - cd ../../ - NODE_PATH=${NODE_PATH:-}:dist/all - $(npm bin)/protractor protractor-examples-e2e.conf.js --bundles=true - ) -) diff --git a/packages/examples/testing/BUILD.bazel b/packages/examples/testing/BUILD.bazel new file mode 100644 index 0000000000..c8c586c77d --- /dev/null +++ b/packages/examples/testing/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "testing_examples", + srcs = glob(["**/*.ts"]), + tsconfig = "//packages:tsconfig-test.json", + deps = [ + "@ngdeps//@types/jasmine", + "@ngdeps//@types/node", + ], +) diff --git a/packages/examples/tsconfig-build.json b/packages/examples/tsconfig-build.json deleted file mode 100644 index b2ca2c29c3..0000000000 --- a/packages/examples/tsconfig-build.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../tsconfig-build.json", - - "compilerOptions": { - "module": "commonjs", - "emitDecoratorMetadata": true, - "baseUrl": ".", - "rootDir": ".", - "paths": { - "@angular/*": ["../../dist/packages-dist/*"], - "rxjs/*": ["../../node_modules/rxjs/*"] - }, - "outDir": "../../dist/examples", - "types": ["angular"] - }, - - "include": [ - "../../node_modules/@types/jasminewd2/index.d.ts", - "../types.d.ts", - "**/*.ts" - ] -} diff --git a/packages/examples/tsconfig-e2e.json b/packages/examples/tsconfig-e2e.json new file mode 100644 index 0000000000..ed38112bb4 --- /dev/null +++ b/packages/examples/tsconfig-e2e.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["es2015"], + "types": ["node", "jasminewd2"] + } +} diff --git a/packages/examples/tsconfig.json b/packages/examples/tsconfig.json deleted file mode 100644 index c13db98f55..0000000000 --- a/packages/examples/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -// WARNING: -// This file is used to build the e2e tests only. -// The rest of the files are included in `/packages/tsconfig.json`. -{ - "extends": "../tsconfig.json", - - "compilerOptions": { - "types": [] - }, - - "include": [ - "../../node_modules/@types/jasminewd2/index.d.ts", - "../types.d.ts", - "**/e2e_test/*" - ], - - "exclude": [] -} diff --git a/packages/examples/upgrade/BUILD.bazel b/packages/examples/upgrade/BUILD.bazel new file mode 100644 index 0000000000..ae7cd15682 --- /dev/null +++ b/packages/examples/upgrade/BUILD.bazel @@ -0,0 +1,4 @@ +exports_files([ + "tsconfig-build.json", + "start-server.js", +]) diff --git a/packages/examples/upgrade/start-server.js b/packages/examples/upgrade/start-server.js new file mode 100644 index 0000000000..e7d432281a --- /dev/null +++ b/packages/examples/upgrade/start-server.js @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const protractorUtils = require('@angular/bazel/protractor-utils'); +const protractor = require('protractor'); + +module.exports = async function(config) { + const {port} = await protractorUtils.runServer(config.workspace, config.server, '-port', []); + const serverUrl = `http://localhost:${port}`; + + protractor.browser.baseUrl = serverUrl; +}; diff --git a/packages/examples/upgrade/static/ts/full/BUILD.bazel b/packages/examples/upgrade/static/ts/full/BUILD.bazel new file mode 100644 index 0000000000..0e1d6defb8 --- /dev/null +++ b/packages/examples/upgrade/static/ts/full/BUILD.bazel @@ -0,0 +1,14 @@ +package(default_visibility = ["//visibility:public"]) + +load("//packages/examples/upgrade:upgrade_example.bzl", "create_upgrade_example_targets") + +create_upgrade_example_targets( + name = "full", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*_spec.ts"], + ), + assets = ["styles.css"], + e2e_srcs = glob(["e2e_test/*_spec.ts"]), + entry_module = "@angular/examples/upgrade/static/ts/full/module", +) diff --git a/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts b/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts index d941609740..442802edd7 100644 --- a/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts +++ b/packages/examples/upgrade/static/ts/full/e2e_test/static_full_spec.ts @@ -7,11 +7,11 @@ */ import {browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; function loadPage() { browser.rootEl = 'example-app'; - browser.get('/upgrade/static/ts/full/'); + browser.get('/'); } describe('upgrade/static (full)', () => { diff --git a/packages/examples/upgrade/static/ts/lite-multi-shared/BUILD.bazel b/packages/examples/upgrade/static/ts/lite-multi-shared/BUILD.bazel new file mode 100644 index 0000000000..63f5064b7c --- /dev/null +++ b/packages/examples/upgrade/static/ts/lite-multi-shared/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +load("//packages/examples/upgrade:upgrade_example.bzl", "create_upgrade_example_targets") + +create_upgrade_example_targets( + name = "lite-multi-shared", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*_spec.ts"], + ), + e2e_srcs = glob(["e2e_test/*_spec.ts"]), + entry_module = "@angular/examples/upgrade/static/ts/lite-multi-shared/module", +) diff --git a/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts b/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts index 8ddefcfae6..9a7c6e45d2 100644 --- a/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts +++ b/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts @@ -8,7 +8,7 @@ import {browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('upgrade/static (lite with multiple downgraded modules and shared root module)', () => { @@ -16,7 +16,7 @@ describe('upgrade/static (lite with multiple downgraded modules and shared root const compB = element(by.css('ng2-b')); const compC = element(by.css('ng2-c')); - beforeEach(() => browser.get('/upgrade/static/ts/lite-multi-shared/')); + beforeEach(() => browser.get('/')); afterEach(verifyNoBrowserErrors); it('should share the same injectable instance across downgraded modules A and B', () => { diff --git a/packages/examples/upgrade/static/ts/lite-multi/BUILD.bazel b/packages/examples/upgrade/static/ts/lite-multi/BUILD.bazel new file mode 100644 index 0000000000..b1e71833a5 --- /dev/null +++ b/packages/examples/upgrade/static/ts/lite-multi/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +load("//packages/examples/upgrade:upgrade_example.bzl", "create_upgrade_example_targets") + +create_upgrade_example_targets( + name = "lite-multi", + srcs = glob( + ["**/*.ts"], + exclude = ["**/*_spec.ts"], + ), + e2e_srcs = glob(["e2e_test/*_spec.ts"]), + entry_module = "@angular/examples/upgrade/static/ts/lite-multi/module", +) diff --git a/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts b/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts index 3a4d571243..2b9c846b74 100644 --- a/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts +++ b/packages/examples/upgrade/static/ts/lite-multi/e2e_test/static_lite_multi_spec.ts @@ -8,14 +8,14 @@ import {browser, by, element} from 'protractor'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('upgrade/static (lite with multiple downgraded modules)', () => { const navButtons = element.all(by.css('nav button')); const mainContent = element(by.css('main')); - beforeEach(() => browser.get('/upgrade/static/ts/lite-multi/')); + beforeEach(() => browser.get('/')); afterEach(verifyNoBrowserErrors); it('should correctly bootstrap multiple downgraded modules', () => { diff --git a/packages/examples/upgrade/static/ts/lite/BUILD.bazel b/packages/examples/upgrade/static/ts/lite/BUILD.bazel new file mode 100644 index 0000000000..910574f326 --- /dev/null +++ b/packages/examples/upgrade/static/ts/lite/BUILD.bazel @@ -0,0 +1,14 @@ +package(default_visibility = ["//visibility:public"]) + +load("//packages/examples/upgrade:upgrade_example.bzl", "create_upgrade_example_targets") + +create_upgrade_example_targets( + name = "lite", + srcs = glob( + ["**/*.ts"], + exclude = ["e2e_test/*"], + ), + assets = ["styles.css"], + e2e_srcs = glob(["e2e_test/*.ts"]), + entry_module = "@angular/examples/upgrade/static/ts/lite/module", +) diff --git a/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts b/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts index 5e7b6395ef..61bf67d64e 100644 --- a/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts +++ b/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts @@ -7,13 +7,13 @@ */ import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../../../test-utils'; -import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util'; import {addCustomMatchers} from './e2e_util'; function loadPage() { browser.rootEl = 'example-app'; - browser.get('/upgrade/static/ts/lite/'); + browser.get('/'); } describe('upgrade/static (lite)', () => { diff --git a/packages/examples/upgrade/tsconfig-build.json b/packages/examples/upgrade/tsconfig-build.json new file mode 100644 index 0000000000..70ccf09202 --- /dev/null +++ b/packages/examples/upgrade/tsconfig-build.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["dom", "es2015"], + "types": ["angular"] + } +} diff --git a/packages/examples/upgrade/upgrade_example.bzl b/packages/examples/upgrade/upgrade_example.bzl new file mode 100644 index 0000000000..3934e0cad8 --- /dev/null +++ b/packages/examples/upgrade/upgrade_example.bzl @@ -0,0 +1,66 @@ +load("//packages/bazel:index.bzl", "protractor_web_test_suite") +load("//tools:defaults.bzl", "ng_module", "ts_library") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +""" + Macro that can be used to create the Bazel targets for an "upgrade" example. Since the + upgrade examples bootstrap their application manually, and we cannot serve all examples, + we need to define the devserver for each example. This macro reduces code duplication + for defining these targets. +""" + +def create_upgrade_example_targets(name, srcs, e2e_srcs, entry_module, assets = []): + ng_module( + name = "%s_sources" % name, + srcs = srcs, + # TODO: FW-1004 Type checking is currently not complete. + type_check = False, + deps = [ + "@ngdeps//@types/angular", + "//packages/core", + "//packages/platform-browser", + "//packages/platform-browser-dynamic", + "//packages/upgrade/static", + ], + tsconfig = "//packages/examples/upgrade:tsconfig-build.json", + ) + + ts_library( + name = "%s_e2e_lib" % name, + srcs = e2e_srcs, + testonly = True, + deps = [ + "@ngdeps//@types/jasminewd2", + "@ngdeps//protractor", + "//packages/examples/test-utils", + "//packages/private/testing", + ], + tsconfig = "//packages/examples:tsconfig-e2e.json", + ) + + ts_devserver( + name = "devserver", + port = 4200, + entry_module = entry_module, + static_files = [ + "@ngdeps//node_modules/zone.js:dist/zone.js", + "@ngdeps//node_modules/angular:angular.js", + "@ngdeps//node_modules/reflect-metadata:Reflect.js", + ], + index_html = "//packages/examples:index.html", + scripts = ["@ngdeps//node_modules/tslib:tslib.js"], + deps = [":%s_sources" % name], + data = assets, + ) + + protractor_web_test_suite( + name = "%s_protractor" % name, + data = ["//packages/bazel/src/protractor/utils"], + on_prepare = "//packages/examples/upgrade:start-server.js", + server = ":devserver", + deps = [ + ":%s_e2e_lib" % name, + "@ngdeps//protractor", + "@ngdeps//selenium-webdriver", + ], + ) diff --git a/packages/forms/BUILD.bazel b/packages/forms/BUILD.bazel index 05d5a41c6d..6391e5e16d 100644 --- a/packages/forms/BUILD.bazel +++ b/packages/forms/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/forms", deps = [ "//packages/core", "//packages/platform-browser", @@ -28,6 +27,7 @@ ng_package( # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", "//packages/compiler-cli/test/diagnostics:__pkg__", "//packages/language-service/test:__pkg__", ], diff --git a/packages/forms/rollup.config.js b/packages/forms/rollup.config.js deleted file mode 100644 index d4567e15c7..0000000000 --- a/packages/forms/rollup.config.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/compiler': 'ng.compiler', - '@angular/platform-browser': 'ng.platformBrowser', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../dist/packages-dist/forms/fesm5/forms.js', - dest: '../../dist/packages-dist/forms/bundles/forms.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/forms'}, - moduleName: 'ng.forms', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/forms/src/directives/abstract_control_directive.ts b/packages/forms/src/directives/abstract_control_directive.ts index 992eeb118f..5c20cda551 100644 --- a/packages/forms/src/directives/abstract_control_directive.ts +++ b/packages/forms/src/directives/abstract_control_directive.ts @@ -150,19 +150,65 @@ export abstract class AbstractControlDirective { /** * @description * Reports whether the control with the given path has the error specified. - * If no path is given, it checks for the error on the present control. + * + * @param errorCode The code of the error to check + * @param path A list of control names that designates how to move from the current control + * to the control that should be queried for errors. + * + * @usageNotes + * For example, for the following `FormGroup`: + * + * ``` + * form = new FormGroup({ + * address: new FormGroup({ street: new FormControl() }) + * }); + * ``` + * + * The path to the 'street' control from the root form would be 'address' -> 'street'. + * + * It can be provided to this method in one of two formats: + * + * 1. An array of string control names, e.g. `['address', 'street']` + * 1. A period-delimited list of control names in one string, e.g. `'address.street'` + * + * If no path is given, this method checks for the error on the current control. + * + * @returns whether the given error is present in the control at the given path. + * * If the control is not present, false is returned. */ - hasError(errorCode: string, path?: string[]): boolean { + hasError(errorCode: string, path?: Array|string): boolean { return this.control ? this.control.hasError(errorCode, path) : false; } /** * @description * Reports error data for the control with the given path. - * If the control is not present, null is returned. + * + * @param errorCode The code of the error to check + * @param path A list of control names that designates how to move from the current control + * to the control that should be queried for errors. + * + * @usageNotes + * For example, for the following `FormGroup`: + * + * ``` + * form = new FormGroup({ + * address: new FormGroup({ street: new FormControl() }) + * }); + * ``` + * + * The path to the 'street' control from the root form would be 'address' -> 'street'. + * + * It can be provided to this method in one of two formats: + * + * 1. An array of string control names, e.g. `['address', 'street']` + * 1. A period-delimited list of control names in one string, e.g. `'address.street'` + * + * @returns error data for that particular error. If the control or error is not present, + * null is returned. */ - getError(errorCode: string, path?: string[]): any { + getError(errorCode: string, path?: Array|string): any { return this.control ? this.control.getError(errorCode, path) : null; } } diff --git a/packages/forms/src/directives/number_value_accessor.ts b/packages/forms/src/directives/number_value_accessor.ts index 4303c183c6..df5edc43fa 100644 --- a/packages/forms/src/directives/number_value_accessor.ts +++ b/packages/forms/src/directives/number_value_accessor.ts @@ -38,6 +38,7 @@ export const NUMBER_VALUE_ACCESSOR: any = { * * @ngModule ReactiveFormsModule * @ngModule FormsModule + * @publicApi */ @Directive({ selector: diff --git a/packages/forms/src/directives/range_value_accessor.ts b/packages/forms/src/directives/range_value_accessor.ts index 8b11c85536..e386fe1444 100644 --- a/packages/forms/src/directives/range_value_accessor.ts +++ b/packages/forms/src/directives/range_value_accessor.ts @@ -38,6 +38,7 @@ export const RANGE_VALUE_ACCESSOR: StaticProvider = { * * @ngModule ReactiveFormsModule * @ngModule FormsModule + * @publicApi */ @Directive({ selector: diff --git a/packages/forms/src/form_providers.ts b/packages/forms/src/form_providers.ts index a8fc4876cf..f5cd700d63 100644 --- a/packages/forms/src/form_providers.ts +++ b/packages/forms/src/form_providers.ts @@ -18,8 +18,6 @@ import {FormBuilder} from './form_builder'; * * 导出模板驱动表单所需的提供商和指令,使其可用于导入了该模块的 NgModule 中。 * - * @see [Forms](guide/forms) - * * @see [Forms Guide](/guide/forms) * * @publicApi diff --git a/packages/forms/src/forms.ts b/packages/forms/src/forms.ts index 324f5668da..235fdf8a03 100644 --- a/packages/forms/src/forms.ts +++ b/packages/forms/src/forms.ts @@ -18,6 +18,7 @@ */ +export {InternalFormsSharedModule as ɵInternalFormsSharedModule} from './directives'; export {AbstractControlDirective} from './directives/abstract_control_directive'; export {AbstractFormGroupDirective} from './directives/abstract_form_group_directive'; export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor'; @@ -31,7 +32,10 @@ export {NgForm} from './directives/ng_form'; export {NgFormSelectorWarning} from './directives/ng_form_selector_warning'; export {NgModel} from './directives/ng_model'; export {NgModelGroup} from './directives/ng_model_group'; +export {NgNoValidate as ɵNgNoValidate} from './directives/ng_no_validate_directive'; +export {NumberValueAccessor} from './directives/number_value_accessor'; export {RadioControlValueAccessor} from './directives/radio_control_value_accessor'; +export {RangeValueAccessor} from './directives/range_value_accessor'; export {FormControlDirective} from './directives/reactive_directives/form_control_directive'; export {FormControlName} from './directives/reactive_directives/form_control_name'; export {FormGroupDirective} from './directives/reactive_directives/form_group_directive'; @@ -39,6 +43,7 @@ export {FormArrayName} from './directives/reactive_directives/form_group_name'; export {FormGroupName} from './directives/reactive_directives/form_group_name'; export {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor'; export {SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor'; +export {NgSelectMultipleOption as ɵNgSelectMultipleOption} from './directives/select_multiple_control_value_accessor'; export {AsyncValidator, AsyncValidatorFn, CheckboxRequiredValidator, EmailValidator, MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator, ValidationErrors, Validator, ValidatorFn} from './directives/validators'; export {FormBuilder} from './form_builder'; export {AbstractControl, AbstractControlOptions, FormArray, FormControl, FormGroup} from './model'; diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index 71fa8644e2..f94ce11d8c 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -267,7 +267,7 @@ export abstract class AbstractControl { * * 当控件的 `status` 为 `VALID` 时,它就是 `valid` 的。 * - * @see `status` + * @see {@link AbstractControl.status} * * @returns True if the control has passed all of its validation tests, * false otherwise. @@ -281,7 +281,7 @@ export abstract class AbstractControl { * * 当控件的 `status` 为 `INVALID` 时,它就是 `invalid` 的。 * - * @see `status` + * @see {@link AbstractControl.status} * * @returns True if this control has failed one or more of its validation checks, * false otherwise. @@ -295,7 +295,7 @@ export abstract class AbstractControl { * * 当控件的 `status` 为 `PENDING` 时,它就是 `pending` 的。 * - * @see `status` + * @see {@link AbstractControl.status} * * @returns True if this control is in the process of conducting a validation check, * false otherwise. @@ -308,7 +308,6 @@ export abstract class AbstractControl { * A control is `disabled` when its `status` is `DISABLED`. * * 当控件的 `status` 为 `DISABLED` 时,它就是 `disabled`。 - * @see `status` * * Disabled controls are exempt from validation checks and * are not included in the aggregate value of their ancestor @@ -316,6 +315,8 @@ export abstract class AbstractControl { * * 被禁用的控件会豁免有效性检查,并且它的值不会聚合进其祖先控件中。 * + * @see {@link AbstractControl.status} + * * @returns True if the control is disabled, false otherwise. * * 如果该控件被禁用了,则为 `true`,否则为 `false`。 @@ -327,13 +328,13 @@ export abstract class AbstractControl { * * 如果控件的 `status` 不是 `DISABLED` 时,它就是 `enabled`。 * - * @see `status` - * * @returns True if the control has any status other than 'DISABLED', * false if the status is 'DISABLED'. * * 如果该控件处于 'DISABLED' 之外的任何状态,则为 `true`,否则为 `false`。 * + * @see {@link AbstractControl.status} + * */ get enabled(): boolean { return this.status !== DISABLED; } @@ -412,6 +413,9 @@ export abstract class AbstractControl { * recalculates. * * 一个多播 Observable(可观察对象),每当控件的验证 `status` 被重新计算时,就会发出一个事件。 + * + * @see {@link AbstractControl.status} + * */ // TODO(issue/24571): remove '!'. public readonly statusChanges !: Observable; @@ -465,7 +469,11 @@ export abstract class AbstractControl { /** * Marks the control as `touched`. A control is touched by focus and - * blur events that do not change the value; compare `markAsDirty`; + * blur events that do not change the value. + * + * @see `markAsUntouched()` + * @see `markAsDirty()` + * @see `markAsPristine()` * * 把该控件标记为 `touched`。控件获得焦点并失去焦点不会修改这个值。与 `markAsDirty` 相对。 * @@ -487,6 +495,16 @@ export abstract class AbstractControl { } } + /** + * Marks the control and all its descendant controls as `touched`. + * @see `markAsTouched()` + */ + markAllAsTouched(): void { + this.markAsTouched({onlySelf: true}); + + this._forEachChild((control: AbstractControl) => control.markAllAsTouched()); + } + /** * Marks the control as `untouched`. * @@ -497,7 +515,11 @@ export abstract class AbstractControl { * * 如果该控件有任何子控件,还会把所有子控件标记为 `untouched`,并重新计算所有父控件的 `touched` 状态。 * - * @param opts Configuration options that determine how the control propagates changes + * @see `markAsTouched()` + * @see `markAsDirty()` + * @see `markAsPristine()` + * + * @param opts Configuration options that determine how the control propagates changes * and emits events after the marking is applied. * * 在应用完此标记后,该配置项会决定控件如何传播变更及发出事件。 @@ -526,7 +548,11 @@ export abstract class AbstractControl { * * 把控件标记为 `dirty`。当控件通过 UI 修改过时控件会变成 `dirty` 的;与 `markAsTouched` 相对。 * - * @param opts Configuration options that determine how the control propagates changes + * @see `markAsTouched()` + * @see `markAsUntouched()` + * @see `markAsPristine()` + * + * @param opts Configuration options that determine how the control propagates changes * and emits events after marking is applied. * * 在应用完此标记后,该配置项会决定控件如何传播变更以及发出事件。 @@ -556,7 +582,11 @@ export abstract class AbstractControl { * * 如果该控件有任何子控件,则把所有子控件标记为 `pristine`,并重新计算所有父控件的 `pristine` 状态。 * - * @param opts Configuration options that determine how the control emits events after + * @see `markAsTouched()` + * @see `markAsUntouched()` + * @see `markAsDirty()` + * + * @param opts Configuration options that determine how the control emits events after * marking is applied. * * 在应用完此标记后,该配置项会决定控件如何传播更改以及发出事件。 @@ -587,7 +617,9 @@ export abstract class AbstractControl { * * 当控件正在执行异步验证时,该控件是 `pending` 的。 * - * @param opts Configuration options that determine how the control propagates changes and + * @see {@link AbstractControl.status} + * + * @param opts Configuration options that determine how the control propagates changes and * emits events after marking is applied. * * 在应用完此标记后,该配置项会决定控件如何传播变更以及发出事件。 @@ -627,7 +659,9 @@ export abstract class AbstractControl { * * 如果该控件有子控件,则所有子控件也会被禁用。 * - * @param opts Configuration options that determine how the control propagates + * @see {@link AbstractControl.status} + * + * @param opts Configuration options that determine how the control propagates * changes and emits events after the control is disabled. * * 在该控件被禁用之后,该配置项决定如何传播更改以及发出事件。 @@ -647,6 +681,10 @@ export abstract class AbstractControl { * */ disable(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { + // If parent has been marked artificially dirty we don't want to re-calculate the + // parent's dirtiness based on the children. + const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf); + (this as{status: string}).status = DISABLED; (this as{errors: ValidationErrors | null}).errors = null; this._forEachChild( @@ -658,7 +696,7 @@ export abstract class AbstractControl { (this.statusChanges as EventEmitter).emit(this.status); } - this._updateAncestors(opts); + this._updateAncestors({...opts, skipPristineCheck}); this._onDisabledChange.forEach((changeFn) => changeFn(true)); } @@ -673,7 +711,9 @@ export abstract class AbstractControl { * * 默认情况下,如果该控件具有子控件,则所有子控件都会被启用。 * - * @param opts Configure options that control how the control propagates changes and + * @see {@link AbstractControl.status} + * + * @param opts Configure options that control how the control propagates changes and * emits events when marked as untouched * * 当标记为 `untouched` 时,该配置项会决定该控件如何传播变更以及发出事件。 @@ -692,19 +732,26 @@ export abstract class AbstractControl { * 如果为 `false`,则不会发出事件。 */ enable(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { + // If parent has been marked artificially dirty we don't want to re-calculate the + // parent's dirtiness based on the children. + const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf); + (this as{status: string}).status = VALID; this._forEachChild( (control: AbstractControl) => { control.enable({...opts, onlySelf: true}); }); this.updateValueAndValidity({onlySelf: true, emitEvent: opts.emitEvent}); - this._updateAncestors(opts); + this._updateAncestors({...opts, skipPristineCheck}); this._onDisabledChange.forEach((changeFn) => changeFn(false)); } - private _updateAncestors(opts: {onlySelf?: boolean, emitEvent?: boolean}) { + private _updateAncestors( + opts: {onlySelf?: boolean, emitEvent?: boolean, skipPristineCheck?: boolean}) { if (this._parent && !opts.onlySelf) { this._parent.updateValueAndValidity(opts); - this._parent._updatePristine(); + if (!opts.skipPristineCheck) { + this._parent._updatePristine(); + } this._parent._updateTouched(); } } @@ -883,48 +930,101 @@ export abstract class AbstractControl { get(path: Array|string): AbstractControl|null { return _find(this, path, '.'); } /** - * Reports error data for a specific error occurring in this control or in another control. + * @description + * Reports error data for the control with the given path. * - * 获取发生在该控件或其他控件中发生的指定错误的出错数据。 + * 报告具有指定路径的控件的错误数据。 * - * @param errorCode The error code for which to retrieve data + * @param errorCode The code of the error to check * - * 要获取的数据的错误码 + * 所查出的错误的错误码 * - * @param path The path to a control to check. If not supplied, checks for the error in this - * control. + * @param path A list of control names that designates how to move from the current control + * to the control that should be queried for errors. * - * 要检查的控件的路径。如果没有提供该参数,则检查该控件中的错误。 + * 一个控件名列表,用于指定要如何从当前控件移动到要查询错误的那个控件。 * - * @returns The error data if the control with the given path has the given error, otherwise null - * or undefined. + * @usageNotes + * For example, for the following `FormGroup`: + * + * 比如,对于下列 `FormGroup`: + * + * ``` + * form = new FormGroup({ + * address: new FormGroup({ street: new FormControl() }) + * }); + * ``` + * + * The path to the 'street' control from the root form would be 'address' -> 'street'. + * + * 从根表单移动到这个 'street' 控件的路径应该是 'address' -> 'street'。 + * + * It can be provided to this method in one of two formats: + * + * 可以用两种格式把它提供给此方法: + * + * 1. An array of string control names, e.g. `['address', 'street']` + * + * 一个表示控件名的字符串数组,比如 `['address', 'street']` + * + * 1. A period-delimited list of control names in one string, e.g. `'address.street'` + * + * 一个点号分隔的控件名列表构成的单一字符串,比如 `'address.street'` + * + * @returns error data for that particular error. If the control or error is not present, + * null is returned. + * + * 特定错误的数据,如果该控件不存在或没有错误,则返回 null。 * - * 如果指定路径下的控件具有指定的错误,则返回出错数据,否则为 `null` 或 `undefined`。 */ - getError(errorCode: string, path?: string[]): any { + getError(errorCode: string, path?: Array|string): any { const control = path ? this.get(path) : this; return control && control.errors ? control.errors[errorCode] : null; } /** + * @description * Reports whether the control with the given path has the error specified. * * 报告指定路径下的控件上是否有指定的错误。 * - * @param errorCode The error code for which to retrieve data + * @param errorCode The code of the error to check * * 要获取的数据的错误码 * - * @param path The path to a control to check. If not supplied, checks for the error in this - * control. + * @param path A list of control names that designates how to move from the current control + * to the control that should be queried for errors. + * + * @usageNotes + * For example, for the following `FormGroup`: + * + * ``` + * form = new FormGroup({ + * address: new FormGroup({ street: new FormControl() }) + * }); + * ``` + * + * The path to the 'street' control from the root form would be 'address' -> 'street'. + * + * It can be provided to this method in one of two formats: + * + * 1. An array of string control names, e.g. `['address', 'street']` + * 1. A period-delimited list of control names in one string, e.g. `'address.street'` + * + * If no path is given, this method checks for the error on the current control. + * * * 要检查的控件的路径。如果没有提供该参数,则检查该控件中的错误。 * - * @returns True when the control with the given path has the error, otherwise false. + * @returns whether the given error is present in the control at the given path. + * + * If the control is not present, false is returned. * * 如果指定路径下的控件有这个错误则返回 `true`,否则返回 `false`。 */ - hasError(errorCode: string, path?: string[]): boolean { return !!this.getError(errorCode, path); } + hasError(errorCode: string, path?: Array|string): boolean { + return !!this.getError(errorCode, path); + } /** * Retrieves the top-level ancestor of this control. @@ -1036,6 +1136,16 @@ export abstract class AbstractControl { this._updateOn = (opts as AbstractControlOptions).updateOn !; } } + + /** + * Check to see if parent has been marked artificially dirty. + * + * @internal + */ + private _parentMarkedDirty(onlySelf?: boolean): boolean { + const parentDirty = this._parent && this._parent.dirty; + return !onlySelf && parentDirty && !this._parent._anyControlsDirty(); + } } /** @@ -1870,9 +1980,9 @@ export class FormGroup extends AbstractControl { this._forEachChild((control: AbstractControl, name: string) => { control.reset(value[name], {onlySelf: true, emitEvent: options.emitEvent}); }); - this.updateValueAndValidity(options); this._updatePristine(options); this._updateTouched(options); + this.updateValueAndValidity(options); } /** @@ -2406,9 +2516,9 @@ export class FormArray extends AbstractControl { this._forEachChild((control: AbstractControl, index: number) => { control.reset(value[index], {onlySelf: true, emitEvent: options.emitEvent}); }); - this.updateValueAndValidity(options); this._updatePristine(options); this._updateTouched(options); + this.updateValueAndValidity(options); } /** diff --git a/packages/forms/test/form_array_spec.ts b/packages/forms/test/form_array_spec.ts index 95c608828c..2a94c68a44 100644 --- a/packages/forms/test/form_array_spec.ts +++ b/packages/forms/test/form_array_spec.ts @@ -96,6 +96,58 @@ import {of } from 'rxjs'; }); }); + describe('markAllAsTouched', () => { + it('should mark all descendants as touched', () => { + const formArray: FormArray = new FormArray([ + new FormControl('v1'), new FormControl('v2'), + new FormGroup({'c1': new FormControl('v1')}), + new FormArray([new FormGroup({'c2': new FormControl('v2')})]) + ]); + + expect(formArray.touched).toBe(false); + + const control1 = formArray.at(0) as FormControl; + + expect(control1.touched).toBe(false); + + const group1 = formArray.at(2) as FormGroup; + + expect(group1.touched).toBe(false); + + const group1Control1 = group1.get('c1') as FormControl; + + expect(group1Control1.touched).toBe(false); + + const innerFormArray = formArray.at(3) as FormArray; + + expect(innerFormArray.touched).toBe(false); + + const innerFormArrayGroup = innerFormArray.at(0) as FormGroup; + + expect(innerFormArrayGroup.touched).toBe(false); + + const innerFormArrayGroupControl1 = innerFormArrayGroup.get('c2') as FormControl; + + expect(innerFormArrayGroupControl1.touched).toBe(false); + + formArray.markAllAsTouched(); + + expect(formArray.touched).toBe(true); + + expect(control1.touched).toBe(true); + + expect(group1.touched).toBe(true); + + expect(group1Control1.touched).toBe(true); + + expect(innerFormArray.touched).toBe(true); + + expect(innerFormArrayGroup.touched).toBe(true); + + expect(innerFormArrayGroupControl1.touched).toBe(true); + }); + }); + describe('setValue', () => { let c: FormControl, c2: FormControl, a: FormArray; @@ -534,6 +586,23 @@ import {of } from 'rxjs'; a.reset(); expect(logger).toEqual(['control1', 'control2', 'array', 'form']); }); + + it('should mark as pristine and not dirty before emitting valueChange and statusChange events when resetting', + () => { + const pristineAndNotDirty = () => { + expect(a.pristine).toBe(true); + expect(a.dirty).toBe(false); + }; + + c2.markAsDirty(); + expect(a.pristine).toBe(false); + expect(a.dirty).toBe(true); + + a.valueChanges.subscribe(pristineAndNotDirty); + a.statusChanges.subscribe(pristineAndNotDirty); + + a.reset(); + }); }); }); diff --git a/packages/forms/test/form_control_spec.ts b/packages/forms/test/form_control_spec.ts index 2bc06e1171..7b90a1e5a4 100644 --- a/packages/forms/test/form_control_spec.ts +++ b/packages/forms/test/form_control_spec.ts @@ -47,6 +47,15 @@ import {FormArray} from '@angular/forms/src/model'; expect(c.value).toBe(null); }); + describe('markAllAsTouched', () => { + it('should mark only the control itself as touched', () => { + const control = new FormControl(''); + expect(control.touched).toBe(false); + control.markAllAsTouched(); + expect(control.touched).toBe(true); + }); + }); + describe('boxed values', () => { it('should support valid boxed values on creation', () => { const c = new FormControl({value: 'some val', disabled: true}, null !, null !); @@ -991,6 +1000,37 @@ import {FormArray} from '@angular/forms/src/model'; expect(a.value).toEqual(['one']); }); + it('should ignore disabled array controls when determining dirtiness', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const a = new FormArray([c, c2]); + c.markAsDirty(); + expect(a.dirty).toBe(true); + + c.disable(); + expect(c.dirty).toBe(true); + expect(a.dirty).toBe(false); + + c.enable(); + expect(a.dirty).toBe(true); + }); + + it('should not make a dirty array not dirty when disabling controls', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const a = new FormArray([c, c2]); + + a.markAsDirty(); + expect(a.dirty).toBe(true); + expect(c.dirty).toBe(false); + + c.disable(); + expect(a.dirty).toBe(true); + + c.enable(); + expect(a.dirty).toBe(true); + }); + it('should ignore disabled controls in validation', () => { const c = new FormControl(null, Validators.required); const c2 = new FormControl(null); @@ -1045,6 +1085,22 @@ import {FormArray} from '@angular/forms/src/model'; expect(g.dirty).toBe(true); }); + it('should not make a dirty group not dirty when disabling controls', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const g = new FormGroup({one: c, two: c2}); + + g.markAsDirty(); + expect(g.dirty).toBe(true); + expect(c.dirty).toBe(false); + + c.disable(); + expect(g.dirty).toBe(true); + + c.enable(); + expect(g.dirty).toBe(true); + }); + it('should ignore disabled controls when determining touched state', () => { const c = new FormControl('one'); const c2 = new FormControl('two'); diff --git a/packages/forms/test/form_group_spec.ts b/packages/forms/test/form_group_spec.ts index 5b3f622070..9e6180fa6a 100644 --- a/packages/forms/test/form_group_spec.ts +++ b/packages/forms/test/form_group_spec.ts @@ -86,6 +86,67 @@ import {of } from 'rxjs'; }); + describe('markAllAsTouched', () => { + it('should mark all descendants as touched', () => { + const formGroup: FormGroup = new FormGroup({ + 'c1': new FormControl('v1'), + 'group': new FormGroup({'c2': new FormControl('v2'), 'c3': new FormControl('v3')}), + 'array': new FormArray([ + new FormControl('v4'), new FormControl('v5'), + new FormGroup({'c4': new FormControl('v4')}) + ]) + }); + + expect(formGroup.touched).toBe(false); + + const control1 = formGroup.get('c1') as FormControl; + + expect(control1.touched).toBe(false); + + const innerGroup = formGroup.get('group') as FormGroup; + + expect(innerGroup.touched).toBe(false); + + const innerGroupFirstChildCtrl = innerGroup.get('c2') as FormControl; + + expect(innerGroupFirstChildCtrl.touched).toBe(false); + + formGroup.markAllAsTouched(); + + expect(formGroup.touched).toBe(true); + + expect(control1.touched).toBe(true); + + expect(innerGroup.touched).toBe(true); + + expect(innerGroupFirstChildCtrl.touched).toBe(true); + + const innerGroupSecondChildCtrl = innerGroup.get('c3') as FormControl; + + expect(innerGroupSecondChildCtrl.touched).toBe(true); + + const array = formGroup.get('array') as FormArray; + + expect(array.touched).toBe(true); + + const arrayFirstChildCtrl = array.at(0) as FormControl; + + expect(arrayFirstChildCtrl.touched).toBe(true); + + const arraySecondChildCtrl = array.at(1) as FormControl; + + expect(arraySecondChildCtrl.touched).toBe(true); + + const arrayFirstChildGroup = array.at(2) as FormGroup; + + expect(arrayFirstChildGroup.touched).toBe(true); + + const arrayFirstChildGroupFirstChildCtrl = arrayFirstChildGroup.get('c4') as FormControl; + + expect(arrayFirstChildGroupFirstChildCtrl.touched).toBe(true); + }); + }); + describe('adding and removing controls', () => { it('should update value and validity when control is added', () => { const g = new FormGroup({'one': new FormControl('1')}); @@ -593,6 +654,23 @@ import {of } from 'rxjs'; g.reset({'one': {value: '', disabled: true}}); expect(logger).toEqual(['control1', 'control2', 'group', 'form']); }); + + it('should mark as pristine and not dirty before emitting valueChange and statusChange events when resetting', + () => { + const pristineAndNotDirty = () => { + expect(form.pristine).toBe(true); + expect(form.dirty).toBe(false); + }; + + c3.markAsDirty(); + expect(form.pristine).toBe(false); + expect(form.dirty).toBe(true); + + form.valueChanges.subscribe(pristineAndNotDirty); + form.statusChanges.subscribe(pristineAndNotDirty); + + form.reset(); + }); }); }); @@ -684,6 +762,70 @@ import {of } from 'rxjs'; expect(g.getError('required', ['one'])).toEqual(null); expect(g.getError('required', ['invalid'])).toEqual(null); }); + + it('should be able to traverse group with single string', () => { + const c = new FormControl('', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.getError('required')).toEqual(true); + expect(g.getError('required', 'one')).toEqual(true); + }); + + it('should be able to traverse group with string delimited by dots', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const g1 = new FormGroup({'one': g2}); + expect(c.getError('required')).toEqual(true); + expect(g1.getError('required', 'one.two')).toEqual(true); + }); + + it('should traverse group with form array using string and numbers', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const a = new FormArray([g2]); + const g1 = new FormGroup({'one': a}); + expect(c.getError('required')).toEqual(true); + expect(g1.getError('required', ['one', 0, 'two'])).toEqual(true); + }); + }); + + describe('hasError', () => { + it('should return true when it is present', () => { + const c = new FormControl('', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.hasError('required')).toEqual(true); + expect(g.hasError('required', ['one'])).toEqual(true); + }); + + it('should return false otherwise', () => { + const c = new FormControl('not empty', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.hasError('invalid')).toEqual(false); + expect(g.hasError('required', ['one'])).toEqual(false); + expect(g.hasError('required', ['invalid'])).toEqual(false); + }); + + it('should be able to traverse group with single string', () => { + const c = new FormControl('', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.hasError('required')).toEqual(true); + expect(g.hasError('required', 'one')).toEqual(true); + }); + + it('should be able to traverse group with string delimited by dots', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const g1 = new FormGroup({'one': g2}); + expect(c.hasError('required')).toEqual(true); + expect(g1.hasError('required', 'one.two')).toEqual(true); + }); + it('should traverse group with form array using string and numbers', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const a = new FormArray([g2]); + const g1 = new FormGroup({'one': a}); + expect(c.getError('required')).toEqual(true); + expect(g1.getError('required', ['one', 0, 'two'])).toEqual(true); + }); }); describe('validator', () => { diff --git a/packages/http/BUILD.bazel b/packages/http/BUILD.bazel index 506939a39c..6eabc9e41a 100644 --- a/packages/http/BUILD.bazel +++ b/packages/http/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/http", deps = [ "//packages/core", "//packages/platform-browser", @@ -30,7 +29,9 @@ ng_package( ], # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. - visibility = ["//visibility:private"], + visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", + ], deps = [ ":http", "//packages/http/testing", diff --git a/packages/http/rollup.config.js b/packages/http/rollup.config.js deleted file mode 100644 index 2557452ef9..0000000000 --- a/packages/http/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/compiler': 'ng.compiler', - '@angular/platform-browser': 'ng.platformBrowser', - 'rxjs': 'rxjs' -}; - -module.exports = { - entry: '../../dist/packages-dist/http/fesm5/http.js', - dest: '../../dist/packages-dist/http/bundles/http.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/http'}, - moduleName: 'ng.http', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/http/test/backends/xhr_backend_spec.ts b/packages/http/test/backends/xhr_backend_spec.ts index 8c2228c711..83872ff412 100644 --- a/packages/http/test/backends/xhr_backend_spec.ts +++ b/packages/http/test/backends/xhr_backend_spec.ts @@ -327,7 +327,7 @@ class MockBrowserXHR extends BrowserXhr { let newBlob: Blob; try { newBlob = new Blob(data || [], datatype ? {type: datatype} : {}); - } catch (e) { + } catch { const BlobBuilder = (global).BlobBuilder || (global).WebKitBlobBuilder || (global).MozBlobBuilder || (global).MSBlobBuilder; const builder = new BlobBuilder(); diff --git a/packages/http/testing/BUILD.bazel b/packages/http/testing/BUILD.bazel index 8b55de61f4..ba1d140b56 100644 --- a/packages/http/testing/BUILD.bazel +++ b/packages/http/testing/BUILD.bazel @@ -7,7 +7,6 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "testing", srcs = glob(["**/*.ts"]), - module_name = "@angular/http/testing", deps = [ "//packages/core", "//packages/http", diff --git a/packages/http/testing/rollup.config.js b/packages/http/testing/rollup.config.js deleted file mode 100644 index 7281922084..0000000000 --- a/packages/http/testing/rollup.config.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/compiler': 'ng.compiler', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/http': 'ng.http', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../../dist/packages-dist/http/fesm5/testing.js', - dest: '../../../dist/packages-dist/http/bundles/http-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/http/testing'}, - moduleName: 'ng.http.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/language-service/BUILD.bazel b/packages/language-service/BUILD.bazel index fbf1030277..4454b2a11c 100644 --- a/packages/language-service/BUILD.bazel +++ b/packages/language-service/BUILD.bazel @@ -10,7 +10,6 @@ ts_library( "src/**/*.ts", ], ), - module_name = "@angular/language-service", deps = [ "//packages:types", "//packages/compiler", diff --git a/packages/language-service/bundles/banner.js.txt b/packages/language-service/bundles/banner.js.txt index 82e0ee92b0..3224f53c79 100644 --- a/packages/language-service/bundles/banner.js.txt +++ b/packages/language-service/bundles/banner.js.txt @@ -1,6 +1,6 @@ /** * @license Angular v0.0.0-PLACEHOLDER - * (c) 2010-2018 Google, Inc. https://angular.io/ + * (c) 2010-2019 Google LLC. https://angular.io/ * License: MIT */ diff --git a/packages/language-service/rollup.config.js b/packages/language-service/rollup.config.js deleted file mode 100644 index 7404f938e4..0000000000 --- a/packages/language-service/rollup.config.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const commonjs = require('rollup-plugin-commonjs'); -const sourcemaps = require('rollup-plugin-sourcemaps'); -const path = require('path'); -const fs = require('fs'); - -var m = /^\@angular\/((\w|\-)+)(\/(\w|\d|\/|\-)+)?$/; -var location = normalize('../../dist/packages-dist') + '/'; -var rxjsLocation = normalize('../../node_modules/rxjs'); -var tslibLocation = normalize('../../node_modules/tslib'); - -var locations = {'compiler-cli': normalize('../../dist/packages') + '/'}; - -var esm_suffixes = {}; - -function normalize(fileName) { - return path.resolve(__dirname, fileName); -} - -function resolve(id, from) { - // console.log('Resolve id:', id, 'from', from) - var match = m.exec(id); - if (match) { - var packageName = match[1]; - var esm_suffix = esm_suffixes[packageName] || ''; - var loc = locations[packageName] || location; - var r = loc !== location && (loc + esm_suffix + packageName + (match[3] || '/index') + '.js') || - loc + packageName + '/fesm5/' + packageName + '.js'; - return r; - } - if (id && (id == 'rxjs' || id.startsWith('rxjs/'))) { - return `${rxjsLocation}${id.replace('rxjs', '')}/index.js`; - } - if (id == 'tslib') { - return tslibLocation + '/tslib.es6.js'; - } -} - -var banner = fs.readFileSync('bundles/banner.js.txt', 'utf8'); - -module.exports = { - entry: '../../dist/packages-dist/language-service/fesm5/language-service.js', - dest: '../../dist/packages-dist/language-service/bundles/language-service.umd.js', - format: 'amd', - amd: { - // Don't name this module, causes - // Loading the language service caused the following exception: TypeError: - // $deferred.modules.map is not a function - // id: '@angular/language-service' - }, - moduleName: 'ng.language_service', - exports: 'named', - external: [ - 'fs', - 'path', - 'typescript', - ], - globals: { - 'typescript': 'ts', - 'path': 'path', - 'fs': 'fs', - }, - banner: banner, - plugins: [{resolveId: resolve}, commonjs(), sourcemaps()] -}; diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index 3412abffef..9192d9f213 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -316,7 +316,7 @@ class ExpressionVisitor extends NullTemplateVisitor { // find the template binding that contains the position if (!this.attr.valueSpan) return; - const valueRelativePosition = this.position - this.attr.valueSpan.start.offset - 1; + const valueRelativePosition = this.position - this.attr.valueSpan.start.offset; const bindings = templateBindingResult.templateBindings; const binding = bindings.find( @@ -401,7 +401,7 @@ class ExpressionVisitor extends NullTemplateVisitor { private get attributeValuePosition() { if (this.attr && this.attr.valueSpan) { - return this.position - this.attr.valueSpan.start.offset - 1; + return this.position - this.attr.valueSpan.start.offset; } return 0; } diff --git a/packages/language-service/src/language_service.ts b/packages/language-service/src/language_service.ts index d3e48a0c12..c76a3039ed 100644 --- a/packages/language-service/src/language_service.ts +++ b/packages/language-service/src/language_service.ts @@ -112,7 +112,7 @@ class LanguageServiceImpl implements LanguageService { const parser = new TemplateParser( config, this.host.resolver.getReflector(), expressionParser, new DomElementSchemaRegistry(), htmlParser, null !, []); - const htmlResult = htmlParser.parse(template.source, '', true); + const htmlResult = htmlParser.parse(template.source, '', {tokenizeExpansionForms: true}); const analyzedModules = this.host.getAnalyzedModules(); let errors: Diagnostic[]|undefined = undefined; let ngModule = analyzedModules.ngModuleByPipeOrDirective.get(template.type); diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index c1e9a0e161..a87750716d 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -33,7 +33,7 @@ export function locateSymbol(info: TemplateInfo): SymbolInfo|undefined { const dinfo = diagnosticInfoFromTemplateInfo(info); const scope = getExpressionScope(dinfo, path, inEvent); if (attribute.valueSpan) { - const expressionOffset = attribute.valueSpan.start.offset + 1; + const expressionOffset = attribute.valueSpan.start.offset; const result = getExpressionSymbol( scope, ast, templatePosition - expressionOffset, info.template.query); if (result) { diff --git a/packages/language-service/src/ts_plugin.ts b/packages/language-service/src/ts_plugin.ts index d3300c39e1..4bd0f83c60 100644 --- a/packages/language-service/src/ts_plugin.ts +++ b/packages/language-service/src/ts_plugin.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {createLanguageService} from './language_service'; -import {Completion, Diagnostic, DiagnosticMessageChain, LanguageService, LanguageServiceHost} from './types'; +import {Completion, Diagnostic, DiagnosticMessageChain} from './types'; import {TypeScriptServiceHost} from './typescript_host'; const projectHostMap = new WeakMap(); @@ -21,183 +21,63 @@ export function getExternalFiles(project: any): string[]|undefined { } } +function completionToEntry(c: Completion): ts.CompletionEntry { + return { + // TODO: remove any and fix type error. + kind: c.kind as any, + name: c.name, + sortText: c.sort, + kindModifiers: '' + }; +} + +function diagnosticChainToDiagnosticChain(chain: DiagnosticMessageChain): + ts.DiagnosticMessageChain { + return { + messageText: chain.message, + category: ts.DiagnosticCategory.Error, + code: 0, + next: chain.next ? diagnosticChainToDiagnosticChain(chain.next) : undefined + }; +} + +function diagnosticMessageToDiagnosticMessageText(message: string | DiagnosticMessageChain): string| + ts.DiagnosticMessageChain { + if (typeof message === 'string') { + return message; + } + return diagnosticChainToDiagnosticChain(message); +} + +function diagnosticToDiagnostic(d: Diagnostic, file: ts.SourceFile): ts.Diagnostic { + const result = { + file, + start: d.span.start, + length: d.span.end - d.span.start, + messageText: diagnosticMessageToDiagnosticMessageText(d.message), + category: ts.DiagnosticCategory.Error, + code: 0, + source: 'ng' + }; + return result; +} + export function create(info: any /* ts.server.PluginCreateInfo */): ts.LanguageService { - // Create the proxy - const proxy: ts.LanguageService = Object.create(null); - let oldLS: ts.LanguageService = info.languageService; - - function tryCall(fileName: string | undefined, callback: () => T): T|undefined { - if (fileName && !oldLS.getProgram() !.getSourceFile(fileName)) { - return undefined; - } - try { - return callback(); - } catch { - return undefined; - } - } - - function tryFilenameCall(m: (fileName: string) => T): (fileName: string) => T | undefined { - return fileName => tryCall(fileName, () => (m.call(ls, fileName))); - } - - function tryFilenameOneCall(m: (fileName: string, p: P) => T): (filename: string, p: P) => - T | undefined { - return (fileName, p) => tryCall(fileName, () => (m.call(ls, fileName, p))); - } - - function tryFilenameTwoCall(m: (fileName: string, p1: P1, p2: P2) => T): ( - filename: string, p1: P1, p2: P2) => T | undefined { - return (fileName, p1, p2) => tryCall(fileName, () => (m.call(ls, fileName, p1, p2))); - } - - function tryFilenameThreeCall(m: (fileName: string, p1: P1, p2: P2, p3: P3) => T): - (filename: string, p1: P1, p2: P2, p3: P3) => T | undefined { - return (fileName, p1, p2, p3) => tryCall(fileName, () => (m.call(ls, fileName, p1, p2, p3))); - } - - function tryFilenameFourCall( - m: (fileName: string, p1: P1, p2: P2, p3: P3, p4: P4) => - T): (fileName: string, p1: P1, p2: P2, p3: P3, p4: P4) => T | undefined { - return (fileName, p1, p2, p3, p4) => - tryCall(fileName, () => (m.call(ls, fileName, p1, p2, p3, p4))); - } - - function tryFilenameFiveCall( - m: (fileName: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => - T): (fileName: string, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) => T | undefined { - return (fileName, p1, p2, p3, p4, p5) => - tryCall(fileName, () => (m.call(ls, fileName, p1, p2, p3, p4, p5))); - } - - function typescriptOnly(ls: ts.LanguageService): ts.LanguageService { - const languageService: ts.LanguageService = { - cleanupSemanticCache: () => ls.cleanupSemanticCache(), - getSyntacticDiagnostics: tryFilenameCall(ls.getSyntacticDiagnostics), - getSemanticDiagnostics: tryFilenameCall(ls.getSemanticDiagnostics), - getCompilerOptionsDiagnostics: () => ls.getCompilerOptionsDiagnostics(), - getSyntacticClassifications: tryFilenameOneCall(ls.getSemanticClassifications), - getSemanticClassifications: tryFilenameOneCall(ls.getSemanticClassifications), - getEncodedSyntacticClassifications: tryFilenameOneCall(ls.getEncodedSyntacticClassifications), - getEncodedSemanticClassifications: tryFilenameOneCall(ls.getEncodedSemanticClassifications), - getCompletionsAtPosition: tryFilenameTwoCall(ls.getCompletionsAtPosition), - getCompletionEntryDetails: tryFilenameFiveCall(ls.getCompletionEntryDetails), - getCompletionEntrySymbol: tryFilenameThreeCall(ls.getCompletionEntrySymbol), - getJsxClosingTagAtPosition: tryFilenameOneCall(ls.getJsxClosingTagAtPosition), - getQuickInfoAtPosition: tryFilenameOneCall(ls.getQuickInfoAtPosition), - getNameOrDottedNameSpan: tryFilenameTwoCall(ls.getNameOrDottedNameSpan), - getBreakpointStatementAtPosition: tryFilenameOneCall(ls.getBreakpointStatementAtPosition), - getSignatureHelpItems: tryFilenameTwoCall(ls.getSignatureHelpItems), - getRenameInfo: tryFilenameOneCall(ls.getRenameInfo), - findRenameLocations: tryFilenameThreeCall(ls.findRenameLocations), - getDefinitionAtPosition: tryFilenameOneCall(ls.getDefinitionAtPosition), - getTypeDefinitionAtPosition: tryFilenameOneCall(ls.getTypeDefinitionAtPosition), - getImplementationAtPosition: tryFilenameOneCall(ls.getImplementationAtPosition), - getReferencesAtPosition: tryFilenameOneCall(ls.getReferencesAtPosition), - findReferences: tryFilenameOneCall(ls.findReferences), - getDocumentHighlights: tryFilenameTwoCall(ls.getDocumentHighlights), - /** @deprecated */ - getOccurrencesAtPosition: tryFilenameOneCall(ls.getOccurrencesAtPosition), - getNavigateToItems: - (searchValue, maxResultCount, fileName, excludeDtsFiles) => tryCall( - fileName, - () => ls.getNavigateToItems(searchValue, maxResultCount, fileName, excludeDtsFiles)), - getNavigationBarItems: tryFilenameCall(ls.getNavigationBarItems), - getNavigationTree: tryFilenameCall(ls.getNavigationTree), - getOutliningSpans: tryFilenameCall(ls.getOutliningSpans), - getTodoComments: tryFilenameOneCall(ls.getTodoComments), - getBraceMatchingAtPosition: tryFilenameOneCall(ls.getBraceMatchingAtPosition), - getIndentationAtPosition: tryFilenameTwoCall(ls.getIndentationAtPosition), - getFormattingEditsForRange: tryFilenameThreeCall(ls.getFormattingEditsForRange), - getFormattingEditsForDocument: tryFilenameOneCall(ls.getFormattingEditsForDocument), - getFormattingEditsAfterKeystroke: tryFilenameThreeCall(ls.getFormattingEditsAfterKeystroke), - getDocCommentTemplateAtPosition: tryFilenameOneCall(ls.getDocCommentTemplateAtPosition), - isValidBraceCompletionAtPosition: tryFilenameTwoCall(ls.isValidBraceCompletionAtPosition), - getSpanOfEnclosingComment: tryFilenameTwoCall(ls.getSpanOfEnclosingComment), - getCodeFixesAtPosition: tryFilenameFiveCall(ls.getCodeFixesAtPosition), - applyCodeActionCommand: - ((action: any) => tryCall(undefined, () => ls.applyCodeActionCommand(action))), - getEmitOutput: tryFilenameCall(ls.getEmitOutput), - getProgram: () => ls.getProgram(), - dispose: () => ls.dispose(), - getApplicableRefactors: tryFilenameTwoCall(ls.getApplicableRefactors), - getEditsForRefactor: tryFilenameFiveCall(ls.getEditsForRefactor), - getDefinitionAndBoundSpan: tryFilenameOneCall(ls.getDefinitionAndBoundSpan), - getCombinedCodeFix: - (scope: ts.CombinedCodeFixScope, fixId: {}, formatOptions: ts.FormatCodeSettings, - preferences: ts.UserPreferences) => - tryCall( - undefined, () => ls.getCombinedCodeFix(scope, fixId, formatOptions, preferences)), - // TODO(kyliau): dummy implementation to compile with ts 2.8, create real one - getSuggestionDiagnostics: (fileName: string) => [], - // TODO(kyliau): dummy implementation to compile with ts 2.8, create real one - organizeImports: (scope: ts.CombinedCodeFixScope, formatOptions: ts.FormatCodeSettings) => [], - // TODO: dummy implementation to compile with ts 2.9, create a real one - getEditsForFileRename: - (oldFilePath: string, newFilePath: string, formatOptions: ts.FormatCodeSettings, - preferences: ts.UserPreferences | undefined) => [] - } as ts.LanguageService; - return languageService; - } - - oldLS = typescriptOnly(oldLS); - - for (const k in oldLS) { - (proxy)[k] = function() { return (oldLS as any)[k].apply(oldLS, arguments); }; - } - - function completionToEntry(c: Completion): ts.CompletionEntry { - return { - // TODO: remove any and fix type error. - kind: c.kind as any, - name: c.name, - sortText: c.sort, - kindModifiers: '' - }; - } - - function diagnosticChainToDiagnosticChain(chain: DiagnosticMessageChain): - ts.DiagnosticMessageChain { - return { - messageText: chain.message, - category: ts.DiagnosticCategory.Error, - code: 0, - next: chain.next ? diagnosticChainToDiagnosticChain(chain.next) : undefined - }; - } - - function diagnosticMessageToDiagnosticMessageText(message: string | DiagnosticMessageChain): - string|ts.DiagnosticMessageChain { - if (typeof message === 'string') { - return message; - } - return diagnosticChainToDiagnosticChain(message); - } - - function diagnosticToDiagnostic(d: Diagnostic, file: ts.SourceFile): ts.Diagnostic { - const result = { - file, - start: d.span.start, - length: d.span.end - d.span.start, - messageText: diagnosticMessageToDiagnosticMessageText(d.message), - category: ts.DiagnosticCategory.Error, - code: 0, - source: 'ng' - }; - return result; - } + const oldLS: ts.LanguageService = info.languageService; + const proxy: ts.LanguageService = Object.assign({}, oldLS); + const logger = info.project.projectService.logger; function tryOperation(attempting: string, callback: () => T): T|null { try { return callback(); } catch (e) { - info.project.projectService.logger.info(`Failed to ${attempting}: ${e.toString()}`); - info.project.projectService.logger.info(`Stack trace: ${e.stack}`); + logger.info(`Failed to ${attempting}: ${e.toString()}`); + logger.info(`Stack trace: ${e.stack}`); return null; } } - const serviceHost = new TypeScriptServiceHost(info.languageServiceHost, info.languageService); + const serviceHost = new TypeScriptServiceHost(info.languageServiceHost, oldLS); const ls = createLanguageService(serviceHost as any); serviceHost.setSite(ls); projectHostMap.set(info.project, serviceHost); @@ -261,7 +141,7 @@ export function create(info: any /* ts.server.PluginCreateInfo */): ts.LanguageS let result = oldLS.getSemanticDiagnostics(fileName); const base = result || []; tryOperation('get diagnostics', () => { - info.project.projectService.logger.info(`Computing Angular semantic diagnostics...`); + logger.info(`Computing Angular semantic diagnostics...`); const ours = ls.getDiagnostics(fileName); if (ours && ours.length) { const file = oldLS.getProgram() !.getSourceFile(fileName); diff --git a/packages/language-service/src/typescript_host.ts b/packages/language-service/src/typescript_host.ts index a9cad8380e..ec1d3c7f87 100644 --- a/packages/language-service/src/typescript_host.ts +++ b/packages/language-service/src/typescript_host.ts @@ -38,11 +38,7 @@ export function createLanguageServiceFromTypescript( * syntactically incorrect templates. */ export class DummyHtmlParser extends HtmlParser { - parse( - source: string, url: string, parseExpansionForms: boolean = false, - interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ParseTreeResult { - return new ParseTreeResult([], []); - } + parse(): ParseTreeResult { return new ParseTreeResult([], []); } } /** diff --git a/packages/language-service/test/test_utils.ts b/packages/language-service/test/test_utils.ts index 9032df6248..e3bb4871e9 100644 --- a/packages/language-service/test/test_utils.ts +++ b/packages/language-service/test/test_utils.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {isInBazel, setup} from '@angular/compiler-cli/test/test_support'; +import {setup} from '@angular/compiler-cli/test/test_support'; import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; @@ -76,20 +76,9 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { constructor( private scriptNames: string[], private data: MockData, private node_modules: string = 'node_modules', private myPath: typeof path = path) { - const moduleFilename = module.filename.replace(/\\/g, '/'); - if (isInBazel()) { - const support = setup(); - this.nodeModulesPath = path.join(support.basePath, 'node_modules'); - this.angularPath = path.join(this.nodeModulesPath, '@angular'); - } else { - const angularIndex = moduleFilename.indexOf('@angular'); - if (angularIndex >= 0) - this.angularPath = - moduleFilename.substr(0, angularIndex).replace('/all/', '/all/@angular/'); - const distIndex = moduleFilename.indexOf('/dist/all'); - if (distIndex >= 0) - this.nodeModulesPath = myPath.join(moduleFilename.substr(0, distIndex), 'node_modules'); - } + const support = setup(); + this.nodeModulesPath = path.join(support.basePath, 'node_modules'); + this.angularPath = path.join(this.nodeModulesPath, '@angular'); this.options = { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, diff --git a/packages/license-banner.txt b/packages/license-banner.txt index 5e6eac320c..f7aafb73f8 100644 --- a/packages/license-banner.txt +++ b/packages/license-banner.txt @@ -1,5 +1,5 @@ /** * @license Angular v0.0.0-PLACEHOLDER - * (c) 2010-2018 Google, Inc. https://angular.io/ + * (c) 2010-2019 Google LLC. https://angular.io/ * License: MIT */ diff --git a/packages/platform-browser-dynamic/BUILD.bazel b/packages/platform-browser-dynamic/BUILD.bazel index 95f39f55fb..a0aff4d0ad 100644 --- a/packages/platform-browser-dynamic/BUILD.bazel +++ b/packages/platform-browser-dynamic/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/platform-browser-dynamic", deps = [ "//packages:types", "//packages/common", @@ -32,7 +31,9 @@ ng_package( ], # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. - visibility = ["//visibility:private"], + visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", + ], deps = [ ":platform-browser-dynamic", "//packages/platform-browser-dynamic/testing", diff --git a/packages/platform-browser-dynamic/rollup.config.js b/packages/platform-browser-dynamic/rollup.config.js deleted file mode 100644 index 7c7d2ae005..0000000000 --- a/packages/platform-browser-dynamic/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/compiler': 'ng.compiler', - '@angular/platform-browser': 'ng.platformBrowser', -}; - -module.exports = { - entry: '../../dist/packages-dist/platform-browser-dynamic/fesm5/platform-browser-dynamic.js', - dest: '../../dist/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-browser-dynamic'}, - moduleName: 'ng.platformBrowserDynamic', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-browser-dynamic/src/compiler_factory.ts b/packages/platform-browser-dynamic/src/compiler_factory.ts index d978a0393a..728117a857 100644 --- a/packages/platform-browser-dynamic/src/compiler_factory.ts +++ b/packages/platform-browser-dynamic/src/compiler_factory.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {Compiler, CompilerFactory, ComponentFactory, CompilerOptions, ModuleWithComponentFactories, Inject, InjectionToken, Optional, PACKAGE_ROOT_URL, PlatformRef, StaticProvider, TRANSLATIONS, Type, isDevMode, platformCore, ɵConsole as Console, ViewEncapsulation, Injector, NgModuleFactory, TRANSLATIONS_FORMAT, MissingTranslationStrategy,} from '@angular/core'; +import {Compiler, CompilerFactory, ComponentFactory, CompilerOptions, ModuleWithComponentFactories, Inject, InjectionToken, Optional, PACKAGE_ROOT_URL, StaticProvider, TRANSLATIONS, Type, isDevMode, ɵConsole as Console, ViewEncapsulation, Injector, NgModuleFactory, TRANSLATIONS_FORMAT, MissingTranslationStrategy,} from '@angular/core'; -import {StaticSymbolCache, JitCompiler, ProviderMeta, ExternalReference, I18NHtmlParser, Identifiers, ViewCompiler, CompileMetadataResolver, UrlResolver, TemplateParser, NgModuleCompiler, JitSummaryResolver, SummaryResolver, StyleCompiler, PipeResolver, ElementSchemaRegistry, DomElementSchemaRegistry, ResourceLoader, NgModuleResolver, HtmlParser, CompileReflector, CompilerConfig, DirectiveNormalizer, DirectiveResolver, Lexer, Parser} from '@angular/compiler'; +import {StaticSymbolCache, JitCompiler, ProviderMeta, I18NHtmlParser, ViewCompiler, CompileMetadataResolver, UrlResolver, TemplateParser, NgModuleCompiler, JitEvaluator, JitSummaryResolver, SummaryResolver, StyleCompiler, PipeResolver, ElementSchemaRegistry, DomElementSchemaRegistry, ResourceLoader, NgModuleResolver, HtmlParser, CompileReflector, CompilerConfig, DirectiveNormalizer, DirectiveResolver, Lexer, Parser} from '@angular/compiler'; import {JitReflector} from './compiler_reflector'; @@ -37,10 +37,11 @@ export class CompilerImpl implements Compiler { injector: Injector, private _metadataResolver: CompileMetadataResolver, templateParser: TemplateParser, styleCompiler: StyleCompiler, viewCompiler: ViewCompiler, ngModuleCompiler: NgModuleCompiler, summaryResolver: SummaryResolver>, - compileReflector: CompileReflector, compilerConfig: CompilerConfig, console: Console) { + compileReflector: CompileReflector, jitEvaluator: JitEvaluator, + compilerConfig: CompilerConfig, console: Console) { this._delegate = new JitCompiler( _metadataResolver, templateParser, styleCompiler, viewCompiler, ngModuleCompiler, - summaryResolver, compileReflector, compilerConfig, console, + summaryResolver, compileReflector, jitEvaluator, compilerConfig, console, this.getExtraNgModuleProviders.bind(this)); this.injector = injector; } @@ -127,6 +128,7 @@ export const COMPILER_PROVIDERS = [ Parser, ElementSchemaRegistry, I18NHtmlParser, Console] }, + { provide: JitEvaluator, useClass: JitEvaluator, deps: [] }, { provide: DirectiveNormalizer, deps: [ResourceLoader, UrlResolver, HtmlParser, CompilerConfig]}, { provide: CompileMetadataResolver, deps: [CompilerConfig, HtmlParser, NgModuleResolver, DirectiveResolver, PipeResolver, @@ -144,7 +146,7 @@ export const COMPILER_PROVIDERS = [ { provide: Compiler, useClass: CompilerImpl, deps: [Injector, CompileMetadataResolver, TemplateParser, StyleCompiler, ViewCompiler, NgModuleCompiler, - SummaryResolver, CompileReflector, CompilerConfig, + SummaryResolver, CompileReflector, JitEvaluator, CompilerConfig, Console]}, { provide: DomElementSchemaRegistry, deps: []}, { provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry}, diff --git a/packages/platform-browser-dynamic/test/BUILD.bazel b/packages/platform-browser-dynamic/test/BUILD.bazel index ba34be3062..df3439a4f5 100644 --- a/packages/platform-browser-dynamic/test/BUILD.bazel +++ b/packages/platform-browser-dynamic/test/BUILD.bazel @@ -12,6 +12,7 @@ ts_library( "//packages/platform-browser-dynamic", "//packages/platform-browser-dynamic/testing", "//packages/platform-browser/testing", + "//packages/private/testing", ], ) @@ -30,9 +31,6 @@ ts_web_test_suite( "//packages/platform-browser/test:static_assets/test.html", "//packages/platform-browser/test:browser/static_assets/200.html", ], - tags = [ - "fixme-ivy-aot", - ], deps = [ ":test_lib", ], diff --git a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts index 1c6ecb17e6..ead5fa17b2 100644 --- a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts +++ b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts @@ -9,12 +9,10 @@ import {ResourceLoader, UrlResolver} from '@angular/compiler'; import {Component} from '@angular/core'; import {TestBed, async, fakeAsync, tick} from '@angular/core/testing'; +import {CachedResourceLoader} from '@angular/platform-browser-dynamic/src/resource_loader/resource_loader_cache'; +import {setTemplateCache} from '@angular/platform-browser-dynamic/test/resource_loader/resource_loader_cache_setter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {CachedResourceLoader} from '../../src/resource_loader/resource_loader_cache'; - -import {setTemplateCache} from './resource_loader_cache_setter'; - if (isBrowser) { describe('CachedResourceLoader', () => { let resourceLoader: CachedResourceLoader; diff --git a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts index 102bbf676d..480cb97de1 100644 --- a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts +++ b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts @@ -7,7 +7,7 @@ */ import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal'; -import {ResourceLoaderImpl} from '../../src/resource_loader/resource_loader_impl'; +import {ResourceLoaderImpl} from '@angular/platform-browser-dynamic/src/resource_loader/resource_loader_impl'; if (isBrowser) { describe('ResourceLoaderImpl', () => { diff --git a/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts b/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts index 5b08d56cce..0c54024787 100644 --- a/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts +++ b/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts @@ -10,7 +10,7 @@ import {ResourceLoader} from '@angular/compiler'; import {Compiler, Component, NgModule} from '@angular/core'; import {TestBed, async, fakeAsync, inject, tick} from '@angular/core/testing'; -import {ResourceLoaderImpl} from '../src/resource_loader/resource_loader_impl'; +import {ResourceLoaderImpl} from '@angular/platform-browser-dynamic/src/resource_loader/resource_loader_impl'; @@ -143,7 +143,8 @@ if (isBrowser) { expect(componentFixture.nativeElement.textContent).toEqual('from external template'); }); }), - 10000); // Long timeout here because this test makes an actual ResourceLoader request, and + 10000); // Long timeout here because this test makes an actual ResourceLoader + // request, and // is slow // on Edge. }); diff --git a/packages/platform-browser-dynamic/testing/BUILD.bazel b/packages/platform-browser-dynamic/testing/BUILD.bazel index eecbc31e88..2f824255bf 100644 --- a/packages/platform-browser-dynamic/testing/BUILD.bazel +++ b/packages/platform-browser-dynamic/testing/BUILD.bazel @@ -7,7 +7,6 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "testing", srcs = glob(["**/*.ts"]), - module_name = "@angular/platform-browser-dynamic/testing", deps = [ "//packages/compiler", "//packages/compiler/testing", diff --git a/packages/platform-browser-dynamic/testing/rollup.config.js b/packages/platform-browser-dynamic/testing/rollup.config.js deleted file mode 100644 index 60e34047f4..0000000000 --- a/packages/platform-browser-dynamic/testing/rollup.config.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/core/testing': 'ng.core.testing', - '@angular/common': 'ng.common', - '@angular/compiler': 'ng.compiler', - '@angular/compiler/testing': 'ng.compiler.testing', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/platform-browser/testing': 'ng.platformBrowser.testing', - '@angular/platform-browser-dynamic': 'ng.platformBrowserDynamic' -}; - -module.exports = { - entry: '../../../dist/packages-dist/platform-browser-dynamic/fesm5/testing.js', - dest: - '../../../dist/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-browser-dynamic/testing'}, - moduleName: 'ng.platformBrowserDynamic.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-browser/BUILD.bazel b/packages/platform-browser/BUILD.bazel index 10b8c56377..4205044eed 100644 --- a/packages/platform-browser/BUILD.bazel +++ b/packages/platform-browser/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/platform-browser", deps = [ "//packages:types", "//packages/common", @@ -34,6 +33,7 @@ ng_package( # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", "//packages/compiler-cli/test:__pkg__", ], deps = [ diff --git a/packages/platform-browser/animations/BUILD.bazel b/packages/platform-browser/animations/BUILD.bazel index efb6d45469..624fe18a59 100644 --- a/packages/platform-browser/animations/BUILD.bazel +++ b/packages/platform-browser/animations/BUILD.bazel @@ -12,7 +12,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/platform-browser/animations", deps = [ "//packages/animations", "//packages/animations/browser", diff --git a/packages/platform-browser/animations/rollup.config.js b/packages/platform-browser/animations/rollup.config.js deleted file mode 100644 index 3faf536738..0000000000 --- a/packages/platform-browser/animations/rollup.config.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/animations': 'ng.animations', - '@angular/animations/browser': 'ng.animations.browser' -}; - -module.exports = { - entry: '../../../dist/packages-dist/platform-browser/fesm5/animations.js', - dest: '../../../dist/packages-dist/platform-browser/bundles/platform-browser-animations.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-browser/animations'}, - moduleName: 'ng.platformBrowser.animations', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-browser/animations/src/animation_renderer.ts b/packages/platform-browser/animations/src/animation_renderer.ts index 3b089ced3a..59b4f48268 100644 --- a/packages/platform-browser/animations/src/animation_renderer.ts +++ b/packages/platform-browser/animations/src/animation_renderer.ts @@ -148,8 +148,8 @@ export class BaseAnimationRenderer implements Renderer2 { this.engine.onInsert(this.namespaceId, newChild, parent, true); } - removeChild(parent: any, oldChild: any): void { - this.engine.onRemove(this.namespaceId, oldChild, this.delegate); + removeChild(parent: any, oldChild: any, isHostElement: boolean): void { + this.engine.onRemove(this.namespaceId, oldChild, this.delegate, isHostElement); } selectRootElement(selectorOrNode: any, preserveContent?: boolean) { diff --git a/packages/platform-browser/animations/test/animation_renderer_spec.ts b/packages/platform-browser/animations/test/animation_renderer_spec.ts index 733aa52763..2f26069c0f 100644 --- a/packages/platform-browser/animations/test/animation_renderer_spec.ts +++ b/packages/platform-browser/animations/test/animation_renderer_spec.ts @@ -279,36 +279,35 @@ import {el} from '../../testing/src/browser_util'; }); }); - fixmeIvy(`FW-802: Animation 'start' and 'end' hooks are invoked twice`) - .it('should provide hooks at the start and end of change detection', () => { - @Component({ - selector: 'my-cmp', - template: ` + it('should provide hooks at the start and end of change detection', () => { + @Component({ + selector: 'my-cmp', + template: `
    `, - animations: [trigger('myAnimation', [])] - }) - class Cmp { - public exp: any; - } + animations: [trigger('myAnimation', [])] + }) + class Cmp { + public exp: any; + } - TestBed.configureTestingModule({ - providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], - declarations: [Cmp] - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], + declarations: [Cmp] + }); - const renderer = TestBed.get(RendererFactory2) as ExtendedAnimationRendererFactory; - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const renderer = TestBed.get(RendererFactory2) as ExtendedAnimationRendererFactory; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - renderer.log = []; - fixture.detectChanges(); - expect(renderer.log).toEqual(['begin', 'end']); + renderer.log = []; + fixture.detectChanges(); + expect(renderer.log).toEqual(['begin', 'end']); - renderer.log = []; - fixture.detectChanges(); - expect(renderer.log).toEqual(['begin', 'end']); - }); + renderer.log = []; + fixture.detectChanges(); + expect(renderer.log).toEqual(['begin', 'end']); + }); }); })(); diff --git a/packages/platform-browser/rollup.config.js b/packages/platform-browser/rollup.config.js deleted file mode 100644 index af01efe10f..0000000000 --- a/packages/platform-browser/rollup.config.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', -}; - -module.exports = { - entry: '../../dist/packages-dist/platform-browser/fesm5/platform-browser.js', - dest: '../../dist/packages-dist/platform-browser/bundles/platform-browser.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-browser'}, - moduleName: 'ng.platformBrowser', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-browser/src/browser/browser_adapter.ts b/packages/platform-browser/src/browser/browser_adapter.ts index 59de0acd3a..dbe7baf085 100644 --- a/packages/platform-browser/src/browser/browser_adapter.ts +++ b/packages/platform-browser/src/browser/browser_adapter.ts @@ -295,7 +295,7 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { getBoundingClientRect(el: Element): any { try { return el.getBoundingClientRect(); - } catch (e) { + } catch { return {top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0}; } } diff --git a/packages/platform-browser/src/browser/generic_browser_adapter.ts b/packages/platform-browser/src/browser/generic_browser_adapter.ts index 9e631917c9..4ab69dca1a 100644 --- a/packages/platform-browser/src/browser/generic_browser_adapter.ts +++ b/packages/platform-browser/src/browser/generic_browser_adapter.ts @@ -48,7 +48,7 @@ export abstract class GenericBrowserDomAdapter extends DomAdapter { this._transitionEnd = transEndEventNames[key]; } }); - } catch (e) { + } catch { this._animationPrefix = null; this._transitionEnd = null; } diff --git a/packages/platform-browser/src/dom/dom_renderer.ts b/packages/platform-browser/src/dom/dom_renderer.ts index 4c32f03c43..719ddce74e 100644 --- a/packages/platform-browser/src/dom/dom_renderer.ts +++ b/packages/platform-browser/src/dom/dom_renderer.ts @@ -111,7 +111,9 @@ class DefaultDomRenderer2 implements Renderer2 { createElement(name: string, namespace?: string): any { if (namespace) { - return document.createElementNS(NAMESPACE_URIS[namespace], name); + // In cases where Ivy (not ViewEngine) is giving us the actual namespace, the look up by key + // will result in undefined, so we just return the namespace here. + return document.createElementNS(NAMESPACE_URIS[namespace] || namespace, name); } return document.createElement(name); @@ -154,6 +156,8 @@ class DefaultDomRenderer2 implements Renderer2 { setAttribute(el: any, name: string, value: string, namespace?: string): void { if (namespace) { name = `${namespace}:${name}`; + // TODO(benlesh): Ivy may cause issues here because it's passing around + // full URIs for namespaces, therefore this lookup will fail. const namespaceUri = NAMESPACE_URIS[namespace]; if (namespaceUri) { el.setAttributeNS(namespaceUri, name, value); @@ -167,10 +171,15 @@ class DefaultDomRenderer2 implements Renderer2 { removeAttribute(el: any, name: string, namespace?: string): void { if (namespace) { + // TODO(benlesh): Ivy may cause issues here because it's passing around + // full URIs for namespaces, therefore this lookup will fail. const namespaceUri = NAMESPACE_URIS[namespace]; if (namespaceUri) { el.removeAttributeNS(namespaceUri, name); } else { + // TODO(benlesh): Since ivy is passing around full URIs for namespaces + // this could result in properties like `http://www.w3.org/2000/svg:cx="123"`, + // which is wrong. el.removeAttribute(`${namespace}:${name}`); } } else { diff --git a/packages/platform-browser/test/browser/bootstrap_spec.ts b/packages/platform-browser/test/browser/bootstrap_spec.ts index 073270b8f5..94d5c3fd3f 100644 --- a/packages/platform-browser/test/browser/bootstrap_spec.ts +++ b/packages/platform-browser/test/browser/bootstrap_spec.ts @@ -18,7 +18,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {DOCUMENT} from '@angular/platform-browser/src/dom/dom_tokens'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy} from '@angular/private/testing'; +import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; @Component({selector: 'non-existent', template: ''}) class NonExistentComp { @@ -160,8 +160,8 @@ function bootstrap( afterEach(destroyPlatform); - // TODO(misko): can't use `fixmeIvy.it` because the `it` is somehow special here. - fixmeIvy('FW-553: TestBed is unaware of async compilation').isEnabled && + // TODO(misko): can't use `modifiedInIvy.it` because the `it` is somehow special here. + modifiedInIvy('bootstrapping non-Component throws in View Engine').isEnabled && it('should throw if bootstrapped Directive is not a Component', inject([AsyncTestCompleter], (done: AsyncTestCompleter) => { const logger = new MockConsole(); @@ -174,6 +174,22 @@ function bootstrap( done.done(); })); + // TODO(misko): can't use `onlyInIvy.it` because the `it` is somehow special here. + onlyInIvy('bootstrapping non-Component rejects Promise in Ivy').isEnabled && + it('should throw if bootstrapped Directive is not a Component', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const logger = new MockConsole(); + const errorHandler = new ErrorHandler(); + (errorHandler as any)._console = logger as any; + bootstrap(HelloRootDirectiveIsNotCmp, [ + {provide: ErrorHandler, useValue: errorHandler} + ]).catch((error: Error) => { + expect(error).toEqual( + new Error(`HelloRootDirectiveIsNotCmp cannot be used as an entry component.`)); + async.done(); + }); + })); + it('should throw if no element is found', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const logger = new MockConsole(); @@ -189,43 +205,48 @@ function bootstrap( }); })); - // TODO(misko): can't use `fixmeIvy.it` because the `it` is somehow special here. - fixmeIvy('FW-553: TestBed is unaware of async compilation').isEnabled && - it('should throw if no provider', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const logger = new MockConsole(); - const errorHandler = new ErrorHandler(); - (errorHandler as any)._console = logger as any; + it('should throw if no provider', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const logger = new MockConsole(); + const errorHandler = new ErrorHandler(); + (errorHandler as any)._console = logger as any; - class IDontExist {} + class IDontExist {} - @Component({selector: 'cmp', template: 'Cmp'}) - class CustomCmp { - constructor(iDontExist: IDontExist) {} - } + @Component({selector: 'cmp', template: 'Cmp'}) + class CustomCmp { + constructor(iDontExist: IDontExist) {} + } - @Component({ - selector: 'hello-app', - template: '', - }) - class RootCmp { - } + @Component({ + selector: 'hello-app', + template: '', + }) + class RootCmp { + } - @NgModule({declarations: [CustomCmp], exports: [CustomCmp]}) - class CustomModule { - } + @NgModule({declarations: [CustomCmp], exports: [CustomCmp]}) + class CustomModule { + } - bootstrap(RootCmp, [{provide: ErrorHandler, useValue: errorHandler}], [], [ - CustomModule - ]).then(null, (e: Error) => { - expect(e.message).toContain( - 'StaticInjectorError(TestModule)[CustomCmp -> IDontExist]: \n' + - ' StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]: \n' + - ' NullInjectorError: No provider for IDontExist!'); - async.done(); - return null; - }); - })); + bootstrap(RootCmp, [{provide: ErrorHandler, useValue: errorHandler}], [], [ + CustomModule + ]).then(null, (e: Error) => { + let errorMsg: string; + if (ivyEnabled) { + errorMsg = `R3InjectorError(TestModule)[IDontExist]: \n` + + ' StaticInjectorError(TestModule)[IDontExist]: \n' + + ' StaticInjectorError(Platform: core)[IDontExist]: \n' + + ' NullInjectorError: No provider for IDontExist!'; + } else { + errorMsg = `StaticInjectorError(TestModule)[CustomCmp -> IDontExist]: \n` + + ' StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]: \n' + + ' NullInjectorError: No provider for IDontExist!'; + } + expect(e.message).toContain(errorMsg); + async.done(); + return null; + }); + })); if (getDOM().supportsDOMEvents()) { it('should forward the error to promise when bootstrap fails', diff --git a/packages/platform-browser/test/dom/dom_renderer_spec.ts b/packages/platform-browser/test/dom/dom_renderer_spec.ts index ae26bce267..ef47b6b14d 100644 --- a/packages/platform-browser/test/dom/dom_renderer_spec.ts +++ b/packages/platform-browser/test/dom/dom_renderer_spec.ts @@ -87,6 +87,17 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); }); + describe('removeChild', () => { + it('should not error when removing a child with a different parent than given', () => { + const savedParent = document.createElement('div'); + const realParent = document.createElement('div'); + const child = document.createElement('div'); + + realParent.appendChild(child); + renderer.removeChild(savedParent, child); + }); + }); + if (browserDetection.supportsDeprecatedShadowDomV0) { it('should allow to style components with emulated encapsulation and no encapsulation inside of components with shadow DOM', () => { diff --git a/packages/platform-browser/test/dom/events/event_manager_spec.ts b/packages/platform-browser/test/dom/events/event_manager_spec.ts index b294e4e5c0..893e8c7ba3 100644 --- a/packages/platform-browser/test/dom/events/event_manager_spec.ts +++ b/packages/platform-browser/test/dom/events/event_manager_spec.ts @@ -296,7 +296,7 @@ import {el} from '../../../testing/src/browser_util'; expect(receivedEvents).toEqual([]); }); - it('should run blackListedEvents handler outside of ngZone', () => { + it('should run blockListedEvents handler outside of ngZone', () => { const Zone = (window as any)['Zone']; const element = el('
    '); getDOM().appendChild(doc.body, element); diff --git a/packages/platform-browser/test/testing_public_spec.ts b/packages/platform-browser/test/testing_public_spec.ts index b2943bce3d..ae85c71ecf 100644 --- a/packages/platform-browser/test/testing_public_spec.ts +++ b/packages/platform-browser/test/testing_public_spec.ts @@ -10,7 +10,7 @@ import {CompilerConfig, ResourceLoader} from '@angular/compiler'; import {CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, Inject, Injectable, Injector, Input, NgModule, Optional, Pipe, SkipSelf, ɵstringify as stringify} from '@angular/core'; import {TestBed, async, fakeAsync, getTestBed, inject, tick, withModule} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy, obsoleteInIvy} from '@angular/private/testing'; +import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; // Services, and components for the tests. @@ -251,14 +251,13 @@ class CompWithUrlTemplate { expect(compFixture.componentInstance).toBeAnInstanceOf(CompUsingModuleDirectiveAndPipe); }); - fixmeIvy('FW-681: not possible to retrieve host property bindings from TView') - .it('should use set up directives and pipes', () => { - const compFixture = TestBed.createComponent(CompUsingModuleDirectiveAndPipe); - const el = compFixture.debugElement; + it('should use set up directives and pipes', () => { + const compFixture = TestBed.createComponent(CompUsingModuleDirectiveAndPipe); + const el = compFixture.debugElement; - compFixture.detectChanges(); - expect(el.children[0].properties['title']).toBe('transformed someValue'); - }); + compFixture.detectChanges(); + expect(el.children[0].properties['title']).toBe('transformed someValue'); + }); it('should use set up imported modules', inject([SomeLibModule], (libModule: SomeLibModule) => { @@ -289,14 +288,13 @@ class CompWithUrlTemplate { expect(service.value).toEqual('real value'); })); - fixmeIvy('FW-681: not possible to retrieve host property bindings from TView') - .it('should use set up directives and pipes', withModule(moduleConfig, () => { - const compFixture = TestBed.createComponent(CompUsingModuleDirectiveAndPipe); - const el = compFixture.debugElement; + it('should use set up directives and pipes', withModule(moduleConfig, () => { + const compFixture = TestBed.createComponent(CompUsingModuleDirectiveAndPipe); + const el = compFixture.debugElement; - compFixture.detectChanges(); - expect(el.children[0].properties['title']).toBe('transformed someValue'); - })); + compFixture.detectChanges(); + expect(el.children[0].properties['title']).toBe('transformed someValue'); + })); it('should use set up library modules', withModule(moduleConfig).inject([SomeLibModule], (libModule: SomeLibModule) => { @@ -311,12 +309,11 @@ class CompWithUrlTemplate { })); isBrowser && - fixmeIvy('FW-553: TestBed is unaware of async compilation') - .it('should allow to createSync components with templateUrl after explicit async compilation', - () => { - const fixture = TestBed.createComponent(CompWithUrlTemplate); - expect(fixture.nativeElement).toHaveText('from external template'); - }); + it('should allow to createSync components with templateUrl after explicit async compilation', + () => { + const fixture = TestBed.createComponent(CompWithUrlTemplate); + expect(fixture.nativeElement).toHaveText('from external template'); + }); }); describe('overwriting metadata', () => { @@ -372,12 +369,11 @@ class CompWithUrlTemplate { .overrideDirective( SomeDirective, {set: {selector: '[someDir]', host: {'[title]': 'someProp'}}}); }); - fixmeIvy('FW-681: not possible to retrieve host property bindings from TView') - .it('should work', () => { - const compFixture = TestBed.createComponent(SomeComponent); - compFixture.detectChanges(); - expect(compFixture.debugElement.children[0].properties['title']).toEqual('hello'); - }); + it('should work', () => { + const compFixture = TestBed.createComponent(SomeComponent); + compFixture.detectChanges(); + expect(compFixture.debugElement.children[0].properties['title']).toEqual('hello'); + }); }); describe('pipe', () => { @@ -458,28 +454,25 @@ class CompWithUrlTemplate { expect(TestBed.get('a')).toBe('mockA: depValue'); }); - fixmeIvy('FW-855: TestBed.get(Compiler) should return TestBed-specific Compiler instance') - .it('should support SkipSelf', () => { - @NgModule({ - providers: [ - {provide: 'a', useValue: 'aValue'}, - {provide: 'dep', useValue: 'depValue'}, - ] - }) - class MyModule { - } + it('should support SkipSelf', () => { + @NgModule({ + providers: [ + {provide: 'a', useValue: 'aValue'}, + {provide: 'dep', useValue: 'depValue'}, + ] + }) + class MyModule { + } - TestBed.overrideProvider( - 'a', - {useFactory: (dep: any) => `mockA: ${dep}`, deps: [[new SkipSelf(), 'dep']]}); - TestBed.configureTestingModule( - {providers: [{provide: 'dep', useValue: 'parentDepValue'}]}); + TestBed.overrideProvider( + 'a', {useFactory: (dep: any) => `mockA: ${dep}`, deps: [[new SkipSelf(), 'dep']]}); + TestBed.configureTestingModule( + {providers: [{provide: 'dep', useValue: 'parentDepValue'}]}); - const compiler = TestBed.get(Compiler) as Compiler; - const modFactory = compiler.compileModuleSync(MyModule); - expect(modFactory.create(getTestBed()).injector.get('a')) - .toBe('mockA: parentDepValue'); - }); + const compiler = TestBed.get(Compiler) as Compiler; + const modFactory = compiler.compileModuleSync(MyModule); + expect(modFactory.create(getTestBed()).injector.get('a')).toBe('mockA: parentDepValue'); + }); it('should keep imported NgModules eager', () => { let someModule: SomeModule|undefined; @@ -727,61 +720,58 @@ class CompWithUrlTemplate { }); describe('overrideTemplateUsingTestingModule', () => { - fixmeIvy('FW-851: TestBed.overrideTemplateUsingTestingModule is not implemented') - .it('should compile the template in the context of the testing module', () => { - @Component({selector: 'comp', template: 'a'}) - class MyComponent { - prop = 'some prop'; - } + it('should compile the template in the context of the testing module', () => { + @Component({selector: 'comp', template: 'a'}) + class MyComponent { + prop = 'some prop'; + } - let testDir: TestDir|undefined; + let testDir: TestDir|undefined; - @Directive({selector: '[test]'}) - class TestDir { - constructor() { testDir = this; } + @Directive({selector: '[test]'}) + class TestDir { + constructor() { testDir = this; } - // TODO(issue/24571): remove '!'. - @Input('test') - test !: string; - } + // TODO(issue/24571): remove '!'. + @Input('test') + test !: string; + } - TestBed.overrideTemplateUsingTestingModule( - MyComponent, '
    Hello world!
    '); + TestBed.overrideTemplateUsingTestingModule( + MyComponent, '
    Hello world!
    '); - const fixture = TestBed.configureTestingModule({declarations: [MyComponent, TestDir]}) - .createComponent(MyComponent); - fixture.detectChanges(); - expect(fixture.nativeElement).toHaveText('Hello world!'); - expect(testDir).toBeAnInstanceOf(TestDir); - expect(testDir !.test).toBe('some prop'); - }); + const fixture = TestBed.configureTestingModule({declarations: [MyComponent, TestDir]}) + .createComponent(MyComponent); + fixture.detectChanges(); + expect(fixture.nativeElement).toHaveText('Hello world!'); + expect(testDir).toBeAnInstanceOf(TestDir); + expect(testDir !.test).toBe('some prop'); + }); - fixmeIvy('FW-851: TestBed.overrideTemplateUsingTestingModule is not implemented') - .it('should throw if the TestBed is already created', () => { - @Component({selector: 'comp', template: 'a'}) - class MyComponent { - } + it('should throw if the TestBed is already created', () => { + @Component({selector: 'comp', template: 'a'}) + class MyComponent { + } - TestBed.get(Injector); + TestBed.get(Injector); - expect(() => TestBed.overrideTemplateUsingTestingModule(MyComponent, 'b')) - .toThrowError( - /Cannot override template when the test module has already been instantiated/); - }); + expect(() => TestBed.overrideTemplateUsingTestingModule(MyComponent, 'b')) + .toThrowError( + /Cannot override template when the test module has already been instantiated/); + }); - fixmeIvy('FW-851: TestBed.overrideTemplateUsingTestingModule is not implemented') - .it('should reset overrides when the testing module is resetted', () => { - @Component({selector: 'comp', template: 'a'}) - class MyComponent { - } + it('should reset overrides when the testing module is resetted', () => { + @Component({selector: 'comp', template: 'a'}) + class MyComponent { + } - TestBed.overrideTemplateUsingTestingModule(MyComponent, 'b'); + TestBed.overrideTemplateUsingTestingModule(MyComponent, 'b'); - const fixture = TestBed.resetTestingModule() - .configureTestingModule({declarations: [MyComponent]}) - .createComponent(MyComponent); - expect(fixture.nativeElement).toHaveText('a'); - }); + const fixture = TestBed.resetTestingModule() + .configureTestingModule({declarations: [MyComponent]}) + .createComponent(MyComponent); + expect(fixture.nativeElement).toHaveText('a'); + }); }); describe('setting up the compiler', () => { @@ -795,13 +785,12 @@ class CompWithUrlTemplate { {providers: [{provide: ResourceLoader, useValue: {get: resourceLoaderGet}}]}); }); - fixmeIvy('FW-553: TestBed is unaware of async compilation') - .it('should use set up providers', fakeAsync(() => { - TestBed.compileComponents(); - tick(); - const compFixture = TestBed.createComponent(CompWithUrlTemplate); - expect(compFixture.nativeElement).toHaveText('Hello world!'); - })); + it('should use set up providers', fakeAsync(() => { + TestBed.compileComponents(); + tick(); + const compFixture = TestBed.createComponent(CompWithUrlTemplate); + expect(compFixture.nativeElement).toHaveText('Hello world!'); + })); }); describe('useJit true', () => { @@ -907,27 +896,30 @@ class CompWithUrlTemplate { {providers: [{provide: ResourceLoader, useValue: {get: resourceLoaderGet}}]}); }); - fixmeIvy('FW-553: TestBed is unaware of async compilation') - .it('should report an error for declared components with templateUrl which never call TestBed.compileComponents', - () => { - const itPromise = patchJasmineIt(); + it('should report an error for declared components with templateUrl which never call TestBed.compileComponents', + () => { + const itPromise = patchJasmineIt(); - expect( - () => it( - 'should fail', withModule( - {declarations: [CompWithUrlTemplate]}, - () => TestBed.createComponent(CompWithUrlTemplate)))) - .toThrowError( - `This test module uses the component ${stringify(CompWithUrlTemplate)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` + - `Please call "TestBed.compileComponents" before your test.`); + expect( + () => + it('should fail', withModule( + {declarations: [CompWithUrlTemplate]}, + () => TestBed.createComponent(CompWithUrlTemplate)))) + .toThrowError( + ivyEnabled ? + `Component 'CompWithUrlTemplate' is not resolved: + - templateUrl: /base/angular/packages/platform-browser/test/static_assets/test.html +Did you run and wait for 'resolveComponentResources()'?` : + `This test module uses the component ${stringify(CompWithUrlTemplate)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` + + `Please call "TestBed.compileComponents" before your test.`); - restoreJasmineIt(); - }); + restoreJasmineIt(); + }); }); - fixmeIvy(`FW-721: Bindings to unknown properties are not reported as errors`) + modifiedInIvy(`Unknown property error thrown during update mode, not creation mode`) .it('should error on unknown bound properties on custom elements by default', () => { @Component({template: ''}) class ComponentUsingInvalidProperty { @@ -945,6 +937,28 @@ class CompWithUrlTemplate { restoreJasmineIt(); }); + + onlyInIvy(`Unknown property error thrown during update mode, not creation mode`) + .it('should error on unknown bound properties on custom elements by default', () => { + @Component({template: ''}) + class ComponentUsingInvalidProperty { + } + + const itPromise = patchJasmineIt(); + + expect( + () => it( + 'should fail', withModule( + {declarations: [ComponentUsingInvalidProperty]}, + () => { + const fixture = + TestBed.createComponent(ComponentUsingInvalidProperty); + fixture.detectChanges(); + }))) + .toThrowError(/Can't bind to 'someUnknownProp'/); + + restoreJasmineIt(); + }); }); describe('creating components', () => { @@ -1018,7 +1032,6 @@ class CompWithUrlTemplate { }); it('should override component dependencies', async(() => { - const componentFixture = TestBed.createComponent(ParentComp); componentFixture.detectChanges(); expect(componentFixture.nativeElement).toHaveText('Parent(Mock)'); diff --git a/packages/platform-browser/testing/BUILD.bazel b/packages/platform-browser/testing/BUILD.bazel index 8f6ce115f9..ad8a09cfa9 100644 --- a/packages/platform-browser/testing/BUILD.bazel +++ b/packages/platform-browser/testing/BUILD.bazel @@ -7,7 +7,6 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "testing", srcs = glob(["**/*.ts"]), - module_name = "@angular/platform-browser/testing", deps = [ "//packages/core", "//packages/core/testing", diff --git a/packages/platform-browser/testing/rollup.config.js b/packages/platform-browser/testing/rollup.config.js deleted file mode 100644 index d2424ff7f5..0000000000 --- a/packages/platform-browser/testing/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/core/testing': 'ng.core.testing', - '@angular/common': 'ng.common', - '@angular/platform-browser': 'ng.platformBrowser' -}; - -module.exports = { - entry: '../../../dist/packages-dist/platform-browser/fesm5/testing.js', - dest: '../../../dist/packages-dist/platform-browser/bundles/platform-browser-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-browser/testing'}, - moduleName: 'ng.platformBrowser.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-server/BUILD.bazel b/packages/platform-server/BUILD.bazel index 5a3fa5b476..7e4e0022a8 100644 --- a/packages/platform-server/BUILD.bazel +++ b/packages/platform-server/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/platform-server", deps = [ "//packages/animations/browser", "//packages/common", @@ -39,7 +38,9 @@ ng_package( ], # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. - visibility = ["//visibility:private"], + visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", + ], deps = [ ":platform-server", "//packages/platform-server/testing", diff --git a/packages/platform-server/rollup.config.js b/packages/platform-server/rollup.config.js deleted file mode 100644 index 81f3915684..0000000000 --- a/packages/platform-server/rollup.config.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/animations': 'ng.animations', - '@angular/animations/browser': 'ng.animations.browser', - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/common/http': 'ng.common.http', - '@angular/compiler': 'ng.compiler', - '@angular/http': 'ng.http', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/platform-browser/animations': 'ng.platformBrowser.animations', - '@angular/platform-browser-dynamic': 'ng.platformBrowserDynamic', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../dist/packages-dist/platform-server/fesm5/platform-server.js', - dest: '../../dist/packages-dist/platform-server/bundles/platform-server.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-server'}, - moduleName: 'ng.platformServer', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-server/src/server_renderer.ts b/packages/platform-server/src/server_renderer.ts index 9cd29cfa6a..f4901fd2d3 100644 --- a/packages/platform-server/src/server_renderer.ts +++ b/packages/platform-server/src/server_renderer.ts @@ -12,11 +12,13 @@ import {DOCUMENT, EventManager, ɵNAMESPACE_URIS as NAMESPACE_URIS, ɵSharedStyl const EMPTY_ARRAY: any[] = []; +const DEFAULT_SCHEMA = new DomElementSchemaRegistry(); + @Injectable() export class ServerRendererFactory2 implements RendererFactory2 { private rendererByCompId = new Map(); private defaultRenderer: Renderer2; - private schema = new DomElementSchemaRegistry(); + private schema = DEFAULT_SCHEMA; constructor( private eventManager: EventManager, private ngZone: NgZone, @@ -41,8 +43,6 @@ export class ServerRendererFactory2 implements RendererFactory2 { (renderer).applyToHost(element); return renderer; } - case ViewEncapsulation.Native: - throw new Error('Native encapsulation is not supported on the server!'); default: { if (!this.rendererByCompId.has(type.id)) { const styles = flattenStyles(type.id, type.styles, []); diff --git a/packages/platform-server/test/integration_spec.ts b/packages/platform-server/test/integration_spec.ts index 2b0a2462f8..3bac6084ad 100644 --- a/packages/platform-server/test/integration_spec.ts +++ b/packages/platform-server/test/integration_spec.ts @@ -17,7 +17,7 @@ import {MockBackend, MockConnection} from '@angular/http/testing'; import {BrowserModule, DOCUMENT, Title, TransferState, makeStateKey} from '@angular/platform-browser'; import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter'; import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG, PlatformState, ServerModule, ServerTransferStateModule, platformDynamicServer, renderModule, renderModuleFactory} from '@angular/platform-server'; -import {fixmeIvy, ivyEnabled} from '@angular/private/testing'; +import {fixmeIvy, ivyEnabled, modifiedInIvy} from '@angular/private/testing'; import {Observable} from 'rxjs'; import {first} from 'rxjs/operators'; @@ -99,7 +99,7 @@ class TitleApp { class TitleAppModule { } -@Component({selector: 'app', template: '{{text}}

    '}) +@Component({selector: 'app', template: '{{text}}

    '}) class MyAsyncServerApp { text = ''; h1 = ''; @@ -276,6 +276,19 @@ class MyHostComponent { class FalseAttributesModule { } +@Component({selector: 'app', template: '
    '}) +class InnerTextComponent { + foo = 'Some text'; +} + +@NgModule({ + declarations: [InnerTextComponent], + bootstrap: [InnerTextComponent], + imports: [ServerModule, BrowserModule.withServerTransition({appId: 'inner-text'})] +}) +class InnerTextModule { +} + @Component({selector: 'app', template: ''}) class MyInputComponent { @Input() @@ -528,7 +541,7 @@ class HiddenModule { let doc: string; let called: boolean; let expectedOutput = - 'Works!

    fine

    '; + 'Works!

    fine

    '; beforeEach(() => { // PlatformConfig takes in a parsed document so that it can be cached across requests. @@ -567,6 +580,15 @@ class HiddenModule { }); })); + modifiedInIvy('Will not support binding to innerText in Ivy since domino does not') + .it('should support binding to innerText', async(() => { + renderModule(InnerTextModule, {document: doc}).then(output => { + expect(output).toBe( + '
    Some text
    '); + called = true; + }); + })); + it('using renderModuleFactory should work', async(inject([PlatformRef], (defaultPlatform: PlatformRef) => { const compilerFactory: CompilerFactory = @@ -579,15 +601,14 @@ class HiddenModule { }); }))); - fixmeIvy('FW-672: SVG xlink:href is sanitized to :xlink:href (extra ":")') - .it('works with SVG elements', async(() => { - renderModule(SVGServerModule, {document: doc}).then(output => { - expect(output).toBe( - '' + - ''); - called = true; - }); - })); + it('works with SVG elements', async(() => { + renderModule(SVGServerModule, {document: doc}).then(output => { + expect(output).toBe( + '' + + ''); + called = true; + }); + })); it('works with animation', async(() => { renderModule(AnimationServerModule, {document: doc}).then(output => { @@ -617,15 +638,14 @@ class HiddenModule { }); })); - fixmeIvy('unknown').it( - 'should handle false values on attributes', async(() => { - renderModule(FalseAttributesModule, {document: doc}).then(output => { - expect(output).toBe( - '' + - 'Works!'); - called = true; - }); - })); + it('should handle false values on attributes', async(() => { + renderModule(FalseAttributesModule, {document: doc}).then(output => { + expect(output).toBe( + '' + + 'Works!'); + called = true; + }); + })); it('should handle element property "name"', async(() => { renderModule(NameModule, {document: doc}).then(output => { diff --git a/packages/platform-server/testing/BUILD.bazel b/packages/platform-server/testing/BUILD.bazel index 5a00c83396..a9a532a720 100644 --- a/packages/platform-server/testing/BUILD.bazel +++ b/packages/platform-server/testing/BUILD.bazel @@ -7,7 +7,6 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "testing", srcs = glob(["**/*.ts"]), - module_name = "@angular/platform-server/testing", deps = [ "//packages/core", "//packages/platform-browser-dynamic/testing", diff --git a/packages/platform-server/testing/rollup.config.js b/packages/platform-server/testing/rollup.config.js deleted file mode 100644 index 1dbe00b8b5..0000000000 --- a/packages/platform-server/testing/rollup.config.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/compiler': 'ng.compiler', - '@angular/compiler/testing': 'ng.compiler.testing', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/platform-browser/animations': 'ng.platformBrowser.animations', - '@angular/platform-server': 'ng.platformServer', - '@angular/platform-browser-dynamic/testing': 'ng.platformBrowserDynamic.testing' -}; - -module.exports = { - entry: '../../../dist/packages-dist/platform-server/fesm5/testing.js', - dest: '../../../dist/packages-dist/platform-server/bundles/platform-server-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-server/testing'}, - moduleName: 'ng.platformServer.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-webworker-dynamic/BUILD.bazel b/packages/platform-webworker-dynamic/BUILD.bazel index dbd16fd4ef..5feac79de4 100644 --- a/packages/platform-webworker-dynamic/BUILD.bazel +++ b/packages/platform-webworker-dynamic/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/platform-webworker-dynamic", deps = [ "//packages:types", "//packages/common", diff --git a/packages/platform-webworker-dynamic/rollup.config.js b/packages/platform-webworker-dynamic/rollup.config.js deleted file mode 100644 index 471ffbe3c9..0000000000 --- a/packages/platform-webworker-dynamic/rollup.config.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/compiler': 'ng.compiler', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/platform-browser-dynamic': 'ng.platformBrowserDynamic', - '@angular/platform-webworker': 'ng.platformWebworker', -}; - -module.exports = { - entry: '../../dist/packages-dist/platform-webworker-dynamic/fesm5/platform-webworker-dynamic.js', - dest: - '../../dist/packages-dist/platform-webworker-dynamic/bundles/platform-webworker-dynamic.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-webworker-dynamic'}, - moduleName: 'ng.platformWebworkerDynamic', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-webworker/BUILD.bazel b/packages/platform-webworker/BUILD.bazel index 207395b8ae..fcc14ecce8 100644 --- a/packages/platform-webworker/BUILD.bazel +++ b/packages/platform-webworker/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/platform-webworker", deps = [ "//packages:types", "//packages/common", diff --git a/packages/platform-webworker/rollup.config.js b/packages/platform-webworker/rollup.config.js deleted file mode 100644 index 91d8e4a14d..0000000000 --- a/packages/platform-webworker/rollup.config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/platform-browser': 'ng.platformBrowser', - 'rxjs': 'rxjs', -}; - -module.exports = { - entry: '../../dist/packages-dist/platform-webworker/fesm5/platform-webworker.js', - dest: '../../dist/packages-dist/platform-webworker/bundles/platform-webworker.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/platform-webworker'}, - moduleName: 'ng.platformWebworker', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/platform-webworker/src/worker_app.ts b/packages/platform-webworker/src/worker_app.ts index 8571fe5798..bee58e6296 100644 --- a/packages/platform-webworker/src/worker_app.ts +++ b/packages/platform-webworker/src/worker_app.ts @@ -7,7 +7,7 @@ */ import {CommonModule, ViewportScroller, ɵNullViewportScroller as NullViewportScroller, ɵPLATFORM_WORKER_APP_ID as PLATFORM_WORKER_APP_ID} from '@angular/common'; -import {APP_INITIALIZER, ApplicationModule, ErrorHandler, NgModule, NgZone, PLATFORM_ID, PlatformRef, RendererFactory2, RootRenderer, StaticProvider, createPlatformFactory, platformCore} from '@angular/core'; +import {APP_INITIALIZER, ApplicationModule, ErrorHandler, NgModule, NgZone, PLATFORM_ID, PlatformRef, RendererFactory2, RootRenderer, StaticProvider, createPlatformFactory, platformCore, ɵAPP_ROOT as APP_ROOT} from '@angular/core'; import {DOCUMENT, ɵBROWSER_SANITIZATION_PROVIDERS as BROWSER_SANITIZATION_PROVIDERS} from '@angular/platform-browser'; import {ON_WEB_WORKER} from './web_workers/shared/api'; @@ -60,6 +60,7 @@ export function setupWebWorker(): void { @NgModule({ providers: [ BROWSER_SANITIZATION_PROVIDERS, + {provide: APP_ROOT, useValue: true}, Serializer, {provide: DOCUMENT, useValue: null}, ClientMessageBrokerFactory, diff --git a/packages/platform-webworker/src/worker_render.ts b/packages/platform-webworker/src/worker_render.ts index 5454c9e7c3..e4d59fb966 100644 --- a/packages/platform-webworker/src/worker_render.ts +++ b/packages/platform-webworker/src/worker_render.ts @@ -133,7 +133,7 @@ function initWebWorkerRenderPlatform(injector: Injector): () => void { let scriptUri: string; try { scriptUri = injector.get(WORKER_SCRIPT); - } catch (e) { + } catch { throw new Error( 'You must provide your WebWorker\'s initialization script with the WORKER_SCRIPT token'); } diff --git a/packages/platform-webworker/test/web_workers/worker/renderer_v2_integration_spec.ts b/packages/platform-webworker/test/web_workers/worker/renderer_v2_integration_spec.ts index 111a2d45f2..6d9ce656b4 100644 --- a/packages/platform-webworker/test/web_workers/worker/renderer_v2_integration_spec.ts +++ b/packages/platform-webworker/test/web_workers/worker/renderer_v2_integration_spec.ts @@ -20,7 +20,7 @@ import {Serializer} from '@angular/platform-webworker/src/web_workers/shared/ser import {ServiceMessageBrokerFactory} from '@angular/platform-webworker/src/web_workers/shared/service_message_broker'; import {MessageBasedRenderer2} from '@angular/platform-webworker/src/web_workers/ui/renderer'; import {WebWorkerRendererFactory2} from '@angular/platform-webworker/src/web_workers/worker/renderer'; -import {fixmeIvy} from '@angular/private/testing'; +import {modifiedInIvy} from '@angular/private/testing'; import {PairedMessageBuses, createPairedMessageBuses} from '../shared/web_worker_test_util'; @@ -95,7 +95,7 @@ let lastCreatedRenderer: Renderer2; expect(renderEl).toHaveText('Hello World!'); }); - fixmeIvy('FW-750: fixture.debugElement.children is null') + modifiedInIvy('DebugElements are not supported on web-worker') .it('should update any element property/attributes/class/style(s) independent of the compilation on the root element and other elements', () => { const fixture = @@ -160,7 +160,7 @@ let lastCreatedRenderer: Renderer2; }); if (getDOM().supportsDOMEvents()) { - fixmeIvy('FW-750: fixture.debugElement.children is null') + modifiedInIvy('DebugElements are not supported on web-worker') .it('should listen to events', () => { const fixture = TestBed.overrideTemplate(MyComp2, '') .createComponent(MyComp2); diff --git a/packages/private/testing/BUILD.bazel b/packages/private/testing/BUILD.bazel index 3c5b80774d..90299288c5 100644 --- a/packages/private/testing/BUILD.bazel +++ b/packages/private/testing/BUILD.bazel @@ -1,4 +1,7 @@ -package(default_visibility = ["//packages:__subpackages__"]) +package(default_visibility = [ + "//modules/playground:__subpackages__", + "//packages:__subpackages__", +]) exports_files(["package.json"]) diff --git a/packages/private/testing/src/goog_get_msg.ts b/packages/private/testing/src/goog_get_msg.ts index 902339e955..2547839cd8 100644 --- a/packages/private/testing/src/goog_get_msg.ts +++ b/packages/private/testing/src/goog_get_msg.ts @@ -16,13 +16,12 @@ export function polyfillGoogGetMsg(translations: {[key: string]: string} = {}): void { const glob = (global as any); glob.goog = glob.goog || {}; - glob.goog.getMsg = - glob.goog.getMsg || function(input: string, placeholders: {[key: string]: string} = {}) { - if (typeof translations[input] !== 'undefined') { // to account for empty string - input = translations[input]; - } - return Object.keys(placeholders).length ? - input.replace(/\{\$(.*?)\}/g, (match, key) => placeholders[key] || '') : - input; - }; -} + glob.goog.getMsg = function(input: string, placeholders: {[key: string]: string} = {}) { + if (typeof translations[input] !== 'undefined') { // to account for empty string + input = translations[input]; + } + return Object.keys(placeholders).length ? + input.replace(/\{\$(.*?)\}/g, (match, key) => placeholders[key] || '') : + input; + }; +} \ No newline at end of file diff --git a/packages/private/testing/src/ivy_test_selectors.ts b/packages/private/testing/src/ivy_test_selectors.ts index 9111b61b45..38b0ceb47e 100644 --- a/packages/private/testing/src/ivy_test_selectors.ts +++ b/packages/private/testing/src/ivy_test_selectors.ts @@ -94,7 +94,7 @@ export function obsoleteInIvy(reason: string): JasmineMethods { * ``` */ export function onlyInIvy(reason: string): JasmineMethods { - return ivyEnabled ? PASSTHROUGH : IGNORE; + return ivyEnabled && !FIND_PASSING_TESTS ? PASSTHROUGH : IGNORE; } /** diff --git a/packages/router/BUILD.bazel b/packages/router/BUILD.bazel index 9d01a2dd5d..480deb3a88 100644 --- a/packages/router/BUILD.bazel +++ b/packages/router/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/router", deps = [ "//packages/common", "//packages/core", @@ -34,6 +33,7 @@ ng_package( # Do not add more to this list. # Dependencies on the full npm_package cause long re-builds. visibility = [ + "//packages/compiler-cli/integrationtest:__pkg__", "//packages/compiler-cli/test:__pkg__", "//packages/compiler-cli/test/transformers:__pkg__", ], diff --git a/packages/router/LICENSE b/packages/router/LICENSE deleted file mode 100644 index 26db104f5f..0000000000 --- a/packages/router/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2017-2018 Google, Inc. http://angular.io - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/packages/router/README.md b/packages/router/README.md index b56a7b5a8b..533956ec1d 100644 --- a/packages/router/README.md +++ b/packages/router/README.md @@ -5,21 +5,5 @@ Managing state transitions is one of the hardest parts of building applications. The Angular router is designed to solve these problems. Using the router, you can declaratively specify application state, manage state transitions while taking care of the URL, and load components on demand. -## Overview -Read the overview of the Router [here](https://vsavkin.com/angular-2-router-d9e30599f9ea). - ## Guide -Read the dev guide [here](https://angular.io/docs/ts/latest/guide/router.html). - -## Local development - -``` -# keep @angular/router fresh -$ ./scripts/karma.sh - -# keep @angular/core fresh -$ ../../../node_modules/.bin/tsc -p modules --emitDecoratorMetadata -w - -# start karma -$ ./scripts/karma.sh -``` +Read the dev guide [here](https://angular.io/guide/router). diff --git a/packages/router/rollup.config.js b/packages/router/rollup.config.js deleted file mode 100644 index 4bdd65fbd9..0000000000 --- a/packages/router/rollup.config.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/platform-browser': 'ng.platformBrowser', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../dist/packages-dist/router/fesm5/router.js', - dest: '../../dist/packages-dist/router/bundles/router.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/router'}, - moduleName: 'ng.router', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/router/src/config.ts b/packages/router/src/config.ts index 5edcaaaf26..d2291b4489 100644 --- a/packages/router/src/config.ts +++ b/packages/router/src/config.ts @@ -30,9 +30,10 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree'; * * `path` 是一个用于路由匹配 DSL 中的字符串。 * - * - `pathMatch` is a string that specifies the matching strategy. + * - `pathMatch` is a string that specifies the matching strategy. Options are `prefix` (default) + * and `full`. See [Matching Strategy](#matching-strategy) below for more information. * - * `pathMatch`是一个用来指定路由匹配策略的字符串。 + * `pathMatch`是一个用来指定路由匹配策略的字符串。可选项有 `prefix`(默认值)和 `full`。参见[匹配策略](#matching-strategy)部分,以了解更多知识。 * * - `matcher` defines a custom strategy for path matching and supersedes `path` and `pathMatch`. * diff --git a/packages/router/src/directives/router_link.ts b/packages/router/src/directives/router_link.ts index ea02573918..842b3ae2eb 100644 --- a/packages/router/src/directives/router_link.ts +++ b/packages/router/src/directives/router_link.ts @@ -95,7 +95,7 @@ import {UrlTree} from '../url_tree'; * * ``` * - * You can tell the directive to how to handle queryParams, available options are: + * You can tell the directive how to handle queryParams. Available options are: * * 你可以告诉该指令要如何处理查询参数,有效的选项包括: * @@ -165,7 +165,7 @@ import {UrlTree} from '../url_tree'; * * @publicApi */ -@Directive({selector: ':not(a)[routerLink]'}) +@Directive({selector: ':not(a):not(area)[routerLink]'}) export class RouterLink { // TODO(issue/24571): remove '!'. @Input() queryParams !: {[k: string]: any}; @@ -249,7 +249,7 @@ export class RouterLink { * * @publicApi */ -@Directive({selector: 'a[routerLink]'}) +@Directive({selector: 'a[routerLink],area[routerLink]'}) export class RouterLinkWithHref implements OnChanges, OnDestroy { // TODO(issue/24571): remove '!'. @HostBinding('attr.target') @Input() target !: string; diff --git a/packages/router/src/directives/router_link_active.ts b/packages/router/src/directives/router_link_active.ts index bd472bce92..f0df73fdfe 100644 --- a/packages/router/src/directives/router_link_active.ts +++ b/packages/router/src/directives/router_link_active.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AfterContentInit, ChangeDetectorRef, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer2, SimpleChanges} from '@angular/core'; +import {AfterContentInit, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, Optional, QueryList, Renderer2, SimpleChanges} from '@angular/core'; import {Subscription} from 'rxjs'; import {NavigationEnd, RouterEvent} from '../events'; @@ -113,7 +113,8 @@ export class RouterLinkActive implements OnChanges, constructor( private router: Router, private element: ElementRef, private renderer: Renderer2, - private cdr: ChangeDetectorRef) { + @Optional() private link?: RouterLink, + @Optional() private linkWithHref?: RouterLinkWithHref) { this.subscription = router.events.subscribe((s: RouterEvent) => { if (s instanceof NavigationEnd) { this.update(); @@ -160,7 +161,9 @@ export class RouterLinkActive implements OnChanges, } private hasActiveLinks(): boolean { - return this.links.some(this.isLinkActive(this.router)) || - this.linksWithHrefs.some(this.isLinkActive(this.router)); + const isActiveCheckFn = this.isLinkActive(this.router); + return this.link && isActiveCheckFn(this.link) || + this.linkWithHref && isActiveCheckFn(this.linkWithHref) || + this.links.some(isActiveCheckFn) || this.linksWithHrefs.some(isActiveCheckFn); } } diff --git a/packages/router/src/interfaces.ts b/packages/router/src/interfaces.ts index 7e0a94f7ee..67ad6a170c 100644 --- a/packages/router/src/interfaces.ts +++ b/packages/router/src/interfaces.ts @@ -359,7 +359,7 @@ export interface Resolve { /** * @description * - * Interface that a class can implement to be a guard deciding if a children can be loaded. + * Interface that a class can implement to be a guard deciding if children can be loaded. * * 一个接口,某些类可以实现它以扮演一个守卫,来决定该路由的子路由能否加载。 * diff --git a/packages/router/src/router.ts b/packages/router/src/router.ts index b080518ff5..6b3f20699b 100644 --- a/packages/router/src/router.ts +++ b/packages/router/src/router.ts @@ -469,7 +469,7 @@ export class Router { this.resetConfig(config); this.currentUrlTree = createEmptyUrlTree(); this.rawUrlTree = this.currentUrlTree; - this.browserUrlTree = this.parseUrl(this.location.path()); + this.browserUrlTree = this.currentUrlTree; this.configLoader = new RouterConfigLoader(loader, compiler, onLoadStart, onLoadEnd); this.routerState = createEmptyState(this.currentUrlTree, this.rootComponentType); @@ -573,8 +573,10 @@ export class Router { // Update URL if in `eager` update mode tap(t => { - if (this.urlUpdateStrategy === 'eager' && !t.extras.skipLocationChange) { - this.setBrowserUrl(t.urlAfterRedirects, !!t.extras.replaceUrl, t.id); + if (this.urlUpdateStrategy === 'eager') { + if (!t.extras.skipLocationChange) { + this.setBrowserUrl(t.urlAfterRedirects, !!t.extras.replaceUrl, t.id); + } this.browserUrlTree = t.urlAfterRedirects; } }), @@ -737,8 +739,11 @@ export class Router { (this as{routerState: RouterState}).routerState = t.targetRouterState !; - if (this.urlUpdateStrategy === 'deferred' && !t.extras.skipLocationChange) { - this.setBrowserUrl(this.rawUrlTree, !!t.extras.replaceUrl, t.id, t.extras.state); + if (this.urlUpdateStrategy === 'deferred') { + if (!t.extras.skipLocationChange) { + this.setBrowserUrl( + this.rawUrlTree, !!t.extras.replaceUrl, t.id, t.extras.state); + } this.browserUrlTree = t.urlAfterRedirects; } }), @@ -778,9 +783,14 @@ export class Router { /* This error type is issued during Redirect, and is handled as a cancellation * rather than an error. */ if (isNavigationCancelingError(e)) { - this.navigated = true; const redirecting = isUrlTree(e.url); if (!redirecting) { + // Set property only if we're not redirecting. If we landed on a page and + // redirect to `/` route, the new navigation is going to see the `/` isn't + // a change from the default currentUrlTree and won't navigate. This is + // only applicable with initial navigation, so setting `navigated` only when + // not redirecting resolves this scenario. + this.navigated = true; this.resetStateAndUrl(t.currentRouterState, t.currentUrlTree, t.rawUrl); } const navCancel = diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 9b8a0d326d..7b7d9fc022 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -12,7 +12,6 @@ import {ChangeDetectionStrategy, Component, Injectable, NgModule, NgModuleFactor import {ComponentFixture, TestBed, fakeAsync, inject, tick} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {fixmeIvy} from '@angular/private/testing'; import {ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, CanActivate, CanDeactivate, ChildActivationEnd, ChildActivationStart, DefaultUrlSerializer, DetachedRouteHandle, Event, GuardsCheckEnd, GuardsCheckStart, Navigation, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, PRIMARY_OUTLET, ParamMap, Params, PreloadAllModules, PreloadingStrategy, Resolve, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, Router, RouterEvent, RouterModule, RouterPreloader, RouterStateSnapshot, RoutesRecognized, RunGuardsAndResolvers, UrlHandlingStrategy, UrlSegmentGroup, UrlSerializer, UrlTree} from '@angular/router'; import {Observable, Observer, Subscription, of } from 'rxjs'; import {filter, first, map, tap} from 'rxjs/operators'; @@ -497,9 +496,6 @@ describe('Integration', () => { fixture.componentInstance.cond = true; advance(fixture); expect(fixture.nativeElement).toHaveText('[simple]'); - - // TODO: remove extra tick for Ivy? - tick(); })); it('should update location when navigating', fakeAsync(() => { @@ -575,6 +571,27 @@ describe('Integration', () => { expect(fixture.nativeElement).toHaveText('team 33 [ , right: ]'); }))); + it('should navigate after navigation with skipLocationChange', + fakeAsync(inject([Router, Location], (router: Router, location: Location) => { + const fixture = TestBed.createComponent(RootCmpWithNamedOutlet); + advance(fixture); + + router.resetConfig([{path: 'show', outlet: 'main', component: SimpleCmp}]); + + router.navigate([{outlets: {main: 'show'}}], {skipLocationChange: true}); + advance(fixture); + expect(location.path()).toEqual(''); + + expect(fixture.nativeElement).toHaveText('main [simple]'); + + router.navigate([{outlets: {main: null}}], {skipLocationChange: true}); + advance(fixture); + + expect(location.path()).toEqual(''); + + expect(fixture.nativeElement).toHaveText('main []'); + }))); + describe('"eager" urlUpdateStrategy', () => { beforeEach(() => { const serializer = new DefaultUrlSerializer(); @@ -1922,6 +1939,25 @@ describe('Integration', () => { expect(history[history.length - 1].state) .toEqual({foo: 'bar', navigationId: history.length}); }))); + + it('should set href on area elements', fakeAsync(() => { + @Component({ + selector: 'someRoot', + template: `` + }) + class RootCmpWithArea { + } + + TestBed.configureTestingModule({declarations: [RootCmpWithArea]}); + const router: Router = TestBed.get(Router); + + const fixture = createRoot(router, RootCmpWithArea); + + router.resetConfig([{path: 'home', component: SimpleCmp}]); + + const native = fixture.nativeElement.querySelector('area'); + expect(native.getAttribute('href')).toEqual('/home'); + })); }); describe('redirects', () => { @@ -2076,7 +2112,6 @@ describe('Integration', () => { router.navigateByUrl('/team/22'); advance(fixture); - expect(location.path()).toEqual('/team/22'); }))); }); @@ -2221,11 +2256,18 @@ describe('Integration', () => { describe('should redirect when guard returns UrlTree', () => { beforeEach(() => TestBed.configureTestingModule({ - providers: [{ - provide: 'returnUrlTree', - useFactory: (router: Router) => () => { return router.parseUrl('/redirected'); }, - deps: [Router] - }] + providers: [ + { + provide: 'returnUrlTree', + useFactory: (router: Router) => () => { return router.parseUrl('/redirected'); }, + deps: [Router] + }, + { + provide: 'returnRootUrlTree', + useFactory: (router: Router) => () => { return router.parseUrl('/'); }, + deps: [Router] + } + ] })); it('works', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { @@ -2270,6 +2312,49 @@ describe('Integration', () => { [NavigationEnd, '/redirected'], ]); }))); + + it('works with root url', + fakeAsync(inject([Router, Location], (router: Router, location: Location) => { + const recordedEvents: any[] = []; + let cancelEvent: NavigationCancel = null !; + router.events.forEach((e: any) => { + recordedEvents.push(e); + if (e instanceof NavigationCancel) cancelEvent = e; + }); + router.resetConfig([ + {path: '', component: SimpleCmp}, + {path: 'one', component: RouteCmp, canActivate: ['returnRootUrlTree']} + ]); + + const fixture = TestBed.createComponent(RootCmp); + router.navigateByUrl('/one'); + + advance(fixture); + + expect(location.path()).toEqual('/'); + expect(fixture.nativeElement).toHaveText('simple'); + expect(cancelEvent && cancelEvent.reason) + .toBe('NavigationCancelingError: Redirecting to "/"'); + expectEvents(recordedEvents, [ + [NavigationStart, '/one'], + [RoutesRecognized, '/one'], + [GuardsCheckStart, '/one'], + [ChildActivationStart, undefined], + [ActivationStart, undefined], + [NavigationCancel, '/one'], + [NavigationStart, '/'], + [RoutesRecognized, '/'], + [GuardsCheckStart, '/'], + [ChildActivationStart, undefined], + [ActivationStart, undefined], + [GuardsCheckEnd, '/'], + [ResolveStart, '/'], + [ResolveEnd, '/'], + [ActivationEnd, undefined], + [ChildActivationEnd, undefined], + [NavigationEnd, '/'], + ]); + }))); }); describe('runGuardsAndResolvers', () => { @@ -3493,7 +3578,6 @@ describe('Integration', () => { TestBed.configureTestingModule({declarations: [RootCmpWithLink]}); const router: Router = TestBed.get(Router); - const loc: any = TestBed.get(Location); const f = TestBed.createComponent(RootCmpWithLink); advance(f); @@ -4074,27 +4158,26 @@ describe('Integration', () => { }); }); - fixmeIvy('FW-887: JIT: compilation of NgModule') - .it('should use the injector of the lazily-loaded configuration', - fakeAsync(inject( - [Router, Location, NgModuleFactoryLoader], - (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { - loader.stubbedModules = {expected: LoadedModule}; + it('should use the injector of the lazily-loaded configuration', + fakeAsync(inject( + [Router, Location, NgModuleFactoryLoader], + (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { + loader.stubbedModules = {expected: LoadedModule}; - const fixture = createRoot(router, RootCmp); + const fixture = createRoot(router, RootCmp); - router.resetConfig([{ - path: 'eager-parent', - component: EagerParentComponent, - children: [{path: 'lazy', loadChildren: 'expected'}] - }]); + router.resetConfig([{ + path: 'eager-parent', + component: EagerParentComponent, + children: [{path: 'lazy', loadChildren: 'expected'}] + }]); - router.navigateByUrl('/eager-parent/lazy/lazy-parent/lazy-child'); - advance(fixture); + router.navigateByUrl('/eager-parent/lazy/lazy-parent/lazy-child'); + advance(fixture); - expect(location.path()).toEqual('/eager-parent/lazy/lazy-parent/lazy-child'); - expect(fixture.nativeElement).toHaveText('eager-parent lazy-parent lazy-child'); - }))); + expect(location.path()).toEqual('/eager-parent/lazy/lazy-parent/lazy-child'); + expect(fixture.nativeElement).toHaveText('eager-parent lazy-parent lazy-child'); + }))); }); it('works when given a callback', @@ -4417,43 +4500,41 @@ describe('Integration', () => { class LazyLoadedModule { } - fixmeIvy('FW-887: JIT: compilation of NgModule') - .it('should not ignore empty path when in legacy mode', - fakeAsync(inject( - [Router, NgModuleFactoryLoader], - (router: Router, loader: SpyNgModuleFactoryLoader) => { - router.relativeLinkResolution = 'legacy'; - loader.stubbedModules = {expected: LazyLoadedModule}; + it('should not ignore empty path when in legacy mode', + fakeAsync(inject( + [Router, NgModuleFactoryLoader], + (router: Router, loader: SpyNgModuleFactoryLoader) => { + router.relativeLinkResolution = 'legacy'; + loader.stubbedModules = {expected: LazyLoadedModule}; - const fixture = createRoot(router, RootCmp); + const fixture = createRoot(router, RootCmp); - router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); + router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); - router.navigateByUrl('/lazy/foo/bar'); - advance(fixture); + router.navigateByUrl('/lazy/foo/bar'); + advance(fixture); - const link = fixture.nativeElement.querySelector('a'); - expect(link.getAttribute('href')).toEqual('/lazy/foo/bar/simple'); - }))); + const link = fixture.nativeElement.querySelector('a'); + expect(link.getAttribute('href')).toEqual('/lazy/foo/bar/simple'); + }))); - fixmeIvy('FW-887: JIT: compilation of NgModule') - .it('should ignore empty path when in corrected mode', - fakeAsync(inject( - [Router, NgModuleFactoryLoader], - (router: Router, loader: SpyNgModuleFactoryLoader) => { - router.relativeLinkResolution = 'corrected'; - loader.stubbedModules = {expected: LazyLoadedModule}; + it('should ignore empty path when in corrected mode', + fakeAsync(inject( + [Router, NgModuleFactoryLoader], + (router: Router, loader: SpyNgModuleFactoryLoader) => { + router.relativeLinkResolution = 'corrected'; + loader.stubbedModules = {expected: LazyLoadedModule}; - const fixture = createRoot(router, RootCmp); + const fixture = createRoot(router, RootCmp); - router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); + router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); - router.navigateByUrl('/lazy/foo/bar'); - advance(fixture); + router.navigateByUrl('/lazy/foo/bar'); + advance(fixture); - const link = fixture.nativeElement.querySelector('a'); - expect(link.getAttribute('href')).toEqual('/lazy/foo/simple'); - }))); + const link = fixture.nativeElement.querySelector('a'); + expect(link.getAttribute('href')).toEqual('/lazy/foo/simple'); + }))); }); }); @@ -4635,9 +4716,6 @@ describe('Integration', () => { router.navigate([{outlets: {toolpanel: 'b'}}]); advance(fixture); expect(fixture).toContainComponent(Tool2Component, '(e)'); - - // TODO: remove extra tick for Ivy? - tick(); })); }); }); @@ -4890,6 +4968,10 @@ class RootCmpWithOnInit { class RootCmpWithTwoOutlets { } +@Component({selector: 'root-cmp', template: `main []`}) +class RootCmpWithNamedOutlet { +} + @Component({selector: 'throwing-cmp', template: ''}) class ThrowingCmp { constructor() { throw new Error('Throwing Cmp'); } @@ -4941,6 +5023,7 @@ class LazyComponent { RootCmp, RelativeLinkInIfCmp, RootCmpWithTwoOutlets, + RootCmpWithNamedOutlet, EmptyQueryParamsCmp, ThrowingCmp ], @@ -4971,6 +5054,7 @@ class LazyComponent { RootCmpWithOnInit, RelativeLinkInIfCmp, RootCmpWithTwoOutlets, + RootCmpWithNamedOutlet, EmptyQueryParamsCmp, ThrowingCmp ], @@ -5002,6 +5086,7 @@ class LazyComponent { RootCmpWithOnInit, RelativeLinkInIfCmp, RootCmpWithTwoOutlets, + RootCmpWithNamedOutlet, EmptyQueryParamsCmp, ThrowingCmp ] diff --git a/packages/router/testing/BUILD.bazel b/packages/router/testing/BUILD.bazel index 51e0b17ee6..4590f3833e 100644 --- a/packages/router/testing/BUILD.bazel +++ b/packages/router/testing/BUILD.bazel @@ -7,7 +7,6 @@ load("//tools:defaults.bzl", "ng_module") ng_module( name = "testing", srcs = glob(["**/*.ts"]), - module_name = "@angular/router/testing", deps = [ "//packages/common", "//packages/common/testing", diff --git a/packages/router/testing/rollup.config.js b/packages/router/testing/rollup.config.js deleted file mode 100644 index 2cddeb51a0..0000000000 --- a/packages/router/testing/rollup.config.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/common/testing': 'ng.common.testing', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/router': 'ng.router' -}; - -module.exports = { - entry: '../../../dist/packages-dist/router/fesm5/testing.js', - dest: '../../../dist/packages-dist/router/bundles/router-testing.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/router/testing'}, - moduleName: 'ng.router.testing', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/router/upgrade/BUILD.bazel b/packages/router/upgrade/BUILD.bazel index 8620441e26..eb0452285d 100644 --- a/packages/router/upgrade/BUILD.bazel +++ b/packages/router/upgrade/BUILD.bazel @@ -12,7 +12,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/router/upgrade", deps = [ "//packages/common", "//packages/core", diff --git a/packages/router/upgrade/rollup.config.js b/packages/router/upgrade/rollup.config.js deleted file mode 100644 index 135b0f9349..0000000000 --- a/packages/router/upgrade/rollup.config.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/router': 'ng.router', - '@angular/upgrade/static': 'ng.upgrade.static' -}; - - -module.exports = { - entry: '../../../dist/packages-dist/router/fesm5/upgrade.js', - dest: '../../../dist/packages-dist/router/bundles/router-upgrade.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/router/upgrade'}, - moduleName: 'ng.router.upgrade', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/service-worker/BUILD.bazel b/packages/service-worker/BUILD.bazel index 1c2876201b..4f2dab5485 100644 --- a/packages/service-worker/BUILD.bazel +++ b/packages/service-worker/BUILD.bazel @@ -10,7 +10,6 @@ ng_module( "src/**/*.ts", ], ), - module_name = "@angular/service-worker", deps = [ "//packages/common", "//packages/core", diff --git a/packages/service-worker/cli/rollup-cli.config.js b/packages/service-worker/cli/rollup-cli.config.js deleted file mode 100644 index c63011679d..0000000000 --- a/packages/service-worker/cli/rollup-cli.config.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); - -module.exports = { - entry: '../../dist/all/@angular/service-worker/cli-custom/main.js', - dest: '../../dist/packages-dist/service-worker/ngsw-config-tmp.js', - format: 'iife', - plugins: [resolve()], - external: [ - 'fs', - 'path', - '@angular/service-worker/config', - ], -}; diff --git a/packages/service-worker/config/BUILD.bazel b/packages/service-worker/config/BUILD.bazel index f96d578375..195e2bdbc3 100644 --- a/packages/service-worker/config/BUILD.bazel +++ b/packages/service-worker/config/BUILD.bazel @@ -10,6 +10,5 @@ ng_module( "*.ts", "src/**/*.ts", ]), - module_name = "@angular/service-worker/config", deps = ["//packages/core"], ) diff --git a/packages/service-worker/config/rollup.config.js b/packages/service-worker/config/rollup.config.js deleted file mode 100644 index 8aa5eb619c..0000000000 --- a/packages/service-worker/config/rollup.config.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = {}; - -module.exports = { - entry: '../../../dist/packages-dist/service-worker/fesm5/config.js', - dest: '../../../dist/packages-dist/service-worker/bundles/service-worker-config.umd.js', - format: 'umd', - exports: 'named', - moduleName: 'ng.serviceWorker.config', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/service-worker/rollup.config.js b/packages/service-worker/rollup.config.js deleted file mode 100644 index c491a87bc5..0000000000 --- a/packages/service-worker/rollup.config.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../dist/packages-dist/service-worker/fesm5/service-worker.js', - dest: '../../dist/packages-dist/service-worker/bundles/service-worker.umd.js', - format: 'umd', - exports: 'named', - moduleName: 'ng.serviceWorker', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/service-worker/testing/BUILD.bazel b/packages/service-worker/testing/BUILD.bazel index e35c353647..1888beac93 100644 --- a/packages/service-worker/testing/BUILD.bazel +++ b/packages/service-worker/testing/BUILD.bazel @@ -6,7 +6,6 @@ ng_module( name = "testing", testonly = True, srcs = glob(["**/*.ts"]), - module_name = "@angular/service-worker/testing", deps = [ "//packages/core", "@rxjs", diff --git a/packages/service-worker/worker/src/app-version.ts b/packages/service-worker/worker/src/app-version.ts index 1329c9aaf4..dafdcabfe0 100644 --- a/packages/service-worker/worker/src/app-version.ts +++ b/packages/service-worker/worker/src/app-version.ts @@ -15,6 +15,12 @@ import {IdleScheduler} from './idle'; import {Manifest} from './manifest'; +const BACKWARDS_COMPATIBILITY_NAVIGATION_URLS = [ + {positive: true, regex: '^/.*$'}, + {positive: false, regex: '^/.*\\.[^/]*$'}, + {positive: false, regex: '^/.*__'}, +]; + /** * A specific version of the application, identified by a unique manifest * as determined by its hash. @@ -85,6 +91,10 @@ export class AppVersion implements UpdateSource { this.scope, this.adapter, config, this.database, `ngsw:${config.version}:data`)); + // This keeps backwards compatibility with app versions without navigation urls. + // Fix: https://github.com/angular/angular/issues/27209 + manifest.navigationUrls = manifest.navigationUrls || BACKWARDS_COMPATIBILITY_NAVIGATION_URLS; + // Create `include`/`exclude` RegExps for the `navigationUrls` declared in the manifest. const includeUrls = manifest.navigationUrls.filter(spec => spec.positive); const excludeUrls = manifest.navigationUrls.filter(spec => !spec.positive); diff --git a/packages/service-worker/worker/src/assets.ts b/packages/service-worker/worker/src/assets.ts index dedbceff3a..8776eb1973 100644 --- a/packages/service-worker/worker/src/assets.ts +++ b/packages/service-worker/worker/src/assets.ts @@ -212,7 +212,7 @@ export abstract class AssetGroup { // Check the metadata table. If a timestamp is there, use it. const metaTable = await this.metadata; ts = (await metaTable.read(req.url)).ts; - } catch (e) { + } catch { // Otherwise, look for a Date header. const date = res.headers.get('Date'); if (date === null) { @@ -224,7 +224,7 @@ export abstract class AssetGroup { } const age = this.adapter.time - ts; return age < 0 || age > maxAge; - } catch (e) { + } catch { // Assume stale. return true; } @@ -235,7 +235,7 @@ export abstract class AssetGroup { // The request needs to be revalidated if the current time is later than the expiration // time, if it parses correctly. return this.adapter.time > Date.parse(expiresStr); - } catch (e) { + } catch { // The expiration date failed to parse, so revalidate as a precaution. return true; } @@ -263,7 +263,7 @@ export abstract class AssetGroup { let metadata: UrlMetadata|undefined = undefined; try { metadata = await metaTable.read(url); - } catch (e) { + } catch { // Do nothing, not found. This shouldn't happen, but it can be handled. } @@ -487,7 +487,7 @@ export abstract class AssetGroup { protected async safeFetch(req: Request): Promise { try { return await this.scope.fetch(req); - } catch (err) { + } catch { return this.adapter.newResponse('', { status: 504, statusText: 'Gateway Timeout', diff --git a/packages/service-worker/worker/src/data.ts b/packages/service-worker/worker/src/data.ts index e1d98f2951..85e797c91c 100644 --- a/packages/service-worker/worker/src/data.ts +++ b/packages/service-worker/worker/src/data.ts @@ -258,7 +258,7 @@ export class DataGroup { const table = await this.lruTable; try { this._lru = new LruList(await table.read('lru')); - } catch (e) { + } catch { this._lru = new LruList(); } } @@ -371,7 +371,7 @@ export class DataGroup { // If that fetch errors, treat it as a timed out request. try { res = await timeoutFetch; - } catch (e) { + } catch { res = undefined; } @@ -407,7 +407,7 @@ export class DataGroup { const safeNetworkFetch = (async() => { try { return await networkFetch; - } catch (err) { + } catch { return this.adapter.newResponse(null, { status: 504, statusText: 'Gateway Timeout', @@ -417,7 +417,7 @@ export class DataGroup { const networkFetchUndefinedError = (async() => { try { return await networkFetch; - } catch (err) { + } catch { return undefined; } })(); @@ -436,7 +436,7 @@ export class DataGroup { private async safeCacheResponse(req: Request, res: Promise): Promise { try { await this.cacheResponse(req, await res, await this.lru()); - } catch (e) { + } catch { // TODO: handle this error somehow? } } @@ -460,7 +460,7 @@ export class DataGroup { } // Otherwise, or if there was an error, assume the response is expired, and evict it. - } catch (e) { + } catch { // Some error getting the age for the response. Assume it's expired. } @@ -546,7 +546,7 @@ export class DataGroup { private async safeFetch(req: Request): Promise { try { return this.scope.fetch(req); - } catch (err) { + } catch { return this.adapter.newResponse(null, { status: 504, statusText: 'Gateway Timeout', diff --git a/packages/service-worker/worker/test/happy_spec.ts b/packages/service-worker/worker/test/happy_spec.ts index d1278434bf..a4fba8680a 100644 --- a/packages/service-worker/worker/test/happy_spec.ts +++ b/packages/service-worker/worker/test/happy_spec.ts @@ -9,7 +9,7 @@ import {processNavigationUrls} from '../../config/src/generator'; import {CacheDatabase} from '../src/db-cache'; import {Driver, DriverReadyState} from '../src/driver'; -import {Manifest} from '../src/manifest'; +import {AssetGroupConfig, DataGroupConfig, Manifest} from '../src/manifest'; import {sha1} from '../src/sha1'; import {MockCache, clearAllCaches} from '../testing/cache'; import {MockRequest} from '../testing/fetch'; @@ -66,6 +66,24 @@ const brokenManifest: Manifest = { hashTable: tmpHashTableForFs(brokenFs, {'/foo.txt': true}), }; +// Manifest without navigation urls to test backward compatibility with +// versions < 6.0.0. +export interface ManifestV5 { + configVersion: number; + appData?: {[key: string]: string}; + index: string; + assetGroups?: AssetGroupConfig[]; + dataGroups?: DataGroupConfig[]; + hashTable: {[url: string]: string}; +} + +// To simulate versions < 6.0.0 +const manifestOld: ManifestV5 = { + configVersion: 1, + index: '/foo.txt', + hashTable: tmpHashTableForFs(dist), +}; + const manifest: Manifest = { configVersion: 1, appData: { @@ -989,6 +1007,28 @@ const manifestUpdateHash = sha1(JSON.stringify(manifestUpdate)); expect(await requestFoo('only-if-cached', 'same-origin')).toBe('this is foo'); expect(await requestFoo('only-if-cached', 'no-cors')).toBeNull(); }); + + describe('Backwards compatibility with v5', () => { + beforeEach(() => { + const serverV5 = new MockServerStateBuilder() + .withStaticFiles(dist) + .withManifest(manifestOld) + .build(); + + scope = new SwTestHarnessBuilder().withServerState(serverV5).build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + }); + + // Test this bug: https://github.com/angular/angular/issues/27209 + async_it( + 'Fill previous versions of manifests with default navigation urls for backwards compatibility', + async() => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + }); + }); }); }); })(); diff --git a/packages/tsconfig-metadata.json b/packages/tsconfig-metadata.json deleted file mode 100644 index 0aeb1e3545..0000000000 --- a/packages/tsconfig-metadata.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "extends": "./tsconfig.json", - - "compilerOptions": { - "paths": { - "@angular/*": ["./*"] - } - }, - - "exclude": [ - "bazel", - "compiler/test", - "compiler-cli/integrationtest", - "platform-server/integrationtest", - "router/test/aot_ngsummary_test", - "common/locales", - "examples", - "**/*_spec.ts", - "**/*.spec.ts" - ], - - "angularCompilerOptions": { - "skipTemplateCodegen": true, - "annotateForClosureCompiler": false, - "annotationsAs": "decorators" - } -} diff --git a/packages/tsconfig.json b/packages/tsconfig.json index 9b8d04667c..720c55d6c9 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -33,7 +33,12 @@ "common/locales", "compiler-cli/integrationtest", "elements/schematics", + // Do not build the example e2e spec files since those require custom typings and + // aren't required to build all packages. "examples/**/e2e_test/*", + // Exclude the "main.ts" files for each example group because this file is used by + // Bazel to launch the devserver and uses AOT compilation. + "examples/*/main.ts", "platform-server/integrationtest", "router/test/aot_ngsummary_test", ] diff --git a/packages/types.d.ts b/packages/types.d.ts index 16e7e07562..87f212e64e 100644 --- a/packages/types.d.ts +++ b/packages/types.d.ts @@ -10,7 +10,7 @@ /// /// -/// +/// /// /// diff --git a/packages/upgrade/BUILD.bazel b/packages/upgrade/BUILD.bazel index 71318db97e..256aa43c4f 100644 --- a/packages/upgrade/BUILD.bazel +++ b/packages/upgrade/BUILD.bazel @@ -11,7 +11,6 @@ ng_module( "src/dynamic/**/*.ts", ], ), - module_name = "@angular/upgrade", deps = [ "//packages/core", "//packages/platform-browser", diff --git a/packages/upgrade/rollup.config.js b/packages/upgrade/rollup.config.js deleted file mode 100644 index c16303ff19..0000000000 --- a/packages/upgrade/rollup.config.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core', - '@angular/common': 'ng.common', - '@angular/compiler': 'ng.compiler', - '@angular/platform-browser': 'ng.platformBrowser', - '@angular/platform-browser-dynamic': 'ng.platformBrowserDynamic', - 'rxjs': 'rxjs', - 'rxjs/operators': 'rxjs.operators', -}; - -module.exports = { - entry: '../../dist/packages-dist/upgrade/fesm5/upgrade.js', - dest: '../../dist/packages-dist/upgrade/bundles/upgrade.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/upgrade'}, - moduleName: 'ng.upgrade', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/upgrade/src/common/angular1.ts b/packages/upgrade/src/common/angular1.ts index a8a4f157a2..f3209a12bd 100644 --- a/packages/upgrade/src/common/angular1.ts +++ b/packages/upgrade/src/common/angular1.ts @@ -250,7 +250,7 @@ try { if (window.hasOwnProperty('angular')) { angular = (window).angular; } -} catch (e) { +} catch { // ignore in CJS mode. } diff --git a/packages/upgrade/src/common/downgrade_component_adapter.ts b/packages/upgrade/src/common/downgrade_component_adapter.ts index b11b8bca50..b3c0f56252 100644 --- a/packages/upgrade/src/common/downgrade_component_adapter.ts +++ b/packages/upgrade/src/common/downgrade_component_adapter.ts @@ -213,6 +213,7 @@ export class DowngradeComponentAdapter { } registerCleanup() { + const testabilityRegistry = this.componentRef.injector.get(TestabilityRegistry); const destroyComponentRef = this.wrapCallback(() => this.componentRef.destroy()); let destroyed = false; @@ -220,8 +221,7 @@ export class DowngradeComponentAdapter { this.componentScope.$on('$destroy', () => { if (!destroyed) { destroyed = true; - this.componentRef.injector.get(TestabilityRegistry) - .unregisterApplication(this.componentRef.location.nativeElement); + testabilityRegistry.unregisterApplication(this.componentRef.location.nativeElement); destroyComponentRef(); } }); diff --git a/packages/upgrade/src/static/angular1_providers.ts b/packages/upgrade/src/static/angular1_providers.ts index 3481f96e8a..ad5d937845 100644 --- a/packages/upgrade/src/static/angular1_providers.ts +++ b/packages/upgrade/src/static/angular1_providers.ts @@ -12,7 +12,7 @@ import * as angular from '../common/angular1'; // We store the ng1 injector so that the provider in the module injector can access it // Then we "get" the ng1 injector from the module injector, which triggers the provider to read // the stored injector and release the reference to it. -let tempInjectorRef: angular.IInjectorService|null; +let tempInjectorRef: angular.IInjectorService|null = null; export function setTempInjectorRef(injector: angular.IInjectorService) { tempInjectorRef = injector; } @@ -21,7 +21,7 @@ export function injectorFactory() { throw new Error('Trying to get the AngularJS injector before it being set.'); } - const injector: angular.IInjectorService|null = tempInjectorRef; + const injector: angular.IInjectorService = tempInjectorRef; tempInjectorRef = null; // clear the value to prevent memory leaks return injector; } diff --git a/packages/upgrade/static/BUILD.bazel b/packages/upgrade/static/BUILD.bazel index 62ce0857d0..2aac672fb9 100644 --- a/packages/upgrade/static/BUILD.bazel +++ b/packages/upgrade/static/BUILD.bazel @@ -15,7 +15,6 @@ ng_module( "src/static/**/*.ts", ], ), - module_name = "@angular/upgrade/static", deps = [ "//packages/core", "//packages/platform-browser", diff --git a/packages/upgrade/static/rollup.config.js b/packages/upgrade/static/rollup.config.js deleted file mode 100644 index 844143c401..0000000000 --- a/packages/upgrade/static/rollup.config.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const resolve = require('rollup-plugin-node-resolve'); -const sourcemaps = require('rollup-plugin-sourcemaps'); - -const globals = { - '@angular/core': 'ng.core' -}; - -module.exports = { - entry: '../../../dist/packages-dist/upgrade/fesm5/static.js', - dest: '../../../dist/packages-dist/upgrade/bundles/upgrade-static.umd.js', - format: 'umd', - exports: 'named', - amd: {id: '@angular/upgrade/static'}, - moduleName: 'ng.upgrade.static', - plugins: [resolve(), sourcemaps()], - external: Object.keys(globals), - globals: globals -}; diff --git a/packages/upgrade/test/BUILD.bazel b/packages/upgrade/test/BUILD.bazel index ed904feebd..8787f0185c 100644 --- a/packages/upgrade/test/BUILD.bazel +++ b/packages/upgrade/test/BUILD.bazel @@ -11,7 +11,6 @@ ts_library( "//packages/platform-browser", "//packages/platform-browser-dynamic", "//packages/platform-browser/testing", - "//packages/private/testing", "//packages/upgrade", "//packages/upgrade/static", "@rxjs", diff --git a/packages/upgrade/test/dynamic/upgrade_spec.ts b/packages/upgrade/test/dynamic/upgrade_spec.ts index b3bb64dee7..32e8626355 100644 --- a/packages/upgrade/test/dynamic/upgrade_spec.ts +++ b/packages/upgrade/test/dynamic/upgrade_spec.ts @@ -10,7 +10,6 @@ import {ChangeDetectorRef, Component, EventEmitter, Input, NO_ERRORS_SCHEMA, NgM import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {fixmeIvy} from '@angular/private/testing'; import * as angular from '@angular/upgrade/src/common/angular1'; import {$EXCEPTION_HANDLER} from '@angular/upgrade/src/common/constants'; import {UpgradeAdapter, UpgradeAdapterRef} from '@angular/upgrade/src/dynamic/upgrade_adapter'; @@ -30,31 +29,30 @@ withEachNg1Version(() => { describe('(basic use)', () => { it('should have AngularJS loaded', () => expect(angular.version.major).toBe(1)); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should instantiate ng2 in ng1 template and project content', async(() => { - const ng1Module = angular.module('ng1', []); + it('should instantiate ng2 in ng1 template and project content', async(() => { + const ng1Module = angular.module('ng1', []); - @Component({ - selector: 'ng2', - template: `{{ 'NG2' }}()`, - }) - class Ng2 { - } + @Component({ + selector: 'ng2', + template: `{{ 'NG2' }}()`, + }) + class Ng2 { + } - @NgModule({declarations: [Ng2], imports: [BrowserModule]}) - class Ng2Module { - } + @NgModule({declarations: [Ng2], imports: [BrowserModule]}) + class Ng2Module { + } - const element = - html('
    {{ \'ng1[\' }}~{{ \'ng-content\' }}~{{ \']\' }}
    '); + const element = + html('
    {{ \'ng1[\' }}~{{ \'ng-content\' }}~{{ \']\' }}
    '); - const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(document.body.textContent).toEqual('ng1[NG2(~ng-content~)]'); - ref.dispose(); - }); - })); + const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(document.body.textContent).toEqual('ng1[NG2(~ng-content~)]'); + ref.dispose(); + }); + })); it('should instantiate ng1 in ng2 template and project content', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -216,63 +214,54 @@ withEachNg1Version(() => { })); - fixmeIvy( - 'FW-712: Rendering is being run on next "animation frame" rather than "Zone.microTaskEmpty" trigger') - .it('should propagate changes to a downgraded component inside the ngZone', async(() => { - let appComponent: AppComponent; - let upgradeRef: UpgradeAdapterRef; + it('should propagate changes to a downgraded component inside the ngZone', async(() => { + let appComponent: AppComponent; + let upgradeRef: UpgradeAdapterRef; - @Component({selector: 'my-app', template: ''}) - class AppComponent { - value?: number; - constructor() { appComponent = this; } - } + @Component({selector: 'my-app', template: ''}) + class AppComponent { + value?: number; + constructor() { appComponent = this; } + } - @Component({ - selector: 'my-child', - template: '
    {{valueFromPromise}}', - }) - class ChildComponent { - valueFromPromise?: number; - @Input() - set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); } + @Component({ + selector: 'my-child', + template: '
    {{valueFromPromise}}', + }) + class ChildComponent { + valueFromPromise?: number; + @Input() + set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); } - constructor(private zone: NgZone) {} + constructor(private zone: NgZone) {} - ngOnChanges(changes: SimpleChanges) { - if (changes['value'].isFirstChange()) return; + ngOnChanges(changes: SimpleChanges) { + if (changes['value'].isFirstChange()) return; - // HACK(ivy): Using setTimeout allows this test to pass but hides the ivy - // renderer timing BC. - // setTimeout(() => { - // expect(element.textContent).toEqual('5'); - // upgradeRef.dispose(); - // }, 0); - this.zone.onMicrotaskEmpty.subscribe(() => { - expect(element.textContent).toEqual('5'); - upgradeRef.dispose(); - }); + this.zone.onMicrotaskEmpty.subscribe(() => { + expect(element.textContent).toEqual('5'); + upgradeRef.dispose(); + }); - Promise.resolve().then( - () => this.valueFromPromise = changes['value'].currentValue); - } - } + Promise.resolve().then(() => this.valueFromPromise = changes['value'].currentValue); + } + } - @NgModule({declarations: [AppComponent, ChildComponent], imports: [BrowserModule]}) - class Ng2Module { - } + @NgModule({declarations: [AppComponent, ChildComponent], imports: [BrowserModule]}) + class Ng2Module { + } - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []).directive( - 'myApp', adapter.downgradeNg2Component(AppComponent)); + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = angular.module('ng1', []).directive( + 'myApp', adapter.downgradeNg2Component(AppComponent)); - const element = html(''); + const element = html(''); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - upgradeRef = ref; - appComponent.value = 5; - }); - })); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + upgradeRef = ref; + appComponent.value = 5; + }); + })); // This test demonstrates https://github.com/angular/angular/issues/6385 // which was invalidly fixed by https://github.com/angular/angular/pull/6386 @@ -326,239 +315,235 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .it('should bind properties, events', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = angular.module('ng1', []).value( - $EXCEPTION_HANDLER, (err: any) => { throw err; }); + it('should bind properties, events', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const ng1Module = + angular.module('ng1', []).value($EXCEPTION_HANDLER, (err: any) => { throw err; }); - ng1Module.run(($rootScope: any) => { - $rootScope.name = 'world'; - $rootScope.dataA = 'A'; - $rootScope.dataB = 'B'; - $rootScope.modelA = 'initModelA'; - $rootScope.modelB = 'initModelB'; - $rootScope.eventA = '?'; - $rootScope.eventB = '?'; - }); - @Component({ - selector: 'ng2', - inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'], - outputs: [ - 'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange', - 'twoWayBEmitter: twoWayBChange' - ], - template: 'ignore: {{ignore}}; ' + - 'literal: {{literal}}; interpolate: {{interpolate}}; ' + - 'oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; ' + - 'twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{ngOnChangesCount}})' - }) - class Ng2 { - ngOnChangesCount = 0; - ignore = '-'; - literal = '?'; - interpolate = '?'; - oneWayA = '?'; - oneWayB = '?'; - twoWayA = '?'; - twoWayB = '?'; - eventA = new EventEmitter(); - eventB = new EventEmitter(); - twoWayAEmitter = new EventEmitter(); - twoWayBEmitter = new EventEmitter(); - ngOnChanges(changes: SimpleChanges) { - const assert = (prop: string, value: any) => { - if ((this as any)[prop] != value) { - throw new Error( - `Expected: '${prop}' to be '${value}' but was '${(this as any)[prop]}'`); - } - }; + ng1Module.run(($rootScope: any) => { + $rootScope.name = 'world'; + $rootScope.dataA = 'A'; + $rootScope.dataB = 'B'; + $rootScope.modelA = 'initModelA'; + $rootScope.modelB = 'initModelB'; + $rootScope.eventA = '?'; + $rootScope.eventB = '?'; + }); + @Component({ + selector: 'ng2', + inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'], + outputs: [ + 'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange', 'twoWayBEmitter: twoWayBChange' + ], + template: 'ignore: {{ignore}}; ' + + 'literal: {{literal}}; interpolate: {{interpolate}}; ' + + 'oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; ' + + 'twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{ngOnChangesCount}})' + }) + class Ng2 { + ngOnChangesCount = 0; + ignore = '-'; + literal = '?'; + interpolate = '?'; + oneWayA = '?'; + oneWayB = '?'; + twoWayA = '?'; + twoWayB = '?'; + eventA = new EventEmitter(); + eventB = new EventEmitter(); + twoWayAEmitter = new EventEmitter(); + twoWayBEmitter = new EventEmitter(); + ngOnChanges(changes: SimpleChanges) { + const assert = (prop: string, value: any) => { + if ((this as any)[prop] != value) { + throw new Error( + `Expected: '${prop}' to be '${value}' but was '${(this as any)[prop]}'`); + } + }; - const assertChange = (prop: string, value: any) => { - assert(prop, value); - if (!changes[prop]) { - throw new Error(`Changes record for '${prop}' not found.`); - } - const actValue = changes[prop].currentValue; - if (actValue != value) { - throw new Error( - `Expected changes record for'${prop}' to be '${value}' but was '${actValue}'`); - } - }; + const assertChange = (prop: string, value: any) => { + assert(prop, value); + if (!changes[prop]) { + throw new Error(`Changes record for '${prop}' not found.`); + } + const actValue = changes[prop].currentValue; + if (actValue != value) { + throw new Error( + `Expected changes record for'${prop}' to be '${value}' but was '${actValue}'`); + } + }; - switch (this.ngOnChangesCount++) { - case 0: - assert('ignore', '-'); - assertChange('literal', 'Text'); - assertChange('interpolate', 'Hello world'); - assertChange('oneWayA', 'A'); - assertChange('oneWayB', 'B'); - assertChange('twoWayA', 'initModelA'); - assertChange('twoWayB', 'initModelB'); + switch (this.ngOnChangesCount++) { + case 0: + assert('ignore', '-'); + assertChange('literal', 'Text'); + assertChange('interpolate', 'Hello world'); + assertChange('oneWayA', 'A'); + assertChange('oneWayB', 'B'); + assertChange('twoWayA', 'initModelA'); + assertChange('twoWayB', 'initModelB'); - this.twoWayAEmitter.emit('newA'); - this.twoWayBEmitter.emit('newB'); - this.eventA.emit('aFired'); - this.eventB.emit('bFired'); - break; - case 1: - assertChange('twoWayA', 'newA'); - assertChange('twoWayB', 'newB'); - break; - case 2: - assertChange('interpolate', 'Hello everyone'); - break; - default: - throw new Error('Called too many times! ' + JSON.stringify(changes)); - } - } - } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + this.twoWayAEmitter.emit('newA'); + this.twoWayBEmitter.emit('newB'); + this.eventA.emit('aFired'); + this.eventB.emit('bFired'); + break; + case 1: + assertChange('twoWayA', 'newA'); + assertChange('twoWayB', 'newB'); + break; + case 2: + assertChange('interpolate', 'Hello everyone'); + break; + default: + throw new Error('Called too many times! ' + JSON.stringify(changes)); + } + } + } + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - @NgModule({ - declarations: [Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - const element = html(`
    + const element = html(`
    | modelA: {{modelA}}; modelB: {{modelB}}; eventA: {{eventA}}; eventB: {{eventB}};
    `); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent !)) - .toEqual( - 'ignore: -; ' + - 'literal: Text; interpolate: Hello world; ' + - 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (2) | ' + - 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(document.body.textContent !)) + .toEqual( + 'ignore: -; ' + + 'literal: Text; interpolate: Hello world; ' + + 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (2) | ' + + 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); - ref.ng1RootScope.$apply('name = "everyone"'); - expect(multiTrim(document.body.textContent !)) - .toEqual( - 'ignore: -; ' + - 'literal: Text; interpolate: Hello everyone; ' + - 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (3) | ' + - 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); + ref.ng1RootScope.$apply('name = "everyone"'); + expect(multiTrim(document.body.textContent !)) + .toEqual( + 'ignore: -; ' + + 'literal: Text; interpolate: Hello everyone; ' + + 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (3) | ' + + 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); - ref.dispose(); - }); + ref.dispose(); + }); - })); + })); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .it('should support two-way binding and event listener', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const listenerSpy = jasmine.createSpy('$rootScope.listener'); - const ng1Module = angular.module('ng1', []).run(($rootScope: angular.IScope) => { - $rootScope['value'] = 'world'; - $rootScope['listener'] = listenerSpy; - }); + it('should support two-way binding and event listener', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const listenerSpy = jasmine.createSpy('$rootScope.listener'); + const ng1Module = angular.module('ng1', []).run(($rootScope: angular.IScope) => { + $rootScope['value'] = 'world'; + $rootScope['listener'] = listenerSpy; + }); - @Component({selector: 'ng2', template: `model: {{model}};`}) - class Ng2Component implements OnChanges { - ngOnChangesCount = 0; - @Input() model = '?'; - @Output() modelChange = new EventEmitter(); + @Component({selector: 'ng2', template: `model: {{model}};`}) + class Ng2Component implements OnChanges { + ngOnChangesCount = 0; + @Input() model = '?'; + @Output() modelChange = new EventEmitter(); - ngOnChanges(changes: SimpleChanges) { - switch (this.ngOnChangesCount++) { - case 0: - expect(changes.model.currentValue).toBe('world'); - this.modelChange.emit('newC'); - break; - case 1: - expect(changes.model.currentValue).toBe('newC'); - break; - default: - throw new Error('Called too many times! ' + JSON.stringify(changes)); - } - } - } + ngOnChanges(changes: SimpleChanges) { + switch (this.ngOnChangesCount++) { + case 0: + expect(changes.model.currentValue).toBe('world'); + this.modelChange.emit('newC'); + break; + case 1: + expect(changes.model.currentValue).toBe('newC'); + break; + default: + throw new Error('Called too many times! ' + JSON.stringify(changes)); + } + } + } - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - @NgModule({declarations: [Ng2Component], imports: [BrowserModule]}) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({declarations: [Ng2Component], imports: [BrowserModule]}) + class Ng2Module { + ngDoBootstrap() {} + } - const element = html(` + const element = html(`
    | value: {{value}}
    `); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(element.textContent)).toEqual('model: newC; | value: newC'); - expect(listenerSpy).toHaveBeenCalledWith('newC'); - ref.dispose(); - }); - })); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(multiTrim(element.textContent)).toEqual('model: newC; | value: newC'); + expect(listenerSpy).toHaveBeenCalledWith('newC'); + ref.dispose(); + }); + })); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .it('should initialize inputs in time for `ngOnChanges`', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + it('should initialize inputs in time for `ngOnChanges`', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - @Component({ - selector: 'ng2', - template: ` + @Component({ + selector: 'ng2', + template: ` ngOnChangesCount: {{ ngOnChangesCount }} | firstChangesCount: {{ firstChangesCount }} | initialValue: {{ initialValue }}` - }) - class Ng2Component implements OnChanges { - ngOnChangesCount = 0; - firstChangesCount = 0; - // TODO(issue/24571): remove '!'. - initialValue !: string; - // TODO(issue/24571): remove '!'. - @Input() foo !: string; + }) + class Ng2Component implements OnChanges { + ngOnChangesCount = 0; + firstChangesCount = 0; + // TODO(issue/24571): remove '!'. + initialValue !: string; + // TODO(issue/24571): remove '!'. + @Input() foo !: string; - ngOnChanges(changes: SimpleChanges) { - this.ngOnChangesCount++; + ngOnChanges(changes: SimpleChanges) { + this.ngOnChangesCount++; - if (this.ngOnChangesCount === 1) { - this.initialValue = this.foo; - } + if (this.ngOnChangesCount === 1) { + this.initialValue = this.foo; + } - if (changes['foo'] && changes['foo'].isFirstChange()) { - this.firstChangesCount++; - } - } - } + if (changes['foo'] && changes['foo'].isFirstChange()) { + this.firstChangesCount++; + } + } + } - @NgModule({imports: [BrowserModule], declarations: [Ng2Component]}) - class Ng2Module { - } + @NgModule({imports: [BrowserModule], declarations: [Ng2Component]}) + class Ng2Module { + } - const ng1Module = angular.module('ng1', []).directive( - 'ng2', adapter.downgradeNg2Component(Ng2Component)); + const ng1Module = angular.module('ng1', []).directive( + 'ng2', adapter.downgradeNg2Component(Ng2Component)); - const element = html(` + const element = html(` `); - adapter.bootstrap(element, ['ng1']).ready(ref => { - const nodes = element.querySelectorAll('ng2'); - const expectedTextWith = (value: string) => - `ngOnChangesCount: 1 | firstChangesCount: 1 | initialValue: ${value}`; + adapter.bootstrap(element, ['ng1']).ready(ref => { + const nodes = element.querySelectorAll('ng2'); + const expectedTextWith = (value: string) => + `ngOnChangesCount: 1 | firstChangesCount: 1 | initialValue: ${value}`; - expect(multiTrim(nodes[0].textContent)).toBe(expectedTextWith('foo')); - expect(multiTrim(nodes[1].textContent)).toBe(expectedTextWith('bar')); - expect(multiTrim(nodes[2].textContent)).toBe(expectedTextWith('baz')); - expect(multiTrim(nodes[3].textContent)).toBe(expectedTextWith('qux')); + expect(multiTrim(nodes[0].textContent)).toBe(expectedTextWith('foo')); + expect(multiTrim(nodes[1].textContent)).toBe(expectedTextWith('bar')); + expect(multiTrim(nodes[2].textContent)).toBe(expectedTextWith('baz')); + expect(multiTrim(nodes[3].textContent)).toBe(expectedTextWith('qux')); - ref.dispose(); - }); - })); + ref.dispose(); + }); + })); it('should bind to ng-model', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -730,72 +715,68 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support multi-slot projection', async(() => { - const ng1Module = angular.module('ng1', []); + it('should support multi-slot projection', async(() => { + const ng1Module = angular.module('ng1', []); - @Component({ - selector: 'ng2', - template: '2a()' + - '2b()' - }) - class Ng2 { - } + @Component({ + selector: 'ng2', + template: '2a()' + + '2b()' + }) + class Ng2 { + } - @NgModule({declarations: [Ng2], imports: [BrowserModule]}) - class Ng2Module { - } + @NgModule({declarations: [Ng2], imports: [BrowserModule]}) + class Ng2Module { + } - // The ng-if on one of the projected children is here to make sure - // the correct slot is targeted even with structural directives in play. - const element = html( - '
    1a
    1b
    '); + // The ng-if on one of the projected children is here to make sure + // the correct slot is targeted even with structural directives in play. + const element = html( + '
    1a
    1b
    '); - const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); - ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(document.body.textContent).toEqual('2a(1a)2b(1b)'); - ref.dispose(); - }); - })); + const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); + ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(document.body.textContent).toEqual('2a(1a)2b(1b)'); + ref.dispose(); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should correctly project structural directives', async(() => { - @Component( - {selector: 'ng2', template: 'ng2-{{ itemId }}()'}) - class Ng2Component { - // TODO(issue/24571): remove '!'. - @Input() itemId !: string; - } + it('should correctly project structural directives', async(() => { + @Component({selector: 'ng2', template: 'ng2-{{ itemId }}()'}) + class Ng2Component { + // TODO(issue/24571): remove '!'. + @Input() itemId !: string; + } - @NgModule({imports: [BrowserModule], declarations: [Ng2Component]}) - class Ng2Module { - } + @NgModule({imports: [BrowserModule], declarations: [Ng2Component]}) + class Ng2Module { + } - const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); - const ng1Module = - angular.module('ng1', []) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)) - .run(($rootScope: angular.IRootScopeService) => { - $rootScope['items'] = [ - {id: 'a', subitems: [1, 2, 3]}, {id: 'b', subitems: [4, 5, 6]}, - {id: 'c', subitems: [7, 8, 9]} - ]; - }); + const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); + const ng1Module = angular.module('ng1', []) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)) + .run(($rootScope: angular.IRootScopeService) => { + $rootScope['items'] = [ + {id: 'a', subitems: [1, 2, 3]}, {id: 'b', subitems: [4, 5, 6]}, + {id: 'c', subitems: [7, 8, 9]} + ]; + }); - const element = html(` + const element = html(`
    {{ subitem }}
    `); - adapter.bootstrap(element, [ng1Module.name]).ready(ref => { - expect(multiTrim(document.body.textContent)) - .toBe('ng2-a( 123 )ng2-b( 456 )ng2-c( 789 )'); - ref.dispose(); - }); - })); + adapter.bootstrap(element, [ng1Module.name]).ready(ref => { + expect(multiTrim(document.body.textContent)) + .toBe('ng2-a( 123 )ng2-b( 456 )ng2-c( 789 )'); + ref.dispose(); + }); + })); it('should allow attribute selectors for components in ng2', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => MyNg2Module)); @@ -2582,68 +2563,65 @@ withEachNg1Version(() => { }); describe('transclusion', () => { - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support single-slot transclusion', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let ng2ComponentAInstance: Ng2ComponentA; - let ng2ComponentBInstance: Ng2ComponentB; + it('should support single-slot transclusion', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let ng2ComponentAInstance: Ng2ComponentA; + let ng2ComponentBInstance: Ng2ComponentB; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: 'ng1(
    )', - transclude: true - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: 'ng1(
    )', + transclude: true + }; - // Define `Ng2Component` - @Component({ - selector: 'ng2A', - template: 'ng2A({{ value }} | )' - }) - class Ng2ComponentA { - value = 'foo'; - showB = false; - constructor() { ng2ComponentAInstance = this; } - } + // Define `Ng2Component` + @Component({ + selector: 'ng2A', + template: 'ng2A({{ value }} | )' + }) + class Ng2ComponentA { + value = 'foo'; + showB = false; + constructor() { ng2ComponentAInstance = this; } + } - @Component({selector: 'ng2B', template: 'ng2B({{ value }})'}) - class Ng2ComponentB { - value = 'bar'; - constructor() { ng2ComponentBInstance = this; } - } + @Component({selector: 'ng2B', template: 'ng2B({{ value }})'}) + class Ng2ComponentB { + value = 'bar'; + constructor() { ng2ComponentBInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA)); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2A', adapter.downgradeNg2Component(Ng2ComponentA)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: - [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2ComponentA, Ng2ComponentB] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready((ref) => { - expect(multiTrim(element.textContent)).toBe('ng2A(ng1(foo | ))'); + adapter.bootstrap(element, ['ng1Module']).ready((ref) => { + expect(multiTrim(element.textContent)).toBe('ng2A(ng1(foo | ))'); - ng2ComponentAInstance.value = 'baz'; - ng2ComponentAInstance.showB = true; - $digest(ref); + ng2ComponentAInstance.value = 'baz'; + ng2ComponentAInstance.showB = true; + $digest(ref); - expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(bar)))'); + expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(bar)))'); - ng2ComponentBInstance.value = 'qux'; - $digest(ref); + ng2ComponentBInstance.value = 'qux'; + $digest(ref); - expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(qux)))'); - }); - })); + expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(qux)))'); + }); + })); it('should support single-slot transclusion with fallback content', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); @@ -2949,22 +2927,21 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support structural directives in transcluded content', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - let ng2ComponentInstance: Ng2Component; + it('should support structural directives in transcluded content', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + let ng2ComponentInstance: Ng2Component; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: - 'ng1(x(
    ) | default(
    ))', - transclude: {slotX: 'contentX'} - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: + 'ng1(x(
    ) | default(
    ))', + transclude: {slotX: 'contentX'} + }; - // Define `Ng2Component` - @Component({ - selector: 'ng2', - template: ` + // Define `Ng2Component` + @Component({ + selector: 'ng2', + template: ` ng2(
    {{ x }}1
    @@ -2973,51 +2950,47 @@ withEachNg1Version(() => {
    {{ y }}2
    )` - }) - class Ng2Component { - x = 'foo'; - y = 'bar'; - show = true; - constructor() { ng2ComponentInstance = this; } - } + }) + class Ng2Component { + x = 'foo'; + y = 'bar'; + show = true; + constructor() { ng2ComponentInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule], - declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule], + declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - adapter.bootstrap(element, ['ng1Module']).ready(ref => { - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(foo1)|default(bar2)))'); + adapter.bootstrap(element, ['ng1Module']).ready(ref => { + expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(foo1)|default(bar2)))'); - ng2ComponentInstance.x = 'baz'; - ng2ComponentInstance.y = 'qux'; - ng2ComponentInstance.show = false; - $digest(ref); + ng2ComponentInstance.x = 'baz'; + ng2ComponentInstance.y = 'qux'; + ng2ComponentInstance.show = false; + $digest(ref); - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(baz2)|default(qux1)))'); + expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(baz2)|default(qux1)))'); - ng2ComponentInstance.show = true; - $digest(ref); + ng2ComponentInstance.show = true; + $digest(ref); - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(baz1)|default(qux2)))'); - }); - })); + expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(baz1)|default(qux2)))'); + }); + })); }); it('should bind input properties (<) of components', async(() => { @@ -3124,33 +3097,31 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should respect hierarchical dependency injection for ng2', async(() => { - const ng1Module = angular.module('ng1', []); + it('should respect hierarchical dependency injection for ng2', async(() => { + const ng1Module = angular.module('ng1', []); - @Component( - {selector: 'ng2-parent', template: `ng2-parent()`}) - class Ng2Parent { - } - @Component({selector: 'ng2-child', template: `ng2-child`}) - class Ng2Child { - constructor(parent: Ng2Parent) {} - } + @Component({selector: 'ng2-parent', template: `ng2-parent()`}) + class Ng2Parent { + } + @Component({selector: 'ng2-child', template: `ng2-child`}) + class Ng2Child { + constructor(parent: Ng2Parent) {} + } - @NgModule({declarations: [Ng2Parent, Ng2Child], imports: [BrowserModule]}) - class Ng2Module { - } + @NgModule({declarations: [Ng2Parent, Ng2Child], imports: [BrowserModule]}) + class Ng2Module { + } - const element = html(''); + const element = html(''); - const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); - ng1Module.directive('ng2Parent', adapter.downgradeNg2Component(Ng2Parent)) - .directive('ng2Child', adapter.downgradeNg2Component(Ng2Child)); - adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(document.body.textContent).toEqual('ng2-parent(ng2-child)'); - ref.dispose(); - }); - })); + const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module); + ng1Module.directive('ng2Parent', adapter.downgradeNg2Component(Ng2Parent)) + .directive('ng2Child', adapter.downgradeNg2Component(Ng2Child)); + adapter.bootstrap(element, ['ng1']).ready((ref) => { + expect(document.body.textContent).toEqual('ng2-parent(ng2-child)'); + ref.dispose(); + }); + })); }); describe('testability', () => { @@ -3227,45 +3198,44 @@ withEachNg1Version(() => { }); describe('examples', () => { - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should verify UpgradeAdapter example', async(() => { - const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const module = angular.module('myExample', []); + it('should verify UpgradeAdapter example', async(() => { + const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); + const module = angular.module('myExample', []); - const ng1 = () => { - return { - scope: {title: '='}, - transclude: true, - template: 'ng1[Hello {{title}}!]()' - }; - }; - module.directive('ng1', ng1); + const ng1 = () => { + return { + scope: {title: '='}, + transclude: true, + template: 'ng1[Hello {{title}}!]()' + }; + }; + module.directive('ng1', ng1); - @Component({ - selector: 'ng2', - inputs: ['name'], - template: 'ng2[transclude]()' - }) - class Ng2 { - } + @Component({ + selector: 'ng2', + inputs: ['name'], + template: 'ng2[transclude]()' + }) + class Ng2 { + } - @NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }) - class Ng2Module { - } + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } - module.directive('ng2', adapter.downgradeNg2Component(Ng2)); + module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - document.body.innerHTML = 'project'; + document.body.innerHTML = 'project'; - adapter.bootstrap(document.body.firstElementChild !, ['myExample']).ready((ref) => { - expect(multiTrim(document.body.textContent)) - .toEqual('ng2[ng1[Hello World!](transclude)](project)'); - ref.dispose(); - }); - })); + adapter.bootstrap(document.body.firstElementChild !, ['myExample']).ready((ref) => { + expect(multiTrim(document.body.textContent)) + .toEqual('ng2[ng1[Hello World!](transclude)](project)'); + ref.dispose(); + }); + })); }); describe('registerForNg1Tests', () => { diff --git a/packages/upgrade/test/static/angular1_providers_spec.ts b/packages/upgrade/test/static/angular1_providers_spec.ts index b43b524cc0..6b44b87143 100644 --- a/packages/upgrade/test/static/angular1_providers_spec.ts +++ b/packages/upgrade/test/static/angular1_providers_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Ng1Token} from '@angular/upgrade/static/src/common/angular1'; +import {IInjectorService, Ng1Token} from '@angular/upgrade/static/src/common/angular1'; import {compileFactory, injectorFactory, parseFactory, rootScopeFactory, setTempInjectorRef} from '@angular/upgrade/static/src/static/angular1_providers'; { @@ -22,19 +22,25 @@ import {compileFactory, injectorFactory, parseFactory, rootScopeFactory, setTemp describe('injectorFactory', () => { it('should return the injector value that was previously set', () => { - const mockInjector = {get: () => {}, has: () => false}; + const mockInjector = {get: () => undefined, has: () => false}; setTempInjectorRef(mockInjector); const injector = injectorFactory(); expect(injector).toBe(mockInjector); }); - it('should throw if the injector value has not been set yet', () => { - const mockInjector = {get: () => {}, has: () => false}; + it('should throw if the injector value is not set', () => { + // Ensure the injector is not set. This shouldn't be necessary, but on CI there seems to be + // some race condition with previous tests not being cleaned up properly. + // Related: + // - https://github.com/angular/angular/pull/28045 + // - https://github.com/angular/angular/pull/28181 + setTempInjectorRef(null as any); + expect(injectorFactory).toThrowError(); }); it('should unset the injector after the first call (to prevent memory leaks)', () => { - const mockInjector = {get: () => {}, has: () => false}; + const mockInjector = {get: () => undefined, has: () => false}; setTempInjectorRef(mockInjector); injectorFactory(); expect(injectorFactory).toThrowError(); // ...because it has been unset diff --git a/packages/upgrade/test/static/integration/change_detection_spec.ts b/packages/upgrade/test/static/integration/change_detection_spec.ts index 9268165ce4..f4008eefcd 100644 --- a/packages/upgrade/test/static/integration/change_detection_spec.ts +++ b/packages/upgrade/test/static/integration/change_detection_spec.ts @@ -10,7 +10,6 @@ import {Component, Directive, ElementRef, Injector, Input, NgModule, NgZone, Sim import {async} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {fixmeIvy} from '@angular/private/testing'; import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static'; import * as angular from '@angular/upgrade/static/src/common/angular1'; @@ -76,60 +75,54 @@ withEachNg1Version(() => { }); })); - fixmeIvy( - 'FW-712: Rendering is being run on next "animation frame" rather than "Zone.microTaskEmpty" trigger') - .it('should propagate changes to a downgraded component inside the ngZone', async(() => { - const element = html(''); - let appComponent: AppComponent; + it('should propagate changes to a downgraded component inside the ngZone', async(() => { + const element = html(''); + let appComponent: AppComponent; - @Component({selector: 'my-app', template: ''}) - class AppComponent { - value?: number; - constructor() { appComponent = this; } - } + @Component({selector: 'my-app', template: ''}) + class AppComponent { + value?: number; + constructor() { appComponent = this; } + } - @Component({ - selector: 'my-child', - template: '
    {{ valueFromPromise }}
    ', - }) - class ChildComponent { - valueFromPromise?: number; - @Input() - set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); } + @Component({ + selector: 'my-child', + template: '
    {{ valueFromPromise }}
    ', + }) + class ChildComponent { + valueFromPromise?: number; + @Input() + set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); } - constructor(private zone: NgZone) {} + constructor(private zone: NgZone) {} - ngOnChanges(changes: SimpleChanges) { - if (changes['value'].isFirstChange()) return; + ngOnChanges(changes: SimpleChanges) { + if (changes['value'].isFirstChange()) return; - // HACK(ivy): Using setTimeout allows this test to pass but hides the ivy renderer - // timing BC. - // setTimeout(() => expect(element.textContent).toEqual('5'), 0); - this.zone.onMicrotaskEmpty.subscribe( - () => { expect(element.textContent).toEqual('5'); }); + this.zone.onMicrotaskEmpty.subscribe( + () => { expect(element.textContent).toEqual('5'); }); - // Create a micro-task to update the value to be rendered asynchronously. - Promise.resolve().then( - () => this.valueFromPromise = changes['value'].currentValue); - } - } + // Create a micro-task to update the value to be rendered asynchronously. + Promise.resolve().then(() => this.valueFromPromise = changes['value'].currentValue); + } + } - @NgModule({ - declarations: [AppComponent, ChildComponent], - entryComponents: [AppComponent], - imports: [BrowserModule, UpgradeModule] - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [AppComponent, ChildComponent], + entryComponents: [AppComponent], + imports: [BrowserModule, UpgradeModule] + }) + class Ng2Module { + ngDoBootstrap() {} + } - const ng1Module = angular.module('ng1', []).directive( - 'myApp', downgradeComponent({component: AppComponent})); + const ng1Module = angular.module('ng1', []).directive( + 'myApp', downgradeComponent({component: AppComponent})); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { - appComponent.value = 5; - }); - })); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { + appComponent.value = 5; + }); + })); // This test demonstrates https://github.com/angular/angular/issues/6385 // which was invalidly fixed by https://github.com/angular/angular/pull/6386 diff --git a/packages/upgrade/test/static/integration/content_projection_spec.ts b/packages/upgrade/test/static/integration/content_projection_spec.ts index b385dec9c1..00b21ad536 100644 --- a/packages/upgrade/test/static/integration/content_projection_spec.ts +++ b/packages/upgrade/test/static/integration/content_projection_spec.ts @@ -10,7 +10,6 @@ import {Component, Directive, ElementRef, Injector, Input, NgModule, destroyPlat import {async} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {fixmeIvy} from '@angular/private/testing'; import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static'; import * as angular from '@angular/upgrade/static/src/common/angular1'; @@ -22,82 +21,78 @@ withEachNg1Version(() => { beforeEach(() => destroyPlatform()); afterEach(() => destroyPlatform()); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should instantiate ng2 in ng1 template and project content', async(() => { + it('should instantiate ng2 in ng1 template and project content', async(() => { - // the ng2 component that will be used in ng1 (downgraded) - @Component({selector: 'ng2', template: `{{ prop }}()`}) - class Ng2Component { - prop = 'NG2'; - ngContent = 'ng2-content'; - } + // the ng2 component that will be used in ng1 (downgraded) + @Component({selector: 'ng2', template: `{{ prop }}()`}) + class Ng2Component { + prop = 'NG2'; + ngContent = 'ng2-content'; + } - // our upgrade module to host the component to downgrade - @NgModule({ - imports: [BrowserModule, UpgradeModule], - declarations: [Ng2Component], - entryComponents: [Ng2Component] - }) - class Ng2Module { - ngDoBootstrap() {} - } + // our upgrade module to host the component to downgrade + @NgModule({ + imports: [BrowserModule, UpgradeModule], + declarations: [Ng2Component], + entryComponents: [Ng2Component] + }) + class Ng2Module { + ngDoBootstrap() {} + } - // the ng1 app module that will consume the downgraded component - const ng1Module = angular - .module('ng1', []) - // create an ng1 facade of the ng2 component - .directive('ng2', downgradeComponent({component: Ng2Component})) - .run(($rootScope: angular.IRootScopeService) => { - $rootScope['prop'] = 'NG1'; - $rootScope['ngContent'] = 'ng1-content'; - }); + // the ng1 app module that will consume the downgraded component + const ng1Module = angular + .module('ng1', []) + // create an ng1 facade of the ng2 component + .directive('ng2', downgradeComponent({component: Ng2Component})) + .run(($rootScope: angular.IRootScopeService) => { + $rootScope['prop'] = 'NG1'; + $rootScope['ngContent'] = 'ng1-content'; + }); - const element = - html('
    {{ \'ng1[\' }}~{{ ngContent }}~{{ \']\' }}
    '); + const element = html('
    {{ \'ng1[\' }}~{{ ngContent }}~{{ \']\' }}
    '); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { - expect(document.body.textContent).toEqual('ng1[NG2(~ng1-content~)]'); - }); - })); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { + expect(document.body.textContent).toEqual('ng1[NG2(~ng1-content~)]'); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should correctly project structural directives', async(() => { - @Component({selector: 'ng2', template: 'ng2-{{ itemId }}()'}) - class Ng2Component { - // TODO(issue/24571): remove '!'. - @Input() itemId !: string; - } + it('should correctly project structural directives', async(() => { + @Component({selector: 'ng2', template: 'ng2-{{ itemId }}()'}) + class Ng2Component { + // TODO(issue/24571): remove '!'. + @Input() itemId !: string; + } - @NgModule({ - imports: [BrowserModule, UpgradeModule], - declarations: [Ng2Component], - entryComponents: [Ng2Component] - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + imports: [BrowserModule, UpgradeModule], + declarations: [Ng2Component], + entryComponents: [Ng2Component] + }) + class Ng2Module { + ngDoBootstrap() {} + } - const ng1Module = - angular.module('ng1', []) - .directive('ng2', downgradeComponent({component: Ng2Component})) - .run(($rootScope: angular.IRootScopeService) => { - $rootScope['items'] = [ - {id: 'a', subitems: [1, 2, 3]}, {id: 'b', subitems: [4, 5, 6]}, - {id: 'c', subitems: [7, 8, 9]} - ]; - }); + const ng1Module = angular.module('ng1', []) + .directive('ng2', downgradeComponent({component: Ng2Component})) + .run(($rootScope: angular.IRootScopeService) => { + $rootScope['items'] = [ + {id: 'a', subitems: [1, 2, 3]}, {id: 'b', subitems: [4, 5, 6]}, + {id: 'c', subitems: [7, 8, 9]} + ]; + }); - const element = html(` + const element = html(`
    {{ subitem }}
    `); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { - expect(multiTrim(document.body.textContent)) - .toBe('ng2-a( 123 )ng2-b( 456 )ng2-c( 789 )'); - }); - })); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { + expect(multiTrim(document.body.textContent)) + .toBe('ng2-a( 123 )ng2-b( 456 )ng2-c( 789 )'); + }); + })); it('should instantiate ng1 in ng2 template and project content', async(() => { @@ -145,39 +140,38 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support multi-slot projection', async(() => { + it('should support multi-slot projection', async(() => { - @Component({ - selector: 'ng2', - template: '2a()' + - '2b()' - }) - class Ng2Component { - constructor() {} - } + @Component({ + selector: 'ng2', + template: '2a()' + + '2b()' + }) + class Ng2Component { + constructor() {} + } - @NgModule({ - declarations: [Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule, UpgradeModule] - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule, UpgradeModule] + }) + class Ng2Module { + ngDoBootstrap() {} + } - const ng1Module = angular.module('ng1', []).directive( - 'ng2', downgradeComponent({component: Ng2Component})); + const ng1Module = angular.module('ng1', []).directive( + 'ng2', downgradeComponent({component: Ng2Component})); - // The ng-if on one of the projected children is here to make sure - // the correct slot is targeted even with structural directives in play. - const element = html( - '
    1a
    1b
    '); + // The ng-if on one of the projected children is here to make sure + // the correct slot is targeted even with structural directives in play. + const element = html( + '
    1a
    1b
    '); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { - expect(document.body.textContent).toEqual('2a(1a)2b(1b)'); - }); - })); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { + expect(document.body.textContent).toEqual('2a(1a)2b(1b)'); + }); + })); }); }); diff --git a/packages/upgrade/test/static/integration/downgrade_component_spec.ts b/packages/upgrade/test/static/integration/downgrade_component_spec.ts index 73b140a510..1b5ade4d2c 100644 --- a/packages/upgrade/test/static/integration/downgrade_component_spec.ts +++ b/packages/upgrade/test/static/integration/downgrade_component_spec.ts @@ -10,7 +10,6 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Compiler, Component, Compone import {async, fakeAsync, tick} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {fixmeIvy} from '@angular/private/testing'; import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static'; import * as angular from '@angular/upgrade/static/src/common/angular1'; @@ -22,106 +21,104 @@ withEachNg1Version(() => { beforeEach(() => destroyPlatform()); afterEach(() => destroyPlatform()); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .it('should bind properties, events', async(() => { - const ng1Module = angular.module('ng1', []).run(($rootScope: angular.IScope) => { - $rootScope['name'] = 'world'; - $rootScope['dataA'] = 'A'; - $rootScope['dataB'] = 'B'; - $rootScope['modelA'] = 'initModelA'; - $rootScope['modelB'] = 'initModelB'; - $rootScope['eventA'] = '?'; - $rootScope['eventB'] = '?'; - }); + it('should bind properties, events', async(() => { + const ng1Module = angular.module('ng1', []).run(($rootScope: angular.IScope) => { + $rootScope['name'] = 'world'; + $rootScope['dataA'] = 'A'; + $rootScope['dataB'] = 'B'; + $rootScope['modelA'] = 'initModelA'; + $rootScope['modelB'] = 'initModelB'; + $rootScope['eventA'] = '?'; + $rootScope['eventB'] = '?'; + }); - @Component({ - selector: 'ng2', - inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'], - outputs: [ - 'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange', - 'twoWayBEmitter: twoWayBChange' - ], - template: 'ignore: {{ignore}}; ' + - 'literal: {{literal}}; interpolate: {{interpolate}}; ' + - 'oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; ' + - 'twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{ngOnChangesCount}})' - }) - class Ng2Component implements OnChanges { - ngOnChangesCount = 0; - ignore = '-'; - literal = '?'; - interpolate = '?'; - oneWayA = '?'; - oneWayB = '?'; - twoWayA = '?'; - twoWayB = '?'; - eventA = new EventEmitter(); - eventB = new EventEmitter(); - twoWayAEmitter = new EventEmitter(); - twoWayBEmitter = new EventEmitter(); + @Component({ + selector: 'ng2', + inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'], + outputs: [ + 'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange', 'twoWayBEmitter: twoWayBChange' + ], + template: 'ignore: {{ignore}}; ' + + 'literal: {{literal}}; interpolate: {{interpolate}}; ' + + 'oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; ' + + 'twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{ngOnChangesCount}})' + }) + class Ng2Component implements OnChanges { + ngOnChangesCount = 0; + ignore = '-'; + literal = '?'; + interpolate = '?'; + oneWayA = '?'; + oneWayB = '?'; + twoWayA = '?'; + twoWayB = '?'; + eventA = new EventEmitter(); + eventB = new EventEmitter(); + twoWayAEmitter = new EventEmitter(); + twoWayBEmitter = new EventEmitter(); - ngOnChanges(changes: SimpleChanges) { - const assert = (prop: string, value: any) => { - const propVal = (this as any)[prop]; - if (propVal != value) { - throw new Error(`Expected: '${prop}' to be '${value}' but was '${propVal}'`); - } - }; + ngOnChanges(changes: SimpleChanges) { + const assert = (prop: string, value: any) => { + const propVal = (this as any)[prop]; + if (propVal != value) { + throw new Error(`Expected: '${prop}' to be '${value}' but was '${propVal}'`); + } + }; - const assertChange = (prop: string, value: any) => { - assert(prop, value); - if (!changes[prop]) { - throw new Error(`Changes record for '${prop}' not found.`); - } - const actualValue = changes[prop].currentValue; - if (actualValue != value) { - throw new Error( - `Expected changes record for'${prop}' to be '${value}' but was '${actualValue}'`); - } - }; + const assertChange = (prop: string, value: any) => { + assert(prop, value); + if (!changes[prop]) { + throw new Error(`Changes record for '${prop}' not found.`); + } + const actualValue = changes[prop].currentValue; + if (actualValue != value) { + throw new Error( + `Expected changes record for'${prop}' to be '${value}' but was '${actualValue}'`); + } + }; - switch (this.ngOnChangesCount++) { - case 0: - assert('ignore', '-'); - assertChange('literal', 'Text'); - assertChange('interpolate', 'Hello world'); - assertChange('oneWayA', 'A'); - assertChange('oneWayB', 'B'); - assertChange('twoWayA', 'initModelA'); - assertChange('twoWayB', 'initModelB'); + switch (this.ngOnChangesCount++) { + case 0: + assert('ignore', '-'); + assertChange('literal', 'Text'); + assertChange('interpolate', 'Hello world'); + assertChange('oneWayA', 'A'); + assertChange('oneWayB', 'B'); + assertChange('twoWayA', 'initModelA'); + assertChange('twoWayB', 'initModelB'); - this.twoWayAEmitter.emit('newA'); - this.twoWayBEmitter.emit('newB'); - this.eventA.emit('aFired'); - this.eventB.emit('bFired'); - break; - case 1: - assertChange('twoWayA', 'newA'); - assertChange('twoWayB', 'newB'); - break; - case 2: - assertChange('interpolate', 'Hello everyone'); - break; - default: - throw new Error('Called too many times! ' + JSON.stringify(changes)); - } - } - } + this.twoWayAEmitter.emit('newA'); + this.twoWayBEmitter.emit('newB'); + this.eventA.emit('aFired'); + this.eventB.emit('bFired'); + break; + case 1: + assertChange('twoWayA', 'newA'); + assertChange('twoWayB', 'newB'); + break; + case 2: + assertChange('interpolate', 'Hello everyone'); + break; + default: + throw new Error('Called too many times! ' + JSON.stringify(changes)); + } + } + } - ng1Module.directive('ng2', downgradeComponent({ - component: Ng2Component, - })); + ng1Module.directive('ng2', downgradeComponent({ + component: Ng2Component, + })); - @NgModule({ - declarations: [Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule, UpgradeModule] - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule, UpgradeModule] + }) + class Ng2Module { + ngDoBootstrap() {} + } - const element = html(` + const element = html(`
    { | modelA: {{modelA}}; modelB: {{modelB}}; eventA: {{eventA}}; eventB: {{eventB}};
    `); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { - expect(multiTrim(document.body.textContent)) - .toEqual( - 'ignore: -; ' + - 'literal: Text; interpolate: Hello world; ' + - 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (2) | ' + - 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { + expect(multiTrim(document.body.textContent)) + .toEqual( + 'ignore: -; ' + + 'literal: Text; interpolate: Hello world; ' + + 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (2) | ' + + 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); - $apply(upgrade, 'name = "everyone"'); - expect(multiTrim(document.body.textContent)) - .toEqual( - 'ignore: -; ' + - 'literal: Text; interpolate: Hello everyone; ' + - 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (3) | ' + - 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); - }); - })); + $apply(upgrade, 'name = "everyone"'); + expect(multiTrim(document.body.textContent)) + .toEqual( + 'ignore: -; ' + + 'literal: Text; interpolate: Hello everyone; ' + + 'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (3) | ' + + 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); + }); + })); it('should bind properties to onpush components', async(() => { const ng1Module = angular.module('ng1', []).run( @@ -189,58 +186,57 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .it('should support two-way binding and event listener', async(() => { - const listenerSpy = jasmine.createSpy('$rootScope.listener'); - const ng1Module = angular.module('ng1', []).run(($rootScope: angular.IScope) => { - $rootScope['value'] = 'world'; - $rootScope['listener'] = listenerSpy; - }); + it('should support two-way binding and event listener', async(() => { + const listenerSpy = jasmine.createSpy('$rootScope.listener'); + const ng1Module = angular.module('ng1', []).run(($rootScope: angular.IScope) => { + $rootScope['value'] = 'world'; + $rootScope['listener'] = listenerSpy; + }); - @Component({selector: 'ng2', template: `model: {{model}};`}) - class Ng2Component implements OnChanges { - ngOnChangesCount = 0; - @Input() model = '?'; - @Output() modelChange = new EventEmitter(); + @Component({selector: 'ng2', template: `model: {{model}};`}) + class Ng2Component implements OnChanges { + ngOnChangesCount = 0; + @Input() model = '?'; + @Output() modelChange = new EventEmitter(); - ngOnChanges(changes: SimpleChanges) { - switch (this.ngOnChangesCount++) { - case 0: - expect(changes.model.currentValue).toBe('world'); - this.modelChange.emit('newC'); - break; - case 1: - expect(changes.model.currentValue).toBe('newC'); - break; - default: - throw new Error('Called too many times! ' + JSON.stringify(changes)); - } - } - } + ngOnChanges(changes: SimpleChanges) { + switch (this.ngOnChangesCount++) { + case 0: + expect(changes.model.currentValue).toBe('world'); + this.modelChange.emit('newC'); + break; + case 1: + expect(changes.model.currentValue).toBe('newC'); + break; + default: + throw new Error('Called too many times! ' + JSON.stringify(changes)); + } + } + } - ng1Module.directive('ng2', downgradeComponent({component: Ng2Component})); + ng1Module.directive('ng2', downgradeComponent({component: Ng2Component})); - @NgModule({ - declarations: [Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule, UpgradeModule] - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule, UpgradeModule] + }) + class Ng2Module { + ngDoBootstrap() {} + } - const element = html(` + const element = html(`
    | value: {{value}}
    `); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { - expect(multiTrim(element.textContent)).toEqual('model: newC; | value: newC'); - expect(listenerSpy).toHaveBeenCalledWith('newC'); - }); - })); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then((upgrade) => { + expect(multiTrim(element.textContent)).toEqual('model: newC; | value: newC'); + expect(listenerSpy).toHaveBeenCalledWith('newC'); + }); + })); it('should run change-detection on every digest (by default)', async(() => { let ng2Component: Ng2Component; @@ -404,66 +400,65 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .it('should initialize inputs in time for `ngOnChanges`', async(() => { - @Component({ - selector: 'ng2', - template: ` + it('should initialize inputs in time for `ngOnChanges`', async(() => { + @Component({ + selector: 'ng2', + template: ` ngOnChangesCount: {{ ngOnChangesCount }} | firstChangesCount: {{ firstChangesCount }} | initialValue: {{ initialValue }}` - }) - class Ng2Component implements OnChanges { - ngOnChangesCount = 0; - firstChangesCount = 0; - // TODO(issue/24571): remove '!'. - initialValue !: string; - // TODO(issue/24571): remove '!'. - @Input() foo !: string; + }) + class Ng2Component implements OnChanges { + ngOnChangesCount = 0; + firstChangesCount = 0; + // TODO(issue/24571): remove '!'. + initialValue !: string; + // TODO(issue/24571): remove '!'. + @Input() foo !: string; - ngOnChanges(changes: SimpleChanges) { - this.ngOnChangesCount++; + ngOnChanges(changes: SimpleChanges) { + this.ngOnChangesCount++; - if (this.ngOnChangesCount === 1) { - this.initialValue = this.foo; - } + if (this.ngOnChangesCount === 1) { + this.initialValue = this.foo; + } - if (changes['foo'] && changes['foo'].isFirstChange()) { - this.firstChangesCount++; - } - } - } + if (changes['foo'] && changes['foo'].isFirstChange()) { + this.firstChangesCount++; + } + } + } - @NgModule({ - imports: [BrowserModule, UpgradeModule], - declarations: [Ng2Component], - entryComponents: [Ng2Component] - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + imports: [BrowserModule, UpgradeModule], + declarations: [Ng2Component], + entryComponents: [Ng2Component] + }) + class Ng2Module { + ngDoBootstrap() {} + } - const ng1Module = angular.module('ng1', []).directive( - 'ng2', downgradeComponent({component: Ng2Component})); + const ng1Module = angular.module('ng1', []).directive( + 'ng2', downgradeComponent({component: Ng2Component})); - const element = html(` + const element = html(` `); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { - const nodes = element.querySelectorAll('ng2'); - const expectedTextWith = (value: string) => - `ngOnChangesCount: 1 | firstChangesCount: 1 | initialValue: ${value}`; + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { + const nodes = element.querySelectorAll('ng2'); + const expectedTextWith = (value: string) => + `ngOnChangesCount: 1 | firstChangesCount: 1 | initialValue: ${value}`; - expect(multiTrim(nodes[0].textContent)).toBe(expectedTextWith('foo')); - expect(multiTrim(nodes[1].textContent)).toBe(expectedTextWith('bar')); - expect(multiTrim(nodes[2].textContent)).toBe(expectedTextWith('baz')); - expect(multiTrim(nodes[3].textContent)).toBe(expectedTextWith('qux')); - }); - })); + expect(multiTrim(nodes[0].textContent)).toBe(expectedTextWith('foo')); + expect(multiTrim(nodes[1].textContent)).toBe(expectedTextWith('bar')); + expect(multiTrim(nodes[2].textContent)).toBe(expectedTextWith('baz')); + expect(multiTrim(nodes[3].textContent)).toBe(expectedTextWith('qux')); + }); + })); it('should bind to ng-model', async(() => { const ng1Module = angular.module('ng1', []).run( @@ -709,88 +704,85 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should respect hierarchical dependency injection for ng2', async(() => { - @Component({selector: 'parent', template: 'parent()'}) - class ParentComponent { - } + it('should respect hierarchical dependency injection for ng2', async(() => { + @Component({selector: 'parent', template: 'parent()'}) + class ParentComponent { + } - @Component({selector: 'child', template: 'child'}) - class ChildComponent { - constructor(parent: ParentComponent) {} - } + @Component({selector: 'child', template: 'child'}) + class ChildComponent { + constructor(parent: ParentComponent) {} + } - @NgModule({ - declarations: [ParentComponent, ChildComponent], - entryComponents: [ParentComponent, ChildComponent], - imports: [BrowserModule, UpgradeModule] - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [ParentComponent, ChildComponent], + entryComponents: [ParentComponent, ChildComponent], + imports: [BrowserModule, UpgradeModule] + }) + class Ng2Module { + ngDoBootstrap() {} + } - const ng1Module = - angular.module('ng1', []) - .directive('parent', downgradeComponent({component: ParentComponent})) - .directive('child', downgradeComponent({component: ChildComponent})); + const ng1Module = + angular.module('ng1', []) + .directive('parent', downgradeComponent({component: ParentComponent})) + .directive('child', downgradeComponent({component: ChildComponent})); - const element = html(''); + const element = html(''); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { - expect(multiTrim(document.body.textContent)).toBe('parent(child)'); - }); - })); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { + expect(multiTrim(document.body.textContent)).toBe('parent(child)'); + }); + })); - fixmeIvy( - 'FW-717: Injector on lazy loaded components are not the same as their NgModule\'s injector') - .it('should work with ng2 lazy loaded components', async(() => { - let componentInjector: Injector; + it('should work with ng2 lazy loaded components', async(() => { + let componentInjector: Injector; - @Component({selector: 'ng2', template: ''}) - class Ng2Component { - constructor(injector: Injector) { componentInjector = injector; } - } + @Component({selector: 'ng2', template: ''}) + class Ng2Component { + constructor(injector: Injector) { componentInjector = injector; } + } - @NgModule({ - declarations: [Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule, UpgradeModule], - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule, UpgradeModule], + }) + class Ng2Module { + ngDoBootstrap() {} + } - @Component({template: ''}) - class LazyLoadedComponent { - constructor(public module: NgModuleRef) {} - } + @Component({template: ''}) + class LazyLoadedComponent { + constructor(public module: NgModuleRef) {} + } - @NgModule({ - declarations: [LazyLoadedComponent], - entryComponents: [LazyLoadedComponent], - }) - class LazyLoadedModule { - } + @NgModule({ + declarations: [LazyLoadedComponent], + entryComponents: [LazyLoadedComponent], + }) + class LazyLoadedModule { + } - const ng1Module = angular.module('ng1', []).directive( - 'ng2', downgradeComponent({component: Ng2Component})); + const ng1Module = angular.module('ng1', []).directive( + 'ng2', downgradeComponent({component: Ng2Component})); - const element = html(''); + const element = html(''); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { - const modInjector = upgrade.injector; - // Emulate the router lazy loading a module and creating a component - const compiler = modInjector.get(Compiler); - const modFactory = compiler.compileModuleSync(LazyLoadedModule); - const childMod = modFactory.create(modInjector); - const cmpFactory = childMod.componentFactoryResolver.resolveComponentFactory( - LazyLoadedComponent) !; - const lazyCmp = cmpFactory.create(componentInjector); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { + const modInjector = upgrade.injector; + // Emulate the router lazy loading a module and creating a component + const compiler = modInjector.get(Compiler); + const modFactory = compiler.compileModuleSync(LazyLoadedModule); + const childMod = modFactory.create(modInjector); + const cmpFactory = + childMod.componentFactoryResolver.resolveComponentFactory(LazyLoadedComponent) !; + const lazyCmp = cmpFactory.create(componentInjector); - expect(lazyCmp.instance.module.injector === childMod.injector).toBe(true); - }); + expect(lazyCmp.instance.module.injector === childMod.injector).toBe(true); + }); - })); + })); it('should throw if `downgradedModule` is specified', async(() => { @Component({selector: 'ng2', template: ''}) diff --git a/packages/upgrade/test/static/integration/downgrade_module_spec.ts b/packages/upgrade/test/static/integration/downgrade_module_spec.ts index 1643f12d94..c76ea86066 100644 --- a/packages/upgrade/test/static/integration/downgrade_module_spec.ts +++ b/packages/upgrade/test/static/integration/downgrade_module_spec.ts @@ -11,11 +11,11 @@ import {async, fakeAsync, tick} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; -import {fixmeIvy} from '@angular/private/testing'; import {UpgradeComponent, downgradeComponent, downgradeModule} from '@angular/upgrade/static'; import * as angular from '@angular/upgrade/static/src/common/angular1'; import {$EXCEPTION_HANDLER, $ROOT_SCOPE, INJECTOR_KEY, LAZY_MODULE_REF} from '@angular/upgrade/static/src/common/constants'; import {LazyModuleRef} from '@angular/upgrade/static/src/common/util'; +import {setTempInjectorRef} from '@angular/upgrade/static/src/static/angular1_providers'; import {html, multiTrim, withEachNg1Version} from '../test_helpers'; @@ -25,6 +25,7 @@ withEachNg1Version(() => { describe(`lazy-load ng2 module (propagateDigest: ${propagateDigest})`, () => { beforeEach(() => destroyPlatform()); + afterEach(() => destroyPlatform()); it('should support multiple downgraded modules', async(() => { @Component({selector: 'ng2A', template: 'a'}) @@ -158,388 +159,381 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support nesting components from different downgraded modules (via projection)', - async(() => { - @Component({ - selector: 'ng2A', - template: 'ng2A()', - }) - class Ng2ComponentA { - } + it('should support nesting components from different downgraded modules (via projection)', + async(() => { + @Component({ + selector: 'ng2A', + template: 'ng2A()', + }) + class Ng2ComponentA { + } - @Component({ - selector: 'ng2B', - template: 'ng2B', - }) - class Ng2ComponentB { - } + @Component({ + selector: 'ng2B', + template: 'ng2B', + }) + class Ng2ComponentB { + } - @NgModule({ - declarations: [Ng2ComponentA], - entryComponents: [Ng2ComponentA], - imports: [BrowserModule], - }) - class Ng2ModuleA { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2ComponentA], + entryComponents: [Ng2ComponentA], + imports: [BrowserModule], + }) + class Ng2ModuleA { + ngDoBootstrap() {} + } - @NgModule({ - declarations: [Ng2ComponentB], - entryComponents: [Ng2ComponentB], - imports: [BrowserModule], - }) - class Ng2ModuleB { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2ComponentB], + entryComponents: [Ng2ComponentB], + imports: [BrowserModule], + }) + class Ng2ModuleB { + ngDoBootstrap() {} + } - const doDowngradeModule = (module: Type) => { - const bootstrapFn = (extraProviders: StaticProvider[]) => { - const platformRef = getPlatform() || platformBrowserDynamic(extraProviders); - return platformRef.bootstrapModule(module); - }; - return downgradeModule(bootstrapFn); - }; + const doDowngradeModule = (module: Type) => { + const bootstrapFn = (extraProviders: StaticProvider[]) => { + const platformRef = getPlatform() || platformBrowserDynamic(extraProviders); + return platformRef.bootstrapModule(module); + }; + return downgradeModule(bootstrapFn); + }; - const downModA = doDowngradeModule(Ng2ModuleA); - const downModB = doDowngradeModule(Ng2ModuleB); - const ng1Module = angular.module('ng1', [downModA, downModB]) - .directive('ng2A', downgradeComponent({ - component: Ng2ComponentA, - downgradedModule: downModA, propagateDigest, - })) - .directive('ng2B', downgradeComponent({ - component: Ng2ComponentB, - downgradedModule: downModB, propagateDigest, - })); + const downModA = doDowngradeModule(Ng2ModuleA); + const downModB = doDowngradeModule(Ng2ModuleB); + const ng1Module = angular.module('ng1', [downModA, downModB]) + .directive('ng2A', downgradeComponent({ + component: Ng2ComponentA, + downgradedModule: downModA, propagateDigest, + })) + .directive('ng2B', downgradeComponent({ + component: Ng2ComponentB, + downgradedModule: downModB, propagateDigest, + })); - const element = html(''); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + const element = html(''); + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - // Wait for module A to be bootstrapped. - setTimeout(() => { - expect(element.textContent).toBe('ng2A()'); + // Wait for module A to be bootstrapped. + setTimeout(() => { + expect(element.textContent).toBe('ng2A()'); - $rootScope.$apply('showB = true'); + $rootScope.$apply('showB = true'); - // Wait for module B to be bootstrapped. - setTimeout(() => expect(element.textContent).toBe('ng2A(ng2B)')); - }); - })); + // Wait for module B to be bootstrapped. + setTimeout(() => expect(element.textContent).toBe('ng2A(ng2B)')); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should support manually setting up a root module for all downgraded modules', - fakeAsync(() => { - @Injectable({providedIn: 'root'}) - class CounterService { - private static counter = 0; - value = ++CounterService.counter; - } + it('should support manually setting up a root module for all downgraded modules', + fakeAsync(() => { + @Injectable({providedIn: 'root'}) + class CounterService { + private static counter = 0; + value = ++CounterService.counter; + } - @Component({ - selector: 'ng2A', - template: 'ng2A(Counter:{{ counter.value }} | )', - }) - class Ng2ComponentA { - constructor(public counter: CounterService) {} - } + @Component({ + selector: 'ng2A', + template: 'ng2A(Counter:{{ counter.value }} | )', + }) + class Ng2ComponentA { + constructor(public counter: CounterService) {} + } - @Component({ - selector: 'ng2B', - template: 'Counter:{{ counter.value }}', - }) - class Ng2ComponentB { - constructor(public counter: CounterService) {} - } + @Component({ + selector: 'ng2B', + template: 'Counter:{{ counter.value }}', + }) + class Ng2ComponentB { + constructor(public counter: CounterService) {} + } - @NgModule({ - declarations: [Ng2ComponentA], - entryComponents: [Ng2ComponentA], - }) - class Ng2ModuleA { - } + @NgModule({ + declarations: [Ng2ComponentA], + entryComponents: [Ng2ComponentA], + }) + class Ng2ModuleA { + } - @NgModule({ - declarations: [Ng2ComponentB], - entryComponents: [Ng2ComponentB], - }) - class Ng2ModuleB { - } + @NgModule({ + declarations: [Ng2ComponentB], + entryComponents: [Ng2ComponentB], + }) + class Ng2ModuleB { + } - // "Empty" module that will serve as root for all downgraded modules, - // ensuring there will only be one instance for all injectables provided in "root". - @NgModule({ - imports: [BrowserModule], - }) - class Ng2ModuleRoot { - ngDoBootstrap() {} - } + // "Empty" module that will serve as root for all downgraded modules, + // ensuring there will only be one instance for all injectables provided in "root". + @NgModule({ + imports: [BrowserModule], + }) + class Ng2ModuleRoot { + ngDoBootstrap() {} + } - let rootInjectorPromise: Promise|null = null; - const doDowngradeModule = (module: Type) => { - const bootstrapFn = (extraProviders: StaticProvider[]) => { - if (!rootInjectorPromise) { - rootInjectorPromise = platformBrowserDynamic(extraProviders) - .bootstrapModule(Ng2ModuleRoot) - .then(ref => ref.injector); - } + let rootInjectorPromise: Promise|null = null; + const doDowngradeModule = (module: Type) => { + const bootstrapFn = (extraProviders: StaticProvider[]) => { + if (!rootInjectorPromise) { + rootInjectorPromise = platformBrowserDynamic(extraProviders) + .bootstrapModule(Ng2ModuleRoot) + .then(ref => ref.injector); + } - return rootInjectorPromise.then(rootInjector => { - const compiler = rootInjector.get(Compiler); - const moduleFactory = compiler.compileModuleSync(module); + return rootInjectorPromise.then(rootInjector => { + const compiler = rootInjector.get(Compiler); + const moduleFactory = compiler.compileModuleSync(module); - return moduleFactory.create(rootInjector); - }); - }; - return downgradeModule(bootstrapFn); - }; + return moduleFactory.create(rootInjector); + }); + }; + return downgradeModule(bootstrapFn); + }; - const downModA = doDowngradeModule(Ng2ModuleA); - const downModB = doDowngradeModule(Ng2ModuleB); - const ng1Module = angular.module('ng1', [downModA, downModB]) - .directive('ng2A', downgradeComponent({ - component: Ng2ComponentA, - downgradedModule: downModA, propagateDigest, - })) - .directive('ng2B', downgradeComponent({ - component: Ng2ComponentB, - downgradedModule: downModB, propagateDigest, - })); + const downModA = doDowngradeModule(Ng2ModuleA); + const downModB = doDowngradeModule(Ng2ModuleB); + const ng1Module = angular.module('ng1', [downModA, downModB]) + .directive('ng2A', downgradeComponent({ + component: Ng2ComponentA, + downgradedModule: downModA, propagateDigest, + })) + .directive('ng2B', downgradeComponent({ + component: Ng2ComponentB, + downgradedModule: downModB, propagateDigest, + })); - const element = html(` + const element = html(` `); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - tick(); // Wait for module A to be bootstrapped. - expect(multiTrim(element.textContent)).toBe('ng2A(Counter:1 | )'); + tick(); // Wait for module A to be bootstrapped. + expect(multiTrim(element.textContent)).toBe('ng2A(Counter:1 | )'); - // Nested component B should use the same `CounterService` instance. - $rootScope.$apply('showB1 = true'); + // Nested component B should use the same `CounterService` instance. + $rootScope.$apply('showB1 = true'); - tick(); // Wait for module B to be bootstrapped. - expect(multiTrim(element.children[0].textContent)) - .toBe('ng2A(Counter:1 | Counter:1)'); + tick(); // Wait for module B to be bootstrapped. + expect(multiTrim(element.children[0].textContent)).toBe('ng2A(Counter:1 | Counter:1)'); - // Top-level component B should use the same `CounterService` instance. - $rootScope.$apply('showB2 = true'); - tick(); + // Top-level component B should use the same `CounterService` instance. + $rootScope.$apply('showB2 = true'); + tick(); - expect(multiTrim(element.children[1].textContent)).toBe('Counter:1'); - })); + expect(multiTrim(element.children[1].textContent)).toBe('Counter:1'); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should correctly traverse the injector tree of downgraded components', async(() => { - @Component({ - selector: 'ng2A', - template: 'ng2A()', - providers: [ - {provide: 'FOO', useValue: 'CompA-foo'}, - {provide: 'BAR', useValue: 'CompA-bar'}, - ], - }) - class Ng2ComponentA { - } + it('should correctly traverse the injector tree of downgraded components', async(() => { + @Component({ + selector: 'ng2A', + template: 'ng2A()', + providers: [ + {provide: 'FOO', useValue: 'CompA-foo'}, + {provide: 'BAR', useValue: 'CompA-bar'}, + ], + }) + class Ng2ComponentA { + } - @Component({ - selector: 'ng2B', - template: ` + @Component({ + selector: 'ng2B', + template: ` FOO:{{ foo }} BAR:{{ bar }} BAZ:{{ baz }} QUX:{{ qux }} `, - providers: [ - {provide: 'FOO', useValue: 'CompB-foo'}, - ], - }) - class Ng2ComponentB { - constructor( - @Inject('FOO') public foo: string, @Inject('BAR') public bar: string, - @Inject('BAZ') public baz: string, @Inject('QUX') public qux: string) {} - } + providers: [ + {provide: 'FOO', useValue: 'CompB-foo'}, + ], + }) + class Ng2ComponentB { + constructor( + @Inject('FOO') public foo: string, @Inject('BAR') public bar: string, + @Inject('BAZ') public baz: string, @Inject('QUX') public qux: string) {} + } - @NgModule({ - declarations: [Ng2ComponentA, Ng2ComponentB], - entryComponents: [Ng2ComponentA, Ng2ComponentB], - imports: [BrowserModule], - providers: [ - {provide: 'FOO', useValue: 'Mod-foo'}, - {provide: 'BAR', useValue: 'Mod-bar'}, - {provide: 'BAZ', useValue: 'Mod-baz'}, - ], - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2ComponentA, Ng2ComponentB], + entryComponents: [Ng2ComponentA, Ng2ComponentB], + imports: [BrowserModule], + providers: [ + {provide: 'FOO', useValue: 'Mod-foo'}, + {provide: 'BAR', useValue: 'Mod-bar'}, + {provide: 'BAZ', useValue: 'Mod-baz'}, + ], + }) + class Ng2Module { + ngDoBootstrap() {} + } - const bootstrapFn = (extraProviders: StaticProvider[]) => { - const platformRef = getPlatform() || platformBrowserDynamic([ - ...extraProviders, - {provide: 'FOO', useValue: 'Plat-foo'}, - {provide: 'BAR', useValue: 'Plat-bar'}, - {provide: 'BAZ', useValue: 'Plat-baz'}, - {provide: 'QUX', useValue: 'Plat-qux'}, - ]); - return platformRef.bootstrapModule(Ng2Module); - }; + const bootstrapFn = (extraProviders: StaticProvider[]) => { + const platformRef = getPlatform() || platformBrowserDynamic([ + ...extraProviders, + {provide: 'FOO', useValue: 'Plat-foo'}, + {provide: 'BAR', useValue: 'Plat-bar'}, + {provide: 'BAZ', useValue: 'Plat-baz'}, + {provide: 'QUX', useValue: 'Plat-qux'}, + ]); + return platformRef.bootstrapModule(Ng2Module); + }; - const downMod = downgradeModule(bootstrapFn); - const ng1Module = - angular.module('ng1', [downMod]) - .directive( - 'ng2A', downgradeComponent({component: Ng2ComponentA, propagateDigest})) - .directive( - 'ng2B', - downgradeComponent({component: Ng2ComponentB, propagateDigest})); + const downMod = downgradeModule(bootstrapFn); + const ng1Module = + angular.module('ng1', [downMod]) + .directive( + 'ng2A', downgradeComponent({component: Ng2ComponentA, propagateDigest})) + .directive( + 'ng2B', downgradeComponent({component: Ng2ComponentB, propagateDigest})); - const element = html(` + const element = html(` `); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - // Wait for the module to be bootstrapped. - setTimeout(() => { - expect(multiTrim(element.textContent)).toBe('ng2A()'); + // Wait for the module to be bootstrapped. + setTimeout(() => { + expect(multiTrim(element.textContent)).toBe('ng2A()'); - // Nested component B. - $rootScope.$apply('showB1 = true'); - expect(multiTrim(element.children[0].textContent)) - .toBe('ng2A( FOO:CompB-foo BAR:CompA-bar BAZ:Mod-baz QUX:Plat-qux )'); + // Nested component B. + $rootScope.$apply('showB1 = true'); + expect(multiTrim(element.children[0].textContent)) + .toBe('ng2A( FOO:CompB-foo BAR:CompA-bar BAZ:Mod-baz QUX:Plat-qux )'); - // Standalone component B. - $rootScope.$apply('showB2 = true'); - expect(multiTrim(element.children[1].textContent)) - .toBe('FOO:CompB-foo BAR:Mod-bar BAZ:Mod-baz QUX:Plat-qux'); - }); - })); + // Standalone component B. + $rootScope.$apply('showB2 = true'); + expect(multiTrim(element.children[1].textContent)) + .toBe('FOO:CompB-foo BAR:Mod-bar BAZ:Mod-baz QUX:Plat-qux'); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should correctly traverse the injector tree of downgraded components (from different modules)', - async(() => { - @Component({ - selector: 'ng2A', - template: 'ng2A()', - providers: [ - {provide: 'FOO', useValue: 'CompA-foo'}, - {provide: 'BAR', useValue: 'CompA-bar'}, - ], - }) - class Ng2ComponentA { - } + it('should correctly traverse the injector tree of downgraded components (from different modules)', + async(() => { + @Component({ + selector: 'ng2A', + template: 'ng2A()', + providers: [ + {provide: 'FOO', useValue: 'CompA-foo'}, + {provide: 'BAR', useValue: 'CompA-bar'}, + ], + }) + class Ng2ComponentA { + } - @Component({ - selector: 'ng2B', - template: ` + @Component({ + selector: 'ng2B', + template: ` FOO:{{ foo }} BAR:{{ bar }} BAZ:{{ baz }} QUX:{{ qux }} QUUX:{{ quux }} `, - providers: [ - {provide: 'FOO', useValue: 'CompB-foo'}, - ], - }) - class Ng2ComponentB { - constructor( - @Inject('FOO') public foo: string, @Inject('BAR') public bar: string, - @Inject('BAZ') public baz: string, @Inject('QUX') public qux: string, - @Inject('QUUX') public quux: string) {} - } + providers: [ + {provide: 'FOO', useValue: 'CompB-foo'}, + ], + }) + class Ng2ComponentB { + constructor( + @Inject('FOO') public foo: string, @Inject('BAR') public bar: string, + @Inject('BAZ') public baz: string, @Inject('QUX') public qux: string, + @Inject('QUUX') public quux: string) {} + } - @NgModule({ - declarations: [Ng2ComponentA], - entryComponents: [Ng2ComponentA], - imports: [BrowserModule], - providers: [ - {provide: 'FOO', useValue: 'ModA-foo'}, - {provide: 'BAR', useValue: 'ModA-bar'}, - {provide: 'BAZ', useValue: 'ModA-baz'}, - {provide: 'QUX', useValue: 'ModA-qux'}, - ], - }) - class Ng2ModuleA { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2ComponentA], + entryComponents: [Ng2ComponentA], + imports: [BrowserModule], + providers: [ + {provide: 'FOO', useValue: 'ModA-foo'}, + {provide: 'BAR', useValue: 'ModA-bar'}, + {provide: 'BAZ', useValue: 'ModA-baz'}, + {provide: 'QUX', useValue: 'ModA-qux'}, + ], + }) + class Ng2ModuleA { + ngDoBootstrap() {} + } - @NgModule({ - declarations: [Ng2ComponentB], - entryComponents: [Ng2ComponentB], - imports: [BrowserModule], - providers: [ - {provide: 'FOO', useValue: 'ModB-foo'}, - {provide: 'BAR', useValue: 'ModB-bar'}, - {provide: 'BAZ', useValue: 'ModB-baz'}, - ], - }) - class Ng2ModuleB { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2ComponentB], + entryComponents: [Ng2ComponentB], + imports: [BrowserModule], + providers: [ + {provide: 'FOO', useValue: 'ModB-foo'}, + {provide: 'BAR', useValue: 'ModB-bar'}, + {provide: 'BAZ', useValue: 'ModB-baz'}, + ], + }) + class Ng2ModuleB { + ngDoBootstrap() {} + } - const doDowngradeModule = (module: Type) => { - const bootstrapFn = (extraProviders: StaticProvider[]) => { - const platformRef = getPlatform() || platformBrowserDynamic([ - ...extraProviders, - {provide: 'FOO', useValue: 'Plat-foo'}, - {provide: 'BAR', useValue: 'Plat-bar'}, - {provide: 'BAZ', useValue: 'Plat-baz'}, - {provide: 'QUX', useValue: 'Plat-qux'}, - {provide: 'QUUX', useValue: 'Plat-quux'}, - ]); - return platformRef.bootstrapModule(module); - }; - return downgradeModule(bootstrapFn); - }; + const doDowngradeModule = (module: Type) => { + const bootstrapFn = (extraProviders: StaticProvider[]) => { + const platformRef = getPlatform() || platformBrowserDynamic([ + ...extraProviders, + {provide: 'FOO', useValue: 'Plat-foo'}, + {provide: 'BAR', useValue: 'Plat-bar'}, + {provide: 'BAZ', useValue: 'Plat-baz'}, + {provide: 'QUX', useValue: 'Plat-qux'}, + {provide: 'QUUX', useValue: 'Plat-quux'}, + ]); + return platformRef.bootstrapModule(module); + }; + return downgradeModule(bootstrapFn); + }; - const downModA = doDowngradeModule(Ng2ModuleA); - const downModB = doDowngradeModule(Ng2ModuleB); - const ng1Module = angular.module('ng1', [downModA, downModB]) - .directive('ng2A', downgradeComponent({ - component: Ng2ComponentA, - downgradedModule: downModA, propagateDigest, - })) - .directive('ng2B', downgradeComponent({ - component: Ng2ComponentB, - downgradedModule: downModB, propagateDigest, - })); + const downModA = doDowngradeModule(Ng2ModuleA); + const downModB = doDowngradeModule(Ng2ModuleB); + const ng1Module = angular.module('ng1', [downModA, downModB]) + .directive('ng2A', downgradeComponent({ + component: Ng2ComponentA, + downgradedModule: downModA, propagateDigest, + })) + .directive('ng2B', downgradeComponent({ + component: Ng2ComponentB, + downgradedModule: downModB, propagateDigest, + })); - const element = html(` + const element = html(` `); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - // Wait for module A to be bootstrapped. - setTimeout(() => { - expect(multiTrim(element.textContent)).toBe('ng2A()'); + // Wait for module A to be bootstrapped. + setTimeout(() => { + expect(multiTrim(element.textContent)).toBe('ng2A()'); - // Nested component B. - $rootScope.$apply('showB1 = true'); + // Nested component B. + $rootScope.$apply('showB1 = true'); - // Wait for module B to be bootstrapped. - setTimeout(() => { - // It is debatable, whether the order of traversal should be: - // CompB > CompA > ModB > ModA > Plat (similar to how lazy-loaded components - // work) - expect(multiTrim(element.children[0].textContent)) - .toBe( - 'ng2A( FOO:CompB-foo BAR:CompA-bar BAZ:ModB-baz QUX:Plat-qux QUUX:Plat-quux )'); + // Wait for module B to be bootstrapped. + setTimeout(() => { + // It is debatable, whether the order of traversal should be: + // CompB > CompA > ModB > ModA > Plat (similar to how lazy-loaded components + // work) + expect(multiTrim(element.children[0].textContent)) + .toBe( + 'ng2A( FOO:CompB-foo BAR:CompA-bar BAZ:ModB-baz QUX:Plat-qux QUUX:Plat-quux )'); - // Standalone component B. - $rootScope.$apply('showB2 = true'); - expect(multiTrim(element.children[1].textContent)) - .toBe( - 'FOO:CompB-foo BAR:ModB-bar BAZ:ModB-baz QUX:Plat-qux QUUX:Plat-quux'); - }); - }); - })); + // Standalone component B. + $rootScope.$apply('showB2 = true'); + expect(multiTrim(element.children[1].textContent)) + .toBe('FOO:CompB-foo BAR:ModB-bar BAZ:ModB-baz QUX:Plat-qux QUUX:Plat-quux'); + }); + }); + })); it('should support downgrading a component and propagate inputs', async(() => { @Component( @@ -595,64 +589,63 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-718: upgraded service not being initialized correctly on the injector') - .it('should support using an upgraded service', async(() => { - class Ng2Service { - constructor(@Inject('ng1Value') private ng1Value: string) {} - getValue = () => `${this.ng1Value}-bar`; - } + it('should support using an upgraded service', async(() => { + @Injectable() + class Ng2Service { + constructor(@Inject('ng1Value') private ng1Value: string) {} + getValue = () => `${this.ng1Value}-bar`; + } - @Component({selector: 'ng2', template: '{{ value }}'}) - class Ng2Component { - value: string; - constructor(ng2Service: Ng2Service) { this.value = ng2Service.getValue(); } - } + @Component({selector: 'ng2', template: '{{ value }}'}) + class Ng2Component { + value: string; + constructor(ng2Service: Ng2Service) { this.value = ng2Service.getValue(); } + } - @NgModule({ - declarations: [Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule], - providers: [ - Ng2Service, - { - provide: 'ng1Value', - useFactory: (i: angular.IInjectorService) => i.get('ng1Value'), - deps: ['$injector'], - }, - ], - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule], + providers: [ + Ng2Service, + { + provide: 'ng1Value', + useFactory: (i: angular.IInjectorService) => i.get('ng1Value'), + deps: ['$injector'], + }, + ], + }) + class Ng2Module { + ngDoBootstrap() {} + } - const bootstrapFn = (extraProviders: StaticProvider[]) => - platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); - const lazyModuleName = downgradeModule(bootstrapFn); - const ng1Module = - angular.module('ng1', [lazyModuleName]) - .directive( - 'ng2', downgradeComponent({component: Ng2Component, propagateDigest})) - .value('ng1Value', 'foo'); + const bootstrapFn = (extraProviders: StaticProvider[]) => + platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); + const lazyModuleName = downgradeModule(bootstrapFn); + const ng1Module = + angular.module('ng1', [lazyModuleName]) + .directive('ng2', downgradeComponent({component: Ng2Component, propagateDigest})) + .value('ng1Value', 'foo'); - const element = html('
    '); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + const element = html('
    '); + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - expect(element.textContent).toBe(''); - expect(() => $injector.get(INJECTOR_KEY)).toThrowError(); + expect(element.textContent).toBe(''); + expect(() => $injector.get(INJECTOR_KEY)).toThrowError(); - $rootScope.$apply('loadNg2 = true'); - expect(element.textContent).toBe(''); - expect(() => $injector.get(INJECTOR_KEY)).toThrowError(); + $rootScope.$apply('loadNg2 = true'); + expect(element.textContent).toBe(''); + expect(() => $injector.get(INJECTOR_KEY)).toThrowError(); - // Wait for the module to be bootstrapped. - setTimeout(() => { - expect(() => $injector.get(INJECTOR_KEY)).not.toThrow(); + // Wait for the module to be bootstrapped. + setTimeout(() => { + expect(() => $injector.get(INJECTOR_KEY)).not.toThrow(); - // Wait for `$evalAsync()` to propagate inputs. - setTimeout(() => expect(element.textContent).toBe('foo-bar')); - }); - })); + // Wait for `$evalAsync()` to propagate inputs. + setTimeout(() => expect(element.textContent).toBe('foo-bar')); + }); + })); it('should create components inside the Angular zone', async(() => { @Component({selector: 'ng2', template: 'In the zone: {{ inTheZone }}'}) @@ -724,129 +717,125 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .it('should propagate input changes inside the Angular zone', async(() => { - let ng2Component: Ng2Component; + it('should propagate input changes inside the Angular zone', async(() => { + let ng2Component: Ng2Component; - @Component({selector: 'ng2', template: ''}) - class Ng2Component implements OnChanges { - @Input() attrInput = 'foo'; - @Input() propInput = 'foo'; + @Component({selector: 'ng2', template: ''}) + class Ng2Component implements OnChanges { + @Input() attrInput = 'foo'; + @Input() propInput = 'foo'; - constructor() { ng2Component = this; } - ngOnChanges() {} - } + constructor() { ng2Component = this; } + ngOnChanges() {} + } - @NgModule({ - declarations: [Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule], - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule], + }) + class Ng2Module { + ngDoBootstrap() {} + } - const bootstrapFn = (extraProviders: StaticProvider[]) => - platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); - const lazyModuleName = downgradeModule(bootstrapFn); - const ng1Module = - angular.module('ng1', [lazyModuleName]) - .directive( - 'ng2', downgradeComponent({component: Ng2Component, propagateDigest})) - .run(($rootScope: angular.IRootScopeService) => { - $rootScope.attrVal = 'bar'; - $rootScope.propVal = 'bar'; - }); + const bootstrapFn = (extraProviders: StaticProvider[]) => + platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); + const lazyModuleName = downgradeModule(bootstrapFn); + const ng1Module = + angular.module('ng1', [lazyModuleName]) + .directive('ng2', downgradeComponent({component: Ng2Component, propagateDigest})) + .run(($rootScope: angular.IRootScopeService) => { + $rootScope.attrVal = 'bar'; + $rootScope.propVal = 'bar'; + }); - const element = - html(''); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + const element = html(''); + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - setTimeout(() => { // Wait for the module to be bootstrapped. - setTimeout(() => { // Wait for `$evalAsync()` to propagate inputs. - const expectToBeInNgZone = () => expect(NgZone.isInAngularZone()).toBe(true); - const changesSpy = - spyOn(ng2Component, 'ngOnChanges').and.callFake(expectToBeInNgZone); + setTimeout(() => { // Wait for the module to be bootstrapped. + setTimeout(() => { // Wait for `$evalAsync()` to propagate inputs. + const expectToBeInNgZone = () => expect(NgZone.isInAngularZone()).toBe(true); + const changesSpy = + spyOn(ng2Component, 'ngOnChanges').and.callFake(expectToBeInNgZone); - expect(ng2Component.attrInput).toBe('bar'); - expect(ng2Component.propInput).toBe('bar'); + expect(ng2Component.attrInput).toBe('bar'); + expect(ng2Component.propInput).toBe('bar'); - $rootScope.$apply('attrVal = "baz"'); - expect(ng2Component.attrInput).toBe('baz'); - expect(ng2Component.propInput).toBe('bar'); - expect(changesSpy).toHaveBeenCalledTimes(1); + $rootScope.$apply('attrVal = "baz"'); + expect(ng2Component.attrInput).toBe('baz'); + expect(ng2Component.propInput).toBe('bar'); + expect(changesSpy).toHaveBeenCalledTimes(1); - $rootScope.$apply('propVal = "qux"'); - expect(ng2Component.attrInput).toBe('baz'); - expect(ng2Component.propInput).toBe('qux'); - expect(changesSpy).toHaveBeenCalledTimes(2); - }); - }); - })); + $rootScope.$apply('propVal = "qux"'); + expect(ng2Component.attrInput).toBe('baz'); + expect(ng2Component.propInput).toBe('qux'); + expect(changesSpy).toHaveBeenCalledTimes(2); + }); + }); + })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should create and destroy nested, asynchronously instantiated components inside the Angular zone', - async(() => { - let createdInTheZone = false; - let destroyedInTheZone = false; + it('should create and destroy nested, asynchronously instantiated components inside the Angular zone', + async(() => { + let createdInTheZone = false; + let destroyedInTheZone = false; - @Component({ - selector: 'test', - template: '', - }) - class TestComponent implements OnDestroy { - constructor() { createdInTheZone = NgZone.isInAngularZone(); } - ngOnDestroy() { destroyedInTheZone = NgZone.isInAngularZone(); } - } + @Component({ + selector: 'test', + template: '', + }) + class TestComponent implements OnDestroy { + constructor() { createdInTheZone = NgZone.isInAngularZone(); } + ngOnDestroy() { destroyedInTheZone = NgZone.isInAngularZone(); } + } - @Component({ - selector: 'wrapper', - template: '', - }) - class WrapperComponent { - } + @Component({ + selector: 'wrapper', + template: '', + }) + class WrapperComponent { + } - @NgModule({ - declarations: [TestComponent, WrapperComponent], - entryComponents: [TestComponent, WrapperComponent], - imports: [BrowserModule], - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [TestComponent, WrapperComponent], + entryComponents: [TestComponent, WrapperComponent], + imports: [BrowserModule], + }) + class Ng2Module { + ngDoBootstrap() {} + } - const bootstrapFn = (extraProviders: StaticProvider[]) => - platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); - const lazyModuleName = downgradeModule(bootstrapFn); - const ng1Module = - angular.module('ng1', [lazyModuleName]) - .directive( - 'test', downgradeComponent({component: TestComponent, propagateDigest})) - .directive( - 'wrapper', - downgradeComponent({component: WrapperComponent, propagateDigest})); + const bootstrapFn = (extraProviders: StaticProvider[]) => + platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); + const lazyModuleName = downgradeModule(bootstrapFn); + const ng1Module = + angular.module('ng1', [lazyModuleName]) + .directive( + 'test', downgradeComponent({component: TestComponent, propagateDigest})) + .directive( + 'wrapper', + downgradeComponent({component: WrapperComponent, propagateDigest})); - // Important: `ng-if` makes `` render asynchronously. - const element = html(''); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + // Important: `ng-if` makes `` render asynchronously. + const element = html(''); + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - // Wait for the module to be bootstrapped. - setTimeout(() => { - // Create nested component asynchronously. - expect(createdInTheZone).toBe(false); + // Wait for the module to be bootstrapped. + setTimeout(() => { + // Create nested component asynchronously. + expect(createdInTheZone).toBe(false); - $rootScope.$apply('showNg2 = true'); - expect(createdInTheZone).toBe(true); + $rootScope.$apply('showNg2 = true'); + expect(createdInTheZone).toBe(true); - // Destroy nested component asynchronously. - expect(destroyedInTheZone).toBe(false); + // Destroy nested component asynchronously. + expect(destroyedInTheZone).toBe(false); - $rootScope.$apply('showNg2 = false'); - expect(destroyedInTheZone).toBe(true); - }); - })); + $rootScope.$apply('showNg2 = false'); + expect(destroyedInTheZone).toBe(true); + }); + })); it('should wire up the component for change detection', async(() => { @Component( @@ -890,228 +879,222 @@ withEachNg1Version(() => { }); })); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should wire up nested, asynchronously instantiated components for change detection', - async(() => { - @Component({ - selector: 'test', - template: '{{ count }}' - }) - class TestComponent { - count = 0; - increment() { ++this.count; } - } + it('should wire up nested, asynchronously instantiated components for change detection', + async(() => { + @Component( + {selector: 'test', template: '{{ count }}'}) + class TestComponent { + count = 0; + increment() { ++this.count; } + } - @Component({ - selector: 'wrapper', - template: '', - }) - class WrapperComponent { - } + @Component({ + selector: 'wrapper', + template: '', + }) + class WrapperComponent { + } - @NgModule({ - declarations: [TestComponent, WrapperComponent], - entryComponents: [TestComponent, WrapperComponent], - imports: [BrowserModule], - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [TestComponent, WrapperComponent], + entryComponents: [TestComponent, WrapperComponent], + imports: [BrowserModule], + }) + class Ng2Module { + ngDoBootstrap() {} + } - const bootstrapFn = (extraProviders: StaticProvider[]) => - platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); - const lazyModuleName = downgradeModule(bootstrapFn); - const ng1Module = - angular.module('ng1', [lazyModuleName]) - .directive( - 'test', downgradeComponent({component: TestComponent, propagateDigest})) - .directive( - 'wrapper', - downgradeComponent({component: WrapperComponent, propagateDigest})); + const bootstrapFn = (extraProviders: StaticProvider[]) => + platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); + const lazyModuleName = downgradeModule(bootstrapFn); + const ng1Module = + angular.module('ng1', [lazyModuleName]) + .directive( + 'test', downgradeComponent({component: TestComponent, propagateDigest})) + .directive( + 'wrapper', + downgradeComponent({component: WrapperComponent, propagateDigest})); - // Important: `ng-if` makes `` render asynchronously. - const element = html(''); - const $injector = angular.bootstrap(element, [ng1Module.name]); - const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; + // Important: `ng-if` makes `` render asynchronously. + const element = html(''); + const $injector = angular.bootstrap(element, [ng1Module.name]); + const $rootScope = $injector.get($ROOT_SCOPE) as angular.IRootScopeService; - // Wait for the module to be bootstrapped. - setTimeout(() => { - // Create nested component asynchronously. - $rootScope.$apply('showNg2 = true'); - const button = element.querySelector('button') !; + // Wait for the module to be bootstrapped. + setTimeout(() => { + // Create nested component asynchronously. + $rootScope.$apply('showNg2 = true'); + const button = element.querySelector('button') !; - expect(element.textContent).toBe('0'); + expect(element.textContent).toBe('0'); - button.click(); - expect(element.textContent).toBe('1'); + button.click(); + expect(element.textContent).toBe('1'); - button.click(); - expect(element.textContent).toBe('2'); - }); - })); + button.click(); + expect(element.textContent).toBe('2'); + }); + })); - fixmeIvy('FW-715: ngOnChanges being called a second time unexpectedly') - .fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should run the lifecycle hooks in the correct order', async(() => { - const logs: string[] = []; - let rootScope: angular.IRootScopeService; + it('should run the lifecycle hooks in the correct order', async(() => { + const logs: string[] = []; + let rootScope: angular.IRootScopeService; - @Component({ - selector: 'ng2', - template: ` + @Component({ + selector: 'ng2', + template: ` {{ value }} ` - }) - class Ng2Component implements AfterContentChecked, - AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, - OnDestroy, OnInit { - @Input() value = 'foo'; + }) + class Ng2Component implements AfterContentChecked, + AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnDestroy, + OnInit { + @Input() value = 'foo'; - ngAfterContentChecked() { this.log('AfterContentChecked'); } - ngAfterContentInit() { this.log('AfterContentInit'); } - ngAfterViewChecked() { this.log('AfterViewChecked'); } - ngAfterViewInit() { this.log('AfterViewInit'); } - ngDoCheck() { this.log('DoCheck'); } - ngOnChanges() { this.log('OnChanges'); } - ngOnDestroy() { this.log('OnDestroy'); } - ngOnInit() { this.log('OnInit'); } + ngAfterContentChecked() { this.log('AfterContentChecked'); } + ngAfterContentInit() { this.log('AfterContentInit'); } + ngAfterViewChecked() { this.log('AfterViewChecked'); } + ngAfterViewInit() { this.log('AfterViewInit'); } + ngDoCheck() { this.log('DoCheck'); } + ngOnChanges() { this.log('OnChanges'); } + ngOnDestroy() { this.log('OnDestroy'); } + ngOnInit() { this.log('OnInit'); } - private log(hook: string) { logs.push(`${hook}(${this.value})`); } - } + private log(hook: string) { logs.push(`${hook}(${this.value})`); } + } - @NgModule({ - declarations: [Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule], - }) - class Ng2Module { - ngDoBootstrap() {} - } + @NgModule({ + declarations: [Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule], + }) + class Ng2Module { + ngDoBootstrap() {} + } - const bootstrapFn = (extraProviders: StaticProvider[]) => - platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); - const lazyModuleName = downgradeModule(bootstrapFn); - const ng1Module = - angular.module('ng1', [lazyModuleName]) - .directive( - 'ng2', downgradeComponent({component: Ng2Component, propagateDigest})) - .run(($rootScope: angular.IRootScopeService) => { - rootScope = $rootScope; - rootScope.value = 'bar'; - }); + const bootstrapFn = (extraProviders: StaticProvider[]) => + platformBrowserDynamic(extraProviders).bootstrapModule(Ng2Module); + const lazyModuleName = downgradeModule(bootstrapFn); + const ng1Module = + angular.module('ng1', [lazyModuleName]) + .directive('ng2', downgradeComponent({component: Ng2Component, propagateDigest})) + .run(($rootScope: angular.IRootScopeService) => { + rootScope = $rootScope; + rootScope.value = 'bar'; + }); - const element = - html('
    Content
    '); - angular.bootstrap(element, [ng1Module.name]); + const element = + html('
    Content
    '); + angular.bootstrap(element, [ng1Module.name]); - setTimeout(() => { // Wait for the module to be bootstrapped. - setTimeout(() => { // Wait for `$evalAsync()` to propagate inputs. - const button = element.querySelector('button') !; + setTimeout(() => { // Wait for the module to be bootstrapped. + setTimeout(() => { // Wait for `$evalAsync()` to propagate inputs. + const button = element.querySelector('button') !; - // Once initialized. - expect(multiTrim(element.textContent)).toBe('bar Content'); - expect(logs).toEqual([ - // `ngOnChanges()` call triggered directly through the `inputChanges` - // $watcher. - 'OnChanges(bar)', - // Initial CD triggered directly through the `detectChanges()` or - // `inputChanges` - // $watcher (for `propagateDigest` true/false respectively). - 'OnInit(bar)', - 'DoCheck(bar)', - 'AfterContentInit(bar)', - 'AfterContentChecked(bar)', - 'AfterViewInit(bar)', - 'AfterViewChecked(bar)', - ...(propagateDigest ? - [ - // CD triggered directly through the `detectChanges()` $watcher (2nd - // $digest). - 'DoCheck(bar)', - 'AfterContentChecked(bar)', - 'AfterViewChecked(bar)', - ] : - []), - // CD triggered due to entering/leaving the NgZone (in `downgradeFn()`). - 'DoCheck(bar)', - 'AfterContentChecked(bar)', - 'AfterViewChecked(bar)', - ]); - logs.length = 0; + // Once initialized. + expect(multiTrim(element.textContent)).toBe('bar Content'); + expect(logs).toEqual([ + // `ngOnChanges()` call triggered directly through the `inputChanges` + // $watcher. + 'OnChanges(bar)', + // Initial CD triggered directly through the `detectChanges()` or + // `inputChanges` + // $watcher (for `propagateDigest` true/false respectively). + 'OnInit(bar)', + 'DoCheck(bar)', + 'AfterContentInit(bar)', + 'AfterContentChecked(bar)', + 'AfterViewInit(bar)', + 'AfterViewChecked(bar)', + ...(propagateDigest ? + [ + // CD triggered directly through the `detectChanges()` $watcher (2nd + // $digest). + 'DoCheck(bar)', + 'AfterContentChecked(bar)', + 'AfterViewChecked(bar)', + ] : + []), + // CD triggered due to entering/leaving the NgZone (in `downgradeFn()`). + 'DoCheck(bar)', + 'AfterContentChecked(bar)', + 'AfterViewChecked(bar)', + ]); + logs.length = 0; - // Change inputs and run `$digest`. - rootScope.$apply('value = "baz"'); - expect(multiTrim(element.textContent)).toBe('baz Content'); - expect(logs).toEqual([ - // `ngOnChanges()` call triggered directly through the `inputChanges` - // $watcher. - 'OnChanges(baz)', - // `propagateDigest: true` (3 CD runs): - // - CD triggered due to entering/leaving the NgZone (in `inputChanges` - // $watcher). - // - CD triggered directly through the `detectChanges()` $watcher. - // - CD triggered due to entering/leaving the NgZone (in `detectChanges` - // $watcher). - // `propagateDigest: false` (2 CD runs): - // - CD triggered directly through the `inputChanges` $watcher. - // - CD triggered due to entering/leaving the NgZone (in `inputChanges` - // $watcher). - 'DoCheck(baz)', - 'AfterContentChecked(baz)', - 'AfterViewChecked(baz)', - 'DoCheck(baz)', - 'AfterContentChecked(baz)', - 'AfterViewChecked(baz)', - ...(propagateDigest ? - [ - 'DoCheck(baz)', - 'AfterContentChecked(baz)', - 'AfterViewChecked(baz)', - ] : - []), - ]); - logs.length = 0; + // Change inputs and run `$digest`. + rootScope.$apply('value = "baz"'); + expect(multiTrim(element.textContent)).toBe('baz Content'); + expect(logs).toEqual([ + // `ngOnChanges()` call triggered directly through the `inputChanges` + // $watcher. + 'OnChanges(baz)', + // `propagateDigest: true` (3 CD runs): + // - CD triggered due to entering/leaving the NgZone (in `inputChanges` + // $watcher). + // - CD triggered directly through the `detectChanges()` $watcher. + // - CD triggered due to entering/leaving the NgZone (in `detectChanges` + // $watcher). + // `propagateDigest: false` (2 CD runs): + // - CD triggered directly through the `inputChanges` $watcher. + // - CD triggered due to entering/leaving the NgZone (in `inputChanges` + // $watcher). + 'DoCheck(baz)', + 'AfterContentChecked(baz)', + 'AfterViewChecked(baz)', + 'DoCheck(baz)', + 'AfterContentChecked(baz)', + 'AfterViewChecked(baz)', + ...(propagateDigest ? + [ + 'DoCheck(baz)', + 'AfterContentChecked(baz)', + 'AfterViewChecked(baz)', + ] : + []), + ]); + logs.length = 0; - // Run `$digest` (without changing inputs). - rootScope.$digest(); - expect(multiTrim(element.textContent)).toBe('baz Content'); - expect(logs).toEqual( - propagateDigest ? - [ - // CD triggered directly through the `detectChanges()` $watcher. - 'DoCheck(baz)', - 'AfterContentChecked(baz)', - 'AfterViewChecked(baz)', - // CD triggered due to entering/leaving the NgZone (in the above - // $watcher). - 'DoCheck(baz)', - 'AfterContentChecked(baz)', - 'AfterViewChecked(baz)', - ] : - []); - logs.length = 0; + // Run `$digest` (without changing inputs). + rootScope.$digest(); + expect(multiTrim(element.textContent)).toBe('baz Content'); + expect(logs).toEqual( + propagateDigest ? + [ + // CD triggered directly through the `detectChanges()` $watcher. + 'DoCheck(baz)', + 'AfterContentChecked(baz)', + 'AfterViewChecked(baz)', + // CD triggered due to entering/leaving the NgZone (in the above + // $watcher). + 'DoCheck(baz)', + 'AfterContentChecked(baz)', + 'AfterViewChecked(baz)', + ] : + []); + logs.length = 0; - // Trigger change detection (without changing inputs). - button.click(); - expect(multiTrim(element.textContent)).toBe('qux Content'); - expect(logs).toEqual([ - 'DoCheck(qux)', - 'AfterContentChecked(qux)', - 'AfterViewChecked(qux)', - ]); - logs.length = 0; + // Trigger change detection (without changing inputs). + button.click(); + expect(multiTrim(element.textContent)).toBe('qux Content'); + expect(logs).toEqual([ + 'DoCheck(qux)', + 'AfterContentChecked(qux)', + 'AfterViewChecked(qux)', + ]); + logs.length = 0; - // Destroy the component. - rootScope.$apply('hideNg2 = true'); - expect(logs).toEqual([ - 'OnDestroy(qux)', - ]); - logs.length = 0; - }); - }); - })); + // Destroy the component. + rootScope.$apply('hideNg2 = true'); + expect(logs).toEqual([ + 'OnDestroy(qux)', + ]); + logs.length = 0; + }); + }); + })); it('should detach hostViews from the ApplicationRef once destroyed', async(() => { let ng2Component: Ng2Component; @@ -1308,6 +1291,12 @@ withEachNg1Version(() => { errorSpy = jasmine.createSpy($EXCEPTION_HANDLER); }); + // In the tests below, some of the components' bootstrap process is interrupted by an error. + // If the bootstrap process for other components/modules is not completed in time, there is + // a chance that some global state is retained, possibly messing subsequent tests. + // Explicitly clean up after each test to prevent that. + afterEach(() => setTempInjectorRef(null !)); + it('should throw if no downgraded module is included', async(() => { const ng1Module = angular.module('ng1', []) .value($EXCEPTION_HANDLER, errorSpy) diff --git a/packages/upgrade/test/static/integration/examples_spec.ts b/packages/upgrade/test/static/integration/examples_spec.ts index 90b66a88fa..f7ec6f52fb 100644 --- a/packages/upgrade/test/static/integration/examples_spec.ts +++ b/packages/upgrade/test/static/integration/examples_spec.ts @@ -10,7 +10,6 @@ import {Component, Directive, ElementRef, Injector, Input, NgModule, destroyPlat import {async} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {fixmeIvy} from '@angular/private/testing'; import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static'; import * as angular from '@angular/upgrade/static/src/common/angular1'; @@ -24,70 +23,69 @@ withEachNg1Version(() => { it('should have AngularJS loaded', () => expect(angular.version.major).toBe(1)); - fixmeIvy('FW-714: ng1 projected content is not being rendered') - .it('should verify UpgradeAdapter example', async(() => { + it('should verify UpgradeAdapter example', async(() => { - // This is wrapping (upgrading) an AngularJS component to be used in an Angular - // component - @Directive({selector: 'ng1'}) - class Ng1Component extends UpgradeComponent { - // TODO(issue/24571): remove '!'. - @Input() title !: string; + // This is wrapping (upgrading) an AngularJS component to be used in an Angular + // component + @Directive({selector: 'ng1'}) + class Ng1Component extends UpgradeComponent { + // TODO(issue/24571): remove '!'. + @Input() title !: string; - constructor(elementRef: ElementRef, injector: Injector) { - super('ng1', elementRef, injector); - } - } + constructor(elementRef: ElementRef, injector: Injector) { + super('ng1', elementRef, injector); + } + } - // This is an Angular component that will be downgraded - @Component({ - selector: 'ng2', - template: 'ng2[transclude]()' - }) - class Ng2Component { - // TODO(issue/24571): remove '!'. - @Input('name') nameProp !: string; - } + // This is an Angular component that will be downgraded + @Component({ + selector: 'ng2', + template: 'ng2[transclude]()' + }) + class Ng2Component { + // TODO(issue/24571): remove '!'. + @Input('name') nameProp !: string; + } - // This module represents the Angular pieces of the application - @NgModule({ - declarations: [Ng1Component, Ng2Component], - entryComponents: [Ng2Component], - imports: [BrowserModule, UpgradeModule] - }) - class Ng2Module { - ngDoBootstrap() { /* this is a placeholder to stop the bootstrapper from - complaining */ - } - } + // This module represents the Angular pieces of the application + @NgModule({ + declarations: [Ng1Component, Ng2Component], + entryComponents: [Ng2Component], + imports: [BrowserModule, UpgradeModule] + }) + class Ng2Module { + ngDoBootstrap() { /* this is a placeholder to stop the bootstrapper from + complaining */ + } + } - // This module represents the AngularJS pieces of the application - const ng1Module = - angular - .module('myExample', []) - // This is an AngularJS component that will be upgraded - .directive( - 'ng1', - () => { - return { - scope: {title: '='}, - transclude: true, - template: 'ng1[Hello {{title}}!]()' - }; - }) - // This is wrapping (downgrading) an Angular component to be used in - // AngularJS - .directive('ng2', downgradeComponent({component: Ng2Component})); + // This module represents the AngularJS pieces of the application + const ng1Module = + angular + .module('myExample', []) + // This is an AngularJS component that will be upgraded + .directive( + 'ng1', + () => { + return { + scope: {title: '='}, + transclude: true, + template: 'ng1[Hello {{title}}!]()' + }; + }) + // This is wrapping (downgrading) an Angular component to be used in + // AngularJS + .directive('ng2', downgradeComponent({component: Ng2Component})); - // This is the (AngularJS) application bootstrap element - // Notice that it is actually a downgraded Angular component - const element = html('project'); + // This is the (AngularJS) application bootstrap element + // Notice that it is actually a downgraded Angular component + const element = html('project'); - // Let's use a helper function to make this simpler - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { - expect(multiTrim(element.textContent)) - .toBe('ng2[ng1[Hello World!](transclude)](project)'); - }); - })); + // Let's use a helper function to make this simpler + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(upgrade => { + expect(multiTrim(element.textContent)) + .toBe('ng2[ng1[Hello World!](transclude)](project)'); + }); + })); }); }); diff --git a/packages/upgrade/test/static/integration/upgrade_component_spec.ts b/packages/upgrade/test/static/integration/upgrade_component_spec.ts index 0f69b35ce8..998873ac74 100644 --- a/packages/upgrade/test/static/integration/upgrade_component_spec.ts +++ b/packages/upgrade/test/static/integration/upgrade_component_spec.ts @@ -10,7 +10,6 @@ import {Component, Directive, ElementRef, ErrorHandler, EventEmitter, Inject, In import {async, fakeAsync, tick} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {fixmeIvy} from '@angular/private/testing'; import {UpgradeComponent, UpgradeModule, downgradeComponent} from '@angular/upgrade/static'; import * as angular from '@angular/upgrade/static/src/common/angular1'; import {$EXCEPTION_HANDLER, $SCOPE} from '@angular/upgrade/static/src/common/constants'; @@ -2134,76 +2133,72 @@ withEachNg1Version(() => { }); describe('transclusion', () => { - fixmeIvy(`FW-863: Error: Failed to execute 'insertBefore' on 'Node'`) - .it('should support single-slot transclusion', async(() => { - let ng2ComponentAInstance: Ng2ComponentA; - let ng2ComponentBInstance: Ng2ComponentB; + it('should support single-slot transclusion', async(() => { + let ng2ComponentAInstance: Ng2ComponentA; + let ng2ComponentBInstance: Ng2ComponentB; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: 'ng1(
    )', - transclude: true - }; + // Define `ng1Component` + const ng1Component: + angular.IComponent = {template: 'ng1(
    )', transclude: true}; - // Define `Ng1ComponentFacade` - @Directive({selector: 'ng1'}) - class Ng1ComponentFacade extends UpgradeComponent { - constructor(elementRef: ElementRef, injector: Injector) { - super('ng1', elementRef, injector); - } - } + // Define `Ng1ComponentFacade` + @Directive({selector: 'ng1'}) + class Ng1ComponentFacade extends UpgradeComponent { + constructor(elementRef: ElementRef, injector: Injector) { + super('ng1', elementRef, injector); + } + } - // Define `Ng2Component` - @Component({ - selector: 'ng2A', - template: 'ng2A({{ value }} | )' - }) - class Ng2ComponentA { - value = 'foo'; - showB = false; - constructor() { ng2ComponentAInstance = this; } - } + // Define `Ng2Component` + @Component({ + selector: 'ng2A', + template: 'ng2A({{ value }} | )' + }) + class Ng2ComponentA { + value = 'foo'; + showB = false; + constructor() { ng2ComponentAInstance = this; } + } - @Component({selector: 'ng2B', template: 'ng2B({{ value }})'}) - class Ng2ComponentB { - value = 'bar'; - constructor() { ng2ComponentBInstance = this; } - } + @Component({selector: 'ng2B', template: 'ng2B({{ value }})'}) + class Ng2ComponentB { + value = 'bar'; + constructor() { ng2ComponentBInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2A', downgradeComponent({component: Ng2ComponentA})); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2A', downgradeComponent({component: Ng2ComponentA})); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule, UpgradeModule], - declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], - entryComponents: [Ng2ComponentA] - }) - class Ng2Module { - ngDoBootstrap() {} - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule, UpgradeModule], + declarations: [Ng1ComponentFacade, Ng2ComponentA, Ng2ComponentB], + entryComponents: [Ng2ComponentA] + }) + class Ng2Module { + ngDoBootstrap() {} + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { - expect(multiTrim(element.textContent)).toBe('ng2A(ng1(foo | ))'); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { + expect(multiTrim(element.textContent)).toBe('ng2A(ng1(foo | ))'); - ng2ComponentAInstance.value = 'baz'; - ng2ComponentAInstance.showB = true; - $digest(adapter); + ng2ComponentAInstance.value = 'baz'; + ng2ComponentAInstance.showB = true; + $digest(adapter); - expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(bar)))'); + expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(bar)))'); - ng2ComponentBInstance.value = 'qux'; - $digest(adapter); + ng2ComponentBInstance.value = 'qux'; + $digest(adapter); - expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(qux)))'); - }); - })); + expect(multiTrim(element.textContent)).toBe('ng2A(ng1(baz | ng2B(qux)))'); + }); + })); it('should support single-slot transclusion with fallback content', async(() => { let ng1ControllerInstances: any[] = []; @@ -2530,29 +2525,28 @@ withEachNg1Version(() => { }); })); - fixmeIvy(`FW-863: Error: Failed to execute 'insertBefore' on 'Node'`) - .it('should support structural directives in transcluded content', async(() => { - let ng2ComponentInstance: Ng2Component; + it('should support structural directives in transcluded content', async(() => { + let ng2ComponentInstance: Ng2Component; - // Define `ng1Component` - const ng1Component: angular.IComponent = { - template: - 'ng1(x(
    ) | default(
    ))', - transclude: {slotX: 'contentX'} - }; + // Define `ng1Component` + const ng1Component: angular.IComponent = { + template: + 'ng1(x(
    ) | default(
    ))', + transclude: {slotX: 'contentX'} + }; - // Define `Ng1ComponentFacade` - @Directive({selector: 'ng1'}) - class Ng1ComponentFacade extends UpgradeComponent { - constructor(elementRef: ElementRef, injector: Injector) { - super('ng1', elementRef, injector); - } - } + // Define `Ng1ComponentFacade` + @Directive({selector: 'ng1'}) + class Ng1ComponentFacade extends UpgradeComponent { + constructor(elementRef: ElementRef, injector: Injector) { + super('ng1', elementRef, injector); + } + } - // Define `Ng2Component` - @Component({ - selector: 'ng2', - template: ` + // Define `Ng2Component` + @Component({ + selector: 'ng2', + template: ` ng2(
    {{ x }}1
    @@ -2561,53 +2555,49 @@ withEachNg1Version(() => {
    {{ y }}2
    )` - }) - class Ng2Component { - x = 'foo'; - y = 'bar'; - show = true; - constructor() { ng2ComponentInstance = this; } - } + }) + class Ng2Component { + x = 'foo'; + y = 'bar'; + show = true; + constructor() { ng2ComponentInstance = this; } + } - // Define `ng1Module` - const ng1Module = - angular.module('ng1Module', []) - .component('ng1', ng1Component) - .directive('ng2', downgradeComponent({component: Ng2Component})); + // Define `ng1Module` + const ng1Module = angular.module('ng1Module', []) + .component('ng1', ng1Component) + .directive('ng2', downgradeComponent({component: Ng2Component})); - // Define `Ng2Module` - @NgModule({ - imports: [BrowserModule, UpgradeModule], - declarations: [Ng1ComponentFacade, Ng2Component], - entryComponents: [Ng2Component], - schemas: [NO_ERRORS_SCHEMA] - }) - class Ng2Module { - ngDoBootstrap() {} - } + // Define `Ng2Module` + @NgModule({ + imports: [BrowserModule, UpgradeModule], + declarations: [Ng1ComponentFacade, Ng2Component], + entryComponents: [Ng2Component], + schemas: [NO_ERRORS_SCHEMA] + }) + class Ng2Module { + ngDoBootstrap() {} + } - // Bootstrap - const element = html(``); + // Bootstrap + const element = html(``); - bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(foo1)|default(bar2)))'); + bootstrap(platformBrowserDynamic(), Ng2Module, element, ng1Module).then(adapter => { + expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(foo1)|default(bar2)))'); - ng2ComponentInstance.x = 'baz'; - ng2ComponentInstance.y = 'qux'; - ng2ComponentInstance.show = false; - $digest(adapter); + ng2ComponentInstance.x = 'baz'; + ng2ComponentInstance.y = 'qux'; + ng2ComponentInstance.show = false; + $digest(adapter); - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(baz2)|default(qux1)))'); + expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(baz2)|default(qux1)))'); - ng2ComponentInstance.show = true; - $digest(adapter); + ng2ComponentInstance.show = true; + $digest(adapter); - expect(multiTrim(element.textContent, true)) - .toBe('ng2(ng1(x(baz1)|default(qux2)))'); - }); - })); + expect(multiTrim(element.textContent, true)).toBe('ng2(ng1(x(baz1)|default(qux2)))'); + }); + })); }); describe('lifecycle hooks', () => { diff --git a/protractor-e2e.conf.js b/protractor-e2e.conf.js deleted file mode 100644 index 7afc6f56f2..0000000000 --- a/protractor-e2e.conf.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// Make sure that the command line is read as the first thing -// as this could exit node if the help script should be printed. -require('./dist/all/e2e_util/e2e_util').readCommandLine(); - -var BROWSER_OPTIONS = { - LocalChrome: { - 'browserName': 'chrome', - }, - ChromeOnTravis: { - browserName: 'chrome', - chromeOptions: { - 'args': ['--no-sandbox'], - 'binary': process.env.CHROME_BIN, - } - } -}; - -exports.config = { - onPrepare: function() { beforeEach(function() { browser.ignoreSynchronization = false; }); }, - allScriptsTimeout: 11000, - specs: ['dist/all/**/e2e_test/**/*_spec.js'], - exclude: [ - 'dist/all/@angular/examples/**', - '**/key_events/**', // can't tell why this is failing - '**/sourcemap/**' // fails only on travis - ], - capabilities: process.env.TRAVIS ? BROWSER_OPTIONS.ChromeOnTravis : BROWSER_OPTIONS.LocalChrome, - directConnect: true, - baseUrl: 'http://localhost:8000/', - framework: 'jasmine2', - jasmineNodeOpts: - {showColors: true, defaultTimeoutInterval: 60000, print: function(msg) { console.log(msg) }}, - useAllAngular2AppRoots: true, -}; diff --git a/protractor-examples-e2e.conf.js b/protractor-examples-e2e.conf.js deleted file mode 100644 index 1259ffab36..0000000000 --- a/protractor-examples-e2e.conf.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// Make sure that the command line is read as the first thing -// as this could exit node if the help script should be printed. -require('./dist/all/e2e_util/e2e_util').readCommandLine(); -require('reflect-metadata'); - -Error.stackTraceLimit = 9999; - -var BROWSER_OPTIONS = { - LocalChrome: {'browserName': 'chrome'}, - ChromeOnTravis: { - browserName: 'chrome', - chromeOptions: { - 'args': ['--no-sandbox'], - 'binary': process.env.CHROME_BIN, - } - }, -}; - -exports.config = { - onPrepare: function() { beforeEach(function() { browser.ignoreSynchronization = false; }); }, - allScriptsTimeout: 11000, - specs: ['dist/examples/**/e2e_test/*_spec.js'], - capabilities: process.env.TRAVIS ? BROWSER_OPTIONS.ChromeOnTravis : BROWSER_OPTIONS.LocalChrome, - directConnect: true, - baseUrl: 'http://localhost:8001/', - framework: 'jasmine2', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 60000, - print: function(msg) { console.log(msg); }, - }, - useAllAngular2AppRoots: true -}; diff --git a/protractor-perf.conf.js b/protractor-perf.conf.js index ddfdc79c4a..2839079890 100644 --- a/protractor-perf.conf.js +++ b/protractor-perf.conf.js @@ -6,18 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -// Determine if we run under bazel -const isBazel = !!process.env.RUNFILES; -// isBazel needed while 'scripts/ci/test-e2e.sh test.e2e.protractor-e2e' is run -// on Travis -// TODO: port remaining protractor e2e tests to bazel protractor_web_test_suite rule - // Make sure that the command line is read as the first thing // as this could exit node if the help script should be printed. -const BASE = isBazel ? 'angular/modules' : 'dist/all'; -require(`./${BASE}/e2e_util/perf_util`).readCommandLine(); +require('angular/modules/e2e_util/perf_util').readCommandLine(); -var CHROME_OPTIONS = { +const CHROME_OPTIONS = { 'args': ['--js-flags=--expose-gc', '--no-sandbox', '--headless', '--disable-dev-shm-usage'], 'perfLoggingPrefs': { 'traceCategories': @@ -25,8 +18,11 @@ var CHROME_OPTIONS = { } }; -var BROWSER_CAPS = { - LocalChrome: { +exports.config = { + onPrepare: function() { beforeEach(function() { browser.ignoreSynchronization = false; }); }, + restartBrowserBetweenTests: true, + allScriptsTimeout: 11000, + capabilities: { 'browserName': 'chrome', chromeOptions: CHROME_OPTIONS, loggingPrefs: { @@ -34,30 +30,6 @@ var BROWSER_CAPS = { browser: 'ALL', } }, - ChromeOnTravis: { - browserName: 'chrome', - chromeOptions: mergeInto(CHROME_OPTIONS, { - 'binary': process.env.CHROME_BIN, - }), - loggingPrefs: { - performance: 'ALL', - browser: 'ALL', - } - } -}; - -function mergeInto(src, target) { - for (var prop in src) { - target[prop] = src[prop]; - } - return target; -} - -const config = { - onPrepare: function() { beforeEach(function() { browser.ignoreSynchronization = false; }); }, - restartBrowserBetweenTests: true, - allScriptsTimeout: 11000, - capabilities: process.env.TRAVIS ? BROWSER_CAPS.ChromeOnTravis : BROWSER_CAPS.LocalChrome, directConnect: true, framework: 'jasmine2', jasmineNodeOpts: { @@ -67,14 +39,3 @@ const config = { }, useAllAngular2AppRoots: true }; - -// Bazel has different strategy for how specs and baseUrl are specified -if (!isBazel) { - config.baseUrl = 'http://localhost:8000/'; - config.specs = [ - 'dist/all/**/e2e_test/**/*_perf.spec.js', - 'dist/all/**/e2e_test/**/*_perf.js', - ] -} - -exports.config = config; diff --git a/scripts/build-ivy-npm-packages.sh b/scripts/build-ivy-npm-packages.sh new file mode 100755 index 0000000000..823bd6ca1f --- /dev/null +++ b/scripts/build-ivy-npm-packages.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +source ./scripts/package-builder.sh + +# Build the ivy packages +buildTargetPackages "dist/packages-dist-ivy-aot" "aot" "Ivy AOT" diff --git a/scripts/build-packages-dist.sh b/scripts/build-packages-dist.sh index 89ecc1b946..76f989ef5a 100755 --- a/scripts/build-packages-dist.sh +++ b/scripts/build-packages-dist.sh @@ -1,69 +1,6 @@ #!/usr/bin/env bash -# Build the dist/packages-dist directory in the same fashion as the legacy -# /build.sh script, by building the npm packages with Bazel and copying files. -# This is needed for scripts and tests which are not updated to the Bazel output -# layout (which always matches the input layout). -# Do not add new dependencies on this script, instead adapt scripts to use the -# new layout, and write new tests as Bazel targets. -set -u -e -o pipefail +source ./scripts/package-builder.sh -cd "$(dirname "$0")" - -# basedir is the workspace root -readonly basedir=$(pwd)/.. -# We need to resolve the Bazel binary in the node modules because running Bazel -# through `yarn bazel` causes additional output that throws off command stdout. -readonly bazelBin=$(yarn bin)/bazel -readonly bin=$(${bazelBin} info bazel-bin) - -function buildTargetPackages() { - targets="$1" - destPath="$2" - compileMode="$3" - desc="$4" - - echo "##################################" - echo "scripts/build-packages-dist.sh:" - echo " building @angular/* npm packages" - echo " mode: ${desc}" - echo "##################################" - - # Use --config=release so that snapshot builds get published with embedded version info - echo "$targets" | xargs ${bazelBin} build --config=release --define=compile=$compileMode - - [ -d "${basedir}/${destPath}" ] || mkdir -p $basedir/${destPath} - - dirs=`echo "$targets" | sed -e 's/\/\/packages\/\(.*\):npm_package/\1/'` - - for pkg in $dirs; do - # Skip any that don't have an "npm_package" target - srcDir="${bin}/packages/${pkg}/npm_package" - destDir="${basedir}/${destPath}/${pkg}" - if [ -d $srcDir ]; then - echo "# Copy artifacts to ${destDir}" - rm -rf $destDir - cp -R $srcDir $destDir - chmod -R u+w $destDir - fi - done -} - -# Ideally these integration tests should run under bazel, and just list the npm -# packages in their deps[]. -# Until then, we have to manually run bazel first to create the npm packages we -# want to test. -BAZEL_TARGETS=`${bazelBin} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind(".*_package", //packages/...)'` -buildTargetPackages "$BAZEL_TARGETS" "dist/packages-dist" "legacy" "Production" - -# We don't use the ivy build in the integration tests, only when publishing -# snapshots. -# This logic matches what we use in the .circleci/config.yml file to short- -# circuit execution of the publish-packages job. -[[ "${CI_PULL_REQUEST-}" != "false" - || "${CI_REPO_OWNER-}" != "angular" - || "${CI_REPO_NAME-}" != "angular" - || "${CI_BRANCH}" != "master" -]] && exit 0 - -buildTargetPackages "$BAZEL_TARGETS" "dist/packages-dist-ivy-aot" "aot" "Ivy AOT" +# Build the legacy (view engine) npm packages into dist/packages-dist +buildTargetPackages "dist/packages-dist" "legacy" "Production" diff --git a/scripts/ci/_travis-fold.sh b/scripts/ci/_travis-fold.sh deleted file mode 100644 index b3dd69c725..0000000000 --- a/scripts/ci/_travis-fold.sh +++ /dev/null @@ -1,83 +0,0 @@ -# private variable to track folds within this script -travisFoldStack=() - -function travisFoldStart() { - local foldName="${0#./} ${1}" - # get current time as nanoseconds since the beginning of the epoch - foldStartTime=$(date +%s%N) - # convert all non alphanum chars except for "-" and "." to "--" - local sanitizedFoldName=${foldName//[^[:alnum:]\-\.]/--} - # strip trailing "-" - sanitizedFoldName=${sanitizedFoldName%-} - # push the foldName onto the stack - travisFoldStack+=("${sanitizedFoldName}|${foldStartTime}") - - echo "" - if [[ ${TRAVIS:-} ]]; then - echo "travis_fold:start:${sanitizedFoldName}" - echo "travis_time:start:${sanitizedFoldName}" - fi - local enterArrow="===> ${foldName} ==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>==>" - # keep all messages consistently wide 80chars regardless of the foldName - echo ${enterArrow:0:100} - if [[ ${2:-} != "no-xtrace" ]]; then - # turn on verbose mode so that we have better visibility into what's going on - # http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_03.html#table_02_01 - set -x - fi -} - -function travisFoldEnd() { - set +x - local foldName="${0#./} ${1}" - # convert all non alphanum chars except for "-" and "." to "--" - local sanitizedFoldName=${foldName//[^[:alnum:]\-\.]/--} - # strip trailing "-" - sanitizedFoldName=${sanitizedFoldName%-} - - # consult and update travisFoldStack - local lastFoldIndex=$(expr ${#travisFoldStack[@]} - 1) - local lastFoldString=${travisFoldStack[$lastFoldIndex]} - # split the string by | and then turn that into an array - local lastFoldArray=(${lastFoldString//\|/ }) - local lastSanitizedFoldName=${lastFoldArray[0]} - - if [[ ${TRAVIS:-} ]]; then - local lastFoldStartTime=${lastFoldArray[1]} - local foldFinishTime=$(date +%s%N) - local foldDuration=$(expr ${foldFinishTime} - ${lastFoldStartTime}) - - # write into build-perf.log file - local logIndent=$(expr ${lastFoldIndex} \* 2) - printf "%6ss%${logIndent}s: %s\n" $(expr ${foldDuration} / 1000000000) " " "${foldName}" >> ${LOGS_DIR}/build-perf.log - fi - - # pop - travisFoldStack=(${travisFoldStack[@]:0:lastFoldIndex}) - - # check for misalignment - if [[ ${lastSanitizedFoldName} != ${sanitizedFoldName} ]]; then - echo "Travis fold mis-alignment detected! travisFoldEnd expected sanitized fold name '${lastSanitizedFoldName}', but received '${sanitizedFoldName}' (after sanitization)" - exit 1 - fi - - local returnArrow="<=== ${foldName} <==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==" - # keep all messages consistently wide 80chars regardless of the foldName - echo ${returnArrow:0:100} - echo "" - if [[ ${TRAVIS:-} ]]; then - echo "travis_time:end:${sanitizedFoldName}:start=${lastFoldStartTime},finish=${foldFinishTime},duration=${foldDuration}" - echo "travis_fold:end:${sanitizedFoldName}" - fi -} - - -function travisFoldReturnArrows() { - # print out return arrows so that it's easy to see the end of the script in the log - echo "" - returnArrow="<=== ${0#./} <==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==" - # keep all messages consistently wide 80chars regardless of the foldName - echo ${returnArrow:0:100} - echo "<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<==<===" - echo "" -} diff --git a/scripts/ci/angular.sh b/scripts/ci/angular.sh deleted file mode 100755 index ec28c34232..0000000000 --- a/scripts/ci/angular.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# If the previous commands in the `script` section of .travis.yaml failed, then abort. -# The variable is not set in early stages of the build, so we default to 0 there. -# https://docs.travis-ci.com/user/environment-variables/ -if [[ ${TRAVIS_TEST_RESULT=0} == 1 ]]; then - exit 1; -fi - - -# this ascii art was created based on the official Angular logo from https://angular.io/presskit.html -# converted using http://www.text-image.com/convert/ -# colors added based on http://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux -RED='\033[0;31m' -LRED='\033[1;31m' -WHITE='\033[1;37m' - - -echo -e ${LRED}' ``'${RED}'`` ' -echo -e ${LRED}' `.--://'${RED}':::--.`' -echo -e ${LRED}' `..-:////////'${RED}':::::::::-.``' -echo -e ${LRED}' `.-::////////////'${WHITE}'oo'${RED}'::::::::::::::-.`' -echo -e ${LRED}' `--://///////////////'${WHITE}'+NN+'${RED}'::::::::::::::::::-.`' -echo -e ${LRED}' `///////////////////'${WHITE}'+NMMN/'${RED}':::::::::::::::::::`' -echo -e ${LRED}' ///////////////////'${WHITE}'mMMMMm/'${RED}'::::::::::::::::::' -echo -e ${LRED}' ://///////////////'${WHITE}'dMMMMMMd/'${RED}':::::::::::::::::' -echo -e ${LRED}' -////////////////'${WHITE}'dMMMNNMMMh/'${RED}':::::::::::::::-' -echo -e ${LRED}' .///////////////'${WHITE}'hMMMM++MMMMh'${RED}':::::::::::::::.' -echo -e ${LRED}' `//////////////'${WHITE}'yMMMMs'${LRED}'/'${RED}':'${WHITE}'sMMMMy'${RED}'::::::::::::::`' -echo -e ${LRED}' :////////////'${WHITE}'sMMMMy'${LRED}'//'${RED}'::'${WHITE}'yMMMMs'${RED}':::::::::::::' -echo -e ${LRED}' -///////////'${WHITE}'oMMMMd'${LRED}'///'${RED}'::'${WHITE}'/dMMMMo'${RED}':::::::::::-' -echo -e ${LRED}' .//////////'${WHITE}'+NMMMMddddddddMMMMN+'${RED}'::::::::::.' -echo -e ${LRED}' `/////////'${WHITE}'+NMMMMMMMMMMMMMMMMMMN+'${RED}':::::::::`' -echo -e ${LRED}' :////////'${WHITE}'mMMMMyyyyyyyyyyyyMMMMm/'${RED}'::::::::' -echo -e ${LRED}' -///////'${WHITE}'mMMMMs'${LRED}'//////'${RED}'::::::'${WHITE}'sMMMMm/'${RED}'::::::-' -echo -e ${LRED}' .//////'${WHITE}'dMMMMy'${LRED}'///////'${RED}':::::::'${WHITE}'yMMMMd/'${RED}':::::.' -echo -e ${LRED}' `/////'${WHITE}'hMMMMd'${LRED}'////////'${RED}':::::::'${WHITE}'/dMMMMh'${RED}':::::`' -echo -e ${LRED}' -://///////////////'${RED}'::::::::::::::::::-' -echo -e ${LRED}' `.://////////////'${RED}'::::::::::::::-.`' -echo -e ${LRED}' `-://////////'${RED}':::::::::::-`' -echo -e ${LRED}' `.-://////'${RED}':::::::-.`' -echo -e ${LRED}' `.:///'${RED}'::::.`' -echo -e ${LRED}' .-'${RED}'-` ' - diff --git a/scripts/ci/build.sh b/scripts/ci/build.sh deleted file mode 100755 index 5e59873204..0000000000 --- a/scripts/ci/build.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -# If the previous commands in the `script` section of .travis.yaml failed, then abort. -# The variable is not set in early stages of the build, so we default to 0 there. -# https://docs.travis-ci.com/user/environment-variables/ -if [[ ${TRAVIS_TEST_RESULT=0} == 1 ]]; then - exit 1; -fi - -# No build needed for bazel or aio docs tests -if [[ ${CI_MODE:-} == "bazel" ]]; then - exit 0; -fi - -travisFoldStart "tsc tools" - $(npm bin)/tsc -p tools - $(npm bin)/tsc -p packages/compiler/tsconfig-tools.json - $(npm bin)/tsc -p packages/compiler-cli/tsconfig-tools.json -travisFoldEnd "tsc tools" - - -travisFoldStart "tsc all" - node dist/tools/@angular/compiler-cli/src/main -p packages/tsconfig-metadata.json - $(npm bin)/tsc -p packages - $(npm bin)/tsc -p packages/examples - $(npm bin)/tsc -p modules -travisFoldEnd "tsc all" diff --git a/scripts/ci/cleanup.sh b/scripts/ci/cleanup.sh deleted file mode 100755 index 7b1046d7c9..0000000000 --- a/scripts/ci/cleanup.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -case ${CI_MODE} in - js) - ;; - saucelabs_required) - travisFoldStart "teardown.sauceConnect" - ./scripts/sauce/sauce_connect_teardown.sh - travisFoldEnd "teardown.sauceConnect" - ;; - browserstack_required) - travisFoldStart "teardown.browserStack" - ./scripts/browserstack/teardown_tunnel.sh - travisFoldEnd "teardown.browserStack" - ;; - saucelabs_optional) - travisFoldStart "teardown.sauceConnect" - ./scripts/sauce/sauce_connect_teardown.sh - travisFoldEnd "teardown.sauceConnect" - ;; - browserstack_optional) - travisFoldStart "teardown.browserStack" - ./scripts/browserstack/teardown_tunnel.sh - travisFoldEnd "teardown.browserStack" - ;; -esac - -# Print return arrows as a log separator -travisFoldReturnArrows diff --git a/scripts/ci/env.sh b/scripts/ci/env.sh deleted file mode 100755 index 78adcf8c5a..0000000000 --- a/scripts/ci/env.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env bash - -# because this script is being source-ed via .travis.yaml, -# we need to restore the original options so that that we don't interfere with -# travis' internals -readonly ORIGINAL_SHELL_OPTIONS=$(set +o) - -# this script is extra noisy and used in many places during the build so we suppress the trace with +x to reduce the noise -set -u -e -o pipefail - -# sets and optionally prints environmental variable -# usage: setEnvVar variableName variableValue -function setEnvVar() { - local name=$1 - local value=$2 - - if [[ ${print} == "print" ]]; then - echo ${name}=${value} - fi - export ${name}="${value}" -} - -# use BASH_SOURCE so that we get the right path when this script is called AND source-d -readonly thisDir=$(cd $(dirname ${BASH_SOURCE[0]}); pwd) -readonly print=${1:-} - -# print bash version just so that we know what is running all the scripts -if [[ ${print} == "print" ]]; then - bash --version -fi - - -####################### -# CUSTOM GLOBALS # -####################### - -setEnvVar NODE_VERSION 10.9.0 -setEnvVar YARN_VERSION 1.12.1 -setEnvVar CHROMIUM_VERSION 561733 # Chrome 68 linux stable, see https://www.chromium.org/developers/calendar -setEnvVar CHROMEDRIVER_VERSION_ARG "--versions.chrome 2.41" -setEnvVar SAUCE_CONNECT_VERSION 4.5.2 -setEnvVar ANGULAR_CLI_VERSION 1.6.3 -setEnvVar CI_AIO_MIN_PWA_SCORE 95 -setEnvVar CI_BRANCH $TRAVIS_BRANCH -setEnvVar CI_COMMIT $TRAVIS_COMMIT -setEnvVar CI_COMMIT_RANGE $TRAVIS_COMMIT_RANGE -setEnvVar CI_PULL_REQUEST $TRAVIS_PULL_REQUEST -setEnvVar PROJECT_ROOT $(cd ${thisDir}/../..; pwd) - -if [[ ${TRAVIS:-} ]]; then - case ${CI_MODE} in - js) - setEnvVar KARMA_JS_BROWSERS ChromeNoSandbox - ;; - saucelabs_required) - setEnvVar KARMA_JS_BROWSERS `node -e "console.log(require('/home/travis/build/angular/angular/browser-providers.conf').sauceAliases.CI_REQUIRED.join(','))"` - ;; - browserstack_required) - setEnvVar KARMA_JS_BROWSERS `node -e "console.log(require('/home/travis/build/angular/angular/browser-providers.conf').browserstackAliases.CI_REQUIRED.join(','))"` - ;; - saucelabs_optional) - setEnvVar KARMA_JS_BROWSERS `node -e "console.log(require('/home/travis/build/angular/angular/browser-providers.conf').sauceAliases.CI_OPTIONAL.join(','))"` - ;; - browserstack_optional) - setEnvVar KARMA_JS_BROWSERS `node -e "console.log(require('/home/travis/build/angular/angular/browser-providers.conf').browserstackAliases.CI_OPTIONAL.join(','))"` - ;; - esac -else - setEnvVar KARMA_JS_BROWSERS Chrome -fi - - -if [[ ${TRAVIS:-} ]]; then - # used by xvfb that is used by Chromium - setEnvVar DISPLAY :99.0 - - # Use newer version of GCC to that is required to compile native npm modules for Node v4+ on Ubuntu Precise - # more info: https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements - setEnvVar CXX g++-4.8 - - # Used by karma and karma-chrome-launcher - # In order to have a meaningful SauceLabs badge on the repo page, - # the angular2-ci account is used only when pushing commits to master; - # in all other cases, the regular angular-ci account is used. - if [ "${CI_PULL_REQUEST}" = "false" ] && [ "${CI_BRANCH}" = "master" ]; then - setEnvVar SAUCE_USERNAME angular2-ci - # Not using use `setEnvVar` so that we don't print the key. - export SAUCE_ACCESS_KEY=693ebc16208a-0b5b-1614-8d66-a2662f4e - else - setEnvVar SAUCE_USERNAME angular-ci - # Not using use `setEnvVar` so that we don't print the key. - export SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987 - fi - - setEnvVar BROWSER_STACK_USERNAME angularteam1 - # not using use setEnvVar so that we don't print the key - export BROWSER_STACK_ACCESS_KEY=CaXMeMHD9pr5PHg8N7Jq - setEnvVar CHROME_BIN ${HOME}/.chrome/chromium/chrome-linux/chrome - setEnvVar BROWSER_PROVIDER_READY_FILE /tmp/angular-build/browser-provider-tunnel-init.lock -fi - - - -####################### -# PREEXISTING GLOBALS # -####################### - -# Prepend `~/.yarn/bin` to the PATH -setEnvVar PATH $HOME/.yarn/bin:$PATH - -# Append dist/all to the NODE_PATH so that cjs module resolver finds find the packages that use -# absolute module ids (e.g. @angular/core) -setEnvVar NODE_PATH ${NODE_PATH:-}:${PROJECT_ROOT}/dist/all:${PROJECT_ROOT}/dist/tools -setEnvVar LOGS_DIR /tmp/angular-build/logs - -# strip leading "/home/travis/build/angular/angular/" or "./" path. Could this be done in one shot? -CURRENT_SHELL_SOURCE_FILE=${BASH_SOURCE#${PROJECT_ROOT}/} -export CURRENT_SHELL_SOURCE_FILE=${CURRENT_SHELL_SOURCE_FILE#./} -# Prefix xtrace output with file name/line and optionally function name -# http://wiki.bash-hackers.org/scripting/debuggingtips#making_xtrace_more_useful -# TODO(i): I couldn't figure out how to set this via `setEnvVar` so I just set it manually -export PS4='+(${CURRENT_SHELL_SOURCE_FILE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' -if [[ ${print} == "print" ]]; then - echo PS4=${PS4} -fi - -eval "${ORIGINAL_SHELL_OPTIONS}" diff --git a/scripts/ci/install-chromium.sh b/scripts/ci/install-chromium.sh deleted file mode 100755 index 627d915694..0000000000 --- a/scripts/ci/install-chromium.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -# This script basically follows the instructions to download an old version of Chromium: https://www.chromium.org/getting-involved/download-chromium -# 1) It retrieves the current stable version number from https://www.chromium.org/developers/calendar (via the https://omahaproxy.appspot.com/all file), e.g. 359700 for Chromium 48. -# 2) It checks the Travis cache for this specific version -# 3) If not available, it downloads and caches it, using the "decrement commit number" trick. - -#Build version read from the OmahaProxy CSV Viewer at https://www.chromium.org/developers/calendar -#Let's use the following version of Chromium, and inform about availability of newer build from https://omahaproxy.appspot.com/all -# -# CHROMIUM_VERSION <<< this variable is now set via env.sh - -PLATFORM="$(uname -s)" -case "$PLATFORM" in - (Darwin) - ARCHITECTURE=Mac - DIST_FILE=chrome-mac.zip - ;; - (Linux) - ARCHITECTURE=Linux_x64 - DIST_FILE=chrome-linux.zip - ;; - (*) - echo Unsupported platform $PLATFORM. Exiting ... >&2 - exit 3 - ;; -esac - -TMP=$(curl -s "https://omahaproxy.appspot.com/all") || true -oldIFS="$IFS" -IFS=' -' -IFS=${IFS:0:1} -lines=( $TMP ) -IFS=',' -for line in "${lines[@]}" - do - lineArray=($line); - if [ "${lineArray[0]}" = "linux" ] && [ "${lineArray[1]}" = "stable" ] ; then - LATEST_CHROMIUM_VERSION="${lineArray[7]}" - fi -done -IFS="$oldIFS" - -CHROMIUM_DIR=$HOME/.chrome/chromium -CHROMIUM_BIN=$CHROMIUM_DIR/chrome-linux/chrome -CHROMIUM_VERSION_FILE=$CHROMIUM_DIR/VERSION - -EXISTING_VERSION="" -if [[ -f $CHROMIUM_VERSION_FILE && -x $CHROMIUM_BIN ]]; then - EXISTING_VERSION=`cat $CHROMIUM_VERSION_FILE` - echo Found cached Chromium version: ${EXISTING_VERSION} -fi - -if [[ "$EXISTING_VERSION" != "$CHROMIUM_VERSION" ]]; then - echo Downloading Chromium version: ${CHROMIUM_VERSION} - rm -fR $CHROMIUM_DIR - mkdir -p $CHROMIUM_DIR - - NEXT=$CHROMIUM_VERSION - FILE="chrome-linux.zip" - STATUS=404 - while [[ $STATUS == 404 && $NEXT -ge 0 ]] - do - echo Fetch Chromium version: ${NEXT} - STATUS=$(curl "https://storage.googleapis.com/chromium-browser-snapshots/${ARCHITECTURE}/${NEXT}/${DIST_FILE}" -s -w %{http_code} --create-dirs -o $FILE) || true - NEXT=$[$NEXT-1] - done - - unzip $FILE -d $CHROMIUM_DIR - rm $FILE - echo $CHROMIUM_VERSION > $CHROMIUM_VERSION_FILE -fi - -if [[ "$CHROMIUM_VERSION" != "$LATEST_CHROMIUM_VERSION" ]]; then - echo "New version of Chromium available. Update 'scripts/ci/env.sh' with build number: $LATEST_CHROMIUM_VERSION" -fi diff --git a/scripts/ci/install.sh b/scripts/ci/install.sh deleted file mode 100755 index ce5b9171b6..0000000000 --- a/scripts/ci/install.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -TRAVIS=${TRAVIS:-} -CI_MODE=${CI_MODE:-} - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -# If the previous commands in the `script` section of .travis.yaml failed, then abort. -# The variable is not set in early stages of the build, so we default to 0 there. -# https://docs.travis-ci.com/user/environment-variables/ -if [[ ${TRAVIS_TEST_RESULT=0} == 1 ]]; then - exit 1; -fi - - -mkdir -p ${LOGS_DIR} - - -# TODO: install nvm?? it's already on travis so we don't need it -#curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash - - -# Install node -#nvm install ${NODE_VERSION} - - -# Install version of yarn that we are locked against -travisFoldStart "install-yarn" - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version "${YARN_VERSION}" -travisFoldEnd "install-yarn" - - -# Install all npm dependencies according to yarn.lock -travisFoldStart "yarn-install" - (node tools/npm/check-node-modules --purge && yarn postinstall) || yarn install --frozen-lockfile --non-interactive -travisFoldEnd "yarn-install" - - -# Install bower packages -travisFoldStart "bower-install" - $(npm bin)/bower install -travisFoldEnd "bower-install" - - -# Install Chromium -if [[ ${TRAVIS} && - ${CI_MODE} == "js" || - ${CI_MODE} == "e2e" || - ${CI_MODE} == "e2e_2" -]]; then - travisFoldStart "install-chromium" - ( - ${thisDir}/install-chromium.sh - - # Start xvfb for local Chrome used for testing - if [[ ${TRAVIS} ]]; then - travisFoldStart "install-chromium.xvfb-start" - sh -e /etc/init.d/xvfb start - travisFoldEnd "install-chromium.xvfb-start" - fi - ) - travisFoldEnd "install-chromium" -fi - - -# Install Sauce Connect -if [[ ${TRAVIS}] && (${CI_MODE} == "saucelabs_required" || ${CI_MODE} == "saucelabs_optional") ]]; then - travisFoldStart "install-sauceConnect" - ( - ${thisDir}/../sauce/sauce_connect_setup.sh - ) - travisFoldEnd "install-sauceConnect" -fi - - -# Install BrowserStack Tunnel -if [[ ${TRAVIS} && (${CI_MODE} == "browserstack_required" || ${CI_MODE} == "browserstack_optional") ]]; then - travisFoldStart "install-browserstack" - ( - ${thisDir}/../browserstack/start_tunnel.sh - ) - travisFoldEnd "install-browserstack" -fi - -# Print return arrows as a log separator -travisFoldReturnArrows diff --git a/scripts/ci/offline_compiler_test.sh b/scripts/ci/offline_compiler_test.sh deleted file mode 100755 index f44acfadbb..0000000000 --- a/scripts/ci/offline_compiler_test.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# npm 5 symlinks from local file installations rather than copying files, but -# webpack will not follow the symlinks. -# We prefer to emulate how a user will install angular, so we `npm pack` the -# packages, then install them from the resulting .tgz files later. -ANGULAR_PKGS=$(npm pack dist/packages-dist/{common,forms,core,compiler,compiler-cli,platform-{browser,server},platform-browser-dynamic,router,http,animations} | awk "{ printf \"$PWD/\"; print }") - - -PKGS=( - $PWD/node_modules/typescript - $PWD/node_modules/reflect-metadata - $PWD/node_modules/rxjs - $PWD/node_modules/zone.js - @types/{node@6.0.38,jasmine@2.2.33} - jasmine@2.4.1 - webpack@2.1.0-beta.21 - source-map-loader@0.2.0 - @angular/{material,cdk}@2.0.0-beta.10 -) - -TMPDIR=${TMPDIR:-.} -readonly TMP=$TMPDIR/e2e_test.$(date +%s) -mkdir -p $TMP -cp -R -v packages/compiler-cli/integrationtest/* $TMP -cp -R -v modules/benchmarks $TMP -# Try to use the same versions as angular, in particular, this will -# cause us to install the same rxjs version. -cp -v package.json $TMP - -# run in subshell to avoid polluting cwd -( - cd $TMP - set -ex -o pipefail - npm install ${PKGS[*]} - npm install ${ANGULAR_PKGS[*]} - - ./node_modules/.bin/tsc --version - # Compile the compiler-cli third_party simulation. - # Use ngc-wrapped directly so we don't produce *.ngfactory.ts files! - - # Compile the compiler-cli integration tests - # TODO(vicb): restore the test for .xtb - #./node_modules/.bin/ngc -p tsconfig-build.json --i18nFile=src/messages.fi.xtb --locale=fi --i18nFormat=xtb - - # Generate the metadata for the third-party modules - ./node_modules/.bin/ngc -p third_party_src/tsconfig-build.json - - # Generate the the bundle modules - ./node_modules/.bin/ngc -p flat_module/tsconfig-build.json - - # Copy the html files from source to the emitted output - cp flat_module/src/*.html node_modules/flat_module/src - - ./node_modules/.bin/ngc -p tsconfig-build.json --i18nFile=src/messages.fi.xlf --locale=fi --i18nFormat=xlf - - ./node_modules/.bin/ng-xi18n -p tsconfig-xi18n.json --i18nFormat=xlf --locale=fr - ./node_modules/.bin/ng-xi18n -p tsconfig-xi18n.json --i18nFormat=xlf2 --outFile=messages.xliff2.xlf - ./node_modules/.bin/ng-xi18n -p tsconfig-xi18n.json --i18nFormat=xmb --outFile=custom_file.xmb - - node test/test_ngtools_api.js - - ./node_modules/.bin/jasmine init - # Run compiler-cli integration tests in node - ./node_modules/.bin/webpack ./webpack.config.js - ./node_modules/.bin/jasmine ./all_spec.js - - # Compile again with a differently named tsconfig file - mv tsconfig-build.json othername.json - ./node_modules/.bin/ngc -p othername.json -) diff --git a/scripts/ci/payload-size.sh b/scripts/ci/payload-size.sh index 350407533b..e29f49b737 100644 --- a/scripts/ci/payload-size.sh +++ b/scripts/ci/payload-size.sh @@ -51,7 +51,7 @@ addTimestamp() { payloadData="$payloadData\"timestamp\": $timestamp, " } -# Write travis commit message to global variable `$payloadData`. +# Write the commit message for the current CI commit range to global variable `$payloadData`. # $1: string - The commit range for this build (in `...` format). addMessage() { commitRange="$1" diff --git a/scripts/ci/print-logs.sh b/scripts/ci/print-logs.sh deleted file mode 100755 index 37cbf74e34..0000000000 --- a/scripts/ci/print-logs.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -for FILE in ${LOGS_DIR}/*; do - travisFoldStart "print log file: ${FILE}" - cat $FILE - travisFoldEnd "print log file: ${FILE}" -done - - -# Print return arrows as a log separator -travisFoldReturnArrows diff --git a/scripts/ci/run_angular_material_unit_tests.sh b/scripts/ci/run_angular_material_unit_tests.sh new file mode 100755 index 0000000000..e22d15e32d --- /dev/null +++ b/scripts/ci/run_angular_material_unit_tests.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -u -e -o pipefail + + +# This script runs unit tests from angular/material2. + +# Save the dir for the root of the Angular repo. +angular_dir=$(pwd) + +# Clone the angular/material2 repo into tmp so we can run the tests from there. +# We specifically use /tmp here because we want the cloned repo to be completely +# isolated from angular/angular in order to avoid any bad interactions between their +# separate build setups. Also note that this is using the ivy-2019 branch, which has +# previously been set up to work with ivy. +cd /tmp +rm -rf /tmp/material2 +git clone --depth 1 --branch ivy-2019 https://github.com/angular/material2.git + +# Install dependencies for the freshly cloned repo. +cd /tmp/material2 +yarn install --frozen-lockfile --non-interactive # TODO: cache + +# Install this version of Angular into the freshly cloned repo. +rm -rf /tmp/material2/node_modules/@angular/* +cp -r ${angular_dir}/dist/packages-dist-ivy-aot/* /tmp/material2/node_modules/@angular/ + +# The angular/material2 CI sets TEST_PLATFORM to either local, saucelabs, or browserstack. +# For angular/angular, we only want to run the local tests. +export TEST_PLATFORM=local + +# Append the test blocklist into angular/material2's karma-test-shim.js. +# This filters out known-failing tests because the goal is to prevent regressions. +cat ${angular_dir}/tools/material-ci/angular_material_test_blocklist.js >> /tmp/material2/test/karma-test-shim.js + +# Now actually run the tests. +yarn gulp test:single-run diff --git a/scripts/ci/test-browserstack.sh b/scripts/ci/test-browserstack.sh deleted file mode 100755 index 008813917e..0000000000 --- a/scripts/ci/test-browserstack.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -travisFoldStart "test.unit.browserstack" - ./scripts/browserstack/waitfor_tunnel.sh - export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev` - $(npm bin)/karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS} -travisFoldEnd "test.unit.browserstack" diff --git a/scripts/ci/test-e2e.sh b/scripts/ci/test-e2e.sh deleted file mode 100755 index bc18b729f6..0000000000 --- a/scripts/ci/test-e2e.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -travisFoldStart "test.e2e.buildPackages" - ./build.sh -travisFoldEnd "test.e2e.buildPackages" - -travisFoldStart "test.e2e.check-cycle" - $(npm bin)/gulp check-cycle -travisFoldEnd "test.e2e.check-cycle" - -# Serve files for e2e tests -( - $(npm bin)/gulp serve & - $(npm bin)/gulp serve-examples & -) - -travisFoldStart "test.e2e.protractor-e2e" - NODE_PATH=$NODE_PATH:./dist/all $(npm bin)/protractor ./protractor-e2e.conf.js --bundles=true -travisFoldEnd "test.e2e.protractor-e2e" -travisFoldStart "test.e2e.protractor-examples-e2e" - NODE_PATH=$NODE_PATH:./dist/all $(npm bin)/protractor ./protractor-examples-e2e.conf.js --bundles=true -travisFoldEnd "test.e2e.protractor-examples-e2e" -travisFoldStart "test.e2e.protractor-perf" - NODE_PATH=$NODE_PATH:./dist/all $(npm bin)/protractor ./protractor-perf.conf.js --bundles=true --dryrun -travisFoldEnd "test.e2e.protractor-perf" - -# TODO(i): temporarily disable this test because we don't have rxjs backwards compatibility package -# and cdk+material are not yet compatible with rxjs v6 -# uncomment when we have cdk and material releases compatible with rxjs v6 -#travisFoldStart "test.e2e.offlineCompiler" -# #TODO(alexeagle): move offline_compiler_test to integration/ -# ${thisDir}/offline_compiler_test.sh -#travisFoldEnd "test.e2e.offlineCompiler" - -travisFoldStart "test.e2e.source-maps" - ./node_modules/.bin/gulp source-map-test -travisFoldEnd "test.e2e.source-maps" diff --git a/scripts/ci/test-js.sh b/scripts/ci/test-js.sh deleted file mode 100755 index cc62811379..0000000000 --- a/scripts/ci/test-js.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - -travisFoldStart "test.unit.localChrome" - $(npm bin)/karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS} -travisFoldEnd "test.unit.localChrome" diff --git a/scripts/ci/test-saucelabs.sh b/scripts/ci/test-saucelabs.sh deleted file mode 100755 index e141d251e8..0000000000 --- a/scripts/ci/test-saucelabs.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -travisFoldStart "test.unit.saucelabs" - ./scripts/sauce/sauce_connect_block.sh - SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev` - $(npm bin)/karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS} --reporters dots,saucelabs -travisFoldEnd "test.unit.saucelabs" diff --git a/scripts/ci/test.sh b/scripts/ci/test.sh deleted file mode 100755 index 2286dbed66..0000000000 --- a/scripts/ci/test.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/_travis-fold.sh - - -# If the previous commands in the `script` section of .travis.yaml failed, then abort. -# The variable is not set in early stages of the build, so we default to 0 there. -# https://docs.travis-ci.com/user/environment-variables/ -if [[ ${TRAVIS_TEST_RESULT=0} == 1 ]]; then - exit 1; -fi - - -case ${CI_MODE} in - js) - ${thisDir}/test-js.sh - ;; - e2e) - ${thisDir}/test-e2e.sh - ;; - saucelabs_required) - ${thisDir}/test-saucelabs.sh - ;; - browserstack_required) - ${thisDir}/test-browserstack.sh - ;; - saucelabs_optional) - ${thisDir}/test-saucelabs.sh - ;; - browserstack_optional) - ${thisDir}/test-browserstack.sh - ;; -esac diff --git a/scripts/github/merge-pr b/scripts/github/merge-pr index a3206c0691..e4dd1e6b49 100755 --- a/scripts/github/merge-pr +++ b/scripts/github/merge-pr @@ -1,6 +1,9 @@ #!/usr/bin/env bash -set -u -e -o pipefail +# https://www.tldp.org/LDP/abs/html/options.html#AEN19601 +# https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html +set -u -e -E -o pipefail + BASEDIR=$(dirname "$0") BASEDIR=`(cd $BASEDIR; pwd)` @@ -107,11 +110,26 @@ REWRITE_MESSAGE="git filter-branch -f --msg-filter \"$BASEDIR/utils/github_close PUSH_BRANCHES="git push git@github.com:angular/angular.git merge_pr_master:$MASTER_BRANCH merge_pr_patch:$PATCH_BRANCH" CHERRY_PICK_PR="git cherry-pick merge_pr_base..merge_pr" +# Checks that each PR branch to be merged upstream contains SHAs of commits that significantly changed our CI infrastructure. +# +# This check is used to enforce that we don't merge PRs that have not been rebased recently and could result in merging +# of non-approved or otherwise bad changes. +REQUIRED_BASE_SHA_MASTER="3fba6eff79a9b50909199eaa4ebf754c1c4adba6" # pullapprove => CODEOWNERS migration +REQUIRED_BASE_SHA_PATCH="e3853e842ea5c10fafbc310a76a4a7f47ed8c65e" # pullapprove => CODEOWNERS migration +if [[ $MERGE_MASTER == 1 ]]; then + REQUIRED_BASE_SHA="$REQUIRED_BASE_SHA_MASTER" +# check patch only if patch-only PR +elif [[ $MERGE_PATCH == 1 ]]; then + REQUIRED_BASE_SHA="$REQUIRED_BASE_SHA_PATCH" +fi +CHECK_IF_PR_REBASED="git branch --quiet merge_pr --contains $REQUIRED_BASE_SHA" + echo "======================" echo "GitHub Merge PR Steps" echo "======================" echo " $FETCH_PR" echo " $BASE_PR" +echo " $CHECK_IF_PR_REBASED" echo " $SQUASH_PR" echo " $REWRITE_MESSAGE" if [[ $MERGE_MASTER == 1 ]]; then @@ -127,6 +145,19 @@ echo ">>> Fetch PR: $FETCH_PR" $FETCH_PR echo ">>> Mark base: $BASE_PR" $BASE_PR +echo ">>> Check if PR rebased: $CHECK_IF_PR_REBASED" +if [[ $($CHECK_IF_PR_REBASED) != "" ]]; then + echo "The PR is sufficiently rebased!" +else + echo "" + echo "" + echo "Failed to merge pull request #${PR_NUMBER} because it hasn't been rebased recently and could be bypassing new or updated CI checks!" + echo "" + echo "Please rebase the PR and try again." + echo "" + $RESTORE_BRANCH + exit 1 +fi echo ">>> Autosquash: $SQUASH_PR" GIT_EDITOR=echo $SQUASH_PR echo ">>> Rewrite message: $REWRITE_MESSAGE" @@ -153,4 +184,3 @@ if [[ $PUSH_UPSTREAM == 1 ]]; then fi echo echo ">>>>>> SUCCESS <<<<<< PR#$PR_NUMBER merged." - diff --git a/scripts/package-builder.sh b/scripts/package-builder.sh new file mode 100755 index 0000000000..a3f349661a --- /dev/null +++ b/scripts/package-builder.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Build the dist/packages-dist directory in the same fashion as the legacy +# /build.sh script, by building the npm packages with Bazel and copying files. +# This is needed for scripts and tests which are not updated to the Bazel output +# layout (which always matches the input layout). +# Do not add new dependencies on this script, instead adapt scripts to use the +# new layout, and write new tests as Bazel targets. +# +# Ideally integration tests should run under bazel, and just consume the npm +# packages via `deps`. Until that works, we manually build the npm packages and then +# copy the results to the appropriate `dist` location. + +set -u -e -o pipefail + +cd "$(dirname "$0")" + +# basedir is the workspace root +readonly base_dir=$(pwd)/.. +# We need to resolve the Bazel binary in the node modules because running Bazel +# through `yarn bazel` causes additional output that throws off command stdout. +readonly bazel_bin=$(yarn bin)/bazel +readonly bin=$(${bazel_bin} info bazel-bin) + +function buildTargetPackages() { + # List of targets to build, e.g. core, common, compiler, etc. + targets=$(${bazel_bin} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind(".*_package", //packages/...)') + + # Path to the output directory into which we copy the npm packages. + dest_path="$1" + + # Either "legacy" (view engine) or "aot" (ivy) + compile_mode="$2" + + # Human-readable description of the build. + desc="$3" + + echo "##################################" + echo "scripts/build-packages-dist.sh:" + echo " building @angular/* npm packages" + echo " mode: ${desc}" + echo "##################################" + + # Use --config=release so that snapshot builds get published with embedded version info + echo "$targets" | xargs ${bazel_bin} build --config=release --define=compile=${compile_mode} + + [[ -d "${base_dir}/${dest_path}" ]] || mkdir -p ${base_dir}/${dest_path} + + dirs=`echo "$targets" | sed -e 's/\/\/packages\/\(.*\):npm_package/\1/'` + + for pkg in ${dirs}; do + # Skip any that don't have an "npm_package" target + src_dir="${bin}/packages/${pkg}/npm_package" + dest_dir="${base_dir}/${dest_path}/${pkg}" + if [[ -d ${src_dir} ]]; then + echo "# Copy artifacts to ${dest_dir}" + rm -rf ${dest_dir} + cp -R ${src_dir} ${dest_dir} + chmod -R u+w ${dest_dir} + fi + done +} + diff --git a/scripts/sauce/sauce_connect_block.sh b/scripts/sauce/sauce_connect_block.sh deleted file mode 100755 index ebda1fccb0..0000000000 --- a/scripts/sauce/sauce_connect_block.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# Wait for Connect to be ready before exiting -printf "Connecting to Sauce." -while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do - printf "." - #dart2js takes longer than the travis 10 min timeout to complete - sleep .5 -done -echo "Connected" \ No newline at end of file diff --git a/scripts/sauce/sauce_connect_setup.sh b/scripts/sauce/sauce_connect_setup.sh deleted file mode 100755 index 2a839722a1..0000000000 --- a/scripts/sauce/sauce_connect_setup.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -set +x -u -e -o pipefail - -# Setup environment -readonly thisDir=$(cd $(dirname $0); pwd) -source ${thisDir}/../ci/_travis-fold.sh - - - -# Setup and start Sauce Connect for your TravisCI build -# This script requires your .travis.yml to include the following two private env variables: -# SAUCE_USERNAME -# SAUCE_ACCESS_KEY -# Follow the steps at https://saucelabs.com/opensource/travis to set that up. -# -# Curl and run this script as part of your .travis.yml before_script section: -# before_script: -# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash - -CONNECT_URL="https://saucelabs.com/downloads/sc-${SAUCE_CONNECT_VERSION}-linux.tar.gz" -CONNECT_DIR="/tmp/sauce-connect-$RANDOM" -CONNECT_DOWNLOAD="sc-latest-linux.tar.gz" - -# We don't want to create a log file because sauceconnect always logs in verbose mode. This seems -# to be overwhelming Travis and causing flakes when we are cat-ing the log in "print-logs.sh" -CONNECT_LOG="/dev/null" - -# Even though the stdout of sauceconnect is not very verbose, we don't want to log this to -# Travis because it will show up in between different travis log-output groups -CONNECT_STDOUT="/dev/null" - -# Get Connect and start it -mkdir -p $CONNECT_DIR -cd $CONNECT_DIR -curl $CONNECT_URL -o $CONNECT_DOWNLOAD 2> /dev/null 1> /dev/null -mkdir sauce-connect -tar --extract --file=$CONNECT_DOWNLOAD --strip-components=1 --directory=sauce-connect > /dev/null -rm $CONNECT_DOWNLOAD - -SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev` - -ARGS="" - -# Set tunnel-id only on Travis, to make local testing easier. -if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then - ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER" -fi -if [ ! -z "$BROWSER_PROVIDER_READY_FILE" ]; then - ARGS="$ARGS --readyfile $BROWSER_PROVIDER_READY_FILE" -fi - -set -v -echo "Starting Sauce Connect in the background." -sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS --logfile $CONNECT_LOG \ - > $CONNECT_STDOUT & -set +v diff --git a/scripts/sauce/sauce_connect_teardown.sh b/scripts/sauce/sauce_connect_teardown.sh deleted file mode 100755 index 91b918a485..0000000000 --- a/scripts/sauce/sauce_connect_teardown.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -set -e -o pipefail - - -echo "Shutting down Sauce Connect tunnel" - -killall sc - -while [[ -n `ps -ef | grep "sauce-connect-" | grep -v "grep"` ]]; do - printf "." - sleep .5 -done - -echo "" -echo "Sauce Connect tunnel has been shut down" diff --git a/scripts/saucelabs/start-tunnel.sh b/scripts/saucelabs/start-tunnel.sh new file mode 100755 index 0000000000..ea9b2a77dc --- /dev/null +++ b/scripts/saucelabs/start-tunnel.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -x -u -e -o pipefail + +readonly currentDir=$(cd $(dirname $0); pwd) + +# Command arguments that will be passed to sauce-connect. +sauceArgs="" + +if [[ ! -z "${SAUCE_READY_FILE}" ]]; then + sauceArgs="${sauceArgs} --readyfile ${SAUCE_READY_FILE}" +fi + +if [[ ! -z "${SAUCE_PID_FILE}" ]]; then + mkdir -p $(dirname ${SAUCE_PID_FILE}) + sauceArgs="${sauceArgs} --pidfile ${SAUCE_PID_FILE}" +fi + +if [[ ! -z "${SAUCE_TUNNEL_IDENTIFIER}" ]]; then + sauceArgs="${sauceArgs} --tunnel-identifier ${SAUCE_TUNNEL_IDENTIFIER}" +fi + +echo "Starting Sauce Connect. Passed arguments: ${sauceArgs}" + +${currentDir}/../../node_modules/sauce-connect/bin/sc -u ${SAUCE_USERNAME} -k ${SAUCE_ACCESS_KEY} ${sauceArgs} diff --git a/scripts/saucelabs/stop-tunnel.sh b/scripts/saucelabs/stop-tunnel.sh new file mode 100755 index 0000000000..c53a7e31ca --- /dev/null +++ b/scripts/saucelabs/stop-tunnel.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Disable printing of any executed command because this would cause a lot +# of spam due to the loop. +set +x -u -e -o pipefail + +if [[ ! -f ${SAUCE_PID_FILE} ]]; then + echo "Could not find Saucelabs tunnel PID file. Cannot stop tunnel.." + exit 1 +fi + +echo "Shutting down Sauce Connect tunnel" + +# The process id for the sauce-connect instance is stored inside of the pidfile. +tunnelProcessId=$(cat ${SAUCE_PID_FILE}) + +# Kill the process by using the PID that has been read from the pidfile. Note that +# we cannot use killall because CircleCI base container images don't have it installed. +kill ${tunnelProcessId} + +while (ps -p ${tunnelProcessId} &> /dev/null); do + printf "." + sleep .5 +done + +echo "" +echo "Sauce Connect tunnel has been shut down" diff --git a/scripts/saucelabs/wait-for-tunnel.sh b/scripts/saucelabs/wait-for-tunnel.sh new file mode 100755 index 0000000000..416cc01216 --- /dev/null +++ b/scripts/saucelabs/wait-for-tunnel.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +# Disable printing of any executed command because this would cause a lot +# of spam due to the loop. +set +x -u -e -o pipefail + +# Waits for Saucelabs Connect to be ready before executing any tests. +counter=0 + +while [[ ! -f ${SAUCE_READY_FILE} ]]; do + counter=$((counter + 1)) + + # Counter needs to be multiplied by two because the while loop only sleeps a half second. + # This has been made in favor of better progress logging (printing dots every half second) + if [ $counter -gt $[${SAUCE_READY_FILE_TIMEOUT} * 2] ]; then + echo "" + echo "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file" + exit 5 + fi + + printf "." + sleep 0.5 +done + +echo "" +echo "Connected to Saucelabs" diff --git a/test.sh b/test.sh deleted file mode 100755 index 812448f086..0000000000 --- a/test.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -e -o pipefail - -if [ $# -eq 0 ] - then - echo "Angular test runner. (No platform specified)" - echo - echo "./test.sh [node|browser|browserNoRouter|router] [--debug]" - echo "(--debug flag only relevant to 'node' testing - see https://github.com/angular/angular/blob/master/docs/DEBUG.md)" - echo -else - cd `dirname $0` - rm -rf dist/tools - if [ -z ${NODE_PATH+x} ]; then - export NODE_PATH=$(pwd)/dist/all:$(pwd)/dist/tools - else - export NODE_PATH=$NODE_PATH:$(pwd)/dist/all/:$(pwd)/dist/tools/ - fi - echo "Compiling tools..." - $(npm bin)/tsc -p tools - if [[ $1 == 'node' ]]; then - # Note: .metadata.json files are needed for the language service tests! - echo "Building compiler..." - $(npm bin)/tsc -p packages/compiler/tsconfig-tools.json - $(npm bin)/tsc -p packages/compiler-cli/tsconfig-tools.json - echo "Creating packages .metadata.json files..." - node --max-old-space-size=3000 dist/tools/@angular/compiler-cli/src/main -p packages/tsconfig-metadata.json - fi - node --harmony dist/tools/tsc-watch/ $1 watch $2 -fi diff --git a/third_party/README.md b/third_party/README.md new file mode 100644 index 0000000000..7659445b2c --- /dev/null +++ b/third_party/README.md @@ -0,0 +1,30 @@ +# third_party vendored sources in Angular + +## TL;DR: don't copy sources into this repo + +All sources in this repo should be authored from scratch by the committer. +Don't copy sources you've found in any other location. + +## What if I have a good reason? + +We do "vendor in" some sources, in cases where we do not want our users to have a transitive dependency. +For example, to make testing more reliable, we copy a font into our repo. +That allows our integration tests to run without dynamically requesting that font. + +Follow these guidelines for adding sources under `third_party`: + +1. Only vendor sources with compatible licenses. Apache 2.0 and MIT are good. Any other licenses, check with your team lead so we can verify our ability to comply with the license. +1. Preserve the license for code. The best thing to do is copy the entire LICENSE file along with the sources. +1. Indicate where the sources came from. Our convention is to create a directory based on the URL where the sources were fetched. Add version number or if missing, the retrieval date, as a comment in the build file just above the license() call. Example: https://github.com/angular/angular/blob/master/third_party/fonts.google.com/open-sans/BUILD.bazel +1. Avoid changing the files you fetched. If you make any changes to the sources, first commit the original, then in a separate commit, make your edits. include another metadata file listing your changes, like https://github.com/bazelbuild/rules_nodejs/blob/master/third_party/github.com/source-map-support/LOCAL_MODS.md +1. Any bundle or distribution which includes this code needs to propagate the LICENSE file or content. Talk to your TL to make sure this is done correctly. + +## Under Bazel + +This directory is treated specially by Bazel. + +All BUILD.bazel files under `third_party` are required to have a `licenses` statement. +See https://docs.bazel.build/versions/master/be/functions.html#licenses + +Note that we don't yet have a way to enumerate the licenses and include them in our distribution. +Follow https://github.com/bazelbuild/bazel/issues/188 diff --git a/third_party/fonts.google.com/open-sans/BUILD.bazel b/third_party/fonts.google.com/open-sans/BUILD.bazel new file mode 100644 index 0000000000..7a1c8120ed --- /dev/null +++ b/third_party/fonts.google.com/open-sans/BUILD.bazel @@ -0,0 +1,11 @@ +licenses(["notice"]) + +# Downloaded from: https://fonts.google.com/?selection.family=Open+Sans:300,400,600,700 +# Timestamp: 03/02/2019 +exports_files(["LICENSE.txt"]) + +filegroup( + name = "open-sans", + srcs = ["open-sans.css"] + glob(["OpenSans-*.ttf"]), + visibility = ["//modules/playground:__subpackages__"], +) diff --git a/third_party/fonts.google.com/open-sans/LICENSE.txt b/third_party/fonts.google.com/open-sans/LICENSE.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/third_party/fonts.google.com/open-sans/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/fonts.google.com/open-sans/OpenSans-Bold.ttf b/third_party/fonts.google.com/open-sans/OpenSans-Bold.ttf new file mode 100644 index 0000000000..7b52945603 Binary files /dev/null and b/third_party/fonts.google.com/open-sans/OpenSans-Bold.ttf differ diff --git a/third_party/fonts.google.com/open-sans/OpenSans-Light.ttf b/third_party/fonts.google.com/open-sans/OpenSans-Light.ttf new file mode 100644 index 0000000000..563872c768 Binary files /dev/null and b/third_party/fonts.google.com/open-sans/OpenSans-Light.ttf differ diff --git a/third_party/fonts.google.com/open-sans/OpenSans-Regular.ttf b/third_party/fonts.google.com/open-sans/OpenSans-Regular.ttf new file mode 100644 index 0000000000..2e31d02424 Binary files /dev/null and b/third_party/fonts.google.com/open-sans/OpenSans-Regular.ttf differ diff --git a/third_party/fonts.google.com/open-sans/OpenSans-SemiBold.ttf b/third_party/fonts.google.com/open-sans/OpenSans-SemiBold.ttf new file mode 100644 index 0000000000..99db86aa02 Binary files /dev/null and b/third_party/fonts.google.com/open-sans/OpenSans-SemiBold.ttf differ diff --git a/third_party/fonts.google.com/open-sans/open-sans.css b/third_party/fonts.google.com/open-sans/open-sans.css new file mode 100644 index 0000000000..7d97c02a3d --- /dev/null +++ b/third_party/fonts.google.com/open-sans/open-sans.css @@ -0,0 +1,24 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), url('./OpenSans-Light.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url('./OpenSans-Regular.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url('./OpenSans-Bold.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url('./OpenSans-SemiBold.ttf') format('truetype'); +} diff --git a/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.20.0.bazelrc b/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.21.0.bazelrc similarity index 92% rename from third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.20.0.bazelrc rename to third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.21.0.bazelrc index 8f5db01d29..120881ef66 100644 --- a/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.20.0.bazelrc +++ b/third_party/github.com/bazelbuild/bazel-toolchains/bazelrc/bazel-0.21.0.bazelrc @@ -40,7 +40,7 @@ build:remote --host_javabase=@bazel_toolchains//configs/ubuntu16_04_clang/1.1:jd build:remote --javabase=@bazel_toolchains//configs/ubuntu16_04_clang/1.1:jdk8 build:remote --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 build:remote --java_toolchain=@bazel_tools//tools/jdk:toolchain_hostjdk8 -build:remote --crosstool_top=@bazel_toolchains//configs/ubuntu16_04_clang/1.1/bazel_0.20.0/default:toolchain +build:remote --crosstool_top=@bazel_toolchains//configs/ubuntu16_04_clang/1.1/bazel_0.21.0/default:toolchain build:remote --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 # Platform flags: # The toolchain container used for execution is defined in the target indicated @@ -50,7 +50,7 @@ build:remote --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 # "extra_toolchains" to be selected (given constraints defined in # "exec_compatible_with"). # More about platforms: https://docs.bazel.build/versions/master/platforms.html -build:remote --extra_toolchains=@bazel_toolchains//configs/ubuntu16_04_clang/1.1/bazel_0.20.0/cpp:cc-toolchain-clang-x86_64-default +build:remote --extra_toolchains=@bazel_toolchains//configs/ubuntu16_04_clang/1.1/bazel_0.21.0/cpp:cc-toolchain-clang-x86_64-default build:remote --extra_execution_platforms=@bazel_toolchains//configs/ubuntu16_04_clang/1.1:rbe_ubuntu1604 build:remote --host_platform=@bazel_toolchains//configs/ubuntu16_04_clang/1.1:rbe_ubuntu1604 build:remote --platforms=@bazel_toolchains//configs/ubuntu16_04_clang/1.1:rbe_ubuntu1604 @@ -74,11 +74,6 @@ build:remote --remote_executor=remotebuildexecution.googleapis.com # Enable encryption. build:remote --tls_enabled=true -# Enforce stricter environment rules, which eliminates some non-hermetic -# behavior and therefore improves both the remote cache hit rate and the -# correctness and repeatability of the build. -build:remote --experimental_strict_action_env=true - # Set a higher timeout value, just in case. build:remote --remote_timeout=3600 @@ -110,7 +105,7 @@ build:results-local --bes_results_url="https://source.cloud.google.com/results/i # with the rbe-ubuntu16-04 container. Use of these flags is still experimental. build:docker-sandbox --host_javabase=@bazel_toolchains//configs/ubuntu16_04_clang/1.1:jdk8 build:docker-sandbox --javabase=@bazel_toolchains//configs/ubuntu16_04_clang/1.1:jdk8 -build:docker-sandbox --crosstool_top=@bazel_toolchains//configs/ubuntu16_04_clang/1.1/bazel_0.20.0/default:toolchain +build:docker-sandbox --crosstool_top=@bazel_toolchains//configs/ubuntu16_04_clang/1.1/bazel_0.21.0/default:toolchain build:docker-sandbox --experimental_docker_image=gcr.io/cloud-marketplace/google/rbe-ubuntu16-04@sha256:9bd8ba020af33edb5f11eff0af2f63b3bcb168cd6566d7b27c6685e717787928 build:docker-sandbox --spawn_strategy=docker build:docker-sandbox --strategy=Javac=docker @@ -124,10 +119,9 @@ build:docker-sandbox --experimental_enable_docker_sandbox # across machines, developers, and workspaces. build:remote-cache --remote_cache=remotebuildexecution.googleapis.com build:remote-cache --tls_enabled=true -build:remote-cache --experimental_strict_action_env=true build:remote-cache --remote_timeout=3600 build:remote-cache --auth_enabled=true build:remote-cache --spawn_strategy=standalone build:remote-cache --strategy=Javac=standalone build:remote-cache --strategy=Closure=standalone -build:remote-cache --genrule_strategy=standalone +build:remote-cache --genrule_strategy=standalone \ No newline at end of file diff --git a/third_party/github.com/google/material-design-icons/BUILD.bazel b/third_party/github.com/google/material-design-icons/BUILD.bazel new file mode 100644 index 0000000000..44038c4689 --- /dev/null +++ b/third_party/github.com/google/material-design-icons/BUILD.bazel @@ -0,0 +1,16 @@ +licenses(["notice"]) + +# Downloaded from: https://github.com/google/material-design-icons/blob/3.0.1/LICENSE +# Timestamp: 06/02/2019 +exports_files(["LICENSE.txt"]) + +filegroup( + name = "material-design-icons", + srcs = [ + # https://github.com/google/material-design-icons/blob/3.0.1/iconfont/material-icons.css + "material-icons.css", + # https://github.com/google/material-design-icons/blob/3.0.1/iconfont/MaterialIcons-Regular.ttf + "MaterialIcons-Regular.ttf", + ], + visibility = ["//modules/playground:__subpackages__"], +) diff --git a/third_party/github.com/google/material-design-icons/LICENSE b/third_party/github.com/google/material-design-icons/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/third_party/github.com/google/material-design-icons/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/github.com/google/material-design-icons/LOCAL_MODS.md b/third_party/github.com/google/material-design-icons/LOCAL_MODS.md new file mode 100644 index 0000000000..315d84caff --- /dev/null +++ b/third_party/github.com/google/material-design-icons/LOCAL_MODS.md @@ -0,0 +1 @@ +- `material-icons.css` has been modified to only load the `truetype` icons font. \ No newline at end of file diff --git a/third_party/github.com/google/material-design-icons/MaterialIcons-Regular.ttf b/third_party/github.com/google/material-design-icons/MaterialIcons-Regular.ttf new file mode 100644 index 0000000000..7015564ad1 Binary files /dev/null and b/third_party/github.com/google/material-design-icons/MaterialIcons-Regular.ttf differ diff --git a/third_party/github.com/google/material-design-icons/material-icons.css b/third_party/github.com/google/material-design-icons/material-icons.css new file mode 100644 index 0000000000..de5cb88b58 --- /dev/null +++ b/third_party/github.com/google/material-design-icons/material-icons.css @@ -0,0 +1,31 @@ +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url("./MaterialIcons-Regular.ttf") format('truetype'); +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + + /* Support for IE. */ + font-feature-settings: 'liga'; +} diff --git a/tools/bazel_stamp_vars.js b/tools/bazel_stamp_vars.js new file mode 100644 index 0000000000..3b7052aae4 --- /dev/null +++ b/tools/bazel_stamp_vars.js @@ -0,0 +1,56 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// tslint:disable:no-console +// Generates the data used by the stamping feature in bazel. +// See the section on stamping in docs / BAZEL.md +// This script must be a NodeJS script in order to be cross-platform. +// See https://github.com/bazelbuild/bazel/issues/5958 +// Note: git operations, especially git status, take a long time inside mounted docker volumes +// in Windows or OSX hosts (https://github.com/docker/for-win/issues/188). +const execSync = require('child_process').execSync; +function _exec(str) { + return execSync(str).toString().trim(); +} + +console.error('Running', process.argv.join(' ')); + +function onError() { + console.error('Failed to execute:,', process.argv.join(' ')); + console.error(''); +} + +// Setup crash handler +process.on('uncaughtException', onError); + +const BUILD_SCM_HASH = _exec(`git rev-parse HEAD`); +console.log(`BUILD_SCM_HASH ${BUILD_SCM_HASH}`); + +if (_exec(`git tag`) == '') { + console.error(`No git tags found, can't stamp the build.`); + console.error('Please fetch the tags first:'); + console.error(' git fetch git@github.com:angular/angular.git --tags'); +} + +// Find out if there are any uncommitted local changes +const LOCAL_CHANGES = _exec(`git status --untracked-files=no --porcelain`) != ''; +console.log(`BUILD_SCM_LOCAL_CHANGES ${LOCAL_CHANGES}`); + +// Only match the latest tag that is a version such as 6.0.0, 6.0.0-rc.5, etc... +// This will ignore non-version tags which would break unit tests expecting a valid version +// number in the package headers +const BUILD_SCM_VERSION_RAW = + _exec(`git describe --match [0-9].[0-9].[0-9]* --abbrev=7 --tags HEAD`); + +// Reformat `git describe` version string into a more semver-ish string +// From: 5.2.0-rc.0-57-g757f886 +// To: 5.2.0-rc.0+57.sha-757f886 +// Or: 5.2.0-rc.0+57.sha-757f886.with-local-changes +const BUILD_SCM_VERSION = BUILD_SCM_VERSION_RAW.replace(/-([0-9]+)-g/, '+$1.sha-') + + (LOCAL_CHANGES ? '.with-local-changes' : ''); +console.log(`BUILD_SCM_VERSION ${BUILD_SCM_VERSION}`); diff --git a/tools/bazel_stamp_vars.sh b/tools/bazel_stamp_vars.sh deleted file mode 100755 index 028877acec..0000000000 --- a/tools/bazel_stamp_vars.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# Generates the data used by the stamping feature in bazel. -# See the section on stamping in docs/BAZEL.md - -set -u -e -E -o pipefail - -echo "Running: $0" >&2 - -function onError { - echo "Failed to execute: $0" - echo "" -} - -# Setup crash trap -trap 'onError' ERR - - -echo BUILD_SCM_HASH $(git rev-parse HEAD) - -if [[ "$(git tag)" == "" ]]; then - echo "No git tags found, can't stamp the build." - echo "Either fetch the tags:" - echo " git fetch git@github.com:angular/angular.git --tags" - echo "or build without stamping by giving an empty workspace_status_command:" - echo " yarn bazel build --workspace_status_command= ..." - echo "" -fi - -# Only match the latest tag that is a version such as 6.0.0, 6.0.0-rc.5, etc... -# This will ignore non-version tags which would break unit tests expecting a valid version -# number in the package headers -BUILD_SCM_VERSION_RAW=$(git describe --match [0-9].[0-9].[0-9]* --abbrev=7 --tags HEAD) - -# Find out if there are any uncommitted local changes -# TODO(i): is it ok to use "--untracked-files=no" to ignore untracked files since they should not affect anything? -if [[ $(git status --untracked-files=no --porcelain) ]]; then LOCAL_CHANGES="true"; else LOCAL_CHANGES="false"; fi -echo BUILD_SCM_LOCAL_CHANGES ${LOCAL_CHANGES} - -# Reformat `git describe` version string into a more semver-ish string -# From: 5.2.0-rc.0-57-g757f886 -# To: 5.2.0-rc.0+57.sha-757f886 -# Or: 5.2.0-rc.0+57.sha-757f886.with-local-changes -BUILD_SCM_VERSION="$(echo ${BUILD_SCM_VERSION_RAW} | sed -E 's/-([0-9]+)-g/+\1.sha-/g')""$( if [[ $LOCAL_CHANGES == "true" ]]; then echo ".with-local-changes"; fi)" -echo BUILD_SCM_VERSION ${BUILD_SCM_VERSION} diff --git a/tools/defaults.bzl b/tools/defaults.bzl index a5204fc103..377c7057a1 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -1,7 +1,8 @@ """Re-export of some bazel rules with repository-wide defaults.""" +load("@build_bazel_rules_karma//:defs.bzl", _ts_web_test_suite = "ts_web_test_suite") load("@build_bazel_rules_nodejs//:defs.bzl", _jasmine_node_test = "jasmine_node_test", _nodejs_binary = "nodejs_binary", _npm_package = "npm_package") -load("@build_bazel_rules_typescript//:defs.bzl", _ts_library = "ts_library", _ts_web_test_suite = "ts_web_test_suite") +load("@build_bazel_rules_typescript//:defs.bzl", _ts_library = "ts_library") load("//packages/bazel:index.bzl", _ng_module = "ng_module", _ng_package = "ng_package") load("//packages/bazel/src:ng_rollup_bundle.bzl", _ng_rollup_bundle = "ng_rollup_bundle") @@ -44,7 +45,38 @@ PKG_GROUP_REPLACEMENTS = { ]""" % ",\n ".join(["\"%s\"" % s for s in ANGULAR_SCOPED_PACKAGES]), } -def ts_library(tsconfig = None, testonly = False, deps = [], **kwargs): +def _default_module_name(testonly): + """ Provide better defaults for package names. + + e.g. rather than angular/packages/core/testing we want @angular/core/testing + + TODO(alexeagle): we ought to supply a default module name for every library in the repo. + But we short-circuit below in cases that are currently not working. + """ + pkg = native.package_name() + + if testonly: + # Some tests currently rely on the long-form package names + return None + + if pkg.startswith("packages/bazel"): + # Avoid infinite recursion in the ViewEngine compiler. Error looks like: + # Compiling Angular templates (ngc) //packages/bazel/test/ngc-wrapped/empty:empty failed (Exit 1) + # : RangeError: Maximum call stack size exceeded + # at normalizeString (path.js:57:25) + # at Object.normalize (path.js:1132:12) + # at Object.join (path.js:1167:18) + # at resolveModule (execroot/angular/bazel-out/host/bin/packages/bazel/src/ngc-wrapped/ngc-wrapped.runfiles/angular/packages/compiler-cli/src/metadata/bundler.js:582:50) + # at MetadataBundler.exportAll (execroot/angular/bazel-out/host/bin/packages/bazel/src/ngc-wrapped/ngc-wrapped.runfiles/angular/packages/compiler-cli/src/metadata/bundler.js:119:42) + # at MetadataBundler.exportAll (execroot/angular/bazel-out/host/bin/packages/bazel/src/ngc-wrapped/ngc-wrapped.runfiles/angular/packages/compiler-cli/src/metadata/bundler.js:121:52) + return None + + if pkg.startswith("packages/"): + return "@angular/" + pkg[len("packages/"):] + + return None + +def ts_library(tsconfig = None, testonly = False, deps = [], module_name = None, **kwargs): """Default values for ts_library""" deps = deps + ["@ngdeps//tslib"] if testonly: @@ -57,15 +89,19 @@ def ts_library(tsconfig = None, testonly = False, deps = [], **kwargs): else: tsconfig = _DEFAULT_TSCONFIG_BUILD + if not module_name: + module_name = _default_module_name(testonly) + _ts_library( tsconfig = tsconfig, testonly = testonly, deps = deps, node_modules = _DEFAULT_TS_TYPINGS, + module_name = module_name, **kwargs ) -def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps = [], **kwargs): +def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps = [], module_name = None, **kwargs): """Default values for ng_module""" deps = deps + ["@ngdeps//tslib"] if testonly: @@ -77,6 +113,8 @@ def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps tsconfig = _DEFAULT_TSCONFIG_TEST else: tsconfig = _DEFAULT_TSCONFIG_BUILD + if not module_name: + module_name = _default_module_name(testonly) if not entry_point: entry_point = "public_api.ts" _ng_module( @@ -89,6 +127,7 @@ def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps compiler = _INTERNAL_NG_MODULE_COMPILER, ng_xi18n = _INTERNAL_NG_MODULE_XI18N, node_modules = _DEFAULT_TS_TYPINGS, + module_name = module_name, **kwargs ) @@ -120,16 +159,19 @@ def npm_package(name, replacements = {}, **kwargs): **kwargs ) -def ts_web_test_suite(bootstrap = [], deps = [], **kwargs): +def ts_web_test_suite(bootstrap = [], deps = [], runtime_deps = [], **kwargs): """Default values for ts_web_test_suite""" if not bootstrap: bootstrap = ["//:web_test_bootstrap_scripts"] local_deps = [ "@ngdeps//node_modules/tslib:tslib.js", - "//tools/testing:browser", ] + deps + local_runtime_deps = [ + "//tools/testing:browser", + ] + runtime_deps _ts_web_test_suite( + runtime_deps = local_runtime_deps, bootstrap = bootstrap, deps = local_deps, karma = _DEFAULT_KARMA_BIN, diff --git a/tools/gulp-tasks/check-cycle.js b/tools/gulp-tasks/check-cycle.js index f068d17150..62315c5bc6 100644 --- a/tools/gulp-tasks/check-cycle.js +++ b/tools/gulp-tasks/check-cycle.js @@ -10,7 +10,10 @@ module.exports = (gulp) => (done) => { const madge = require('madge'); - const dependencyObject = madge(['dist/all/'], { + // TODO: This only checks for circular dependencies within each package because + // imports to other packages cannot be resolved by Madge when CommonJS is used. + // We should consider updating Madge and use a tsonfig to check across packages. + const dependencyObject = madge(['dist/packages-dist/'], { format: 'cjs', extensions: ['.js'], onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, '//'); } diff --git a/tools/gulp-tasks/cldr/util.js b/tools/gulp-tasks/cldr/util.js index 692f051560..ded4d56c35 100644 --- a/tools/gulp-tasks/cldr/util.js +++ b/tools/gulp-tasks/cldr/util.js @@ -146,7 +146,7 @@ module.exports.stringify = function(obj, quoteKeys) { objStack.push(obj_part); for (var prop in obj_part) { if (obj_part.hasOwnProperty(prop)) { - var value = internalStringify(obj_part, prop, false); + var value = internalStringify(obj_part, prop); if (typeof value !== 'undefined' && value !== null) { nonEmpty = true; key = isWord(prop) && !quoteKeys ? prop : escapeString(prop, quoteKeys); @@ -173,7 +173,7 @@ module.exports.stringify = function(obj, quoteKeys) { // but when top-level, return undefined var topLevelHolder = {'': obj}; if (obj === undefined) { - return getReplacedValueOrUndefined(topLevelHolder, '', true); + return getReplacedValueOrUndefined(topLevelHolder, ''); } return internalStringify(topLevelHolder, ''); }; diff --git a/tools/gulp-tasks/serve.js b/tools/gulp-tasks/serve.js index 0c0dda239a..d3f476cbd2 100644 --- a/tools/gulp-tasks/serve.js +++ b/tools/gulp-tasks/serve.js @@ -23,19 +23,4 @@ module.exports = { }); }, - // Serve the examples - examples: (gulp) => () => { - const connect = require('gulp-connect'); - const cors = require('cors'); - const path = require('path'); - - connect.server({ - root: path.resolve(__dirname, '../../dist/examples'), - port: 8001, - livereload: false, - open: false, - middleware: (connect, opt) => [cors()], - }); - } - }; diff --git a/tools/material-ci/angular_material_test_blocklist.js b/tools/material-ci/angular_material_test_blocklist.js new file mode 100644 index 0000000000..f92d5c8bd4 --- /dev/null +++ b/tools/material-ci/angular_material_test_blocklist.js @@ -0,0 +1,2773 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * Blocklist of unit tests from angular/material2 with ivy that are skipped when running on + * angular/angular. As bugs are resolved, items should be removed from this blocklist. + * + * The `notes` section should be used to keep track of specific issues associated with the failures. + */ + +// clang-format off +// tslint:disable + +window.testBlocklist = { + "Portals CdkPortalOutlet should load a template into the portal": { + "error": "TypeError: Cannot read property 'createEmbeddedView' of undefined", + "notes": "Unknown" + }, + "Portals CdkPortalOutlet should project template context bindings in the portal": { + "error": "TypeError: Cannot read property 'createEmbeddedView' of undefined", + "notes": "Unknown" + }, + "Portals CdkPortalOutlet should set the `portal` when attaching a component portal programmatically": { + "error": "TypeError: Cannot read property 'attachComponentPortal' of undefined", + "notes": "Unknown" + }, + "Portals CdkPortalOutlet should not clear programmatically-attached portals on init": { + "error": "TypeError: Cannot read property 'attach' of undefined", + "notes": "Unknown" + }, + "Portals CdkPortalOutlet should be considered attached when attaching using `attach`": { + "error": "TypeError: Cannot read property 'hasAttached' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "Portals CdkPortalOutlet should be considered attached when attaching using `attachComponentPortal`": { + "error": "TypeError: Cannot read property 'hasAttached' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "Portals CdkPortalOutlet should be considered attached when attaching using `attachTemplatePortal`": { + "error": "TypeError: Cannot read property 'hasAttached' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "Portals CdkPortalOutlet should use the `ComponentFactoryResolver` from the portal, if available": { + "error": "TypeError: Cannot read property 'attachComponentPortal' of undefined", + "notes": "Unknown" + }, + "Portals DomPortalOutlet should attach and detach a component portal without a ViewContainerRef": { + "error": "Error: Expected '

    Pizza

    Chocolate

    ' to be '', 'Expected the DomPortalOutlet to be empty after detach'.", + "notes": "Unknown" + }, + "AutofillMonitor should add monitored class and listener upon monitoring": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should not add multiple listeners to the same element": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should remove monitored class and listener upon stop monitoring": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should stop monitoring all monitored elements upon destroy": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should emit and add filled class upon start animation": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should emit and remove filled class upon end animation": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should cleanup filled class if monitoring stopped in autofilled state": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should complete the stream when monitoring is stopped": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should emit on stream inside the NgZone": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AutofillMonitor should not emit on init if input is unfilled": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should be able to create a message element": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should not register empty strings": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should not register non-string values": { + "error": "Error: Expected function not to throw, but it threw TypeError: Cannot read property 'nativeElement' of undefined.", + "notes": "Unknown" + }, + "AriaDescriber should not throw when trying to remove non-string value": { + "error": "Error: Expected function not to throw, but it threw TypeError: Cannot read property 'nativeElement' of undefined.", + "notes": "Unknown" + }, + "AriaDescriber should de-dupe a message registered multiple times": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should be able to register multiple messages": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should be able to unregister messages": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should be able to unregister messages while having others registered": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should be able to append to an existing list of aria describedby": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should be able to handle multiple regisitrations of the same message to an element": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "AriaDescriber should clear any pre-existing containers": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render initial state": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the data length": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the viewport size": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport size": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the rendered range": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the rendered content offset": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the scroll offset": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should get the rendered content size": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should measure range size": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set total content size": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set total content size in horizontal mode": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set a class based on the orientation": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set the vertical class if an invalid orientation is set": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set rendered range": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set content offset to top of content": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should set content offset to bottom of content": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to offset": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to index": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to offset in horizontal mode": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should scroll to index in horizontal mode": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should output scrolled index": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls down": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls up": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render buffer element at the end when scrolled to the top": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render buffer element at the start and end when scrolled to the middle": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render buffer element at the start when scrolled to the bottom": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should handle dynamic item size": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should handle dynamic buffer size": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should handle dynamic item array": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls right in horizontal mode": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should update viewport as user scrolls left in horizontal mode": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should work with an Observable": { + "error": "TypeError: Cannot read property 'getRenderedRange' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should work with a DataSource": { + "error": "TypeError: Cannot read property 'getRenderedRange' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should trackBy value by default": { + "error": "Error: : could not find an object to spy upon for detach()", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should trackBy index when specified": { + "error": "Error: : could not find an object to spy upon for detach()", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should recycle views when template cache is large enough to accommodate": { + "error": "Error: : could not find an object to spy upon for createEmbeddedView()", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should not recycle views when template cache is full": { + "error": "Error: : could not find an object to spy upon for createEmbeddedView()", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should render up to maxBufferPx when buffer dips below minBufferPx": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should throw if maxBufferPx is less than minBufferPx": { + "error": "Error: Uncaught (in promise): TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should register and degregister with ScrollDispatcher": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should emit on viewChange inside the Angular zone": { + "error": "TypeError: Cannot read property 'viewChange' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with FixedSizeVirtualScrollStrategy should not throw when disposing of a view that will not fit in the cache": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with RTL direction should initially be scrolled all the way right and showing the first item in horizontal mode": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with RTL direction should scroll through items as user scrolls to the left in horizontal mode": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with RTL direction should interpret scrollToOffset amount as an offset from the right in horizontal mode": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with RTL direction should scroll to the correct index in horizontal mode": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with RTL direction should emit the scrolled to index in horizontal mode": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with RTL direction should set total content size": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with RTL direction should set total content size in horizontal mode": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with AutoSizeVirtualScrollStrategy should render initial state for uniform items": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with AutoSizeVirtualScrollStrategy should render extra content if first item is smaller than average": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkVirtualScrollViewport with AutoSizeVirtualScrollStrategy should throw if maxBufferPx is less than minBufferPx": { + "error": "Error: Uncaught (in promise): TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "CdkAccordion should not register nested items to the same accordion": { + "error": "TypeError: Cannot read property 'accordion' of undefined", + "notes": "Unknown" + }, + "CdkTable in a typical simple use case should initialize with a connected data source": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should initialize with a rendered header with the right number of header cells": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should initialize with rendered rows with right number of row cells": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should initialize with column class names provided to header and data row cells": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should initialize with the right accessibility roles": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should disconnect the data source when table is destroyed": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should re-render the rows when the data changes": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should clear the `mostRecentCellOutlet` on destroy": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should correctly use the differ to add/remove/move rows when the data is heterogeneous": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should correctly use the differ to add/remove/move rows when the data contains multiple occurrences of the same object instance": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should clear the row view containers on destroy": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should match the right table content with dynamic data": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable in a typical simple use case should be able to dynamically change the columns for header and rows": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should render no rows when the data is null": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should be able to render multiple header and footer rows": { + "error": "Error: Missing definitions for header, footer, and row; cannot determine which columns should be rendered.", + "notes": "Attempting to access content children before view is initialized" + }, + "CdkTable should be able to render and change multiple header and footer rows": { + "error": "Error: Missing definitions for header, footer, and row; cannot determine which columns should be rendered.", + "notes": "Attempting to access content children before view is initialized" + }, + "CdkTable with different data inputs other than data source should render with data array input": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with different data inputs other than data source should render with data stream input": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with different data inputs other than data source should throw an error if the data source is not valid": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable missing row defs should be able to render without a header row def": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable missing row defs should be able to render without a data row def": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable missing row defs should be able to render without a footer row def": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should render correctly when using native HTML tags": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "FW-856: Attempting to access content children before view is initialized" + }, + "CdkTable should render cells even if row data is falsy": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should be able to apply class-friendly css class names for the column cells": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should not clobber an existing table role": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should throw an error if two column definitions have the same name": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should throw an error if a column definition is requested but not defined": { + "error": "Error: Expected function to throw an exception with message 'Could not find column with id \"column_a\".', but it threw an exception with message 'Cannot read property 'viewContainer' of undefined'.", + "notes": "Unknown" + }, + "CdkTable should throw an error if the row definitions are missing": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should not throw an error if columns are undefined on initialization": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should be able to dynamically add/remove column definitions": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should be able to register column, row, and header row definitions outside content": { + "error": "TypeError: Cannot read property 'addColumnDef' of undefined", + "notes": "Unknown" + }, + "CdkTable using when predicate should be able to display different row templates based on the row data": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable using when predicate should error if there is row data that does not have a matching row template": { + "error": "Error: Expected function to throw an Error.", + "notes": "Unknown" + }, + "CdkTable using when predicate should fail when multiple rows match data without multiTemplateDataRows": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable using when predicate with multiTemplateDataRows should be able to render multiple rows per data object": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable using when predicate with multiTemplateDataRows should have the correct data and row indicies": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable using when predicate with multiTemplateDataRows should have the correct data and row indicies when data contains multiple instances of the same object instance": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with sticky positioning on \"display: flex\" table style should stick and unstick headers": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with sticky positioning on \"display: flex\" table style should stick and unstick footers": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with sticky positioning on \"display: flex\" table style should stick and unstick left columns": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with sticky positioning on \"display: flex\" table style should stick and unstick right columns": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with sticky positioning on \"display: flex\" table style should reverse directions for sticky columns in rtl": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with sticky positioning on \"display: flex\" table style should stick and unstick combination of sticky header, footer, and columns": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with sticky positioning on native table layout should stick and unstick headers": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "FW-856: Attempting to access content children before view is initialized" + }, + "CdkTable with sticky positioning on native table layout should stick and unstick footers": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "FW-856: Attempting to access content children before view is initialized" + }, + "CdkTable with sticky positioning on native table layout should stick tfoot when all rows are stuck": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "FW-856: Attempting to access content children before view is initialized" + }, + "CdkTable with sticky positioning on native table layout should stick and unstick left columns": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "FW-856: Attempting to access content children before view is initialized" + }, + "CdkTable with sticky positioning on native table layout should stick and unstick right columns": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "FW-856: Attempting to access content children before view is initialized" + }, + "CdkTable with sticky positioning on native table layout should stick and unstick combination of sticky header, footer, and columns": { + "error": "TypeError: Cannot read property 'elementRef' of undefined", + "notes": "FW-856: Attempting to access content children before view is initialized" + }, + "CdkTable with trackBy should add/remove/move rows with reference-based trackBy": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with trackBy should add/remove/move rows with changed references without property-based trackBy": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with trackBy should add/remove/move rows with changed references with property-based trackBy": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with trackBy should add/remove/move rows with changed references with index-based trackBy": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable with trackBy should change row implicit data even when trackBy finds no changes": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should match the right table content with dynamic data source": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should be able to apply classes to rows based on their context": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTable should be able to apply classes to cells based on their row context": { + "error": "TypeError: Cannot read property 'viewContainer' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkDrag standalone draggable should enable native drag interactions when there is a drag handle": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should not be able to drag the entire element if it has a handle": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should be able to drag an element using its handle": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should not be able to drag the element if the handle is disabled": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should not be able to drag using the handle if the element is disabled": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should be able to use a handle that was added after init": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should be able to use more than one handle to drag the element": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should be able to drag with a handle that is not a direct descendant": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should disable the tap highlight while dragging via the handle": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag draggable with a handle should preserve any existing `webkitTapHighlightColor`": { + "error": "TypeError: Cannot read property 'removeEventListener' of null", + "notes": "FW-1010: onDestroy hook is called twice for directives that are also used in a provider" + }, + "CdkDrag in a drop container should be able to customize the preview element": { + "error": "Error: Expected cdk-drag cdk-drag-preview to contain 'custom-preview'.", + "notes": "Unknown" + }, + "CdkDrag in a drop container should position custom previews next to the pointer": { + "error": "Error: Expected 'translate3d(8px, 33px, 0px)' to be 'translate3d(50px, 50px, 0px)'.", + "notes": "Unknown" + }, + "CdkDrag in a drop container should lock position inside a drop container along the x axis": { + "error": "Error: Expected 'translate3d(58px, 33px, 0px)' to be 'translate3d(100px, 50px, 0px)'.", + "notes": "Unknown" + }, + "CdkDrag in a drop container should lock position inside a drop container along the y axis": { + "error": "Error: Expected 'translate3d(8px, 83px, 0px)' to be 'translate3d(50px, 100px, 0px)'.", + "notes": "Unknown" + }, + "CdkDrag in a drop container should inherit the position locking from the drop container": { + "error": "Error: Expected 'translate3d(58px, 33px, 0px)' to be 'translate3d(100px, 50px, 0px)'.", + "notes": "Unknown" + }, + "CdkDrag in a drop container should be able to customize the placeholder": { + "error": "Error: Expected cdk-drag cdk-drag-placeholder to contain 'custom-placeholder'.", + "notes": "Unknown" + }, + "CdkTree should clear out the `mostRecentTreeNode` on destroy": { + "error": "Error: Expected false to be true.", + "notes": "Unknown" + }, + "CdkTree flat tree should initialize with a connected data source": { + "error": "TypeError: Cannot read property 'dataSource' of undefined", + "notes": "Unknown" + }, + "CdkTree flat tree should initialize with rendered dataNodes": { + "error": "TypeError: Cannot read property 'classList' of undefined", + "notes": "Unknown" + }, + "CdkTree flat tree with toggle should expand/collapse the node": { + "error": "TypeError: Cannot read property 'click' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTree flat tree with toggle should expand/collapse the node recursively": { + "error": "TypeError: Cannot read property 'click' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTree flat tree with trackBy should add/remove/move nodes with reference-based trackBy": { + "error": "TypeError: Cannot read property 'getAttribute' of undefined", + "notes": "Unknown" + }, + "CdkTree flat tree with trackBy should add/remove/move nodes with property-based trackBy": { + "error": "TypeError: Cannot read property 'getAttribute' of undefined", + "notes": "Unknown" + }, + "CdkTree flat tree with trackBy should add/remove/move nodes with index-based trackBy": { + "error": "TypeError: Cannot read property 'getAttribute' of undefined", + "notes": "Unknown" + }, + "CdkTree nested tree should initialize with a connected data source": { + "error": "TypeError: Cannot read property 'dataSource' of undefined", + "notes": "Unknown" + }, + "CdkTree nested tree should initialize with rendered dataNodes": { + "error": "TypeError: Cannot read property 'classList' of undefined", + "notes": "Unknown" + }, + "CdkTree nested tree with toggle should expand/collapse the node multiple times": { + "error": "TypeError: Cannot read property 'click' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTree nested tree with toggle should expand/collapse the node recursively": { + "error": "TypeError: Cannot read property 'click' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "CdkTree nested tree with trackBy should add/remove/move children nodes with reference-based trackBy": { + "error": "Error: Expected 0 to be 3.", + "notes": "Unknown" + }, + "CdkTree nested tree with trackBy should add/remove/move children nodes with property-based trackBy": { + "error": "Error: Expected 0 to be 3.", + "notes": "Unknown" + }, + "CdkTree nested tree with trackBy should add/remove/move children nodes with index-based trackBy": { + "error": "Error: Expected 0 to be 3.", + "notes": "Unknown" + }, + "CdkTree nested tree should throw an error when missing function in nested tree": { + "error": "Error: Expected function to throw an exception with message 'Could not find functions for nested/flat tree in tree control.', but it threw an exception with message 'Cannot read property 'viewContainer' of undefined'.", + "notes": "Unknown" + }, + "CdkTree nested tree should throw an error when missing function in flat tree": { + "error": "Error: Expected function to throw an exception with message 'Could not find functions for nested/flat tree in tree control.', but it threw an exception with message 'Cannot read property 'viewContainer' of undefined'.", + "notes": "Unknown" + }, + "CdkTree with depth should have correct depth for nested tree": { + "error": "Error: Expected 0 to be 5.", + "notes": "Unknown" + }, + "MatButton should apply class based on color attribute": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "Unknown" + }, + "MatButton should expose the ripple instance": { + "error": "Error: Expected undefined to be truthy.", + "notes": "Unknown" + }, + "MatButton should not clear previous defined classes": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton button[mat-fab] should have accent palette by default": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton button[mat-mini-fab] should have accent palette by default": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton button[mat-button] should not increment if disabled": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton button[mat-button] should disable the native button element": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton a[mat-button] should not redirect if disabled": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton a[mat-button] should remove tabindex if disabled": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton a[mat-button] should add aria-disabled attribute if disabled": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton a[mat-button] should not add aria-disabled attribute if disabled is false": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton a[mat-button] should be able to set a custom tabindex": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton button ripples should disable the ripple if matRippleDisabled input is set": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatButton button ripples should disable the ripple when the button is disabled": { + "error": "Error: Template error: Can't bind to 'disabled' since it isn't a known property of 'a'.", + "notes": "FW-1037: Host bindings for host objects in metadata are inherited" + }, + "MatTabHeader focusing should initialize to the selected index": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should send focus change event": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should not set focus a disabled tab": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should move focus right and skip disabled tabs": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should move focus left and skip disabled tabs": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should support key down events to move and select focus": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should move focus to the first tab when pressing HOME": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should skip disabled items when moving focus using HOME": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should move focus to the last tab when pressing END": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader focusing should skip disabled items when moving focus using END": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader pagination ltr should show width when tab list width exceeds container": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader pagination ltr should scroll to show the focused tab label": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader pagination ltr should show ripples for pagination buttons": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader pagination ltr should allow disabling ripples for pagination buttons": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader pagination rtl should scroll to show the focused tab label": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader pagination should re-align the ink bar when the direction changes": { + "error": "TypeError: Cannot read property '_inkBar' of undefined", + "notes": "Unknown" + }, + "MatTabHeader pagination should re-align the ink bar when the window is resized": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatTabHeader pagination should update arrows when the window is resized": { + "error": "Error: : could not find an object to spy upon for _checkPaginationEnabled()", + "notes": "Unknown" + }, + "MatTabHeader pagination should update the pagination state if the content of the labels changes": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "FW-1019: Design new API to replace static queries" + }, + "MatChipList StandardChipList basic behaviors should toggle the chips disabled state based on whether it is disabled": { + "error": "Error: Expected true to be false.", + "notes": "Unknown" + }, + "MatChipList StandardChipList focus behaviors should focus the first chip on focus": { + "error": "Error: Expected -1 to be 0.", + "notes": "Unknown" + }, + "MatChipList StandardChipList focus behaviors should watch for chip focus": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList focus behaviors on chip destroy should focus the next item": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList focus behaviors on chip destroy should focus the previous item": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList focus behaviors on chip destroy should not focus if chip list is not focused": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList keyboard behavior LTR (default) should focus previous item when press LEFT ARROW": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList keyboard behavior LTR (default) should focus next item when press RIGHT ARROW": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList keyboard behavior LTR (default) should focus the first item when pressing HOME": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList keyboard behavior RTL should focus previous item when press RIGHT ARROW": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList keyboard behavior RTL should focus next item when press LEFT ARROW": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList StandardChipList keyboard behavior should account for the direction changing": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatChipList FormFieldChipList keyboard behavior should maintain focus if the active chip is deleted": { + "error": "TypeError: Cannot read property 'nativeElement' of null", + "notes": "Unknown" + }, + "MatChipList FormFieldChipList keyboard behavior when the input has focus should not focus the last chip when press DELETE": { + "error": "TypeError: Cannot read property 'nativeElement' of null", + "notes": "Unknown" + }, + "MatChipList FormFieldChipList keyboard behavior when the input has focus should focus the last chip when press BACKSPACE": { + "error": "TypeError: Cannot read property 'nativeElement' of null", + "notes": "Unknown" + }, + "MatChipList FormFieldChipList should complete the stateChanges stream on destroy": { + "error": "TypeError: Cannot read property 'nativeElement' of null", + "notes": "Unknown" + }, + "MatChipList FormFieldChipList should point the label id to the chip input": { + "error": "TypeError: Cannot read property 'nativeElement' of null", + "notes": "Unknown" + }, + "MatChipList with chip remove should properly focus next item if chip is removed through click": { + "error": "TypeError: Cannot read property 'focus' of undefined", + "notes": "MatChipList does not find MatChip content children because descendants is not true anymore. TODO: Fix spec so that it does not have the wrapping div" + }, + "MatStepper basic stepper should go to next available step when the next button is clicked": { + "error": "Error: Expected 2 to be 1.", + "notes": "Unknown" + }, + "MatStepper basic stepper should go to previous available step when the previous button is clicked": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "MatStepper basic stepper should not set focus on header of selected step if header is not clicked": { + "error": "Error: Expected 2 to be 1.", + "notes": "Unknown" + }, + "MatStepper basic stepper should focus next step header if focus is inside the stepper": { + "error": "Error: Expected 2 to be 1.", + "notes": "Unknown" + }, + "MatStepper basic stepper should only be able to return to a previous step if it is editable": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "MatStepper basic stepper should set the correct aria-posinset and aria-setsize": { + "error": "Error: Expected $.length = 0 to equal 3.", + "notes": "Unknown" + }, + "MatStepper basic stepper should adjust the index when removing a step before the current one": { + "error": "Error: Expected 2 to be 1.", + "notes": "Unknown" + }, + "MatStepper linear stepper should not move to next step if current step is pending": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "MatStepper aria labelling should not set aria-label or aria-labelledby attributes if they are not passed in": { + "error": "TypeError: Cannot read property 'hasAttribute' of null", + "notes": "Unknown" + }, + "MatStepper aria labelling should set the aria-label attribute": { + "error": "TypeError: Cannot read property 'getAttribute' of null", + "notes": "Unknown" + }, + "MatStepper aria labelling should set the aria-labelledby attribute": { + "error": "TypeError: Cannot read property 'getAttribute' of null", + "notes": "Unknown" + }, + "MatStepper aria labelling should not be able to set both an aria-label and aria-labelledby": { + "error": "TypeError: Cannot read property 'getAttribute' of null", + "notes": "Unknown" + }, + "MatStepper stepper with error state should show error state": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "MatStepper stepper with error state should respect a custom falsy hasError value": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "MatStepper stepper using Material UI Guideline logic should show done state when step is completed and its not the current step": { + "error": "TypeError: Cannot read property 'nativeElement' of undefined", + "notes": "Unknown" + }, + "MatSlideToggle without forms custom action configuration should not change value on dragging when drag action is noop": { + "error": "Error: Expected mat-slide-toggle-thumb-container to contain 'mat-dragging'.", + "notes": "Unknown" + }, + "MatSlideToggle without forms custom action configuration should not change value on click when click action is noop": { + "error": "TypeError: this._inputElement is undefined", + "notes": "Unknown" + }, + "MatDrawer methods should be able to open": { + "error": "Error: Expected 0 to be 1.", + "notes": "Unknown" + }, + "MatDrawer methods should be able to close": { + "error": "Error: Expected 0 to be 1.", + "notes": "Unknown" + }, + "MatDrawer methods should be able to close while the open animation is running": { + "error": "Error: Expected 0 to be 1.", + "notes": "Unknown" + }, + "MatDrawer methods should close when pressing escape": { + "error": "Error: Expected 0 to be 1, 'Expected one open event.'.", + "notes": "Unknown" + }, + "MatDrawer methods should fire the open event when open on init": { + "error": "Error: Expected spy open callback to have been called once. It was called 0 times.", + "notes": "Unknown" + }, + "MatDrawer methods should restore focus on close if focus is inside drawer": { + "error": "Error: Expected to be