diff --git a/.bazelrc b/.bazelrc index 49d20925c2..c1321d4bf9 100644 --- a/.bazelrc +++ b/.bazelrc @@ -43,6 +43,7 @@ test --incompatible_strict_action_env # 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" +build:release --stamp ############################### # Output # @@ -111,6 +112,16 @@ build:remote --project_id=internal-200822 build:remote --remote_cache=remotebuildexecution.googleapis.com build:remote --remote_executor=remotebuildexecution.googleapis.com +################################## +# Saucelabs tests settings # +# Turn on these settings with # +# --config=saucelabs # +################################## + +# For saucelabs tests we don't want to enable flaky test attempts. Karma has its own integrated +# retry mechanism and we do not want to retry unnecessarily if Karma already tried multiple times. +test:saucelabs --flaky_test_attempts=1 + ############################### # NodeJS rules settings # These settings are required for rules_nodejs diff --git a/.circleci/bazel.common.rc b/.circleci/bazel.common.rc index ab84c0ed80..f70a957aea 100644 --- a/.circleci/bazel.common.rc +++ b/.circleci/bazel.common.rc @@ -13,7 +13,3 @@ test --flaky_test_attempts=2 # More details on failures build --verbose_failures=true - -# For saucelabs tests we don't want to enable flaky test attempts. Karma has its own integrated -# retry mechanism and we do not want to retry unnecessarily if Karma already tried multiple times. -test:saucelabs --flaky_test_attempts=1 diff --git a/.circleci/bazel.linux.rc b/.circleci/bazel.linux.rc index f79956d523..4889f934b2 100644 --- a/.circleci/bazel.linux.rc +++ b/.circleci/bazel.linux.rc @@ -4,7 +4,7 @@ # Import config items common to both Linux and Windows setups. # https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics -import %workspace%/.circleci/bazel.common.rc +try-import %workspace%/.circleci/bazel.common.rc # 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. @@ -15,3 +15,7 @@ build --repository_cache=/home/circleci/bazel_repository_cache # 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 + +# All build executed remotely should be done using our RBE configuration. +build:remote --google_default_credentials +build --config=remote diff --git a/.circleci/bazel.windows.rc b/.circleci/bazel.windows.rc index eee8e7e791..9efa954554 100644 --- a/.circleci/bazel.windows.rc +++ b/.circleci/bazel.windows.rc @@ -4,7 +4,7 @@ # Import config items common to both Linux and Windows setups. # https://docs.bazel.build/versions/master/guide.html#bazelrc-syntax-and-semantics -import %workspace%/.circleci/bazel.common.rc +try-import %workspace%/.circleci/bazel.common.rc # 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. diff --git a/.circleci/config.yml b/.circleci/config.yml index ead922855a..df4fc03619 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,15 +22,15 @@ version: 2.1 # **NOTE 1 **: If you change the cache key prefix, also sync the cache_key_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 v3-angular-node-10.16-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} -var_4: &cache_key_fallback v3-angular-node-10.16- -var_3_win: &cache_key_win v5-angular-win-node-12.0-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} -var_4_win: &cache_key_win_fallback v5-angular-win-node-12.0- +var_3: &cache_key v3-angular-node-12-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} +var_4: &cache_key_fallback v3-angular-node-12- +var_3_win: &cache_key_win v5-angular-win-node-12-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} +var_4_win: &cache_key_win_fallback v5-angular-win-node-12- -# Cache key for the Material unit tests job. **Note** when updating the SHA in the cache keys, -# also update the SHA for the "MATERIAL_REPO_COMMIT" environment variable. -var_5: &material_unit_tests_cache_key v5-angular-material-c734deb14bb28579ba59e7e065a39e3c4ed54458 -var_6: &material_unit_tests_cache_key_fallback v5-angular-material- +# Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the +# cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable. +var_5: &components_repo_unit_tests_cache_key v5-angular-components-97a7e2babbccd3dc58e7b3364004e45ed5bd9968 +var_6: &components_repo_unit_tests_cache_key_fallback v5-angular-components- # Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages` and # `build-ivy-npm-packages`. @@ -74,7 +74,7 @@ executors: type: string default: medium docker: - - image: circleci/node:10.16@sha256:75c05084fff4afa3683a03c5a04a4a3ad95c536ff2439d8fe14e7e1f5c58b09a + - image: circleci/node:12.14.1@sha256:f9de24fc0017059cc42ef7d07db060008af65a98b1f0cdd1ef3339213226bf6d resource_class: << parameters.resource_class >> working_directory: ~/ng @@ -88,7 +88,7 @@ executors: # 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. - - image: circleci/node:10.16-browsers@sha256:d2a96fe1cbef51257ee626b5f645e64dade3e886f00ba9cb7e8ea65b4efe8db1 + - image: circleci/node:12.14.1-browsers@sha256:792797ab9be3179be7c9fc38a0931a3349288e699467c8d646d7c54e148ae46c resource_class: << parameters.resource_class >> working_directory: ~/ng @@ -172,37 +172,11 @@ commands: - *cache_key_win_fallback # Reinstall to get windows binaries. - run: yarn install --frozen-lockfile --non-interactive - - setup_circleci_bazel_config_win # Install @bazel/bazel globally and use that for the first run. # Workaround for https://github.com/bazelbuild/rules_nodejs/issues/894 - run: yarn global add @bazel/bazel@$env:BAZEL_VERSION - run: bazel info - setup_circleci_bazel_config: - description: Set up CircleCI bazel configuration on Linux - steps: - - run: sudo cp .circleci/bazel.linux.rc $HOME/.bazelrc - - setup_circleci_bazel_config_win: - description: Set up CircleCI bazel configuration on Windows - steps: - - run: copy .circleci\bazel.windows.rc $env:USERPROFILE\.bazelrc - - run: mkdir $env:APPDATA\gcloud - # We need ensure that the same default digest is used for encoding and decoding - # with openssl. Openssl versions might have different default digests which can - # cause decryption failures based on the openssl version. https://stackoverflow.com/a/39641378/4317734 - - run: openssl aes-256-cbc -d -in .circleci\gcp_token -md md5 -out "$env:APPDATA\gcloud\application_default_credentials.json" -k "$env:CIRCLE_PROJECT_REPONAME" - - setup_bazel_rbe: - description: Setup bazel RBE remote execution - steps: - # We need ensure that the same default digest is used for encoding and decoding - # with openssl. Openssl versions might have different default digests which can - # cause decryption failures based on the openssl version. https://stackoverflow.com/a/39641378/4317734 - - run: openssl aes-256-cbc -d -in .circleci/gcp_token -md md5 -k "$CI_REPO_NAME" -out /home/circleci/.gcp_credentials - - run: echo "export GOOGLE_APPLICATION_CREDENTIALS=/home/circleci/.gcp_credentials" >> $BASH_ENV - - run: ./.circleci/setup-rbe.sh .bazelrc.user - notify_webhook_on_fail: description: Notify a webhook about failure parameters: @@ -278,7 +252,6 @@ jobs: (echo -e "\n.bzl files have lint errors. Please run ''yarn bazel:lint-fix''"; exit 1)' - run: yarn gulp lint - - run: node tools/verify-codeownership test: executor: @@ -287,9 +260,6 @@ jobs: steps: - custom_attach_workspace - init_environment - - setup_circleci_bazel_config - # Setup remote execution and run RBE-compatible tests. - - setup_bazel_rbe - run: command: yarn bazel test //... --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only no_output_timeout: 20m @@ -302,12 +272,9 @@ jobs: steps: - custom_attach_workspace - init_environment - - setup_circleci_bazel_config - - setup_bazel_rbe - - # We need to explicitly specify the --symlink_prefix option because otherwise we would - # not be able to easily find the output bin directory when uploading artifacts for size - # measurements. + # We need to explicitly specify the --symlink_prefix option because otherwise we would + # not be able to easily find the output bin directory when uploading artifacts for size + # measurements. - run: command: yarn test-ivy-aot //... --symlink_prefix=dist/ no_output_timeout: 20m @@ -346,22 +313,16 @@ jobs: steps: - custom_attach_workspace - init_environment - - setup_circleci_bazel_config - - setup_bazel_rbe - run: - name: Run Bazel tests in saucelabs - # All web tests are contained within a single //:saucelabs_unit_tests_poc target - # for Saucelabs as running each set of tests as a separate target will attempt to acquire - # too many browsers on Saucelabs (7 per target currently) and some tests will always - # fail to acquire browsers. For example: - # 14 02 2019 19:52:33.170:WARN [launcher]: chrome beta on SauceLabs have not captured in 180000 ms, killing. - # //packages/forms/test:web_test_sauce TIMEOUT in 315.0s - command: | - ./scripts/saucelabs/run-bazel-via-tunnel.sh \ - --tunnel-id angular-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX} \ - --username $SAUCE_USERNAME \ - --key $(echo $SAUCE_ACCESS_KEY | rev) \ - -- yarn bazel test //:saucelabs_unit_tests_poc --config=saucelabs + name: Preparing environment for running tests on Saucelabs. + command: setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev) + - run: + name: Run Bazel tests on Saucelabs + # See /tools/saucelabs/README.md for more info + command: | + yarn bazel run //tools/saucelabs:sauce_service_setup + yarn bazel test //:saucelabs_unit_tests_poc_suite --config=saucelabs + yarn bazel run //tools/saucelabs:sauce_service_stop no_output_timeout: 20m - notify_webhook_on_fail: webhook_url_env_var: SLACK_DEV_INFRA_CI_FAILURES_WEBHOOK_URL @@ -376,17 +337,16 @@ jobs: steps: - custom_attach_workspace - init_environment - - setup_circleci_bazel_config - - setup_bazel_rbe + - run: + name: Preparing environment for running tests on Saucelabs. + command: setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev) - run: name: Run Bazel tests on Saucelabs - # Runs the //:saucelabs_tests target with Saucelabs and Ivy. - command: | - ./scripts/saucelabs/run-bazel-via-tunnel.sh \ - --tunnel-id angular-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX} \ - --username $SAUCE_USERNAME \ - --key $(echo $SAUCE_ACCESS_KEY | rev) \ - -- yarn bazel test //:saucelabs_unit_tests --config=ivy --config=saucelabs + # See /tools/saucelabs/README.md for more info + command: | + yarn bazel run //tools/saucelabs:sauce_service_setup + yarn bazel test //:saucelabs_unit_tests --config=saucelabs --config=ivy + yarn bazel run //tools/saucelabs:sauce_service_stop no_output_timeout: 20m test_aio: @@ -532,9 +492,6 @@ jobs: steps: - custom_attach_workspace - init_environment - - setup_circleci_bazel_config - - setup_bazel_rbe - - run: node scripts/build-packages-dist.js # Save the npm packages from //packages/... for other workflow jobs to read @@ -560,9 +517,6 @@ jobs: steps: - custom_attach_workspace - init_environment - - setup_circleci_bazel_config - - setup_bazel_rbe - - run: node scripts/build-ivy-npm-packages.js # Save the npm packages from //packages/... for other workflow jobs to read @@ -663,16 +617,15 @@ jobs: - init_environment - run: setPublicVar_CI_STABLE_BRANCH - run: - name: Check out `aio/` and `third_party/github.com/yarnpkg/` from the stable branch + name: Check out `aio/` and yarn from the stable branch command: | - localYarnDir=third_party/github.com/yarnpkg/ - # Remove the directory to ensure there will be only one version available (the one - # checked out from the stable branch below). - rm -rf $localYarnDir git fetch origin $CI_STABLE_BRANCH - git checkout --force origin/$CI_STABLE_BRANCH -- aio/ $localYarnDir + git checkout --force origin/$CI_STABLE_BRANCH -- aio/ .yarn/ .yarnrc # Overwrite yarn again to use the version from the checked out branch. - overwrite_yarn + # Ignore yarn's engines check, because we checked out `aio/package.json` from the stable + # branch and there could be a node version skew, which is acceptable in this monitoring job. + - run: yarn config set ignore-engines true - run: name: Run tests against https://angular.io/ command: ./aio/scripts/test-production.sh https://angular.io/ $CI_AIO_MIN_PWA_SCORE @@ -712,71 +665,69 @@ jobs: 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 + name: Starting Saucelabs tunnel service + command: ./tools/saucelabs/sauce-service.sh run background: true - run: yarn tsc -p packages - run: yarn tsc -p modules - run: yarn bazel build //packages/zone.js:npm_package - # 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: + # Waiting on ready ensures that we don't run tests too early without Saucelabs not being ready. + name: Waiting for Saucelabs tunnel to connect + command: ./tools/saucelabs/sauce-service.sh ready-wait - run: yarn karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS} - - run: ./scripts/saucelabs/stop-tunnel.sh + - run: + name: Stop Saucelabs tunnel service + command: ./tools/saucelabs/sauce-service.sh stop - legacy-misc-tests: - executor: default-executor - steps: - - custom_attach_workspace - - init_environment - - 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/components. Needs a browser since all - # component unit tests assume they're running in the browser environment. - material-unit-tests: + # Job that runs all unit tests of the `angular/components` repository. + components-repo-unit-tests: executor: - name: browsers-executor + name: default-executor resource_class: xlarge steps: - custom_attach_workspace - init_environment - # Although RBE is configured below for the Material repo, also setup RBE in the Angular repo - # to provision Angular's GCP token into the environment variables. - - setup_bazel_rbe # Restore the cache before cloning the repository because the clone script re-uses # the restored repository if present. This reduces the amount of times the components # repository needs to be cloned (this is slow and increases based on commits in the repo). - restore_cache: keys: - - *material_unit_tests_cache_key - - *material_unit_tests_cache_key_fallback + - *components_repo_unit_tests_cache_key + # Whenever the `angular/components` SHA is updated, the cache key will no longer + # match. The fallback cache will still match, and CircleCI will restore the most + # recently cached repository folder. Without the fallback cache, we'd need to download + # the repository from scratch and it would slow down the job. This is because we can't + # clone the repository with reduced `--depth`, but rather need to clone the whole + # repository to be able to support arbitrary SHAs. + - *components_repo_unit_tests_cache_key_fallback - run: - name: "Fetching Material repository" - command: ./scripts/ci/clone_angular_material_repo.sh + name: "Fetching angular/components repository" + command: ./scripts/ci/clone_angular_components_repo.sh - run: - # Run yarn install to fetch the Bazel binaries as used in the Material repo. - name: Installing Material dependencies. + # Run yarn install to fetch the Bazel binaries as used in the components repo. + name: Installing dependencies. # TODO: remove this once the repo has been updated to use NodeJS v12 and Yarn 1.19.1. # We temporarily ignore the "engines" because the Angular components repository has # minimum dependency on NodeJS v12 and Yarn 1.19.1, but the framework repository uses # older versions. - command: yarn --ignore-engines --cwd ${MATERIAL_REPO_TMP_DIR} install --frozen-lockfile --non-interactive + command: yarn --ignore-engines --cwd ${COMPONENTS_REPO_TMP_DIR} install --frozen-lockfile --non-interactive - save_cache: - key: *material_unit_tests_cache_key + key: *components_repo_unit_tests_cache_key paths: - # Material directory must be kept in sync with the `$MATERIAL_REPO_TMP_DIR` env variable. - # It needs to be hardcoded here, because env variables interpolation is not supported. - - "/tmp/material2" + # Temporary directory must be kept in sync with the `$COMPONENTS_REPO_TMP_DIR` env + # variable. It needs to be hardcoded here, because env variables interpolation is + # not supported. + - "/tmp/angular-components-repo" - run: - name: "Setup Bazel RBE remote execution in Material repo" - command: | - ./.circleci/setup-rbe.sh "${MATERIAL_REPO_TMP_DIR}/.bazelrc.user" + # Updates the `angular/components` `package.json` file to refer to the release output + # inside the `packages-dist` directory. Note that it's not necessary to perform a yarn + # install as Bazel runs Yarn automatically when needed. + name: Setting up release packages. + command: node scripts/ci/update-deps-to-dist-packages.js ${COMPONENTS_REPO_TMP_DIR}/package.json dist/packages-dist/ - run: - name: "Running Material unit tests" - command: ./scripts/ci/run_angular_material_unit_tests.sh + name: "Running `angular/components` unit tests" + command: ./scripts/ci/run_angular_components_unit_tests.sh | exit 0 test_zonejs: executor: @@ -785,8 +736,6 @@ jobs: steps: - custom_attach_workspace - init_environment - - setup_circleci_bazel_config - - setup_bazel_rbe # Install - run: yarn --cwd packages/zone.js install --frozen-lockfile --non-interactive # Run zone.js tools tests @@ -848,15 +797,12 @@ workflows: - build-ivy-npm-packages: requires: - setup - - legacy-misc-tests: - requires: - - build-npm-packages - legacy-unit-tests-saucelabs: requires: - setup - saucelabs_ivy: - requires: - - test_ivy_aot + requires: + - test_ivy_aot - saucelabs_view_engine: # This job is currently a PoC and a subset of `legacy-unit-tests-saucelabs`. Running on # master only to avoid wasting resources. @@ -925,10 +871,10 @@ workflows: - build-npm-packages - build-ivy-npm-packages - legacy-unit-tests-saucelabs - - legacy-misc-tests - - material-unit-tests: - requires: - - build-npm-packages + # FIXME - uncomment this job once https://github.com/angular/components/pull/18355 lands + # - components-repo-unit-tests: + # requires: + # - build-npm-packages - test_zonejs: requires: - setup diff --git a/.circleci/env.sh b/.circleci/env.sh index f9734fbfa5..f38beb05e0 100755 --- a/.circleci/env.sh +++ b/.circleci/env.sh @@ -23,7 +23,7 @@ setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL"; # `.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 75.0.3770.90"; +setPublicVar CI_CHROMEDRIVER_VERSION_ARG "--versions.chrome 79.0.3945.130"; setPublicVar CI_COMMIT "$CIRCLE_SHA1"; # `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun # workflows of such builds). @@ -66,16 +66,34 @@ setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-framework-${CIRCLE_BUILD_NUM}-${CI setPublicVar SAUCE_READY_FILE_TIMEOUT 120 #################################################################################################### -# Define environment variables for the Angular Material unit tests job. +# Define environment variables for the `angular/components` repo unit tests job. #################################################################################################### # We specifically use a directory within "/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. -setPublicVar MATERIAL_REPO_TMP_DIR "/tmp/material2" -setPublicVar MATERIAL_REPO_URL "https://github.com/angular/material2.git" -setPublicVar MATERIAL_REPO_BRANCH "master" -# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI "config.yml". -setPublicVar MATERIAL_REPO_COMMIT "c734deb14bb28579ba59e7e065a39e3c4ed54458" +# their separate build setups. **NOTE**: When updating the temporary directory, also update +# the `save_cache` path configuration in `config.yml` +setPublicVar COMPONENTS_REPO_TMP_DIR "/tmp/angular-components-repo" +setPublicVar COMPONENTS_REPO_URL "https://github.com/angular/components.git" +setPublicVar COMPONENTS_REPO_BRANCH "master" +# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`. +setPublicVar COMPONENTS_REPO_COMMIT "97a7e2babbccd3dc58e7b3364004e45ed5bd9968" -# Source `$BASH_ENV` to make the variables available immediately. + +#################################################################################################### +# Decrypt GCP Credentials and store them as the Google default credentials. +#################################################################################################### +mkdir -p "$HOME/.config/gcloud"; +openssl aes-256-cbc -d -in "${projectDir}/.circleci/gcp_token" \ + -md md5 -k "$CIRCLE_PROJECT_REPONAME" -out "$HOME/.config/gcloud/application_default_credentials.json" +#################################################################################################### +# Set bazel configuration for CircleCI runs. +#################################################################################################### +cp "${projectDir}/.circleci/bazel.linux.rc" "$HOME/.bazelrc"; + +#################################################################################################### +#################################################################################################### +## Source `$BASH_ENV` to make the variables available immediately. ## +## ***NOTE: This must remain the the last action in this script*** ## +#################################################################################################### +#################################################################################################### source $BASH_ENV; diff --git a/.circleci/setup-rbe.sh b/.circleci/setup-rbe.sh deleted file mode 100755 index 07bbc6bd5d..0000000000 --- a/.circleci/setup-rbe.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -u -e -o pipefail - -# The path of the .bazelrc.user file to update should be passed as first parameter to this script. -# This allows to setup RBE for both the Angular repo and the Material repo. -bazelrc_user="$1" - -echo "Writing RBE configuration to ${bazelrc_user}" - -touch ${bazelrc_user} -echo -e 'build --config=remote\n' >> ${bazelrc_user} -echo -e 'build:remote --remote_accept_cached=true\n' >> ${bazelrc_user} -echo "Reading from remote cache for bazel remote jobs." -if [[ "$CI_PULL_REQUEST" == "false" ]]; then - echo -e 'build:remote --remote_upload_local_results=true\n' >> ${bazelrc_user} - echo "Uploading local build results to remote cache." -else - echo -e 'build:remote --remote_upload_local_results=false\n' >> ${bazelrc_user} - echo "Not uploading local build results to remote cache." -fi diff --git a/.circleci/windows-env.ps1 b/.circleci/windows-env.ps1 index 39008b37b4..a5b065d584 100644 --- a/.circleci/windows-env.ps1 +++ b/.circleci/windows-env.ps1 @@ -27,8 +27,23 @@ Add-Content $profile $bazelVersionGlobalVar git config --global --unset url.ssh://git@github.com.insteadOf +#################################################################################################### +# Decrypt GCP Credentials and store them as the Google default credentials. +#################################################################################################### +mkdir ${env:APPDATA}\gcloud +openssl aes-256-cbc -d -in .circleci\gcp_token -md md5 -out "$env:APPDATA\gcloud\application_default_credentials.json" -k "$env:CIRCLE_PROJECT_REPONAME" + +#################################################################################################### +# Set bazel configuration for CircleCI runs. +#################################################################################################### +copy .circleci\bazel.windows.rc ${Env:USERPROFILE}\.bazelrc + +#################################################################################################### +# Install specific version of node. +#################################################################################################### +choco install nodejs --version 12.14.1 --no-progress + # These Bazel prereqs aren't needed because the CircleCI image already includes them. -# choco install nodejs --version 10.16.0 --no-progress # choco install yarn --version 1.16.0 --no-progress # choco install vcredist2015 --version 14.0.24215.20170201 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 4cfbb5f6a0..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,979 +0,0 @@ -# ================================================================================== -# ================================================================================== -# 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) -# ================================================ - -# alan-agius4 - Alan Agius -# alexeagle - Alex Eagle -# alxhub - Alex Rickabaugh -# AndrewKushnir - Andrew Kushnir -# andrewseguin - Andrew Seguin -# atscott - Andrew Scott -# devversion - Paul Gschwendtner -# filipesilva - Filipe Silva -# gkalpak - George Kalpakas -# IgorMinar - Igor Minar -# JiaLiPassion - Jia Li -# JoostK - Joost Koehoorn -# josephperrott - Joey Perrott -# kapunahelewong - Kapunahele Wong -# kara - Kara Erickson -# kyliau - Keen Yee Liau -# matsko - Matias Niemelä -# mgechev - Minko Gechev -# mhevery - Misko Hevery -# 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 -# - josephperrott -# - 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) -# -# - gkalpak -# - kapunahelewong -# - petebacondarwin - - -# =========================================================== -# @angular/fw-animations -# =========================================================== -# -# - matsko - - -# =========================================================== -# @angular/tools-bazel -# =========================================================== -# -# - alexeagle -# - kyliau -# - IgorMinar -# - mgechev - - -# =========================================================== -# @angular/tools-cli -# =========================================================== -# -# - filipesilva -# - mgechev -# - vikerman - - -# =========================================================== -# @angular/fw-compiler -# =========================================================== -# -# - alxhub -# - AndrewKushnir -# - kara -# - JoostK - - -# =========================================================== -# @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 -# =========================================================== -# -# - AndrewKushnir - - -# =========================================================== -# @angular/tools-language-service -# =========================================================== -# -# - kyliau - - -# =========================================================== -# @angular/fw-server -# =========================================================== -# -# - alxhub -# - vikerman - - -# =========================================================== -# @angular/fw-router -# =========================================================== -# -# - atscott - - -# =========================================================== -# @angular/fw-service-worker -# =========================================================== -# -# - alxhub -# - gkalpak -# - IgorMinar - - -# =========================================================== -# @angular/fw-upgrade -# =========================================================== -# -# - gkalpak -# - petebacondarwin - - -# =========================================================== -# @angular/fw-testing -# =========================================================== -# -# - vikerman - - -# =========================================================== -# @angular/fw-i18n -# =========================================================== -# -# - AndrewKushnir -# - mhevery -# - petebacondarwin -# - vikerman - - -# =========================================================== -# @angular/fw-security -# =========================================================== -# -# - IgorMinar -# - mhevery - - -# =========================================================== -# @angular/fw-zones -# =========================================================== -# -# - JiaLiPassion -# - mhevery -# - vikerman - - -# =========================================================== -# @angular/tools-benchpress -# =========================================================== -# -# - alxhub - - -# =========================================================== -# @angular/fw-integration -# =========================================================== -# -# - IgorMinar -# - josephperrott -# - mhevery - - -# =========================================================== -# @angular/docs-infra -# =========================================================== -# -# - gkalpak -# - IgorMinar -# - petebacondarwin - - -# =========================================================== -# @angular/fw-docs-intro -# =========================================================== -# -# - IgorMinar -# - stephenfluin - - -# =========================================================== -# @angular/fw-docs-observables -# =========================================================== -# -# - alxhub - - -# =========================================================== -# @angular/fw-docs-packaging -# =========================================================== -# -# - IgorMinar -# - vikerman - - -# =========================================================== -# @angular/tools-docs-libraries -# =========================================================== -# -# - alan-agius4 -# - IgorMinar -# - mgechev -# - vikerman - - -# =========================================================== -# @angular/tools-docs-schematics -# =========================================================== -# -# - alan-agius4 -# - IgorMinar -# - mgechev -# - vikerman - - -# =========================================================== -# @angular/fw-docs-marketing -# =========================================================== -# -# - IgorMinar -# - stephenfluin - - -# =========================================================== -# @angular/fw-public-api -# =========================================================== -# -# - IgorMinar - - -# =========================================================== -# @angular/dev-infra-framework -# =========================================================== -# -# - devversion -# - filipesilva -# - gkalpak -# - IgorMinar -# - josephperrott - - -# =========================================================== -# @angular/fw-size-tracking -# =========================================================== -# -# - IgorMinar -# - kara - - - - -###################################################################################################### -# -# 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 - - - -# ================================================ -# Build, CI & Dev-infra Owners -# ================================================ - -/* @angular/dev-infra-framework -/.buildkite/** @angular/dev-infra-framework -/.circleci/** @angular/dev-infra-framework -/.devcontainer/** @angular/dev-infra-framework -/.github/** @angular/dev-infra-framework -/.vscode/** @angular/dev-infra-framework -/docs/BAZEL.md @angular/dev-infra-framework -/packages/* @angular/dev-infra-framework -/packages/examples/test-utils/** @angular/dev-infra-framework -/packages/private/** @angular/dev-infra-framework -/scripts/** @angular/dev-infra-framework -/third_party/** @angular/dev-infra-framework -/tools/build/** @angular/dev-infra-framework -/tools/cjs-jasmine/** @angular/dev-infra-framework -/tools/gulp-tasks/** @angular/dev-infra-framework -/tools/ngcontainer/** @angular/dev-infra-framework -/tools/npm/** @angular/dev-infra-framework -/tools/npm_workspace/** @angular/dev-infra-framework -/tools/public_api_guard/** @angular/dev-infra-framework -/tools/rxjs/** @angular/dev-infra-framework -/tools/size-tracking/** @angular/dev-infra-framework -/tools/source-map-test/** @angular/dev-infra-framework -/tools/symbol-extractor/** @angular/dev-infra-framework -/tools/testing/** @angular/dev-infra-framework -/tools/ts-api-guardian/** @angular/dev-infra-framework -/tools/tslint/** @angular/dev-infra-framework -/tools/validate-commit-message/** @angular/dev-infra-framework -/tools/yarn/** @angular/dev-infra-framework -/tools/* @angular/dev-infra-framework -*.BAZEL @angular/dev-infra-framework -*.bzl @angular/dev-infra-framework - - - -# ================================================ -# @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 - -/aio/content/guide/complex-animation-sequences.md @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - -/aio/content/guide/reusable-animations.md @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - -/aio/content/guide/route-animations.md @angular/fw-animations @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - -/aio/content/guide/transition-and-triggers.md @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 -/aio/content/guide/bazel.md @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/examples/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/angular-compiler-options.md @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 -/aio/content/guide/aot-metadata-errors.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/template-typecheck.md @angular/fw-compiler @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - - - -# ================================================ -# packages/compiler-cli/ngcc/ -# ================================================ - -/packages/compiler-cli/ngcc/** @angular/fw-ngcc @angular/framework-global-approvers - - - -# ================================================ -# Framework/cli integration -# -# 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 -/aio/content/guide/cli-builder.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/ivy.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/web-worker.md @angular/tools-cli @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - - -# ================================================ -# @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/examples/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/examples/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 -/packages/examples/common/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/packages/docs/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - -/aio/content/guide/accessibility.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/accessibility/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - -/aio/content/guide/architecture-components.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/architecture-modules.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/architecture-next-steps.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/architecture-services.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/architecture.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/architecture/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/architecture/** @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/cheatsheet.md @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-navtree.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - -/aio/content/guide/dependency-injection-providers.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - -/aio/content/guide/displaying-data.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/displaying-data/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/displaying-data/** @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/examples/providers-viewproviders/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/resolution-modifiers/** @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/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/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/built-in-template-functions/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/event-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/interpolation/** @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/examples/binding-syntax/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/property-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/attribute-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/two-way-binding/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/built-in-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/built-in-directives/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/template-reference-variables/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/inputs-outputs/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/inputs-outputs/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/template-expression-operators/** @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 - -/aio/content/guide/user-input.md @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/user-input/** @angular/fw-core @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/user-input/** @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 -/packages/examples/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 -/packages/examples/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 -/packages/examples/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 -/packages/examples/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/app-shell.md @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/common/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-lazy-load-ajs/** @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/upgrade-setup.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 -/packages/localize/** @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 -/aio/content/images/guide/security/** @angular/fw-security @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - - - -# ================================================ -# zone.js -# ================================================ - -/packages/zone.js/** @angular/fw-zones @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/content/examples/* @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 - -# Hidden docs -/aio/content/guide/docs-style-guide.md @angular/docs-infra @angular/framework-global-approvers -/aio/content/examples/docs-style-guide/** @angular/docs-infra @angular/framework-global-approvers -/aio/content/images/guide/docs-style-guide/** @angular/docs-infra @angular/framework-global-approvers -/aio/content/guide/visual-studio-2015.md @angular/docs-infra @angular/framework-global-approvers -/aio/content/examples/visual-studio-2015/** @angular/docs-infra @angular/framework-global-approvers - - - -# ================================================ -# Docs: getting started & tutorial -# ================================================ - -/aio/content/guide/setup-local.md @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/setup-local/** @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 -/aio/content/images/guide/toh/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/toh-pt0/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/toh-pt1/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/toh-pt2/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/toh-pt3/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/toh-pt4/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/toh-pt5/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/toh-pt6/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/getting-started-v0/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/getting-started/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/start/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/start/** @angular/fw-docs-intro @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - - -# ================================================ -# Docs: observables -# ================================================ - -/aio/content/guide/observables.md @angular/fw-docs-observables @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/observables/** @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/guide/observables-in-angular.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/guide/practical-observable-usage.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/rx-library.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 - - - -# ================================================ -# 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/examples/setup/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/build.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/build/** @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/images/guide/deployment/** @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/file-structure.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 -/aio/content/guide/workspace-config.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/deprecations.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/migration-renderer.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/migration-undecorated-classes.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/migration-dynamic-flag.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/migration-injectable.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/migration-localize.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/migration-module-with-providers.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/updating-to-version-9.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/ivy-compatibility.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/ivy-compatibility-examples.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - - -# ================================================ -# Docs: libraries -# ================================================ - -/aio/content/guide/creating-libraries.md @angular/tools-docs-libraries @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/libraries.md @angular/tools-docs-libraries @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/using-libraries.md @angular/tools-docs-libraries @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - - -# ================================================ -# Docs: schematics -# ================================================ - -/aio/content/guide/schematics.md @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/schematics-authoring.md @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/guide/schematics-for-libraries.md @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/images/guide/schematics/** @angular/tools-docs-schematics @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes -/aio/content/examples/schematics-for-libraries/** @angular/tools-docs-schematics @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/bios/** @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 - - - -# ================================================ -# Material CI -# ================================================ - -/tools/material-ci/** @angular/fw-core @angular/framework-global-approvers - - - -# ================================================ -# Public API -# ================================================ - -/tools/public_api_guard/** @angular/fw-public-api -/aio/content/guide/glossary.md @angular/fw-public-api -/aio/content/guide/styleguide.md @angular/fw-public-api -/aio/content/examples/styleguide/** @angular/fw-public-api -/aio/content/images/guide/styleguide/** @angular/fw-public-api - - - -# ================================================ -# Size tracking -# ================================================ - -/aio/scripts/_payload-limits.json @angular/fw-size-tracking -/integration/_payload-limits.json @angular/fw-size-tracking - - -# ================================================ -# Special cases -# ================================================ - -/aio/content/guide/static-query-migration.md @kara @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes - - - -# ================================================ -# CODEOWNERS Owners owners ... -# ================================================ - -/.github/CODEOWNERS @IgorMinar @angular/framework-global-approvers diff --git a/.github/angular-robot.yml b/.github/angular-robot.yml index 1c69dcd509..171b2336c1 100644 --- a/.github/angular-robot.yml +++ b/.github/angular-robot.yml @@ -30,7 +30,7 @@ merge: # text to show when the status is success successDesc: "Does not affect google3" # link to use for the details - url: "http://go/angular-g3sync" + url: "http://go/angular/g3sync" # list of patterns to check for the files changed by the PR # this list must be manually kept in sync with google3/third_party/javascript/angular2/copy.bara.sky include: @@ -115,6 +115,7 @@ merge: - "ci/angular: size" - "cla/google" - "google3" + - "pullapprove" # the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable diff --git a/.gitignore b/.gitignore index 8b7a3f78e0..1dfe1345ba 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ /dist/ /bazel-out /integration/bazel/bazel-* -e2e_test.* *.log node_modules diff --git a/.nvmrc b/.nvmrc index db24ab967f..5c088ddb94 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -10.13.0 +12.14.1 diff --git a/.pullapprove.yml b/.pullapprove.yml new file mode 100644 index 0000000000..8477de32ec --- /dev/null +++ b/.pullapprove.yml @@ -0,0 +1,1073 @@ +#################################################################################### +#################################################################################### +# Angular Code Ownership # +#################################################################################### +#################################################################################### +# +# Configuration of code ownership and review approvals for the angular/angular repo. +# +# More info: https://docs.pullapprove.com/ +# +# ========================================================= +# General rules / philosophy +# ========================================================= +# +# - We trust that people do the right thing and won't approve changes they don't feel confident reviewing +# - We enforce that only approved PRs are merged ensuring that unreviewed code isn't accidentally merged +# - We distribute approval rights as much as possible to help us scale better +# - 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. +# - All groups whose pullapprove rules are matched will be required for overall approval. +# +# NOTE: +# In the case of emergency, the repo administrators which include the current angular caretaker +# can bypass this reviewer approval requirement, this is expected as a last resort and to be +# done exceedingly sparingly. + +#################################################################################### +# GitHub usernames +#################################################################################### +# aikidave - Dave Shevitz +# alan-agius4 - Alan Agius +# alxhub - Alex Rickabaugh +# AndrewKushnir - Andrew Kushnir +# andrewseguin - Andrew Seguin +# atscott - Andrew Scott +# clydin - Charles Lyding +# crisbeto - Kristiyan Kostadinov +# dennispbrown - Denny Brown +# devversion - Paul Gschwendtner +# dgp1130 - Doug Parker +# filipesilva - Filipe Silva +# gkalpak - Georgios Kalpakas +# gregmagolan - Greg Magolan +# IgorMinar - Igor Minar +# jbogarthyde - Judy Bogart +# jelbourn - Jeremy Elbourn +# JiaLiPassion - Jia Li +# JoostK - Joost Koehoorn +# josephperrott - Joey Perrott +# juleskremer - Jules Kremer +# kapunahelewong - Kapunahele Wong +# kara - Kara Erickson +# kyliau - Keen Yee Liau +# manughub - Manu Murthy +# matsko - Matias Niemela +# mgechev - Minko Gechev +# mhevery - Miško Hevery +# michaelprentice - Michael Prentice +# mmalerba - Miles Malerba +# petebacondarwin - Pete Bacon Darwin +# pkozlowski-opensource - Pawel Kozlowski +# robwormald - Rob Wormald +# StephenFluin - Stephen Fluin + + +#################################################################################### +# Approval Groups +#################################################################################### +# ========================================================= +# @angular/framework-global-approvers +# ========================================================= +# Used for approving minor changes, large-scale refactorings, and in emergency situations. +# +# IgorMinar +# josephperrott +# kara +# mhevery +# +# ========================================================= +# @angular/framework-global-approvers-for-docs-only-changes +# ========================================================= +# Used for approving minor documentation-only changes that don't require engineering review. +# +# aikidave +# gkalpak +# kapunahelewong +# petebacondarwin + + +version: 3 + +# turn on 'draft' support +# https://docs.pullapprove.com/config/github-api-version/ +# https://developer.github.com/v3/previews/#draft-pull-requests +github_api_version: "shadow-cat-preview" + +pullapprove_conditions: + - condition: "'WIP' not in title" + unmet_status: pending + explanation: "Waiting to send reviews as PR is WIP" + - condition: "'PR state: WIP' not in labels" + unmet_status: pending + explanation: "Waiting to send reviews as PR is WIP" + + +groups: + # ========================================================= + # Framework: Animations + # ========================================================= + fw-animations: + conditions: + - > + contains_any_globs(files, [ + 'packages/animations/**', + 'packages/platform-browser/animations/**', + 'aio/content/guide/animations.md', + 'aio/content/examples/animations/**', + 'aio/content/images/guide/animations/**', + 'aio/content/guide/complex-animation-sequences.md', + 'aio/content/guide/reusable-animations.md', + 'aio/content/guide/route-animations.md', + 'aio/content/guide/transition-and-triggers.md' + ]) + reviewers: + users: + - matsko + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Compiler + # ========================================================= + fw-compiler: + conditions: + - > + contains_any_globs(files, [ + 'packages/compiler/**', + 'packages/examples/compiler/**', + 'packages/compiler-cli/**', + 'aio/content/guide/angular-compiler-options.md', + 'aio/content/guide/aot-compiler.md', + 'aio/content/guide/aot-metadata-errors.md', + 'aio/content/guide/template-typecheck.md ' + ]) + reviewers: + users: + - alxhub + - AndrewKushnir + - JoostK + - kara + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Compiler / ngcc + # ========================================================= + fw-ngcc: + conditions: + - > + contains_any_globs(files, [ + 'packages/compiler-cli/ngcc/**' + ]) + reviewers: + users: + - alxhub + - gkalpak + - JoostK + - petebacondarwin + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Core + # ========================================================= + fw-core: + conditions: + - > + contains_any_globs(files, [ + 'packages/core/**', + 'packages/examples/core/**', + 'packages/common/**', + 'packages/platform-browser/**', + 'packages/examples/platform-browser/**', + 'packages/platform-browser-dynamic/**', + 'packages/platform-webworker/**', + 'packages/platform-webworker-dynamic/**', + 'packages/examples/common/**', + 'packages/docs/**', + 'aio/content/guide/accessibility.md', + 'aio/content/examples/accessibility/**', + 'aio/content/guide/architecture-components.md', + 'aio/content/guide/architecture-modules.md', + 'aio/content/guide/architecture-next-steps.md', + 'aio/content/guide/architecture-services.md', + 'aio/content/guide/architecture.md', + 'aio/content/examples/architecture/**', + 'aio/content/images/guide/architecture/**', + 'aio/content/guide/attribute-directives.md', + 'aio/content/examples/attribute-directives/**', + 'aio/content/images/guide/attribute-directives/**', + 'aio/content/guide/bootstrapping.md', + 'aio/content/examples/bootstrapping/**', + 'aio/content/guide/cheatsheet.md', + '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/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/dependency-injection-navtree.md', + 'aio/content/guide/dependency-injection-providers.md', + 'aio/content/guide/displaying-data.md', + 'aio/content/examples/displaying-data/**', + 'aio/content/images/guide/displaying-data/**', + 'aio/content/guide/dynamic-component-loader.md', + 'aio/content/examples/dynamic-component-loader/**', + 'aio/content/images/guide/dynamic-component-loader/**', + 'aio/content/guide/entry-components.md', + 'aio/content/guide/feature-modules.md', + 'aio/content/examples/feature-modules/**', + 'aio/content/images/guide/feature-modules/**', + 'aio/content/guide/frequent-ngmodules.md', + 'aio/content/images/guide/frequent-ngmodules/**', + 'aio/content/guide/hierarchical-dependency-injection.md', + 'aio/content/examples/hierarchical-dependency-injection/**', + 'aio/content/examples/providers-viewproviders/**', + 'aio/content/examples/resolution-modifiers/**', + 'aio/content/guide/lazy-loading-ngmodules.md', + 'aio/content/examples/lazy-loading-ngmodules/**', + 'aio/content/images/guide/lazy-loading-ngmodules/**', + 'aio/content/guide/lifecycle-hooks.md', + 'aio/content/examples/lifecycle-hooks/**', + 'aio/content/images/guide/lifecycle-hooks/**', + 'aio/content/examples/ngcontainer/**', + 'aio/content/guide/ngmodules.md', + 'aio/content/examples/ngmodules/**', + 'aio/content/guide/ngmodule-api.md', + 'aio/content/guide/ngmodule-faq.md', + 'aio/content/examples/ngmodule-faq/**', + 'aio/content/guide/ngmodule-vs-jsmodule.md', + 'aio/content/guide/module-types.md', + 'aio/content/guide/template-syntax.md', + 'aio/content/examples/built-in-template-functions/**', + 'aio/content/examples/event-binding/**', + 'aio/content/examples/interpolation/**', + 'aio/content/examples/template-syntax/**', + 'aio/content/images/guide/template-syntax/**', + 'aio/content/examples/binding-syntax/**', + 'aio/content/examples/property-binding/**', + 'aio/content/examples/attribute-binding/**', + 'aio/content/examples/two-way-binding/**', + 'aio/content/examples/built-in-directives/**', + 'aio/content/images/guide/built-in-directives/**', + 'aio/content/examples/template-reference-variables/**', + 'aio/content/examples/inputs-outputs/**', + 'aio/content/images/guide/inputs-outputs/**', + 'aio/content/examples/template-expression-operators/**', + 'aio/content/guide/pipes.md', + 'aio/content/examples/pipes/**', + 'aio/content/images/guide/pipes/**', + 'aio/content/guide/providers.md', + 'aio/content/examples/providers/**', + 'aio/content/guide/singleton-services.md', + 'aio/content/guide/set-document-title.md', + 'aio/content/examples/set-document-title/**', + 'aio/content/images/guide/set-document-title/**', + 'aio/content/guide/sharing-ngmodules.md', + 'aio/content/guide/structural-directives.md', + 'aio/content/examples/structural-directives/**', + 'aio/content/images/guide/structural-directives/**', + 'aio/content/guide/user-input.md', + 'aio/content/examples/user-input/**', + 'aio/content/images/guide/user-input/**' + ]) + reviewers: + users: + - alxhub + - AndrewKushnir + - kara + - mhevery + - pkozlowski-opensource + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Http + # ========================================================= + fw-http: + conditions: + - > + contains_any_globs(files, [ + 'packages/common/http/**', + 'packages/http/**', + 'packages/examples/http/**', + 'aio/content/guide/http.md', + 'aio/content/examples/http/**', + 'aio/content/images/guide/http/**' + ]) + reviewers: + users: + - alxhub + - IgorMinar + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Elements + # ========================================================= + fw-elements: + conditions: + - > + contains_any_globs(files, [ + 'packages/elements/**', + 'aio/content/examples/elements/**', + 'aio/content/images/guide/elements/**', + 'aio/content/guide/elements.md' + ]) + reviewers: + users: + - andrewseguin + - gkalpak + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Forms + # ========================================================= + fw-forms: + conditions: + - > + contains_any_globs(files, [ + 'packages/forms/**', + 'packages/examples/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/**' + ]) + reviewers: + users: + - AndrewKushnir + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: i18n + # ========================================================= + fw-i18n: + conditions: + - > + contains_any_globs(files, [ + 'packages/core/src/i18n/**', + 'packages/core/src/render3/i18n.ts', + 'packages/core/src/render3/i18n.md', + 'packages/core/src/render3/interfaces/i18n.ts', + 'packages/common/locales/**', + 'packages/common/src/i18n/**', + 'packages/common/src/pipes/date_pipe.ts', + 'packages/common/src/pipes/i18n_plural_pipe.ts', + 'packages/common/src/pipes/i18n_select_pipe.ts', + 'packages/common/src/pipes/number_pipe.ts', + 'packages/compiler/src/i18n/**', + 'packages/compiler/src/render3/view/i18n/**', + 'packages/compiler-cli/src/extract_i18n.ts', + 'packages/localize/**', + 'aio/content/guide/i18n.md', + 'aio/content/examples/i18n/**' + ]) + reviewers: + users: + - AndrewKushnir + - mhevery + - petebacondarwin + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Platform Server + # ========================================================= + fw-platform-server: + conditions: + - > + contains_any_globs(files, [ + 'packages/platform-server/**', + 'aio/content/guide/universal.md', + 'aio/content/examples/universal/**' + ]) + reviewers: + users: + - alxhub + - kyliau + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Router + # ========================================================= + fw-router: + conditions: + - > + contains_any_globs(files, [ + 'packages/router/**', + 'packages/examples/router/**', + 'aio/content/guide/router.md', + 'aio/content/examples/router/**', + 'aio/content/images/guide/router/**' + ]) + reviewers: + users: + - atscott + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Service Worker + # ========================================================= + fw-server-worker: + conditions: + - > + contains_any_globs(files, [ + 'packages/service-worker/**', + 'packages/examples/service-worker/**', + 'aio/content/guide/service-worker-getting-started.md', + 'aio/content/examples/service-worker-getting-started/**', + 'aio/content/guide/app-shell.md', + '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/**' + ]) + reviewers: + users: + - alxhub + - gkalpak + - IgorMinar + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Upgrade + # ========================================================= + fw-upgrade: + conditions: + - > + contains_any_globs(files, [ + 'packages/upgrade/**', + 'packages/common/upgrade/**', + 'packages/examples/upgrade/**', + 'aio/content/guide/upgrade.md', + 'aio/content/examples/upgrade-lazy-load-ajs/**', + '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/upgrade-setup.md', + 'aio/content/guide/ajs-quick-reference.md', + 'aio/content/examples/ajs-quick-reference/**' + ]) + reviewers: + users: + - gkalpak + - petebacondarwin + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Testing + # ========================================================= + fw-testing: + conditions: + - > + contains_any_globs(files, [ + '**/testing/**', + 'aio/content/guide/testing.md', + 'aio/content/examples/testing/**', + 'aio/content/images/guide/testing/**' + ]) + reviewers: + users: + - IgorMinar + - kara + - pkozlowski-opensource + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Framework: Benchmarks + # ========================================================= + fw-benchmarks: + conditions: + - > + contains_any_globs(files, [ + 'modules/benchmarks_external/**', + 'modules/benchmarks/**' + ]) + reviewers: + users: + - IgorMinar + - kara + - pkozlowski-opensource + teams: + - ~framework-global-approvers + + + # ========================================================= + # Framework: Playground + # ========================================================= + fw-playground: + conditions: + - > + contains_any_globs(files, [ + 'modules/playground/**' + ]) + reviewers: + users: + - IgorMinar + - kara + teams: + - ~framework-global-approvers + + + # ========================================================= + # Framework: Security + # ========================================================= + fw-security: + conditions: + - > + contains_any_globs(files, [ + 'packages/core/src/sanitization/**', + 'packages/core/test/linker/security_integration_spec.ts', + 'packages/compiler/src/schema/**', + 'packages/platform-browser/src/security/**', + 'aio/content/guide/security.md', + 'aio/content/examples/security/**', + 'aio/content/images/guide/security/**' + ]) + reviewers: + users: + - IgorMinar + - mhevery + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + # ========================================================= + # Bazel + # ========================================================= + bazel: + conditions: + - > + contains_any_globs(files, [ + 'packages/bazel/**', + 'aio/content/guide/bazel.md' + ]) + reviewers: + users: + - IgorMinar + - josephperrott + - kyliau + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Language Service + # ========================================================= + language-service: + conditions: + - > + contains_any_globs(files, [ + 'packages/language-service/**', + 'aio/content/guide/language-service.md', + 'aio/content/images/guide/language-service/**' + ]) + reviewers: + users: + - kyliau + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # zone.js + # ========================================================= + zone-js: + conditions: + - > + contains_any_globs(files, [ + 'packages/zone.js/**' + ]) + reviewers: + users: + - JiaLiPassion + - mhevery + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Benchpress + # ========================================================= + benchpress: + conditions: + - > + contains_any_globs(files, [ + 'packages/benchpress/**' + ]) + reviewers: + users: + - alxhub + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Integration Tests + # ========================================================= + integration-tests: + conditions: + - > + contains_any_globs(files, [ + 'integration/**' + ]) + reviewers: + users: + - IgorMinar + - josephperrott + - kara + - mhevery + teams: + - ~framework-global-approvers + + + # ========================================================= + # Docs: Gettings Started & Tutorial + # ========================================================= + docs-getting-started-and-tutorial: + conditions: + - > + contains_any_globs(files, [ + 'aio/content/guide/setup-local.md', + 'aio/content/images/guide/setup-local/**', + 'aio/content/tutorial/**', + 'aio/content/images/guide/toh/**', + 'aio/content/examples/toh-pt0/**', + 'aio/content/examples/toh-pt1/**', + 'aio/content/examples/toh-pt2/**', + 'aio/content/examples/toh-pt3/**', + 'aio/content/examples/toh-pt4/**', + 'aio/content/examples/toh-pt5/**', + 'aio/content/examples/toh-pt6/**', + 'aio/content/examples/getting-started-v0/**', + 'aio/content/examples/getting-started/**', + 'aio/content/start/**', + 'aio/content/images/guide/start/**' + ]) + reviewers: + users: + - aikidave + - IgorMinar + - StephenFluin + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Docs: Marketing + # ========================================================= + docs-marketing: + conditions: + - > + contains_any_globs(files, [ + 'aio/content/marketing/**', + 'aio/content/images/bios/**', + 'aio/content/images/marketing/**', + 'aio/content/file-not-found.md', + 'aio/content/license.md', + 'aio/content/navigation.json' + ]) + reviewers: + users: + - IgorMinar + - StephenFluin + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Docs: Observables + # ========================================================= + docs-observables: + conditions: + - > + contains_any_globs(files, [ + 'aio/content/guide/observables.md', + 'aio/content/examples/observables/**', + 'aio/content/guide/comparing-observables.md', + 'aio/content/examples/comparing-observables/**', + 'aio/content/guide/observables-in-angular.md', + 'aio/content/examples/observables-in-angular/**', + 'aio/content/guide/practical-observable-usage.md', + 'aio/content/examples/practical-observable-usage/**', + 'aio/content/guide/rx-library.md', + 'aio/content/examples/rx-library/**' + ]) + reviewers: + users: + - alxhub + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Docs: Packaging, Tooling, Releasing + # ========================================================= + docs-packaging-and-releasing: + conditions: + - > + contains_any_globs(files, [ + 'docs/PUBLIC_API.md', + 'docs/RELEASE_SCHEDULE.md', + 'aio/content/guide/npm-packages.md', + 'aio/content/guide/browser-support.md', + 'aio/content/guide/releases.md', + 'aio/content/guide/updating.md', + 'aio/content/guide/deprecations.md', + 'aio/content/guide/migration-renderer.md', + 'aio/content/guide/migration-undecorated-classes.md', + 'aio/content/guide/migration-dynamic-flag.md', + 'aio/content/guide/migration-injectable.md', + 'aio/content/guide/migration-localize.md', + 'aio/content/guide/migration-module-with-providers.md', + 'aio/content/guide/static-query-migration.md', + 'aio/content/guide/updating-to-version-9.md', + 'aio/content/guide/ivy-compatibility.md', + 'aio/content/guide/ivy-compatibility-examples.md' + ]) + reviewers: + users: + - IgorMinar + - kara + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Docs: CLI + # ========================================================= + docs-cli: + conditions: + - > + contains_any_globs(files, [ + 'aio/content/cli/**', + 'aio/content/guide/typescript-configuration.md', + 'aio/content/examples/setup/**', + 'aio/content/guide/build.md', + 'aio/content/images/guide/build/**', + 'aio/content/guide/cli-builder.md', + 'aio/content/examples/cli-builder/**', + 'aio/content/guide/deployment.md', + 'aio/content/images/guide/deployment/**', + 'aio/content/guide/file-structure.md', + 'aio/content/guide/ivy.md', + 'aio/content/guide/web-worker.md' + 'aio/content/guide/workspace-config.md', + ]) + reviewers: + users: + - clydin + - IgorMinar + - mgechev + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Docs: CLI Libraries + # ========================================================= + docs-libraries: + conditions: + - > + contains_any_globs(files, [ + 'aio/content/guide/creating-libraries.md', + 'aio/content/guide/libraries.md', + 'aio/content/guide/using-libraries.md' + ]) + reviewers: + users: + - alan-agius4 + - IgorMinar + - mgechev + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Docs: Schematics + # ========================================================= + docs-schematics: + conditions: + - > + contains_any_globs(files, [ + 'aio/content/guide/schematics.md', + 'aio/content/guide/schematics-authoring.md', + 'aio/content/guide/schematics-for-libraries.md', + 'aio/content/images/guide/schematics/**', + 'aio/content/examples/schematics-for-libraries/**' + ]) + reviewers: + users: + - alan-agius4 + - IgorMinar + - mgechev + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Docs-infra + # ========================================================= + docs-infra: + conditions: + - > + contains_any_globs(files, [ + 'aio/*', + 'aio/aio-builds-setup/**', + 'aio/content/cli-src/**', + 'aio/content/examples/*', + 'aio/scripts/**', + 'aio/src/**', + 'aio/tests/**', + 'aio/tools/**', + 'aio/content/guide/docs-style-guide.md', + 'aio/content/examples/docs-style-guide/**', + 'aio/content/images/guide/docs-style-guide/**', + 'aio/content/guide/visual-studio-2015.md', + 'aio/content/examples/visual-studio-2015/**' + ]) + reviewers: + users: + - gkalpak + - IgorMinar + - petebacondarwin + teams: + - ~framework-global-approvers + - ~framework-global-approvers-for-docs-only-changes + + + # ========================================================= + # Dev-infra + # ========================================================= + dev-infra: + conditions: + - > + contains_any_globs(files, [ + '*', + '.circleci/**', + '.devcontainer/**', + '.github/**', + '.vscode/**', + '.yarn/**', + 'docs/BAZEL.md', + 'docs/CARETAKER.md', + 'docs/COMMITTER.md', + 'docs/DEBUG.md', + 'docs/DEBUG_COMPONENTS_REPO_IVY.md', + 'docs/DEVELOPER.md', + 'docs/GITHUB_PROCESS.md', + 'docs/PR_REVIEW.md', + 'docs/SAVED_REPLIES.md', + 'docs/TOOLS.md', + 'docs/TRIAGE_AND_LABELS.md', + 'modules/e2e_util/e2e_util.ts', + 'modules/e2e_util/perf_util.ts', + 'modules/*', + 'packages/*', + 'packages/examples/test-utils/**', + 'packages/private/**', + 'packages/examples/*', + 'scripts/**', + 'third_party/**', + 'tools/brotli-cli/**', + 'tools/browsers/**', + 'tools/build/**', + 'tools/circular_dependency_test/**', + 'tools/gulp-tasks/**', + 'tools/ng_rollup_bundle/**', + 'tools/ngcontainer/**', + 'tools/npm/**', + 'tools/public_api_guard/BUILD.bazel', + 'tools/public_api_guard/public_api_guard.bzl', + 'tools/pullapprove/**', + 'tools/rxjs/**', + 'tools/saucelabs/**', + 'tools/size-tracking/**', + 'tools/source-map-test/**', + 'tools/symbol-extractor/**', + 'tools/testing/**', + 'tools/ts-api-guardian/**', + 'tools/tslint/**', + 'tools/validate-commit-message/**', + 'tools/yarn/**', + 'tools/*', + '**/*.bzl', + '**/*.bazel' + ]) + reviewers: + users: + - devversion + - filipesilva + - gkalpak + - IgorMinar + - josephperrott + teams: + - ~framework-global-approvers + + + # ========================================================= + # Material CI + # ========================================================= + material-ci: + conditions: + - > + contains_any_globs(files, [ + 'tools/components-repo-ci/**' + ]) + reviewers: + users: + - alxhub + - AndrewKushnir + - kara + - mhevery + - pkozlowski-opensource + teams: + - ~framework-global-approvers + + + # ========================================================= + # Public API + # ========================================================= + public-api: + conditions: + - > + contains_any_globs(files, [ + 'tools/public_api_guard/**', + 'docs/NAMING.md', + 'aio/content/guide/glossary.md', + 'aio/content/guide/styleguide.md', + 'aio/content/examples/styleguide/**', + 'aio/content/images/guide/styleguide/*' + ]) + reviewers: + users: + - IgorMinar + teams: + - ~framework-global-approvers + + + # ================================================ + # Size tracking + # ================================================ + size-tracking: + conditions: + - > + contains_any_globs(files, [ + 'aio/scripts/_payload-limits.json', + 'integration/_payload-limits.json' + ]) + reviewers: + users: + - IgorMinar + - kara + teams: + - ~framework-global-approvers + + +#################################################################################### +# Special Cases +#################################################################################### + + # ========================================================= + # Code Ownership + # ========================================================= + code-ownership: + conditions: + - > + contains_any_globs(files, [ + '.pullapprove.yml' + ]) + reviewers: + users: + - IgorMinar + teams: + - ~framework-global-approvers + + + # ==================================================== + # Catch all for if no groups match the code change + # ==================================================== + fallback: + conditions: + # Groups which are found to have matching conditions are `active` + # according to PullApprove. If no groups are matched and considered + # active, we still want to have a review occur. + - len(groups.active) == 0 + reviewers: + users: + - IgorMinar + teams: + - ~framework-global-approvers diff --git a/.yarn/README.md b/.yarn/README.md new file mode 100644 index 0000000000..de1653b9de --- /dev/null +++ b/.yarn/README.md @@ -0,0 +1,13 @@ +# Yarn Vendoring +We utilize Yarn's `yarn-path` configuration in a shared `.yarnrc` file to enforce +everyone using the same version of Yarn. Yarn checks the `.yarnrc` file to +determine if yarn should delegate the command to a vendored version at the +provided path. + +## How to update +To update to the latest version of Yarn as our vendored version: +- Run this command +```sh +yarn policies set-version latest +``` +- Remove the previous version diff --git a/.yarn/releases/yarn-1.21.1.js b/.yarn/releases/yarn-1.21.1.js new file mode 100755 index 0000000000..9420daa5b2 --- /dev/null +++ b/.yarn/releases/yarn-1.21.1.js @@ -0,0 +1,147315 @@ +#!/usr/bin/env node +module.exports = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 549); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = require("path"); + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = __extends; +/* unused harmony export __assign */ +/* unused harmony export __rest */ +/* unused harmony export __decorate */ +/* unused harmony export __param */ +/* unused harmony export __metadata */ +/* unused harmony export __awaiter */ +/* unused harmony export __generator */ +/* unused harmony export __exportStar */ +/* unused harmony export __values */ +/* unused harmony export __read */ +/* unused harmony export __spread */ +/* unused harmony export __await */ +/* unused harmony export __asyncGenerator */ +/* unused harmony export __asyncDelegator */ +/* unused harmony export __asyncValues */ +/* unused harmony export __makeTemplateObject */ +/* unused harmony export __importStar */ +/* unused harmony export __importDefault */ +/*! ***************************************************************************** +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. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +} + +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; +} + +function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +function __awaiter(thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +function __exportStar(m, exports) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} + +function __values(o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +} + +function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } +} + +function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result.default = mod; + return result; +} + +function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +var _promise = __webpack_require__(227); + +var _promise2 = _interopRequireDefault(_promise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new _promise2.default(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return _promise2.default.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; +}; + +/***/ }), +/* 3 */ +/***/ (function(module, exports) { + +module.exports = require("util"); + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getFirstSuitableFolder = exports.readFirstAvailableStream = exports.makeTempDir = exports.hardlinksWork = exports.writeFilePreservingEol = exports.getFileSizeOnDisk = exports.walk = exports.symlink = exports.find = exports.readJsonAndFile = exports.readJson = exports.readFileAny = exports.hardlinkBulk = exports.copyBulk = exports.unlink = exports.glob = exports.link = exports.chmod = exports.lstat = exports.exists = exports.mkdirp = exports.stat = exports.access = exports.rename = exports.readdir = exports.realpath = exports.readlink = exports.writeFile = exports.open = exports.readFileBuffer = exports.lockQueue = exports.constants = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let buildActionsForCopy = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { + + // + let build = (() => { + var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + const src = data.src, + dest = data.dest, + type = data.type; + + const onFresh = data.onFresh || noop; + const onDone = data.onDone || noop; + + // TODO https://github.com/yarnpkg/yarn/issues/3751 + // related to bundled dependencies handling + if (files.has(dest.toLowerCase())) { + reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); + } else { + files.add(dest.toLowerCase()); + } + + if (type === 'symlink') { + yield mkdirp((_path || _load_path()).default.dirname(dest)); + onFresh(); + actions.symlink.push({ + dest, + linkname: src + }); + onDone(); + return; + } + + if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { + // ignored file + return; + } + + const srcStat = yield lstat(src); + let srcFiles; + + if (srcStat.isDirectory()) { + srcFiles = yield readdir(src); + } + + let destStat; + try { + // try accessing the destination + destStat = yield lstat(dest); + } catch (e) { + // proceed if destination doesn't exist, otherwise error + if (e.code !== 'ENOENT') { + throw e; + } + } + + // if destination exists + if (destStat) { + const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); + const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); + const bothFiles = srcStat.isFile() && destStat.isFile(); + + // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving + // us modes that aren't valid. investigate this, it's generally safe to proceed. + + /* if (srcStat.mode !== destStat.mode) { + try { + await access(dest, srcStat.mode); + } catch (err) {} + } */ + + if (bothFiles && artifactFiles.has(dest)) { + // this file gets changed during build, likely by a custom install script. Don't bother checking it. + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); + return; + } + + if (bothFiles && srcStat.size === destStat.size && (0, (_fsNormalized || _load_fsNormalized()).fileDatesEqual)(srcStat.mtime, destStat.mtime)) { + // we can safely assume this is the same file + onDone(); + reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); + return; + } + + if (bothSymlinks) { + const srcReallink = yield readlink(src); + if (srcReallink === (yield readlink(dest))) { + // if both symlinks are the same then we can continue on + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); + return; + } + } + + if (bothFolders) { + // mark files that aren't in this folder as possibly extraneous + const destFiles = yield readdir(dest); + invariant(srcFiles, 'src files not initialised'); + + for (var _iterator4 = destFiles, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref6; + + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref6 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref6 = _i4.value; + } + + const file = _ref6; + + if (srcFiles.indexOf(file) < 0) { + const loc = (_path || _load_path()).default.join(dest, file); + possibleExtraneous.add(loc); + + if ((yield lstat(loc)).isDirectory()) { + for (var _iterator5 = yield readdir(loc), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref7; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref7 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref7 = _i5.value; + } + + const file = _ref7; + + possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); + } + } + } + } + } + } + + if (destStat && destStat.isSymbolicLink()) { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); + destStat = null; + } + + if (srcStat.isSymbolicLink()) { + onFresh(); + const linkname = yield readlink(src); + actions.symlink.push({ + dest, + linkname + }); + onDone(); + } else if (srcStat.isDirectory()) { + if (!destStat) { + reporter.verbose(reporter.lang('verboseFileFolder', dest)); + yield mkdirp(dest); + } + + const destParts = dest.split((_path || _load_path()).default.sep); + while (destParts.length) { + files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); + destParts.pop(); + } + + // push all files to queue + invariant(srcFiles, 'src files not initialised'); + let remaining = srcFiles.length; + if (!remaining) { + onDone(); + } + for (var _iterator6 = srcFiles, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref8; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref8 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref8 = _i6.value; + } + + const file = _ref8; + + queue.push({ + dest: (_path || _load_path()).default.join(dest, file), + onFresh, + onDone: function (_onDone) { + function onDone() { + return _onDone.apply(this, arguments); + } + + onDone.toString = function () { + return _onDone.toString(); + }; + + return onDone; + }(function () { + if (--remaining === 0) { + onDone(); + } + }), + src: (_path || _load_path()).default.join(src, file) + }); + } + } else if (srcStat.isFile()) { + onFresh(); + actions.file.push({ + src, + dest, + atime: srcStat.atime, + mtime: srcStat.mtime, + mode: srcStat.mode + }); + onDone(); + } else { + throw new Error(`unsure how to copy this: ${src}`); + } + }); + + return function build(_x5) { + return _ref5.apply(this, arguments); + }; + })(); + + const artifactFiles = new Set(events.artifactFiles || []); + const files = new Set(); + + // initialise events + for (var _iterator = queue, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref2; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref2 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref2 = _i.value; + } + + const item = _ref2; + + const onDone = item.onDone; + item.onDone = function () { + events.onProgress(item.dest); + if (onDone) { + onDone(); + } + }; + } + events.onStart(queue.length); + + // start building actions + const actions = { + file: [], + symlink: [], + link: [] + }; + + // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items + // at a time due to the requirement to push items onto the queue + while (queue.length) { + const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); + yield Promise.all(items.map(build)); + } + + // simulate the existence of some files to prevent considering them extraneous + for (var _iterator2 = artifactFiles, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref3; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref3 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref3 = _i2.value; + } + + const file = _ref3; + + if (possibleExtraneous.has(file)) { + reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); + possibleExtraneous.delete(file); + } + } + + for (var _iterator3 = possibleExtraneous, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref4; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref4 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref4 = _i3.value; + } + + const loc = _ref4; + + if (files.has(loc.toLowerCase())) { + possibleExtraneous.delete(loc); + } + } + + return actions; + }); + + return function buildActionsForCopy(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); + +let buildActionsForHardlink = (() => { + var _ref9 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { + + // + let build = (() => { + var _ref13 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + const src = data.src, + dest = data.dest; + + const onFresh = data.onFresh || noop; + const onDone = data.onDone || noop; + if (files.has(dest.toLowerCase())) { + // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 + // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, + // package-linker passes that modules A1 and B1 need to be hardlinked, + // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case + // an exception. + onDone(); + return; + } + files.add(dest.toLowerCase()); + + if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { + // ignored file + return; + } + + const srcStat = yield lstat(src); + let srcFiles; + + if (srcStat.isDirectory()) { + srcFiles = yield readdir(src); + } + + const destExists = yield exists(dest); + if (destExists) { + const destStat = yield lstat(dest); + + const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); + const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); + const bothFiles = srcStat.isFile() && destStat.isFile(); + + if (srcStat.mode !== destStat.mode) { + try { + yield access(dest, srcStat.mode); + } catch (err) { + // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving + // us modes that aren't valid. investigate this, it's generally safe to proceed. + reporter.verbose(err); + } + } + + if (bothFiles && artifactFiles.has(dest)) { + // this file gets changed during build, likely by a custom install script. Don't bother checking it. + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); + return; + } + + // correct hardlink + if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { + onDone(); + reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); + return; + } + + if (bothSymlinks) { + const srcReallink = yield readlink(src); + if (srcReallink === (yield readlink(dest))) { + // if both symlinks are the same then we can continue on + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); + return; + } + } + + if (bothFolders) { + // mark files that aren't in this folder as possibly extraneous + const destFiles = yield readdir(dest); + invariant(srcFiles, 'src files not initialised'); + + for (var _iterator10 = destFiles, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref14; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref14 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref14 = _i10.value; + } + + const file = _ref14; + + if (srcFiles.indexOf(file) < 0) { + const loc = (_path || _load_path()).default.join(dest, file); + possibleExtraneous.add(loc); + + if ((yield lstat(loc)).isDirectory()) { + for (var _iterator11 = yield readdir(loc), _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref15; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref15 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref15 = _i11.value; + } + + const file = _ref15; + + possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); + } + } + } + } + } + } + + if (srcStat.isSymbolicLink()) { + onFresh(); + const linkname = yield readlink(src); + actions.symlink.push({ + dest, + linkname + }); + onDone(); + } else if (srcStat.isDirectory()) { + reporter.verbose(reporter.lang('verboseFileFolder', dest)); + yield mkdirp(dest); + + const destParts = dest.split((_path || _load_path()).default.sep); + while (destParts.length) { + files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); + destParts.pop(); + } + + // push all files to queue + invariant(srcFiles, 'src files not initialised'); + let remaining = srcFiles.length; + if (!remaining) { + onDone(); + } + for (var _iterator12 = srcFiles, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref16; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref16 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref16 = _i12.value; + } + + const file = _ref16; + + queue.push({ + onFresh, + src: (_path || _load_path()).default.join(src, file), + dest: (_path || _load_path()).default.join(dest, file), + onDone: function (_onDone2) { + function onDone() { + return _onDone2.apply(this, arguments); + } + + onDone.toString = function () { + return _onDone2.toString(); + }; + + return onDone; + }(function () { + if (--remaining === 0) { + onDone(); + } + }) + }); + } + } else if (srcStat.isFile()) { + onFresh(); + actions.link.push({ + src, + dest, + removeDest: destExists + }); + onDone(); + } else { + throw new Error(`unsure how to copy this: ${src}`); + } + }); + + return function build(_x10) { + return _ref13.apply(this, arguments); + }; + })(); + + const artifactFiles = new Set(events.artifactFiles || []); + const files = new Set(); + + // initialise events + for (var _iterator7 = queue, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref10; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref10 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref10 = _i7.value; + } + + const item = _ref10; + + const onDone = item.onDone || noop; + item.onDone = function () { + events.onProgress(item.dest); + onDone(); + }; + } + events.onStart(queue.length); + + // start building actions + const actions = { + file: [], + symlink: [], + link: [] + }; + + // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items + // at a time due to the requirement to push items onto the queue + while (queue.length) { + const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); + yield Promise.all(items.map(build)); + } + + // simulate the existence of some files to prevent considering them extraneous + for (var _iterator8 = artifactFiles, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref11; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref11 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref11 = _i8.value; + } + + const file = _ref11; + + if (possibleExtraneous.has(file)) { + reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); + possibleExtraneous.delete(file); + } + } + + for (var _iterator9 = possibleExtraneous, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref12; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref12 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref12 = _i9.value; + } + + const loc = _ref12; + + if (files.has(loc.toLowerCase())) { + possibleExtraneous.delete(loc); + } + } + + return actions; + }); + + return function buildActionsForHardlink(_x6, _x7, _x8, _x9) { + return _ref9.apply(this, arguments); + }; +})(); + +let copyBulk = exports.copyBulk = (() => { + var _ref17 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { + const events = { + onStart: _events && _events.onStart || noop, + onProgress: _events && _events.onProgress || noop, + possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), + ignoreBasenames: _events && _events.ignoreBasenames || [], + artifactFiles: _events && _events.artifactFiles || [] + }; + + const actions = yield buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); + events.onStart(actions.file.length + actions.symlink.length + actions.link.length); + + const fileActions = actions.file; + + const currentlyWriting = new Map(); + + yield (_promise || _load_promise()).queue(fileActions, (() => { + var _ref18 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + let writePromise; + while (writePromise = currentlyWriting.get(data.dest)) { + yield writePromise; + } + + reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); + const copier = (0, (_fsNormalized || _load_fsNormalized()).copyFile)(data, function () { + return currentlyWriting.delete(data.dest); + }); + currentlyWriting.set(data.dest, copier); + events.onProgress(data.dest); + return copier; + }); + + return function (_x14) { + return _ref18.apply(this, arguments); + }; + })(), CONCURRENT_QUEUE_ITEMS); + + // we need to copy symlinks last as they could reference files we were copying + const symlinkActions = actions.symlink; + yield (_promise || _load_promise()).queue(symlinkActions, function (data) { + const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); + reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); + return symlink(linkname, data.dest); + }); + }); + + return function copyBulk(_x11, _x12, _x13) { + return _ref17.apply(this, arguments); + }; +})(); + +let hardlinkBulk = exports.hardlinkBulk = (() => { + var _ref19 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { + const events = { + onStart: _events && _events.onStart || noop, + onProgress: _events && _events.onProgress || noop, + possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), + artifactFiles: _events && _events.artifactFiles || [], + ignoreBasenames: [] + }; + + const actions = yield buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); + events.onStart(actions.file.length + actions.symlink.length + actions.link.length); + + const fileActions = actions.link; + + yield (_promise || _load_promise()).queue(fileActions, (() => { + var _ref20 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); + if (data.removeDest) { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(data.dest); + } + yield link(data.src, data.dest); + }); + + return function (_x18) { + return _ref20.apply(this, arguments); + }; + })(), CONCURRENT_QUEUE_ITEMS); + + // we need to copy symlinks last as they could reference files we were copying + const symlinkActions = actions.symlink; + yield (_promise || _load_promise()).queue(symlinkActions, function (data) { + const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); + reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); + return symlink(linkname, data.dest); + }); + }); + + return function hardlinkBulk(_x15, _x16, _x17) { + return _ref19.apply(this, arguments); + }; +})(); + +let readFileAny = exports.readFileAny = (() => { + var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (files) { + for (var _iterator13 = files, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref22; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref22 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref22 = _i13.value; + } + + const file = _ref22; + + if (yield exists(file)) { + return readFile(file); + } + } + return null; + }); + + return function readFileAny(_x19) { + return _ref21.apply(this, arguments); + }; +})(); + +let readJson = exports.readJson = (() => { + var _ref23 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + return (yield readJsonAndFile(loc)).object; + }); + + return function readJson(_x20) { + return _ref23.apply(this, arguments); + }; +})(); + +let readJsonAndFile = exports.readJsonAndFile = (() => { + var _ref24 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + const file = yield readFile(loc); + try { + return { + object: (0, (_map || _load_map()).default)(JSON.parse(stripBOM(file))), + content: file + }; + } catch (err) { + err.message = `${loc}: ${err.message}`; + throw err; + } + }); + + return function readJsonAndFile(_x21) { + return _ref24.apply(this, arguments); + }; +})(); + +let find = exports.find = (() => { + var _ref25 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (filename, dir) { + const parts = dir.split((_path || _load_path()).default.sep); + + while (parts.length) { + const loc = parts.concat(filename).join((_path || _load_path()).default.sep); + + if (yield exists(loc)) { + return loc; + } else { + parts.pop(); + } + } + + return false; + }); + + return function find(_x22, _x23) { + return _ref25.apply(this, arguments); + }; +})(); + +let symlink = exports.symlink = (() => { + var _ref26 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (src, dest) { + if (process.platform !== 'win32') { + // use relative paths otherwise which will be retained if the directory is moved + src = (_path || _load_path()).default.relative((_path || _load_path()).default.dirname(dest), src); + // When path.relative returns an empty string for the current directory, we should instead use + // '.', which is a valid fs.symlink target. + src = src || '.'; + } + + try { + const stats = yield lstat(dest); + if (stats.isSymbolicLink()) { + const resolved = dest; + if (resolved === src) { + return; + } + } + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } + + // We use rimraf for unlink which never throws an ENOENT on missing target + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); + + if (process.platform === 'win32') { + // use directory junctions if possible on win32, this requires absolute paths + yield fsSymlink(src, dest, 'junction'); + } else { + yield fsSymlink(src, dest); + } + }); + + return function symlink(_x24, _x25) { + return _ref26.apply(this, arguments); + }; +})(); + +let walk = exports.walk = (() => { + var _ref27 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir, relativeDir, ignoreBasenames = new Set()) { + let files = []; + + let filenames = yield readdir(dir); + if (ignoreBasenames.size) { + filenames = filenames.filter(function (name) { + return !ignoreBasenames.has(name); + }); + } + + for (var _iterator14 = filenames, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref28; + + if (_isArray14) { + if (_i14 >= _iterator14.length) break; + _ref28 = _iterator14[_i14++]; + } else { + _i14 = _iterator14.next(); + if (_i14.done) break; + _ref28 = _i14.value; + } + + const name = _ref28; + + const relative = relativeDir ? (_path || _load_path()).default.join(relativeDir, name) : name; + const loc = (_path || _load_path()).default.join(dir, name); + const stat = yield lstat(loc); + + files.push({ + relative, + basename: name, + absolute: loc, + mtime: +stat.mtime + }); + + if (stat.isDirectory()) { + files = files.concat((yield walk(loc, relative, ignoreBasenames))); + } + } + + return files; + }); + + return function walk(_x26, _x27) { + return _ref27.apply(this, arguments); + }; +})(); + +let getFileSizeOnDisk = exports.getFileSizeOnDisk = (() => { + var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + const stat = yield lstat(loc); + const size = stat.size, + blockSize = stat.blksize; + + + return Math.ceil(size / blockSize) * blockSize; + }); + + return function getFileSizeOnDisk(_x28) { + return _ref29.apply(this, arguments); + }; +})(); + +let getEolFromFile = (() => { + var _ref30 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path) { + if (!(yield exists(path))) { + return undefined; + } + + const buffer = yield readFileBuffer(path); + + for (let i = 0; i < buffer.length; ++i) { + if (buffer[i] === cr) { + return '\r\n'; + } + if (buffer[i] === lf) { + return '\n'; + } + } + return undefined; + }); + + return function getEolFromFile(_x29) { + return _ref30.apply(this, arguments); + }; +})(); + +let writeFilePreservingEol = exports.writeFilePreservingEol = (() => { + var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path, data) { + const eol = (yield getEolFromFile(path)) || (_os || _load_os()).default.EOL; + if (eol !== '\n') { + data = data.replace(/\n/g, eol); + } + yield writeFile(path, data); + }); + + return function writeFilePreservingEol(_x30, _x31) { + return _ref31.apply(this, arguments); + }; +})(); + +let hardlinksWork = exports.hardlinksWork = (() => { + var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir) { + const filename = 'test-file' + Math.random(); + const file = (_path || _load_path()).default.join(dir, filename); + const fileLink = (_path || _load_path()).default.join(dir, filename + '-link'); + try { + yield writeFile(file, 'test'); + yield link(file, fileLink); + } catch (err) { + return false; + } finally { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(file); + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(fileLink); + } + return true; + }); + + return function hardlinksWork(_x32) { + return _ref32.apply(this, arguments); + }; +})(); + +// not a strict polyfill for Node's fs.mkdtemp + + +let makeTempDir = exports.makeTempDir = (() => { + var _ref33 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (prefix) { + const dir = (_path || _load_path()).default.join((_os || _load_os()).default.tmpdir(), `yarn-${prefix || ''}-${Date.now()}-${Math.random()}`); + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dir); + yield mkdirp(dir); + return dir; + }); + + return function makeTempDir(_x33) { + return _ref33.apply(this, arguments); + }; +})(); + +let readFirstAvailableStream = exports.readFirstAvailableStream = (() => { + var _ref34 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths) { + for (var _iterator15 = paths, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref35; + + if (_isArray15) { + if (_i15 >= _iterator15.length) break; + _ref35 = _iterator15[_i15++]; + } else { + _i15 = _iterator15.next(); + if (_i15.done) break; + _ref35 = _i15.value; + } + + const path = _ref35; + + try { + const fd = yield open(path, 'r'); + return (_fs || _load_fs()).default.createReadStream(path, { fd }); + } catch (err) { + // Try the next one + } + } + return null; + }); + + return function readFirstAvailableStream(_x34) { + return _ref34.apply(this, arguments); + }; +})(); + +let getFirstSuitableFolder = exports.getFirstSuitableFolder = (() => { + var _ref36 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths, mode = constants.W_OK | constants.X_OK) { + const result = { + skipped: [], + folder: null + }; + + for (var _iterator16 = paths, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { + var _ref37; + + if (_isArray16) { + if (_i16 >= _iterator16.length) break; + _ref37 = _iterator16[_i16++]; + } else { + _i16 = _iterator16.next(); + if (_i16.done) break; + _ref37 = _i16.value; + } + + const folder = _ref37; + + try { + yield mkdirp(folder); + yield access(folder, mode); + + result.folder = folder; + + return result; + } catch (error) { + result.skipped.push({ + error, + folder + }); + } + } + return result; + }); + + return function getFirstSuitableFolder(_x35) { + return _ref36.apply(this, arguments); + }; +})(); + +exports.copy = copy; +exports.readFile = readFile; +exports.readFileRaw = readFileRaw; +exports.normalizeOS = normalizeOS; + +var _fs; + +function _load_fs() { + return _fs = _interopRequireDefault(__webpack_require__(5)); +} + +var _glob; + +function _load_glob() { + return _glob = _interopRequireDefault(__webpack_require__(99)); +} + +var _os; + +function _load_os() { + return _os = _interopRequireDefault(__webpack_require__(46)); +} + +var _path; + +function _load_path() { + return _path = _interopRequireDefault(__webpack_require__(0)); +} + +var _blockingQueue; + +function _load_blockingQueue() { + return _blockingQueue = _interopRequireDefault(__webpack_require__(110)); +} + +var _promise; + +function _load_promise() { + return _promise = _interopRequireWildcard(__webpack_require__(50)); +} + +var _promise2; + +function _load_promise2() { + return _promise2 = __webpack_require__(50); +} + +var _map; + +function _load_map() { + return _map = _interopRequireDefault(__webpack_require__(29)); +} + +var _fsNormalized; + +function _load_fsNormalized() { + return _fsNormalized = __webpack_require__(218); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const constants = exports.constants = typeof (_fs || _load_fs()).default.constants !== 'undefined' ? (_fs || _load_fs()).default.constants : { + R_OK: (_fs || _load_fs()).default.R_OK, + W_OK: (_fs || _load_fs()).default.W_OK, + X_OK: (_fs || _load_fs()).default.X_OK +}; + +const lockQueue = exports.lockQueue = new (_blockingQueue || _load_blockingQueue()).default('fs lock'); + +const readFileBuffer = exports.readFileBuffer = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readFile); +const open = exports.open = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.open); +const writeFile = exports.writeFile = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.writeFile); +const readlink = exports.readlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readlink); +const realpath = exports.realpath = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.realpath); +const readdir = exports.readdir = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readdir); +const rename = exports.rename = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.rename); +const access = exports.access = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.access); +const stat = exports.stat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.stat); +const mkdirp = exports.mkdirp = (0, (_promise2 || _load_promise2()).promisify)(__webpack_require__(145)); +const exists = exports.exists = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.exists, true); +const lstat = exports.lstat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.lstat); +const chmod = exports.chmod = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.chmod); +const link = exports.link = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.link); +const glob = exports.glob = (0, (_promise2 || _load_promise2()).promisify)((_glob || _load_glob()).default); +exports.unlink = (_fsNormalized || _load_fsNormalized()).unlink; + +// fs.copyFile uses the native file copying instructions on the system, performing much better +// than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the +// concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD. + +const CONCURRENT_QUEUE_ITEMS = (_fs || _load_fs()).default.copyFile ? 128 : 4; + +const fsSymlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.symlink); +const invariant = __webpack_require__(9); +const stripBOM = __webpack_require__(160); + +const noop = () => {}; + +function copy(src, dest, reporter) { + return copyBulk([{ src, dest }], reporter); +} + +function _readFile(loc, encoding) { + return new Promise((resolve, reject) => { + (_fs || _load_fs()).default.readFile(loc, encoding, function (err, content) { + if (err) { + reject(err); + } else { + resolve(content); + } + }); + }); +} + +function readFile(loc) { + return _readFile(loc, 'utf8').then(normalizeOS); +} + +function readFileRaw(loc) { + return _readFile(loc, 'binary'); +} + +function normalizeOS(body) { + return body.replace(/\r\n/g, '\n'); +} + +const cr = '\r'.charCodeAt(0); +const lf = '\n'.charCodeAt(0); + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + +module.exports = require("fs"); + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +class MessageError extends Error { + constructor(msg, code) { + super(msg); + this.code = code; + } + +} + +exports.MessageError = MessageError; +class ProcessSpawnError extends MessageError { + constructor(msg, code, process) { + super(msg, code); + this.process = process; + } + +} + +exports.ProcessSpawnError = ProcessSpawnError; +class SecurityError extends MessageError {} + +exports.SecurityError = SecurityError; +class ProcessTermError extends MessageError {} + +exports.ProcessTermError = ProcessTermError; +class ResponseError extends Error { + constructor(msg, responseCode) { + super(msg); + this.responseCode = responseCode; + } + +} + +exports.ResponseError = ResponseError; +class OneTimePasswordError extends Error {} +exports.OneTimePasswordError = OneTimePasswordError; + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscriber; }); +/* unused harmony export SafeSubscriber */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isFunction__ = __webpack_require__(154); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Observer__ = __webpack_require__(420); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__ = __webpack_require__(321); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__config__ = __webpack_require__(185); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__ = __webpack_require__(323); +/** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */ + + + + + + + +var Subscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subscriber, _super); + function Subscriber(destinationOrNext, error, complete) { + var _this = _super.call(this) || this; + _this.syncErrorValue = null; + _this.syncErrorThrown = false; + _this.syncErrorThrowable = false; + _this.isStopped = false; + _this._parentSubscription = null; + switch (arguments.length) { + case 0: + _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; + break; + case 1: + if (!destinationOrNext) { + _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; + break; + } + if (typeof destinationOrNext === 'object') { + if (destinationOrNext instanceof Subscriber) { + _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; + _this.destination = destinationOrNext; + destinationOrNext.add(_this); + } + else { + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext); + } + break; + } + default: + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete); + break; + } + return _this; + } + Subscriber.prototype[__WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { return this; }; + Subscriber.create = function (next, error, complete) { + var subscriber = new Subscriber(next, error, complete); + subscriber.syncErrorThrowable = false; + return subscriber; + }; + Subscriber.prototype.next = function (value) { + if (!this.isStopped) { + this._next(value); + } + }; + Subscriber.prototype.error = function (err) { + if (!this.isStopped) { + this.isStopped = true; + this._error(err); + } + }; + Subscriber.prototype.complete = function () { + if (!this.isStopped) { + this.isStopped = true; + this._complete(); + } + }; + Subscriber.prototype.unsubscribe = function () { + if (this.closed) { + return; + } + this.isStopped = true; + _super.prototype.unsubscribe.call(this); + }; + Subscriber.prototype._next = function (value) { + this.destination.next(value); + }; + Subscriber.prototype._error = function (err) { + this.destination.error(err); + this.unsubscribe(); + }; + Subscriber.prototype._complete = function () { + this.destination.complete(); + this.unsubscribe(); + }; + Subscriber.prototype._unsubscribeAndRecycle = function () { + var _a = this, _parent = _a._parent, _parents = _a._parents; + this._parent = null; + this._parents = null; + this.unsubscribe(); + this.closed = false; + this.isStopped = false; + this._parent = _parent; + this._parents = _parents; + this._parentSubscription = null; + return this; + }; + return Subscriber; +}(__WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */])); + +var SafeSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SafeSubscriber, _super); + function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) { + var _this = _super.call(this) || this; + _this._parentSubscriber = _parentSubscriber; + var next; + var context = _this; + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(observerOrNext)) { + next = observerOrNext; + } + else if (observerOrNext) { + next = observerOrNext.next; + error = observerOrNext.error; + complete = observerOrNext.complete; + if (observerOrNext !== __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]) { + context = Object.create(observerOrNext); + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(context.unsubscribe)) { + _this.add(context.unsubscribe.bind(context)); + } + context.unsubscribe = _this.unsubscribe.bind(_this); + } + } + _this._context = context; + _this._next = next; + _this._error = error; + _this._complete = complete; + return _this; + } + SafeSubscriber.prototype.next = function (value) { + if (!this.isStopped && this._next) { + var _parentSubscriber = this._parentSubscriber; + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._next, value); + } + else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + var useDeprecatedSynchronousErrorHandling = __WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling; + if (this._error) { + if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._error, err); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, this._error, err); + this.unsubscribe(); + } + } + else if (!_parentSubscriber.syncErrorThrowable) { + this.unsubscribe(); + if (useDeprecatedSynchronousErrorHandling) { + throw err; + } + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + else { + if (useDeprecatedSynchronousErrorHandling) { + _parentSubscriber.syncErrorValue = err; + _parentSubscriber.syncErrorThrown = true; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.complete = function () { + var _this = this; + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + if (this._complete) { + var wrappedComplete = function () { return _this._complete.call(_this._context); }; + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(wrappedComplete); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, wrappedComplete); + this.unsubscribe(); + } + } + else { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) { + try { + fn.call(this._context, value); + } + catch (err) { + this.unsubscribe(); + if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + throw err; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + } + }; + SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) { + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + throw new Error('bad call'); + } + try { + fn.call(this._context, value); + } + catch (err) { + if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + parent.syncErrorValue = err; + parent.syncErrorThrown = true; + return true; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + return true; + } + } + return false; + }; + SafeSubscriber.prototype._unsubscribe = function () { + var _parentSubscriber = this._parentSubscriber; + this._context = null; + this._parentSubscriber = null; + _parentSubscriber.unsubscribe(); + }; + return SafeSubscriber; +}(Subscriber)); + +//# sourceMappingURL=Subscriber.js.map + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getPathKey = getPathKey; +const os = __webpack_require__(46); +const path = __webpack_require__(0); +const userHome = __webpack_require__(67).default; + +var _require = __webpack_require__(225); + +const getCacheDir = _require.getCacheDir, + getConfigDir = _require.getConfigDir, + getDataDir = _require.getDataDir; + +const isWebpackBundle = __webpack_require__(278); + +const DEPENDENCY_TYPES = exports.DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies', 'peerDependencies']; +const OWNED_DEPENDENCY_TYPES = exports.OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies']; + +const RESOLUTIONS = exports.RESOLUTIONS = 'resolutions'; +const MANIFEST_FIELDS = exports.MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; + +const SUPPORTED_NODE_VERSIONS = exports.SUPPORTED_NODE_VERSIONS = '^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0'; + +const YARN_REGISTRY = exports.YARN_REGISTRY = 'https://registry.yarnpkg.com'; +const NPM_REGISTRY_RE = exports.NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; + +const YARN_DOCS = exports.YARN_DOCS = 'https://yarnpkg.com/en/docs/cli/'; +const YARN_INSTALLER_SH = exports.YARN_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; +const YARN_INSTALLER_MSI = exports.YARN_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; + +const SELF_UPDATE_VERSION_URL = exports.SELF_UPDATE_VERSION_URL = 'https://yarnpkg.com/latest-version'; + +// cache version, bump whenever we make backwards incompatible changes +const CACHE_VERSION = exports.CACHE_VERSION = 6; + +// lockfile version, bump whenever we make backwards incompatible changes +const LOCKFILE_VERSION = exports.LOCKFILE_VERSION = 1; + +// max amount of network requests to perform concurrently +const NETWORK_CONCURRENCY = exports.NETWORK_CONCURRENCY = 8; + +// HTTP timeout used when downloading packages +const NETWORK_TIMEOUT = exports.NETWORK_TIMEOUT = 30 * 1000; // in milliseconds + +// max amount of child processes to execute concurrently +const CHILD_CONCURRENCY = exports.CHILD_CONCURRENCY = 5; + +const REQUIRED_PACKAGE_KEYS = exports.REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; + +function getPreferredCacheDirectories() { + const preferredCacheDirectories = [getCacheDir()]; + + if (process.getuid) { + // $FlowFixMe: process.getuid exists, dammit + preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache-${process.getuid()}`)); + } + + preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache`)); + + return preferredCacheDirectories; +} + +const PREFERRED_MODULE_CACHE_DIRECTORIES = exports.PREFERRED_MODULE_CACHE_DIRECTORIES = getPreferredCacheDirectories(); +const CONFIG_DIRECTORY = exports.CONFIG_DIRECTORY = getConfigDir(); +const DATA_DIRECTORY = exports.DATA_DIRECTORY = getDataDir(); +const LINK_REGISTRY_DIRECTORY = exports.LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'); +const GLOBAL_MODULE_DIRECTORY = exports.GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'); + +const NODE_BIN_PATH = exports.NODE_BIN_PATH = process.execPath; +const YARN_BIN_PATH = exports.YARN_BIN_PATH = getYarnBinPath(); + +// Webpack needs to be configured with node.__dirname/__filename = false +function getYarnBinPath() { + if (isWebpackBundle) { + return __filename; + } else { + return path.join(__dirname, '..', 'bin', 'yarn.js'); + } +} + +const NODE_MODULES_FOLDER = exports.NODE_MODULES_FOLDER = 'node_modules'; +const NODE_PACKAGE_JSON = exports.NODE_PACKAGE_JSON = 'package.json'; + +const PNP_FILENAME = exports.PNP_FILENAME = '.pnp.js'; + +const POSIX_GLOBAL_PREFIX = exports.POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; +const FALLBACK_GLOBAL_PREFIX = exports.FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn'); + +const META_FOLDER = exports.META_FOLDER = '.yarn-meta'; +const INTEGRITY_FILENAME = exports.INTEGRITY_FILENAME = '.yarn-integrity'; +const LOCKFILE_FILENAME = exports.LOCKFILE_FILENAME = 'yarn.lock'; +const METADATA_FILENAME = exports.METADATA_FILENAME = '.yarn-metadata.json'; +const TARBALL_FILENAME = exports.TARBALL_FILENAME = '.yarn-tarball.tgz'; +const CLEAN_FILENAME = exports.CLEAN_FILENAME = '.yarnclean'; + +const NPM_LOCK_FILENAME = exports.NPM_LOCK_FILENAME = 'package-lock.json'; +const NPM_SHRINKWRAP_FILENAME = exports.NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; + +const DEFAULT_INDENT = exports.DEFAULT_INDENT = ' '; +const SINGLE_INSTANCE_PORT = exports.SINGLE_INSTANCE_PORT = 31997; +const SINGLE_INSTANCE_FILENAME = exports.SINGLE_INSTANCE_FILENAME = '.yarn-single-instance'; + +const ENV_PATH_KEY = exports.ENV_PATH_KEY = getPathKey(process.platform, process.env); + +function getPathKey(platform, env) { + let pathKey = 'PATH'; + + // windows calls its path "Path" usually, but this is not guaranteed. + if (platform === 'win32') { + pathKey = 'Path'; + + for (const key in env) { + if (key.toLowerCase() === 'path') { + pathKey = key; + } + } + } + + return pathKey; +} + +const VERSION_COLOR_SCHEME = exports.VERSION_COLOR_SCHEME = { + major: 'red', + premajor: 'red', + minor: 'yellow', + preminor: 'yellow', + patch: 'green', + prepatch: 'green', + prerelease: 'red', + unchanged: 'white', + unknown: 'red' +}; + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +var NODE_ENV = process.env.NODE_ENV; + +var invariant = function(condition, format, a, b, c, d, e, f) { + if (NODE_ENV !== 'production') { + if (format === undefined) { + throw new Error('invariant requires an error message argument'); + } + } + + if (!condition) { + var error; + if (format === undefined) { + error = new Error( + 'Minified exception occurred; use the non-minified dev environment ' + + 'for the full error message and additional helpful warnings.' + ); + } else { + var args = [a, b, c, d, e, f]; + var argIndex = 0; + error = new Error( + format.replace(/%s/g, function() { return args[argIndex++]; }) + ); + error.name = 'Invariant Violation'; + } + + error.framesToPop = 1; // we don't care about invariant's own frame + throw error; + } +}; + +module.exports = invariant; + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var YAMLException = __webpack_require__(54); + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new YAMLException('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new YAMLException('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +module.exports = Type; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + +module.exports = require("crypto"); + +/***/ }), +/* 12 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Observable; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_canReportError__ = __webpack_require__(322); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__ = __webpack_require__(932); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__ = __webpack_require__(117); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_pipe__ = __webpack_require__(324); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(185); +/** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ + + + + + +var Observable = /*@__PURE__*/ (function () { + function Observable(subscribe) { + this._isScalar = false; + if (subscribe) { + this._subscribe = subscribe; + } + } + Observable.prototype.lift = function (operator) { + var observable = new Observable(); + observable.source = this; + observable.operator = operator; + return observable; + }; + Observable.prototype.subscribe = function (observerOrNext, error, complete) { + var operator = this.operator; + var sink = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__["a" /* toSubscriber */])(observerOrNext, error, complete); + if (operator) { + operator.call(sink, this.source); + } + else { + sink.add(this.source || (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? + this._subscribe(sink) : + this._trySubscribe(sink)); + } + if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + if (sink.syncErrorThrowable) { + sink.syncErrorThrowable = false; + if (sink.syncErrorThrown) { + throw sink.syncErrorValue; + } + } + } + return sink; + }; + Observable.prototype._trySubscribe = function (sink) { + try { + return this._subscribe(sink); + } + catch (err) { + if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + sink.syncErrorThrown = true; + sink.syncErrorValue = err; + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_canReportError__["a" /* canReportError */])(sink)) { + sink.error(err); + } + else { + console.warn(err); + } + } + }; + Observable.prototype.forEach = function (next, promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var subscription; + subscription = _this.subscribe(function (value) { + try { + next(value); + } + catch (err) { + reject(err); + if (subscription) { + subscription.unsubscribe(); + } + } + }, reject, resolve); + }); + }; + Observable.prototype._subscribe = function (subscriber) { + var source = this.source; + return source && source.subscribe(subscriber); + }; + Observable.prototype[__WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__["a" /* observable */]] = function () { + return this; + }; + Observable.prototype.pipe = function () { + var operations = []; + for (var _i = 0; _i < arguments.length; _i++) { + operations[_i] = arguments[_i]; + } + if (operations.length === 0) { + return this; + } + return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_pipe__["b" /* pipeFromArray */])(operations)(this); + }; + Observable.prototype.toPromise = function (promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var value; + _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); }); + }); + }; + Observable.create = function (subscribe) { + return new Observable(subscribe); + }; + return Observable; +}()); + +function getPromiseCtor(promiseCtor) { + if (!promiseCtor) { + promiseCtor = __WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].Promise || Promise; + } + if (!promiseCtor) { + throw new Error('no Promise impl found'); + } + return promiseCtor; +} +//# sourceMappingURL=Observable.js.map + + +/***/ }), +/* 13 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return OuterSubscriber; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(7); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + + +var OuterSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](OuterSubscriber, _super); + function OuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(innerValue); + }; + OuterSubscriber.prototype.notifyError = function (error, innerSub) { + this.destination.error(error); + }; + OuterSubscriber.prototype.notifyComplete = function (innerSub) { + this.destination.complete(); + }; + return OuterSubscriber; +}(__WEBPACK_IMPORTED_MODULE_1__Subscriber__["a" /* Subscriber */])); + +//# sourceMappingURL=OuterSubscriber.js.map + + +/***/ }), +/* 14 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = subscribeToResult; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__ = __webpack_require__(84); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__subscribeTo__ = __webpack_require__(446); +/** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo PURE_IMPORTS_END */ + + +function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, destination) { + if (destination === void 0) { + destination = new __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__["a" /* InnerSubscriber */](outerSubscriber, outerValue, outerIndex); + } + if (destination.closed) { + return; + } + return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__subscribeTo__["a" /* subscribeTo */])(result)(destination); +} +//# sourceMappingURL=subscribeToResult.js.map + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* eslint-disable node/no-deprecated-api */ + + + +var buffer = __webpack_require__(64) +var Buffer = buffer.Buffer + +var safer = {} + +var key + +for (key in buffer) { + if (!buffer.hasOwnProperty(key)) continue + if (key === 'SlowBuffer' || key === 'Buffer') continue + safer[key] = buffer[key] +} + +var Safer = safer.Buffer = {} +for (key in Buffer) { + if (!Buffer.hasOwnProperty(key)) continue + if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue + Safer[key] = Buffer[key] +} + +safer.Buffer.prototype = Buffer.prototype + +if (!Safer.from || Safer.from === Uint8Array.from) { + Safer.from = function (value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) + } + if (value && typeof value.length === 'undefined') { + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) + } + return Buffer(value, encodingOrOffset, length) + } +} + +if (!Safer.alloc) { + Safer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + var buf = Buffer(size) + if (!fill || fill.length === 0) { + buf.fill(0) + } else if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + return buf + } +} + +if (!safer.kStringMaxLength) { + try { + safer.kStringMaxLength = process.binding('buffer').kStringMaxLength + } catch (e) { + // we can't determine kStringMaxLength in environments where process.binding + // is unsupported, so let's not set it + } +} + +if (!safer.constants) { + safer.constants = { + MAX_LENGTH: safer.kMaxLength + } + if (safer.kStringMaxLength) { + safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength + } +} + +module.exports = safer + + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright (c) 2012, Mark Cavage. All rights reserved. +// Copyright 2015 Joyent, Inc. + +var assert = __webpack_require__(28); +var Stream = __webpack_require__(23).Stream; +var util = __webpack_require__(3); + + +///--- Globals + +/* JSSTYLED */ +var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; + + +///--- Internal + +function _capitalize(str) { + return (str.charAt(0).toUpperCase() + str.slice(1)); +} + +function _toss(name, expected, oper, arg, actual) { + throw new assert.AssertionError({ + message: util.format('%s (%s) is required', name, expected), + actual: (actual === undefined) ? typeof (arg) : actual(arg), + expected: expected, + operator: oper || '===', + stackStartFunction: _toss.caller + }); +} + +function _getClass(arg) { + return (Object.prototype.toString.call(arg).slice(8, -1)); +} + +function noop() { + // Why even bother with asserts? +} + + +///--- Exports + +var types = { + bool: { + check: function (arg) { return typeof (arg) === 'boolean'; } + }, + func: { + check: function (arg) { return typeof (arg) === 'function'; } + }, + string: { + check: function (arg) { return typeof (arg) === 'string'; } + }, + object: { + check: function (arg) { + return typeof (arg) === 'object' && arg !== null; + } + }, + number: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg); + } + }, + finite: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); + } + }, + buffer: { + check: function (arg) { return Buffer.isBuffer(arg); }, + operator: 'Buffer.isBuffer' + }, + array: { + check: function (arg) { return Array.isArray(arg); }, + operator: 'Array.isArray' + }, + stream: { + check: function (arg) { return arg instanceof Stream; }, + operator: 'instanceof', + actual: _getClass + }, + date: { + check: function (arg) { return arg instanceof Date; }, + operator: 'instanceof', + actual: _getClass + }, + regexp: { + check: function (arg) { return arg instanceof RegExp; }, + operator: 'instanceof', + actual: _getClass + }, + uuid: { + check: function (arg) { + return typeof (arg) === 'string' && UUID_REGEXP.test(arg); + }, + operator: 'isUUID' + } +}; + +function _setExports(ndebug) { + var keys = Object.keys(types); + var out; + + /* re-export standard assert */ + if (process.env.NODE_NDEBUG) { + out = noop; + } else { + out = function (arg, msg) { + if (!arg) { + _toss(msg, 'true', arg); + } + }; + } + + /* standard checks */ + keys.forEach(function (k) { + if (ndebug) { + out[k] = noop; + return; + } + var type = types[k]; + out[k] = function (arg, msg) { + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* optional checks */ + keys.forEach(function (k) { + var name = 'optional' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* arrayOf checks */ + keys.forEach(function (k) { + var name = 'arrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* optionalArrayOf checks */ + keys.forEach(function (k) { + var name = 'optionalArrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* re-export built-in assertions */ + Object.keys(assert).forEach(function (k) { + if (k === 'AssertionError') { + out[k] = assert[k]; + return; + } + if (ndebug) { + out[k] = noop; + return; + } + out[k] = assert[k]; + }); + + /* export ourselves (for unit tests _only_) */ + out._setExports = _setExports; + + return out; +} + +module.exports = _setExports(process.env.NODE_NDEBUG); + + +/***/ }), +/* 17 */ +/***/ (function(module, exports) { + +// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 +var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self + // eslint-disable-next-line no-new-func + : Function('return this')(); +if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.sortAlpha = sortAlpha; +exports.sortOptionsByFlags = sortOptionsByFlags; +exports.entries = entries; +exports.removePrefix = removePrefix; +exports.removeSuffix = removeSuffix; +exports.addSuffix = addSuffix; +exports.hyphenate = hyphenate; +exports.camelCase = camelCase; +exports.compareSortedArrays = compareSortedArrays; +exports.sleep = sleep; +const _camelCase = __webpack_require__(230); + +function sortAlpha(a, b) { + // sort alphabetically in a deterministic way + const shortLen = Math.min(a.length, b.length); + for (let i = 0; i < shortLen; i++) { + const aChar = a.charCodeAt(i); + const bChar = b.charCodeAt(i); + if (aChar !== bChar) { + return aChar - bChar; + } + } + return a.length - b.length; +} + +function sortOptionsByFlags(a, b) { + const aOpt = a.flags.replace(/-/g, ''); + const bOpt = b.flags.replace(/-/g, ''); + return sortAlpha(aOpt, bOpt); +} + +function entries(obj) { + const entries = []; + if (obj) { + for (const key in obj) { + entries.push([key, obj[key]]); + } + } + return entries; +} + +function removePrefix(pattern, prefix) { + if (pattern.startsWith(prefix)) { + pattern = pattern.slice(prefix.length); + } + + return pattern; +} + +function removeSuffix(pattern, suffix) { + if (pattern.endsWith(suffix)) { + return pattern.slice(0, -suffix.length); + } + + return pattern; +} + +function addSuffix(pattern, suffix) { + if (!pattern.endsWith(suffix)) { + return pattern + suffix; + } + + return pattern; +} + +function hyphenate(str) { + return str.replace(/[A-Z]/g, match => { + return '-' + match.charAt(0).toLowerCase(); + }); +} + +function camelCase(str) { + if (/[A-Z]/.test(str)) { + return null; + } else { + return _camelCase(str); + } +} + +function compareSortedArrays(array1, array2) { + if (array1.length !== array2.length) { + return false; + } + for (let i = 0, len = array1.length; i < len; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + return true; +} + +function sleep(ms) { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.stringify = exports.parse = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +var _parse; + +function _load_parse() { + return _parse = __webpack_require__(105); +} + +Object.defineProperty(exports, 'parse', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_parse || _load_parse()).default; + } +}); + +var _stringify; + +function _load_stringify() { + return _stringify = __webpack_require__(199); +} + +Object.defineProperty(exports, 'stringify', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_stringify || _load_stringify()).default; + } +}); +exports.implodeEntry = implodeEntry; +exports.explodeEntry = explodeEntry; + +var _misc; + +function _load_misc() { + return _misc = __webpack_require__(18); +} + +var _normalizePattern; + +function _load_normalizePattern() { + return _normalizePattern = __webpack_require__(37); +} + +var _parse2; + +function _load_parse2() { + return _parse2 = _interopRequireDefault(__webpack_require__(105)); +} + +var _constants; + +function _load_constants() { + return _constants = __webpack_require__(8); +} + +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(4)); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const invariant = __webpack_require__(9); + +const path = __webpack_require__(0); +const ssri = __webpack_require__(65); + +function getName(pattern) { + return (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern).name; +} + +function blankObjectUndefined(obj) { + return obj && Object.keys(obj).length ? obj : undefined; +} + +function keyForRemote(remote) { + return remote.resolved || (remote.reference && remote.hash ? `${remote.reference}#${remote.hash}` : null); +} + +function serializeIntegrity(integrity) { + // We need this because `Integrity.toString()` does not use sorting to ensure a stable string output + // See https://git.io/vx2Hy + return integrity.toString().split(' ').sort().join(' '); +} + +function implodeEntry(pattern, obj) { + const inferredName = getName(pattern); + const integrity = obj.integrity ? serializeIntegrity(obj.integrity) : ''; + const imploded = { + name: inferredName === obj.name ? undefined : obj.name, + version: obj.version, + uid: obj.uid === obj.version ? undefined : obj.uid, + resolved: obj.resolved, + registry: obj.registry === 'npm' ? undefined : obj.registry, + dependencies: blankObjectUndefined(obj.dependencies), + optionalDependencies: blankObjectUndefined(obj.optionalDependencies), + permissions: blankObjectUndefined(obj.permissions), + prebuiltVariants: blankObjectUndefined(obj.prebuiltVariants) + }; + if (integrity) { + imploded.integrity = integrity; + } + return imploded; +} + +function explodeEntry(pattern, obj) { + obj.optionalDependencies = obj.optionalDependencies || {}; + obj.dependencies = obj.dependencies || {}; + obj.uid = obj.uid || obj.version; + obj.permissions = obj.permissions || {}; + obj.registry = obj.registry || 'npm'; + obj.name = obj.name || getName(pattern); + const integrity = obj.integrity; + if (integrity && integrity.isIntegrity) { + obj.integrity = ssri.parse(integrity); + } + return obj; +} + +class Lockfile { + constructor({ cache, source, parseResultType } = {}) { + this.source = source || ''; + this.cache = cache; + this.parseResultType = parseResultType; + } + + // source string if the `cache` was parsed + + + // if true, we're parsing an old yarn file and need to update integrity fields + hasEntriesExistWithoutIntegrity() { + if (!this.cache) { + return false; + } + + for (const key in this.cache) { + // $FlowFixMe - `this.cache` is clearly defined at this point + if (!/^.*@(file:|http)/.test(key) && this.cache[key] && !this.cache[key].integrity) { + return true; + } + } + + return false; + } + + static fromDirectory(dir, reporter) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // read the manifest in this directory + const lockfileLoc = path.join(dir, (_constants || _load_constants()).LOCKFILE_FILENAME); + + let lockfile; + let rawLockfile = ''; + let parseResult; + + if (yield (_fs || _load_fs()).exists(lockfileLoc)) { + rawLockfile = yield (_fs || _load_fs()).readFile(lockfileLoc); + parseResult = (0, (_parse2 || _load_parse2()).default)(rawLockfile, lockfileLoc); + + if (reporter) { + if (parseResult.type === 'merge') { + reporter.info(reporter.lang('lockfileMerged')); + } else if (parseResult.type === 'conflict') { + reporter.warn(reporter.lang('lockfileConflict')); + } + } + + lockfile = parseResult.object; + } else if (reporter) { + reporter.info(reporter.lang('noLockfileFound')); + } + + if (lockfile && lockfile.__metadata) { + const lockfilev2 = lockfile; + lockfile = {}; + } + + return new Lockfile({ cache: lockfile, source: rawLockfile, parseResultType: parseResult && parseResult.type }); + })(); + } + + getLocked(pattern) { + const cache = this.cache; + if (!cache) { + return undefined; + } + + const shrunk = pattern in cache && cache[pattern]; + + if (typeof shrunk === 'string') { + return this.getLocked(shrunk); + } else if (shrunk) { + explodeEntry(pattern, shrunk); + return shrunk; + } + + return undefined; + } + + removePattern(pattern) { + const cache = this.cache; + if (!cache) { + return; + } + delete cache[pattern]; + } + + getLockfile(patterns) { + const lockfile = {}; + const seen = new Map(); + + // order by name so that lockfile manifest is assigned to the first dependency with this manifest + // the others that have the same remoteKey will just refer to the first + // ordering allows for consistency in lockfile when it is serialized + const sortedPatternsKeys = Object.keys(patterns).sort((_misc || _load_misc()).sortAlpha); + + for (var _iterator = sortedPatternsKeys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const pattern = _ref; + + const pkg = patterns[pattern]; + const remote = pkg._remote, + ref = pkg._reference; + + invariant(ref, 'Package is missing a reference'); + invariant(remote, 'Package is missing a remote'); + + const remoteKey = keyForRemote(remote); + const seenPattern = remoteKey && seen.get(remoteKey); + if (seenPattern) { + // no point in duplicating it + lockfile[pattern] = seenPattern; + + // if we're relying on our name being inferred and two of the patterns have + // different inferred names then we need to set it + if (!seenPattern.name && getName(pattern) !== pkg.name) { + seenPattern.name = pkg.name; + } + continue; + } + const obj = implodeEntry(pattern, { + name: pkg.name, + version: pkg.version, + uid: pkg._uid, + resolved: remote.resolved, + integrity: remote.integrity, + registry: remote.registry, + dependencies: pkg.dependencies, + peerDependencies: pkg.peerDependencies, + optionalDependencies: pkg.optionalDependencies, + permissions: ref.permissions, + prebuiltVariants: pkg.prebuiltVariants + }); + + lockfile[pattern] = obj; + + if (remoteKey) { + seen.set(remoteKey, obj); + } + } + + return lockfile; + } +} +exports.default = Lockfile; + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +var store = __webpack_require__(133)('wks'); +var uid = __webpack_require__(137); +var Symbol = __webpack_require__(17).Symbol; +var USE_SYMBOL = typeof Symbol == 'function'; + +var $exports = module.exports = function (name) { + return store[name] || (store[name] = + USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); +}; + +$exports.store = store; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +var _assign = __webpack_require__(591); + +var _assign2 = _interopRequireDefault(_assign); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = _assign2.default || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; +}; + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +exports = module.exports = SemVer; + +// The debug function is excluded entirely from the minified version. +/* nomin */ var debug; +/* nomin */ if (typeof process === 'object' && + /* nomin */ process.env && + /* nomin */ process.env.NODE_DEBUG && + /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)) + /* nomin */ debug = function() { + /* nomin */ var args = Array.prototype.slice.call(arguments, 0); + /* nomin */ args.unshift('SEMVER'); + /* nomin */ console.log.apply(console, args); + /* nomin */ }; +/* nomin */ else + /* nomin */ debug = function() {}; + +// Note: this is the semver.org version of the spec that it implements +// Not necessarily the package version of this code. +exports.SEMVER_SPEC_VERSION = '2.0.0'; + +var MAX_LENGTH = 256; +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; + +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16; + +// The actual regexps go on exports.re +var re = exports.re = []; +var src = exports.src = []; +var R = 0; + +// The following Regular Expressions can be used for tokenizing, +// validating, and parsing SemVer version strings. + +// ## Numeric Identifier +// A single `0`, or a non-zero digit followed by zero or more digits. + +var NUMERICIDENTIFIER = R++; +src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'; +var NUMERICIDENTIFIERLOOSE = R++; +src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'; + + +// ## Non-numeric Identifier +// Zero or more digits, followed by a letter or hyphen, and then zero or +// more letters, digits, or hyphens. + +var NONNUMERICIDENTIFIER = R++; +src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'; + + +// ## Main Version +// Three dot-separated numeric identifiers. + +var MAINVERSION = R++; +src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')'; + +var MAINVERSIONLOOSE = R++; +src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')'; + +// ## Pre-release Version Identifier +// A numeric identifier, or a non-numeric identifier. + +var PRERELEASEIDENTIFIER = R++; +src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + + '|' + src[NONNUMERICIDENTIFIER] + ')'; + +var PRERELEASEIDENTIFIERLOOSE = R++; +src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + + '|' + src[NONNUMERICIDENTIFIER] + ')'; + + +// ## Pre-release Version +// Hyphen, followed by one or more dot-separated pre-release version +// identifiers. + +var PRERELEASE = R++; +src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'; + +var PRERELEASELOOSE = R++; +src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'; + +// ## Build Metadata Identifier +// Any combination of digits, letters, or hyphens. + +var BUILDIDENTIFIER = R++; +src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'; + +// ## Build Metadata +// Plus sign, followed by one or more period-separated build metadata +// identifiers. + +var BUILD = R++; +src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'; + + +// ## Full Version String +// A main version, followed optionally by a pre-release version and +// build metadata. + +// Note that the only major, minor, patch, and pre-release sections of +// the version string are capturing groups. The build metadata is not a +// capturing group, because it should not ever be used in version +// comparison. + +var FULL = R++; +var FULLPLAIN = 'v?' + src[MAINVERSION] + + src[PRERELEASE] + '?' + + src[BUILD] + '?'; + +src[FULL] = '^' + FULLPLAIN + '$'; + +// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. +// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty +// common in the npm registry. +var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + + src[PRERELEASELOOSE] + '?' + + src[BUILD] + '?'; + +var LOOSE = R++; +src[LOOSE] = '^' + LOOSEPLAIN + '$'; + +var GTLT = R++; +src[GTLT] = '((?:<|>)?=?)'; + +// Something like "2.*" or "1.2.x". +// Note that "x.x" is a valid xRange identifer, meaning "any version" +// Only the first item is strictly required. +var XRANGEIDENTIFIERLOOSE = R++; +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'; +var XRANGEIDENTIFIER = R++; +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'; + +var XRANGEPLAIN = R++; +src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:' + src[PRERELEASE] + ')?' + + src[BUILD] + '?' + + ')?)?'; + +var XRANGEPLAINLOOSE = R++; +src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[PRERELEASELOOSE] + ')?' + + src[BUILD] + '?' + + ')?)?'; + +var XRANGE = R++; +src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'; +var XRANGELOOSE = R++; +src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'; + +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +var COERCE = R++; +src[COERCE] = '(?:^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])'; + +// Tilde ranges. +// Meaning is "reasonably at or greater than" +var LONETILDE = R++; +src[LONETILDE] = '(?:~>?)'; + +var TILDETRIM = R++; +src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'; +re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g'); +var tildeTrimReplace = '$1~'; + +var TILDE = R++; +src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'; +var TILDELOOSE = R++; +src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'; + +// Caret ranges. +// Meaning is "at least and backwards compatible with" +var LONECARET = R++; +src[LONECARET] = '(?:\\^)'; + +var CARETTRIM = R++; +src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'; +re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g'); +var caretTrimReplace = '$1^'; + +var CARET = R++; +src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'; +var CARETLOOSE = R++; +src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'; + +// A simple gt/lt/eq thing, or just "" to indicate "any version" +var COMPARATORLOOSE = R++; +src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'; +var COMPARATOR = R++; +src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'; + + +// An expression to strip any whitespace between the gtlt and the thing +// it modifies, so that `> 1.2.3` ==> `>1.2.3` +var COMPARATORTRIM = R++; +src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'; + +// this one has to use the /g flag +re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g'); +var comparatorTrimReplace = '$1$2$3'; + + +// Something like `1.2.3 - 1.2.4` +// Note that these all use the loose form, because they'll be +// checked against either the strict or loose comparator form +// later. +var HYPHENRANGE = R++; +src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAIN] + ')' + + '\\s*$'; + +var HYPHENRANGELOOSE = R++; +src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s*$'; + +// Star ranges basically just allow anything at all. +var STAR = R++; +src[STAR] = '(<|>)?=?\\s*\\*'; + +// Compile to actual regexp objects. +// All are flag-free, unless they were created above with a flag. +for (var i = 0; i < R; i++) { + debug(i, src[i]); + if (!re[i]) + re[i] = new RegExp(src[i]); +} + +exports.parse = parse; +function parse(version, loose) { + if (version instanceof SemVer) + return version; + + if (typeof version !== 'string') + return null; + + if (version.length > MAX_LENGTH) + return null; + + var r = loose ? re[LOOSE] : re[FULL]; + if (!r.test(version)) + return null; + + try { + return new SemVer(version, loose); + } catch (er) { + return null; + } +} + +exports.valid = valid; +function valid(version, loose) { + var v = parse(version, loose); + return v ? v.version : null; +} + + +exports.clean = clean; +function clean(version, loose) { + var s = parse(version.trim().replace(/^[=v]+/, ''), loose); + return s ? s.version : null; +} + +exports.SemVer = SemVer; + +function SemVer(version, loose) { + if (version instanceof SemVer) { + if (version.loose === loose) + return version; + else + version = version.version; + } else if (typeof version !== 'string') { + throw new TypeError('Invalid Version: ' + version); + } + + if (version.length > MAX_LENGTH) + throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + + if (!(this instanceof SemVer)) + return new SemVer(version, loose); + + debug('SemVer', version, loose); + this.loose = loose; + var m = version.trim().match(loose ? re[LOOSE] : re[FULL]); + + if (!m) + throw new TypeError('Invalid Version: ' + version); + + this.raw = version; + + // these are actually numbers + this.major = +m[1]; + this.minor = +m[2]; + this.patch = +m[3]; + + if (this.major > MAX_SAFE_INTEGER || this.major < 0) + throw new TypeError('Invalid major version') + + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) + throw new TypeError('Invalid minor version') + + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) + throw new TypeError('Invalid patch version') + + // numberify any prerelease numeric ids + if (!m[4]) + this.prerelease = []; + else + this.prerelease = m[4].split('.').map(function(id) { + if (/^[0-9]+$/.test(id)) { + var num = +id; + if (num >= 0 && num < MAX_SAFE_INTEGER) + return num; + } + return id; + }); + + this.build = m[5] ? m[5].split('.') : []; + this.format(); +} + +SemVer.prototype.format = function() { + this.version = this.major + '.' + this.minor + '.' + this.patch; + if (this.prerelease.length) + this.version += '-' + this.prerelease.join('.'); + return this.version; +}; + +SemVer.prototype.toString = function() { + return this.version; +}; + +SemVer.prototype.compare = function(other) { + debug('SemVer.compare', this.version, this.loose, other); + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + return this.compareMain(other) || this.comparePre(other); +}; + +SemVer.prototype.compareMain = function(other) { + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + return compareIdentifiers(this.major, other.major) || + compareIdentifiers(this.minor, other.minor) || + compareIdentifiers(this.patch, other.patch); +}; + +SemVer.prototype.comparePre = function(other) { + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + // NOT having a prerelease is > having one + if (this.prerelease.length && !other.prerelease.length) + return -1; + else if (!this.prerelease.length && other.prerelease.length) + return 1; + else if (!this.prerelease.length && !other.prerelease.length) + return 0; + + var i = 0; + do { + var a = this.prerelease[i]; + var b = other.prerelease[i]; + debug('prerelease compare', i, a, b); + if (a === undefined && b === undefined) + return 0; + else if (b === undefined) + return 1; + else if (a === undefined) + return -1; + else if (a === b) + continue; + else + return compareIdentifiers(a, b); + } while (++i); +}; + +// preminor will bump the version up to the next minor release, and immediately +// down to pre-release. premajor and prepatch work the same way. +SemVer.prototype.inc = function(release, identifier) { + switch (release) { + case 'premajor': + this.prerelease.length = 0; + this.patch = 0; + this.minor = 0; + this.major++; + this.inc('pre', identifier); + break; + case 'preminor': + this.prerelease.length = 0; + this.patch = 0; + this.minor++; + this.inc('pre', identifier); + break; + case 'prepatch': + // If this is already a prerelease, it will bump to the next version + // drop any prereleases that might already exist, since they are not + // relevant at this point. + this.prerelease.length = 0; + this.inc('patch', identifier); + this.inc('pre', identifier); + break; + // If the input is a non-prerelease version, this acts the same as + // prepatch. + case 'prerelease': + if (this.prerelease.length === 0) + this.inc('patch', identifier); + this.inc('pre', identifier); + break; + + case 'major': + // If this is a pre-major version, bump up to the same major version. + // Otherwise increment major. + // 1.0.0-5 bumps to 1.0.0 + // 1.1.0 bumps to 2.0.0 + if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) + this.major++; + this.minor = 0; + this.patch = 0; + this.prerelease = []; + break; + case 'minor': + // If this is a pre-minor version, bump up to the same minor version. + // Otherwise increment minor. + // 1.2.0-5 bumps to 1.2.0 + // 1.2.1 bumps to 1.3.0 + if (this.patch !== 0 || this.prerelease.length === 0) + this.minor++; + this.patch = 0; + this.prerelease = []; + break; + case 'patch': + // If this is not a pre-release version, it will increment the patch. + // If it is a pre-release it will bump up to the same patch version. + // 1.2.0-5 patches to 1.2.0 + // 1.2.0 patches to 1.2.1 + if (this.prerelease.length === 0) + this.patch++; + this.prerelease = []; + break; + // This probably shouldn't be used publicly. + // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. + case 'pre': + if (this.prerelease.length === 0) + this.prerelease = [0]; + else { + var i = this.prerelease.length; + while (--i >= 0) { + if (typeof this.prerelease[i] === 'number') { + this.prerelease[i]++; + i = -2; + } + } + if (i === -1) // didn't increment anything + this.prerelease.push(0); + } + if (identifier) { + // 1.2.0-beta.1 bumps to 1.2.0-beta.2, + // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 + if (this.prerelease[0] === identifier) { + if (isNaN(this.prerelease[1])) + this.prerelease = [identifier, 0]; + } else + this.prerelease = [identifier, 0]; + } + break; + + default: + throw new Error('invalid increment argument: ' + release); + } + this.format(); + this.raw = this.version; + return this; +}; + +exports.inc = inc; +function inc(version, release, loose, identifier) { + if (typeof(loose) === 'string') { + identifier = loose; + loose = undefined; + } + + try { + return new SemVer(version, loose).inc(release, identifier).version; + } catch (er) { + return null; + } +} + +exports.diff = diff; +function diff(version1, version2) { + if (eq(version1, version2)) { + return null; + } else { + var v1 = parse(version1); + var v2 = parse(version2); + if (v1.prerelease.length || v2.prerelease.length) { + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return 'pre'+key; + } + } + } + return 'prerelease'; + } + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return key; + } + } + } + } +} + +exports.compareIdentifiers = compareIdentifiers; + +var numeric = /^[0-9]+$/; +function compareIdentifiers(a, b) { + var anum = numeric.test(a); + var bnum = numeric.test(b); + + if (anum && bnum) { + a = +a; + b = +b; + } + + return (anum && !bnum) ? -1 : + (bnum && !anum) ? 1 : + a < b ? -1 : + a > b ? 1 : + 0; +} + +exports.rcompareIdentifiers = rcompareIdentifiers; +function rcompareIdentifiers(a, b) { + return compareIdentifiers(b, a); +} + +exports.major = major; +function major(a, loose) { + return new SemVer(a, loose).major; +} + +exports.minor = minor; +function minor(a, loose) { + return new SemVer(a, loose).minor; +} + +exports.patch = patch; +function patch(a, loose) { + return new SemVer(a, loose).patch; +} + +exports.compare = compare; +function compare(a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)); +} + +exports.compareLoose = compareLoose; +function compareLoose(a, b) { + return compare(a, b, true); +} + +exports.rcompare = rcompare; +function rcompare(a, b, loose) { + return compare(b, a, loose); +} + +exports.sort = sort; +function sort(list, loose) { + return list.sort(function(a, b) { + return exports.compare(a, b, loose); + }); +} + +exports.rsort = rsort; +function rsort(list, loose) { + return list.sort(function(a, b) { + return exports.rcompare(a, b, loose); + }); +} + +exports.gt = gt; +function gt(a, b, loose) { + return compare(a, b, loose) > 0; +} + +exports.lt = lt; +function lt(a, b, loose) { + return compare(a, b, loose) < 0; +} + +exports.eq = eq; +function eq(a, b, loose) { + return compare(a, b, loose) === 0; +} + +exports.neq = neq; +function neq(a, b, loose) { + return compare(a, b, loose) !== 0; +} + +exports.gte = gte; +function gte(a, b, loose) { + return compare(a, b, loose) >= 0; +} + +exports.lte = lte; +function lte(a, b, loose) { + return compare(a, b, loose) <= 0; +} + +exports.cmp = cmp; +function cmp(a, op, b, loose) { + var ret; + switch (op) { + case '===': + if (typeof a === 'object') a = a.version; + if (typeof b === 'object') b = b.version; + ret = a === b; + break; + case '!==': + if (typeof a === 'object') a = a.version; + if (typeof b === 'object') b = b.version; + ret = a !== b; + break; + case '': case '=': case '==': ret = eq(a, b, loose); break; + case '!=': ret = neq(a, b, loose); break; + case '>': ret = gt(a, b, loose); break; + case '>=': ret = gte(a, b, loose); break; + case '<': ret = lt(a, b, loose); break; + case '<=': ret = lte(a, b, loose); break; + default: throw new TypeError('Invalid operator: ' + op); + } + return ret; +} + +exports.Comparator = Comparator; +function Comparator(comp, loose) { + if (comp instanceof Comparator) { + if (comp.loose === loose) + return comp; + else + comp = comp.value; + } + + if (!(this instanceof Comparator)) + return new Comparator(comp, loose); + + debug('comparator', comp, loose); + this.loose = loose; + this.parse(comp); + + if (this.semver === ANY) + this.value = ''; + else + this.value = this.operator + this.semver.version; + + debug('comp', this); +} + +var ANY = {}; +Comparator.prototype.parse = function(comp) { + var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; + var m = comp.match(r); + + if (!m) + throw new TypeError('Invalid comparator: ' + comp); + + this.operator = m[1]; + if (this.operator === '=') + this.operator = ''; + + // if it literally is just '>' or '' then allow anything. + if (!m[2]) + this.semver = ANY; + else + this.semver = new SemVer(m[2], this.loose); +}; + +Comparator.prototype.toString = function() { + return this.value; +}; + +Comparator.prototype.test = function(version) { + debug('Comparator.test', version, this.loose); + + if (this.semver === ANY) + return true; + + if (typeof version === 'string') + version = new SemVer(version, this.loose); + + return cmp(version, this.operator, this.semver, this.loose); +}; + +Comparator.prototype.intersects = function(comp, loose) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required'); + } + + var rangeTmp; + + if (this.operator === '') { + rangeTmp = new Range(comp.value, loose); + return satisfies(this.value, rangeTmp, loose); + } else if (comp.operator === '') { + rangeTmp = new Range(this.value, loose); + return satisfies(comp.semver, rangeTmp, loose); + } + + var sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>'); + var sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<'); + var sameSemVer = this.semver.version === comp.semver.version; + var differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<='); + var oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, loose) && + ((this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<')); + var oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, loose) && + ((this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>')); + + return sameDirectionIncreasing || sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan; +}; + + +exports.Range = Range; +function Range(range, loose) { + if (range instanceof Range) { + if (range.loose === loose) { + return range; + } else { + return new Range(range.raw, loose); + } + } + + if (range instanceof Comparator) { + return new Range(range.value, loose); + } + + if (!(this instanceof Range)) + return new Range(range, loose); + + this.loose = loose; + + // First, split based on boolean or || + this.raw = range; + this.set = range.split(/\s*\|\|\s*/).map(function(range) { + return this.parseRange(range.trim()); + }, this).filter(function(c) { + // throw out any that are not relevant for whatever reason + return c.length; + }); + + if (!this.set.length) { + throw new TypeError('Invalid SemVer Range: ' + range); + } + + this.format(); +} + +Range.prototype.format = function() { + this.range = this.set.map(function(comps) { + return comps.join(' ').trim(); + }).join('||').trim(); + return this.range; +}; + +Range.prototype.toString = function() { + return this.range; +}; + +Range.prototype.parseRange = function(range) { + var loose = this.loose; + range = range.trim(); + debug('range', range, loose); + // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` + var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]; + range = range.replace(hr, hyphenReplace); + debug('hyphen replace', range); + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` + range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace); + debug('comparator trim', range, re[COMPARATORTRIM]); + + // `~ 1.2.3` => `~1.2.3` + range = range.replace(re[TILDETRIM], tildeTrimReplace); + + // `^ 1.2.3` => `^1.2.3` + range = range.replace(re[CARETTRIM], caretTrimReplace); + + // normalize spaces + range = range.split(/\s+/).join(' '); + + // At this point, the range is completely trimmed and + // ready to be split into comparators. + + var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; + var set = range.split(' ').map(function(comp) { + return parseComparator(comp, loose); + }).join(' ').split(/\s+/); + if (this.loose) { + // in loose mode, throw out any that are not valid comparators + set = set.filter(function(comp) { + return !!comp.match(compRe); + }); + } + set = set.map(function(comp) { + return new Comparator(comp, loose); + }); + + return set; +}; + +Range.prototype.intersects = function(range, loose) { + if (!(range instanceof Range)) { + throw new TypeError('a Range is required'); + } + + return this.set.some(function(thisComparators) { + return thisComparators.every(function(thisComparator) { + return range.set.some(function(rangeComparators) { + return rangeComparators.every(function(rangeComparator) { + return thisComparator.intersects(rangeComparator, loose); + }); + }); + }); + }); +}; + +// Mostly just for testing and legacy API reasons +exports.toComparators = toComparators; +function toComparators(range, loose) { + return new Range(range, loose).set.map(function(comp) { + return comp.map(function(c) { + return c.value; + }).join(' ').trim().split(' '); + }); +} + +// comprised of xranges, tildes, stars, and gtlt's at this point. +// already replaced the hyphen ranges +// turn into a set of JUST comparators. +function parseComparator(comp, loose) { + debug('comp', comp); + comp = replaceCarets(comp, loose); + debug('caret', comp); + comp = replaceTildes(comp, loose); + debug('tildes', comp); + comp = replaceXRanges(comp, loose); + debug('xrange', comp); + comp = replaceStars(comp, loose); + debug('stars', comp); + return comp; +} + +function isX(id) { + return !id || id.toLowerCase() === 'x' || id === '*'; +} + +// ~, ~> --> * (any, kinda silly) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 +function replaceTildes(comp, loose) { + return comp.trim().split(/\s+/).map(function(comp) { + return replaceTilde(comp, loose); + }).join(' '); +} + +function replaceTilde(comp, loose) { + var r = loose ? re[TILDELOOSE] : re[TILDE]; + return comp.replace(r, function(_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr); + var ret; + + if (isX(M)) + ret = ''; + else if (isX(m)) + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + else if (isX(p)) + // ~1.2 == >=1.2.0 <1.3.0 + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + else if (pr) { + debug('replaceTilde pr', pr); + if (pr.charAt(0) !== '-') + pr = '-' + pr; + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + // ~1.2.3 == >=1.2.3 <1.3.0 + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0'; + + debug('tilde return', ret); + return ret; + }); +} + +// ^ --> * (any, kinda silly) +// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 +// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 +// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2.0 --> >=1.2.0 <2.0.0 +function replaceCarets(comp, loose) { + return comp.trim().split(/\s+/).map(function(comp) { + return replaceCaret(comp, loose); + }).join(' '); +} + +function replaceCaret(comp, loose) { + debug('caret', comp, loose); + var r = loose ? re[CARETLOOSE] : re[CARET]; + return comp.replace(r, function(_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr); + var ret; + + if (isX(M)) + ret = ''; + else if (isX(m)) + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + else if (isX(p)) { + if (M === '0') + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + else + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'; + } else if (pr) { + debug('replaceCaret pr', pr); + if (pr.charAt(0) !== '-') + pr = '-' + pr; + if (M === '0') { + if (m === '0') + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + m + '.' + (+p + 1); + else + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + (+M + 1) + '.0.0'; + } else { + debug('no pr'); + if (M === '0') { + if (m === '0') + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + m + '.' + (+p + 1); + else + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + ret = '>=' + M + '.' + m + '.' + p + + ' <' + (+M + 1) + '.0.0'; + } + + debug('caret return', ret); + return ret; + }); +} + +function replaceXRanges(comp, loose) { + debug('replaceXRanges', comp, loose); + return comp.split(/\s+/).map(function(comp) { + return replaceXRange(comp, loose); + }).join(' '); +} + +function replaceXRange(comp, loose) { + comp = comp.trim(); + var r = loose ? re[XRANGELOOSE] : re[XRANGE]; + return comp.replace(r, function(ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr); + var xM = isX(M); + var xm = xM || isX(m); + var xp = xm || isX(p); + var anyX = xp; + + if (gtlt === '=' && anyX) + gtlt = ''; + + if (xM) { + if (gtlt === '>' || gtlt === '<') { + // nothing is allowed + ret = '<0.0.0'; + } else { + // nothing is forbidden + ret = '*'; + } + } else if (gtlt && anyX) { + // replace X with 0 + if (xm) + m = 0; + if (xp) + p = 0; + + if (gtlt === '>') { + // >1 => >=2.0.0 + // >1.2 => >=1.3.0 + // >1.2.3 => >= 1.2.4 + gtlt = '>='; + if (xm) { + M = +M + 1; + m = 0; + p = 0; + } else if (xp) { + m = +m + 1; + p = 0; + } + } else if (gtlt === '<=') { + // <=0.7.x is actually <0.8.0, since any 0.7.x should + // pass. Similarly, <=7.x is actually <8.0.0, etc. + gtlt = '<'; + if (xm) + M = +M + 1; + else + m = +m + 1; + } + + ret = gtlt + M + '.' + m + '.' + p; + } else if (xm) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + } else if (xp) { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + } + + debug('xRange return', ret); + + return ret; + }); +} + +// Because * is AND-ed with everything else in the comparator, +// and '' means "any version", just remove the *s entirely. +function replaceStars(comp, loose) { + debug('replaceStars', comp, loose); + // Looseness is ignored here. star is always as loose as it gets! + return comp.trim().replace(re[STAR], ''); +} + +// This function is passed to string.replace(re[HYPHENRANGE]) +// M, m, patch, prerelease, build +// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 +// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do +// 1.2 - 3.4 => >=1.2.0 <3.5.0 +function hyphenReplace($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + + if (isX(fM)) + from = ''; + else if (isX(fm)) + from = '>=' + fM + '.0.0'; + else if (isX(fp)) + from = '>=' + fM + '.' + fm + '.0'; + else + from = '>=' + from; + + if (isX(tM)) + to = ''; + else if (isX(tm)) + to = '<' + (+tM + 1) + '.0.0'; + else if (isX(tp)) + to = '<' + tM + '.' + (+tm + 1) + '.0'; + else if (tpr) + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr; + else + to = '<=' + to; + + return (from + ' ' + to).trim(); +} + + +// if ANY of the sets match ALL of its comparators, then pass +Range.prototype.test = function(version) { + if (!version) + return false; + + if (typeof version === 'string') + version = new SemVer(version, this.loose); + + for (var i = 0; i < this.set.length; i++) { + if (testSet(this.set[i], version)) + return true; + } + return false; +}; + +function testSet(set, version) { + for (var i = 0; i < set.length; i++) { + if (!set[i].test(version)) + return false; + } + + if (version.prerelease.length) { + // Find the set of versions that are allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (var i = 0; i < set.length; i++) { + debug(set[i].semver); + if (set[i].semver === ANY) + continue; + + if (set[i].semver.prerelease.length > 0) { + var allowed = set[i].semver; + if (allowed.major === version.major && + allowed.minor === version.minor && + allowed.patch === version.patch) + return true; + } + } + + // Version has a -pre, but it's not one of the ones we like. + return false; + } + + return true; +} + +exports.satisfies = satisfies; +function satisfies(version, range, loose) { + try { + range = new Range(range, loose); + } catch (er) { + return false; + } + return range.test(version); +} + +exports.maxSatisfying = maxSatisfying; +function maxSatisfying(versions, range, loose) { + var max = null; + var maxSV = null; + try { + var rangeObj = new Range(range, loose); + } catch (er) { + return null; + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { // satisfies(v, range, loose) + if (!max || maxSV.compare(v) === -1) { // compare(max, v, true) + max = v; + maxSV = new SemVer(max, loose); + } + } + }) + return max; +} + +exports.minSatisfying = minSatisfying; +function minSatisfying(versions, range, loose) { + var min = null; + var minSV = null; + try { + var rangeObj = new Range(range, loose); + } catch (er) { + return null; + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { // satisfies(v, range, loose) + if (!min || minSV.compare(v) === 1) { // compare(min, v, true) + min = v; + minSV = new SemVer(min, loose); + } + } + }) + return min; +} + +exports.validRange = validRange; +function validRange(range, loose) { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, loose).range || '*'; + } catch (er) { + return null; + } +} + +// Determine if version is less than all the versions possible in the range +exports.ltr = ltr; +function ltr(version, range, loose) { + return outside(version, range, '<', loose); +} + +// Determine if version is greater than all the versions possible in the range. +exports.gtr = gtr; +function gtr(version, range, loose) { + return outside(version, range, '>', loose); +} + +exports.outside = outside; +function outside(version, range, hilo, loose) { + version = new SemVer(version, loose); + range = new Range(range, loose); + + var gtfn, ltefn, ltfn, comp, ecomp; + switch (hilo) { + case '>': + gtfn = gt; + ltefn = lte; + ltfn = lt; + comp = '>'; + ecomp = '>='; + break; + case '<': + gtfn = lt; + ltefn = gte; + ltfn = gt; + comp = '<'; + ecomp = '<='; + break; + default: + throw new TypeError('Must provide a hilo val of "<" or ">"'); + } + + // If it satisifes the range it is not outside + if (satisfies(version, range, loose)) { + return false; + } + + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. + + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i]; + + var high = null; + var low = null; + + comparators.forEach(function(comparator) { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') + } + high = high || comparator; + low = low || comparator; + if (gtfn(comparator.semver, high.semver, loose)) { + high = comparator; + } else if (ltfn(comparator.semver, low.semver, loose)) { + low = comparator; + } + }); + + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false; + } + + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false; + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false; + } + } + return true; +} + +exports.prerelease = prerelease; +function prerelease(version, loose) { + var parsed = parse(version, loose); + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null; +} + +exports.intersects = intersects; +function intersects(r1, r2, loose) { + r1 = new Range(r1, loose) + r2 = new Range(r2, loose) + return r1.intersects(r2) +} + +exports.coerce = coerce; +function coerce(version) { + if (version instanceof SemVer) + return version; + + if (typeof version !== 'string') + return null; + + var match = version.match(re[COERCE]); + + if (match == null) + return null; + + return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0')); +} + + +/***/ }), +/* 23 */ +/***/ (function(module, exports) { + +module.exports = require("stream"); + +/***/ }), +/* 24 */ +/***/ (function(module, exports) { + +module.exports = require("url"); + +/***/ }), +/* 25 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscription; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_isArray__ = __webpack_require__(41); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isObject__ = __webpack_require__(444); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isFunction__ = __webpack_require__(154); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_tryCatch__ = __webpack_require__(56); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_errorObject__ = __webpack_require__(48); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__ = __webpack_require__(441); +/** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_tryCatch,_util_errorObject,_util_UnsubscriptionError PURE_IMPORTS_END */ + + + + + + +var Subscription = /*@__PURE__*/ (function () { + function Subscription(unsubscribe) { + this.closed = false; + this._parent = null; + this._parents = null; + this._subscriptions = null; + if (unsubscribe) { + this._unsubscribe = unsubscribe; + } + } + Subscription.prototype.unsubscribe = function () { + var hasErrors = false; + var errors; + if (this.closed) { + return; + } + var _a = this, _parent = _a._parent, _parents = _a._parents, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions; + this.closed = true; + this._parent = null; + this._parents = null; + this._subscriptions = null; + var index = -1; + var len = _parents ? _parents.length : 0; + while (_parent) { + _parent.remove(this); + _parent = ++index < len && _parents[index] || null; + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__util_isFunction__["a" /* isFunction */])(_unsubscribe)) { + var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(_unsubscribe).call(this); + if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { + hasErrors = true; + errors = errors || (__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */] ? + flattenUnsubscriptionErrors(__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e.errors) : [__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e]); + } + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_isArray__["a" /* isArray */])(_subscriptions)) { + index = -1; + len = _subscriptions.length; + while (++index < len) { + var sub = _subscriptions[index]; + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isObject__["a" /* isObject */])(sub)) { + var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(sub.unsubscribe).call(sub); + if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { + hasErrors = true; + errors = errors || []; + var err = __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e; + if (err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) { + errors = errors.concat(flattenUnsubscriptionErrors(err.errors)); + } + else { + errors.push(err); + } + } + } + } + } + if (hasErrors) { + throw new __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */](errors); + } + }; + Subscription.prototype.add = function (teardown) { + if (!teardown || (teardown === Subscription.EMPTY)) { + return Subscription.EMPTY; + } + if (teardown === this) { + return this; + } + var subscription = teardown; + switch (typeof teardown) { + case 'function': + subscription = new Subscription(teardown); + case 'object': + if (subscription.closed || typeof subscription.unsubscribe !== 'function') { + return subscription; + } + else if (this.closed) { + subscription.unsubscribe(); + return subscription; + } + else if (typeof subscription._addParent !== 'function') { + var tmp = subscription; + subscription = new Subscription(); + subscription._subscriptions = [tmp]; + } + break; + default: + throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); + } + var subscriptions = this._subscriptions || (this._subscriptions = []); + subscriptions.push(subscription); + subscription._addParent(this); + return subscription; + }; + Subscription.prototype.remove = function (subscription) { + var subscriptions = this._subscriptions; + if (subscriptions) { + var subscriptionIndex = subscriptions.indexOf(subscription); + if (subscriptionIndex !== -1) { + subscriptions.splice(subscriptionIndex, 1); + } + } + }; + Subscription.prototype._addParent = function (parent) { + var _a = this, _parent = _a._parent, _parents = _a._parents; + if (!_parent || _parent === parent) { + this._parent = parent; + } + else if (!_parents) { + this._parents = [parent]; + } + else if (_parents.indexOf(parent) === -1) { + _parents.push(parent); + } + }; + Subscription.EMPTY = (function (empty) { + empty.closed = true; + return empty; + }(new Subscription())); + return Subscription; +}()); + +function flattenUnsubscriptionErrors(errors) { + return errors.reduce(function (errs, err) { return errs.concat((err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) ? err.errors : err); }, []); +} +//# sourceMappingURL=Subscription.js.map + + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2015 Joyent, Inc. + +module.exports = { + bufferSplit: bufferSplit, + addRSAMissing: addRSAMissing, + calculateDSAPublic: calculateDSAPublic, + calculateED25519Public: calculateED25519Public, + calculateX25519Public: calculateX25519Public, + mpNormalize: mpNormalize, + mpDenormalize: mpDenormalize, + ecNormalize: ecNormalize, + countZeros: countZeros, + assertCompatible: assertCompatible, + isCompatible: isCompatible, + opensslKeyDeriv: opensslKeyDeriv, + opensshCipherInfo: opensshCipherInfo, + publicFromPrivateECDSA: publicFromPrivateECDSA, + zeroPadToLength: zeroPadToLength, + writeBitString: writeBitString, + readBitString: readBitString +}; + +var assert = __webpack_require__(16); +var Buffer = __webpack_require__(15).Buffer; +var PrivateKey = __webpack_require__(33); +var Key = __webpack_require__(27); +var crypto = __webpack_require__(11); +var algs = __webpack_require__(32); +var asn1 = __webpack_require__(66); + +var ec, jsbn; +var nacl; + +var MAX_CLASS_DEPTH = 3; + +function isCompatible(obj, klass, needVer) { + if (obj === null || typeof (obj) !== 'object') + return (false); + if (needVer === undefined) + needVer = klass.prototype._sshpkApiVersion; + if (obj instanceof klass && + klass.prototype._sshpkApiVersion[0] == needVer[0]) + return (true); + var proto = Object.getPrototypeOf(obj); + var depth = 0; + while (proto.constructor.name !== klass.name) { + proto = Object.getPrototypeOf(proto); + if (!proto || ++depth > MAX_CLASS_DEPTH) + return (false); + } + if (proto.constructor.name !== klass.name) + return (false); + var ver = proto._sshpkApiVersion; + if (ver === undefined) + ver = klass._oldVersionDetect(obj); + if (ver[0] != needVer[0] || ver[1] < needVer[1]) + return (false); + return (true); +} + +function assertCompatible(obj, klass, needVer, name) { + if (name === undefined) + name = 'object'; + assert.ok(obj, name + ' must not be null'); + assert.object(obj, name + ' must be an object'); + if (needVer === undefined) + needVer = klass.prototype._sshpkApiVersion; + if (obj instanceof klass && + klass.prototype._sshpkApiVersion[0] == needVer[0]) + return; + var proto = Object.getPrototypeOf(obj); + var depth = 0; + while (proto.constructor.name !== klass.name) { + proto = Object.getPrototypeOf(proto); + assert.ok(proto && ++depth <= MAX_CLASS_DEPTH, + name + ' must be a ' + klass.name + ' instance'); + } + assert.strictEqual(proto.constructor.name, klass.name, + name + ' must be a ' + klass.name + ' instance'); + var ver = proto._sshpkApiVersion; + if (ver === undefined) + ver = klass._oldVersionDetect(obj); + assert.ok(ver[0] == needVer[0] && ver[1] >= needVer[1], + name + ' must be compatible with ' + klass.name + ' klass ' + + 'version ' + needVer[0] + '.' + needVer[1]); +} + +var CIPHER_LEN = { + 'des-ede3-cbc': { key: 7, iv: 8 }, + 'aes-128-cbc': { key: 16, iv: 16 } +}; +var PKCS5_SALT_LEN = 8; + +function opensslKeyDeriv(cipher, salt, passphrase, count) { + assert.buffer(salt, 'salt'); + assert.buffer(passphrase, 'passphrase'); + assert.number(count, 'iteration count'); + + var clen = CIPHER_LEN[cipher]; + assert.object(clen, 'supported cipher'); + + salt = salt.slice(0, PKCS5_SALT_LEN); + + var D, D_prev, bufs; + var material = Buffer.alloc(0); + while (material.length < clen.key + clen.iv) { + bufs = []; + if (D_prev) + bufs.push(D_prev); + bufs.push(passphrase); + bufs.push(salt); + D = Buffer.concat(bufs); + for (var j = 0; j < count; ++j) + D = crypto.createHash('md5').update(D).digest(); + material = Buffer.concat([material, D]); + D_prev = D; + } + + return ({ + key: material.slice(0, clen.key), + iv: material.slice(clen.key, clen.key + clen.iv) + }); +} + +/* Count leading zero bits on a buffer */ +function countZeros(buf) { + var o = 0, obit = 8; + while (o < buf.length) { + var mask = (1 << obit); + if ((buf[o] & mask) === mask) + break; + obit--; + if (obit < 0) { + o++; + obit = 8; + } + } + return (o*8 + (8 - obit) - 1); +} + +function bufferSplit(buf, chr) { + assert.buffer(buf); + assert.string(chr); + + var parts = []; + var lastPart = 0; + var matches = 0; + for (var i = 0; i < buf.length; ++i) { + if (buf[i] === chr.charCodeAt(matches)) + ++matches; + else if (buf[i] === chr.charCodeAt(0)) + matches = 1; + else + matches = 0; + + if (matches >= chr.length) { + var newPart = i + 1; + parts.push(buf.slice(lastPart, newPart - matches)); + lastPart = newPart; + matches = 0; + } + } + if (lastPart <= buf.length) + parts.push(buf.slice(lastPart, buf.length)); + + return (parts); +} + +function ecNormalize(buf, addZero) { + assert.buffer(buf); + if (buf[0] === 0x00 && buf[1] === 0x04) { + if (addZero) + return (buf); + return (buf.slice(1)); + } else if (buf[0] === 0x04) { + if (!addZero) + return (buf); + } else { + while (buf[0] === 0x00) + buf = buf.slice(1); + if (buf[0] === 0x02 || buf[0] === 0x03) + throw (new Error('Compressed elliptic curve points ' + + 'are not supported')); + if (buf[0] !== 0x04) + throw (new Error('Not a valid elliptic curve point')); + if (!addZero) + return (buf); + } + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x0; + buf.copy(b, 1); + return (b); +} + +function readBitString(der, tag) { + if (tag === undefined) + tag = asn1.Ber.BitString; + var buf = der.readString(tag, true); + assert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' + + 'not supported (0x' + buf[0].toString(16) + ')'); + return (buf.slice(1)); +} + +function writeBitString(der, buf, tag) { + if (tag === undefined) + tag = asn1.Ber.BitString; + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + der.writeBuffer(b, tag); +} + +function mpNormalize(buf) { + assert.buffer(buf); + while (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00) + buf = buf.slice(1); + if ((buf[0] & 0x80) === 0x80) { + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + buf = b; + } + return (buf); +} + +function mpDenormalize(buf) { + assert.buffer(buf); + while (buf.length > 1 && buf[0] === 0x00) + buf = buf.slice(1); + return (buf); +} + +function zeroPadToLength(buf, len) { + assert.buffer(buf); + assert.number(len); + while (buf.length > len) { + assert.equal(buf[0], 0x00); + buf = buf.slice(1); + } + while (buf.length < len) { + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + buf = b; + } + return (buf); +} + +function bigintToMpBuf(bigint) { + var buf = Buffer.from(bigint.toByteArray()); + buf = mpNormalize(buf); + return (buf); +} + +function calculateDSAPublic(g, p, x) { + assert.buffer(g); + assert.buffer(p); + assert.buffer(x); + try { + var bigInt = __webpack_require__(81).BigInteger; + } catch (e) { + throw (new Error('To load a PKCS#8 format DSA private key, ' + + 'the node jsbn library is required.')); + } + g = new bigInt(g); + p = new bigInt(p); + x = new bigInt(x); + var y = g.modPow(x, p); + var ybuf = bigintToMpBuf(y); + return (ybuf); +} + +function calculateED25519Public(k) { + assert.buffer(k); + + if (nacl === undefined) + nacl = __webpack_require__(76); + + var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k)); + return (Buffer.from(kp.publicKey)); +} + +function calculateX25519Public(k) { + assert.buffer(k); + + if (nacl === undefined) + nacl = __webpack_require__(76); + + var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k)); + return (Buffer.from(kp.publicKey)); +} + +function addRSAMissing(key) { + assert.object(key); + assertCompatible(key, PrivateKey, [1, 1]); + try { + var bigInt = __webpack_require__(81).BigInteger; + } catch (e) { + throw (new Error('To write a PEM private key from ' + + 'this source, the node jsbn lib is required.')); + } + + var d = new bigInt(key.part.d.data); + var buf; + + if (!key.part.dmodp) { + var p = new bigInt(key.part.p.data); + var dmodp = d.mod(p.subtract(1)); + + buf = bigintToMpBuf(dmodp); + key.part.dmodp = {name: 'dmodp', data: buf}; + key.parts.push(key.part.dmodp); + } + if (!key.part.dmodq) { + var q = new bigInt(key.part.q.data); + var dmodq = d.mod(q.subtract(1)); + + buf = bigintToMpBuf(dmodq); + key.part.dmodq = {name: 'dmodq', data: buf}; + key.parts.push(key.part.dmodq); + } +} + +function publicFromPrivateECDSA(curveName, priv) { + assert.string(curveName, 'curveName'); + assert.buffer(priv); + if (ec === undefined) + ec = __webpack_require__(139); + if (jsbn === undefined) + jsbn = __webpack_require__(81).BigInteger; + var params = algs.curves[curveName]; + var p = new jsbn(params.p); + var a = new jsbn(params.a); + var b = new jsbn(params.b); + var curve = new ec.ECCurveFp(p, a, b); + var G = curve.decodePointHex(params.G.toString('hex')); + + var d = new jsbn(mpNormalize(priv)); + var pub = G.multiply(d); + pub = Buffer.from(curve.encodePointHex(pub), 'hex'); + + var parts = []; + parts.push({name: 'curve', data: Buffer.from(curveName)}); + parts.push({name: 'Q', data: pub}); + + var key = new Key({type: 'ecdsa', curve: curve, parts: parts}); + return (key); +} + +function opensshCipherInfo(cipher) { + var inf = {}; + switch (cipher) { + case '3des-cbc': + inf.keySize = 24; + inf.blockSize = 8; + inf.opensslName = 'des-ede3-cbc'; + break; + case 'blowfish-cbc': + inf.keySize = 16; + inf.blockSize = 8; + inf.opensslName = 'bf-cbc'; + break; + case 'aes128-cbc': + case 'aes128-ctr': + case 'aes128-gcm@openssh.com': + inf.keySize = 16; + inf.blockSize = 16; + inf.opensslName = 'aes-128-' + cipher.slice(7, 10); + break; + case 'aes192-cbc': + case 'aes192-ctr': + case 'aes192-gcm@openssh.com': + inf.keySize = 24; + inf.blockSize = 16; + inf.opensslName = 'aes-192-' + cipher.slice(7, 10); + break; + case 'aes256-cbc': + case 'aes256-ctr': + case 'aes256-gcm@openssh.com': + inf.keySize = 32; + inf.blockSize = 16; + inf.opensslName = 'aes-256-' + cipher.slice(7, 10); + break; + default: + throw (new Error( + 'Unsupported openssl cipher "' + cipher + '"')); + } + return (inf); +} + + +/***/ }), +/* 27 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2017 Joyent, Inc. + +module.exports = Key; + +var assert = __webpack_require__(16); +var algs = __webpack_require__(32); +var crypto = __webpack_require__(11); +var Fingerprint = __webpack_require__(156); +var Signature = __webpack_require__(75); +var DiffieHellman = __webpack_require__(325).DiffieHellman; +var errs = __webpack_require__(74); +var utils = __webpack_require__(26); +var PrivateKey = __webpack_require__(33); +var edCompat; + +try { + edCompat = __webpack_require__(454); +} catch (e) { + /* Just continue through, and bail out if we try to use it. */ +} + +var InvalidAlgorithmError = errs.InvalidAlgorithmError; +var KeyParseError = errs.KeyParseError; + +var formats = {}; +formats['auto'] = __webpack_require__(455); +formats['pem'] = __webpack_require__(86); +formats['pkcs1'] = __webpack_require__(327); +formats['pkcs8'] = __webpack_require__(157); +formats['rfc4253'] = __webpack_require__(103); +formats['ssh'] = __webpack_require__(456); +formats['ssh-private'] = __webpack_require__(192); +formats['openssh'] = formats['ssh-private']; +formats['dnssec'] = __webpack_require__(326); + +function Key(opts) { + assert.object(opts, 'options'); + assert.arrayOfObject(opts.parts, 'options.parts'); + assert.string(opts.type, 'options.type'); + assert.optionalString(opts.comment, 'options.comment'); + + var algInfo = algs.info[opts.type]; + if (typeof (algInfo) !== 'object') + throw (new InvalidAlgorithmError(opts.type)); + + var partLookup = {}; + for (var i = 0; i < opts.parts.length; ++i) { + var part = opts.parts[i]; + partLookup[part.name] = part; + } + + this.type = opts.type; + this.parts = opts.parts; + this.part = partLookup; + this.comment = undefined; + this.source = opts.source; + + /* for speeding up hashing/fingerprint operations */ + this._rfc4253Cache = opts._rfc4253Cache; + this._hashCache = {}; + + var sz; + this.curve = undefined; + if (this.type === 'ecdsa') { + var curve = this.part.curve.data.toString(); + this.curve = curve; + sz = algs.curves[curve].size; + } else if (this.type === 'ed25519' || this.type === 'curve25519') { + sz = 256; + this.curve = 'curve25519'; + } else { + var szPart = this.part[algInfo.sizePart]; + sz = szPart.data.length; + sz = sz * 8 - utils.countZeros(szPart.data); + } + this.size = sz; +} + +Key.formats = formats; + +Key.prototype.toBuffer = function (format, options) { + if (format === undefined) + format = 'ssh'; + assert.string(format, 'format'); + assert.object(formats[format], 'formats[format]'); + assert.optionalObject(options, 'options'); + + if (format === 'rfc4253') { + if (this._rfc4253Cache === undefined) + this._rfc4253Cache = formats['rfc4253'].write(this); + return (this._rfc4253Cache); + } + + return (formats[format].write(this, options)); +}; + +Key.prototype.toString = function (format, options) { + return (this.toBuffer(format, options).toString()); +}; + +Key.prototype.hash = function (algo) { + assert.string(algo, 'algorithm'); + algo = algo.toLowerCase(); + if (algs.hashAlgs[algo] === undefined) + throw (new InvalidAlgorithmError(algo)); + + if (this._hashCache[algo]) + return (this._hashCache[algo]); + var hash = crypto.createHash(algo). + update(this.toBuffer('rfc4253')).digest(); + this._hashCache[algo] = hash; + return (hash); +}; + +Key.prototype.fingerprint = function (algo) { + if (algo === undefined) + algo = 'sha256'; + assert.string(algo, 'algorithm'); + var opts = { + type: 'key', + hash: this.hash(algo), + algorithm: algo + }; + return (new Fingerprint(opts)); +}; + +Key.prototype.defaultHashAlgorithm = function () { + var hashAlgo = 'sha1'; + if (this.type === 'rsa') + hashAlgo = 'sha256'; + if (this.type === 'dsa' && this.size > 1024) + hashAlgo = 'sha256'; + if (this.type === 'ed25519') + hashAlgo = 'sha512'; + if (this.type === 'ecdsa') { + if (this.size <= 256) + hashAlgo = 'sha256'; + else if (this.size <= 384) + hashAlgo = 'sha384'; + else + hashAlgo = 'sha512'; + } + return (hashAlgo); +}; + +Key.prototype.createVerify = function (hashAlgo) { + if (hashAlgo === undefined) + hashAlgo = this.defaultHashAlgorithm(); + assert.string(hashAlgo, 'hash algorithm'); + + /* ED25519 is not supported by OpenSSL, use a javascript impl. */ + if (this.type === 'ed25519' && edCompat !== undefined) + return (new edCompat.Verifier(this, hashAlgo)); + if (this.type === 'curve25519') + throw (new Error('Curve25519 keys are not suitable for ' + + 'signing or verification')); + + var v, nm, err; + try { + nm = hashAlgo.toUpperCase(); + v = crypto.createVerify(nm); + } catch (e) { + err = e; + } + if (v === undefined || (err instanceof Error && + err.message.match(/Unknown message digest/))) { + nm = 'RSA-'; + nm += hashAlgo.toUpperCase(); + v = crypto.createVerify(nm); + } + assert.ok(v, 'failed to create verifier'); + var oldVerify = v.verify.bind(v); + var key = this.toBuffer('pkcs8'); + var curve = this.curve; + var self = this; + v.verify = function (signature, fmt) { + if (Signature.isSignature(signature, [2, 0])) { + if (signature.type !== self.type) + return (false); + if (signature.hashAlgorithm && + signature.hashAlgorithm !== hashAlgo) + return (false); + if (signature.curve && self.type === 'ecdsa' && + signature.curve !== curve) + return (false); + return (oldVerify(key, signature.toBuffer('asn1'))); + + } else if (typeof (signature) === 'string' || + Buffer.isBuffer(signature)) { + return (oldVerify(key, signature, fmt)); + + /* + * Avoid doing this on valid arguments, walking the prototype + * chain can be quite slow. + */ + } else if (Signature.isSignature(signature, [1, 0])) { + throw (new Error('signature was created by too old ' + + 'a version of sshpk and cannot be verified')); + + } else { + throw (new TypeError('signature must be a string, ' + + 'Buffer, or Signature object')); + } + }; + return (v); +}; + +Key.prototype.createDiffieHellman = function () { + if (this.type === 'rsa') + throw (new Error('RSA keys do not support Diffie-Hellman')); + + return (new DiffieHellman(this)); +}; +Key.prototype.createDH = Key.prototype.createDiffieHellman; + +Key.parse = function (data, format, options) { + if (typeof (data) !== 'string') + assert.buffer(data, 'data'); + if (format === undefined) + format = 'auto'; + assert.string(format, 'format'); + if (typeof (options) === 'string') + options = { filename: options }; + assert.optionalObject(options, 'options'); + if (options === undefined) + options = {}; + assert.optionalString(options.filename, 'options.filename'); + if (options.filename === undefined) + options.filename = '(unnamed)'; + + assert.object(formats[format], 'formats[format]'); + + try { + var k = formats[format].read(data, options); + if (k instanceof PrivateKey) + k = k.toPublic(); + if (!k.comment) + k.comment = options.filename; + return (k); + } catch (e) { + if (e.name === 'KeyEncryptedError') + throw (e); + throw (new KeyParseError(options.filename, format, e)); + } +}; + +Key.isKey = function (obj, ver) { + return (utils.isCompatible(obj, Key, ver)); +}; + +/* + * API versions for Key: + * [1,0] -- initial ver, may take Signature for createVerify or may not + * [1,1] -- added pkcs1, pkcs8 formats + * [1,2] -- added auto, ssh-private, openssh formats + * [1,3] -- added defaultHashAlgorithm + * [1,4] -- added ed support, createDH + * [1,5] -- first explicitly tagged version + * [1,6] -- changed ed25519 part names + */ +Key.prototype._sshpkApiVersion = [1, 6]; + +Key._oldVersionDetect = function (obj) { + assert.func(obj.toBuffer); + assert.func(obj.fingerprint); + if (obj.createDH) + return ([1, 4]); + if (obj.defaultHashAlgorithm) + return ([1, 3]); + if (obj.formats['auto']) + return ([1, 2]); + if (obj.formats['pkcs1']) + return ([1, 1]); + return ([1, 0]); +}; + + +/***/ }), +/* 28 */ +/***/ (function(module, exports) { + +module.exports = require("assert"); + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = nullify; +function nullify(obj = {}) { + if (Array.isArray(obj)) { + for (var _iterator = obj, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const item = _ref; + + nullify(item); + } + } else if (obj !== null && typeof obj === 'object' || typeof obj === 'function') { + Object.setPrototypeOf(obj, null); + + // for..in can only be applied to 'object', not 'function' + if (typeof obj === 'object') { + for (const key in obj) { + nullify(obj[key]); + } + } + } + + return obj; +} + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const escapeStringRegexp = __webpack_require__(388); +const ansiStyles = __webpack_require__(506); +const stdoutColor = __webpack_require__(598).stdout; + +const template = __webpack_require__(599); + +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); + +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; + +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = new Set(['gray']); + +const styles = Object.create(null); + +function applyOptions(obj, options) { + options = options || {}; + + // Detect level if not set manually + const scLevel = stdoutColor ? stdoutColor.level : 0; + obj.level = options.level === undefined ? scLevel : options.level; + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; +} + +function Chalk(options) { + // We check for this.template here since calling `chalk.constructor()` + // by itself will have a `this` of a previously constructed chalk object + if (!this || !(this instanceof Chalk) || this.template) { + const chalk = {}; + applyOptions(chalk, options); + + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; + + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); + + chalk.template.constructor = Chalk; + + return chalk.template; + } + + applyOptions(this, options); +} + +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; +} + +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} + +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); + } +}; + +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; + } + + styles[model] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.color.close, + closeRe: ansiStyles.color.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} + +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; + } + + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.bgColor.close, + closeRe: ansiStyles.bgColor.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} + +const proto = Object.defineProperties(() => {}, styles); + +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; + + builder._styles = _styles; + builder._empty = _empty; + + const self = this; + + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); + + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); + + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + + // `__proto__` is used because we must return a function, but there is + // no way to create a function with a different prototype + builder.__proto__ = proto; // eslint-disable-line no-proto + + return builder; +} + +function applyStyle() { + // Support varags, but simply cast to string in case there's only one arg + const args = arguments; + const argsLen = args.length; + let str = String(arguments[0]); + + if (argsLen === 0) { + return ''; + } + + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } + + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; + } + + // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, + // see https://github.com/chalk/chalk/issues/58 + // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. + const originalDim = ansiStyles.dim.open; + if (isSimpleWindowsTerm && this.hasGrey) { + ansiStyles.dim.open = ''; + } + + for (const code of this._styles.slice().reverse()) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + str = code.open + str.replace(code.closeRe, code.open) + code.close; + + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS + // https://github.com/chalk/chalk/pull/92 + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + } + + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; + + return str; +} + +function chalkTag(chalk, strings) { + if (!Array.isArray(strings)) { + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return [].slice.call(arguments, 1).join(' '); + } + + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; + + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } + + return template(chalk, parts.join('')); +} + +Object.defineProperties(Chalk.prototype, styles); + +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript + + +/***/ }), +/* 31 */ +/***/ (function(module, exports) { + +var core = module.exports = { version: '2.5.7' }; +if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef + + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2015 Joyent, Inc. + +var Buffer = __webpack_require__(15).Buffer; + +var algInfo = { + 'dsa': { + parts: ['p', 'q', 'g', 'y'], + sizePart: 'p' + }, + 'rsa': { + parts: ['e', 'n'], + sizePart: 'n' + }, + 'ecdsa': { + parts: ['curve', 'Q'], + sizePart: 'Q' + }, + 'ed25519': { + parts: ['A'], + sizePart: 'A' + } +}; +algInfo['curve25519'] = algInfo['ed25519']; + +var algPrivInfo = { + 'dsa': { + parts: ['p', 'q', 'g', 'y', 'x'] + }, + 'rsa': { + parts: ['n', 'e', 'd', 'iqmp', 'p', 'q'] + }, + 'ecdsa': { + parts: ['curve', 'Q', 'd'] + }, + 'ed25519': { + parts: ['A', 'k'] + } +}; +algPrivInfo['curve25519'] = algPrivInfo['ed25519']; + +var hashAlgs = { + 'md5': true, + 'sha1': true, + 'sha256': true, + 'sha384': true, + 'sha512': true +}; + +/* + * Taken from + * http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf + */ +var curves = { + 'nistp256': { + size: 256, + pkcs8oid: '1.2.840.10045.3.1.7', + p: Buffer.from(('00' + + 'ffffffff 00000001 00000000 00000000' + + '00000000 ffffffff ffffffff ffffffff'). + replace(/ /g, ''), 'hex'), + a: Buffer.from(('00' + + 'FFFFFFFF 00000001 00000000 00000000' + + '00000000 FFFFFFFF FFFFFFFF FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(( + '5ac635d8 aa3a93e7 b3ebbd55 769886bc' + + '651d06b0 cc53b0f6 3bce3c3e 27d2604b'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'c49d3608 86e70493 6a6678e1 139d26b7' + + '819f7e90'). + replace(/ /g, ''), 'hex'), + n: Buffer.from(('00' + + 'ffffffff 00000000 ffffffff ffffffff' + + 'bce6faad a7179e84 f3b9cac2 fc632551'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + '6b17d1f2 e12c4247 f8bce6e5 63a440f2' + + '77037d81 2deb33a0 f4a13945 d898c296' + + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' + + '2bce3357 6b315ece cbb64068 37bf51f5'). + replace(/ /g, ''), 'hex') + }, + 'nistp384': { + size: 384, + pkcs8oid: '1.3.132.0.34', + p: Buffer.from(('00' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff fffffffe' + + 'ffffffff 00000000 00000000 ffffffff'). + replace(/ /g, ''), 'hex'), + a: Buffer.from(('00' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' + + 'FFFFFFFF 00000000 00000000 FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(( + 'b3312fa7 e23ee7e4 988e056b e3f82d19' + + '181d9c6e fe814112 0314088f 5013875a' + + 'c656398d 8a2ed19d 2a85c8ed d3ec2aef'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'a335926a a319a27a 1d00896a 6773a482' + + '7acdac73'). + replace(/ /g, ''), 'hex'), + n: Buffer.from(('00' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff c7634d81 f4372ddf' + + '581a0db2 48b0a77a ecec196a ccc52973'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + 'aa87ca22 be8b0537 8eb1c71e f320ad74' + + '6e1d3b62 8ba79b98 59f741e0 82542a38' + + '5502f25d bf55296c 3a545e38 72760ab7' + + '3617de4a 96262c6f 5d9e98bf 9292dc29' + + 'f8f41dbd 289a147c e9da3113 b5f0b8c0' + + '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'). + replace(/ /g, ''), 'hex') + }, + 'nistp521': { + size: 521, + pkcs8oid: '1.3.132.0.35', + p: Buffer.from(( + '01ffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffff').replace(/ /g, ''), 'hex'), + a: Buffer.from(('01FF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(('51' + + '953eb961 8e1c9a1f 929a21a0 b68540ee' + + 'a2da725b 99b315f3 b8b48991 8ef109e1' + + '56193951 ec7e937b 1652c0bd 3bb1bf07' + + '3573df88 3d2c34f1 ef451fd4 6b503f00'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'd09e8800 291cb853 96cc6717 393284aa' + + 'a0da64ba').replace(/ /g, ''), 'hex'), + n: Buffer.from(('01ff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff fffffffa' + + '51868783 bf2f966b 7fcc0148 f709a5d0' + + '3bb5c9b8 899c47ae bb6fb71e 91386409'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + '00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' + + '9c648139 053fb521 f828af60 6b4d3dba' + + 'a14b5e77 efe75928 fe1dc127 a2ffa8de' + + '3348b3c1 856a429b f97e7e31 c2e5bd66' + + '0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' + + '98f54449 579b4468 17afbd17 273e662c' + + '97ee7299 5ef42640 c550b901 3fad0761' + + '353c7086 a272c240 88be9476 9fd16650'). + replace(/ /g, ''), 'hex') + } +}; + +module.exports = { + info: algInfo, + privInfo: algPrivInfo, + hashAlgs: hashAlgs, + curves: curves +}; + + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2017 Joyent, Inc. + +module.exports = PrivateKey; + +var assert = __webpack_require__(16); +var Buffer = __webpack_require__(15).Buffer; +var algs = __webpack_require__(32); +var crypto = __webpack_require__(11); +var Fingerprint = __webpack_require__(156); +var Signature = __webpack_require__(75); +var errs = __webpack_require__(74); +var util = __webpack_require__(3); +var utils = __webpack_require__(26); +var dhe = __webpack_require__(325); +var generateECDSA = dhe.generateECDSA; +var generateED25519 = dhe.generateED25519; +var edCompat; +var nacl; + +try { + edCompat = __webpack_require__(454); +} catch (e) { + /* Just continue through, and bail out if we try to use it. */ +} + +var Key = __webpack_require__(27); + +var InvalidAlgorithmError = errs.InvalidAlgorithmError; +var KeyParseError = errs.KeyParseError; +var KeyEncryptedError = errs.KeyEncryptedError; + +var formats = {}; +formats['auto'] = __webpack_require__(455); +formats['pem'] = __webpack_require__(86); +formats['pkcs1'] = __webpack_require__(327); +formats['pkcs8'] = __webpack_require__(157); +formats['rfc4253'] = __webpack_require__(103); +formats['ssh-private'] = __webpack_require__(192); +formats['openssh'] = formats['ssh-private']; +formats['ssh'] = formats['ssh-private']; +formats['dnssec'] = __webpack_require__(326); + +function PrivateKey(opts) { + assert.object(opts, 'options'); + Key.call(this, opts); + + this._pubCache = undefined; +} +util.inherits(PrivateKey, Key); + +PrivateKey.formats = formats; + +PrivateKey.prototype.toBuffer = function (format, options) { + if (format === undefined) + format = 'pkcs1'; + assert.string(format, 'format'); + assert.object(formats[format], 'formats[format]'); + assert.optionalObject(options, 'options'); + + return (formats[format].write(this, options)); +}; + +PrivateKey.prototype.hash = function (algo) { + return (this.toPublic().hash(algo)); +}; + +PrivateKey.prototype.toPublic = function () { + if (this._pubCache) + return (this._pubCache); + + var algInfo = algs.info[this.type]; + var pubParts = []; + for (var i = 0; i < algInfo.parts.length; ++i) { + var p = algInfo.parts[i]; + pubParts.push(this.part[p]); + } + + this._pubCache = new Key({ + type: this.type, + source: this, + parts: pubParts + }); + if (this.comment) + this._pubCache.comment = this.comment; + return (this._pubCache); +}; + +PrivateKey.prototype.derive = function (newType) { + assert.string(newType, 'type'); + var priv, pub, pair; + + if (this.type === 'ed25519' && newType === 'curve25519') { + if (nacl === undefined) + nacl = __webpack_require__(76); + + priv = this.part.k.data; + if (priv[0] === 0x00) + priv = priv.slice(1); + + pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv)); + pub = Buffer.from(pair.publicKey); + + return (new PrivateKey({ + type: 'curve25519', + parts: [ + { name: 'A', data: utils.mpNormalize(pub) }, + { name: 'k', data: utils.mpNormalize(priv) } + ] + })); + } else if (this.type === 'curve25519' && newType === 'ed25519') { + if (nacl === undefined) + nacl = __webpack_require__(76); + + priv = this.part.k.data; + if (priv[0] === 0x00) + priv = priv.slice(1); + + pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv)); + pub = Buffer.from(pair.publicKey); + + return (new PrivateKey({ + type: 'ed25519', + parts: [ + { name: 'A', data: utils.mpNormalize(pub) }, + { name: 'k', data: utils.mpNormalize(priv) } + ] + })); + } + throw (new Error('Key derivation not supported from ' + this.type + + ' to ' + newType)); +}; + +PrivateKey.prototype.createVerify = function (hashAlgo) { + return (this.toPublic().createVerify(hashAlgo)); +}; + +PrivateKey.prototype.createSign = function (hashAlgo) { + if (hashAlgo === undefined) + hashAlgo = this.defaultHashAlgorithm(); + assert.string(hashAlgo, 'hash algorithm'); + + /* ED25519 is not supported by OpenSSL, use a javascript impl. */ + if (this.type === 'ed25519' && edCompat !== undefined) + return (new edCompat.Signer(this, hashAlgo)); + if (this.type === 'curve25519') + throw (new Error('Curve25519 keys are not suitable for ' + + 'signing or verification')); + + var v, nm, err; + try { + nm = hashAlgo.toUpperCase(); + v = crypto.createSign(nm); + } catch (e) { + err = e; + } + if (v === undefined || (err instanceof Error && + err.message.match(/Unknown message digest/))) { + nm = 'RSA-'; + nm += hashAlgo.toUpperCase(); + v = crypto.createSign(nm); + } + assert.ok(v, 'failed to create verifier'); + var oldSign = v.sign.bind(v); + var key = this.toBuffer('pkcs1'); + var type = this.type; + var curve = this.curve; + v.sign = function () { + var sig = oldSign(key); + if (typeof (sig) === 'string') + sig = Buffer.from(sig, 'binary'); + sig = Signature.parse(sig, type, 'asn1'); + sig.hashAlgorithm = hashAlgo; + sig.curve = curve; + return (sig); + }; + return (v); +}; + +PrivateKey.parse = function (data, format, options) { + if (typeof (data) !== 'string') + assert.buffer(data, 'data'); + if (format === undefined) + format = 'auto'; + assert.string(format, 'format'); + if (typeof (options) === 'string') + options = { filename: options }; + assert.optionalObject(options, 'options'); + if (options === undefined) + options = {}; + assert.optionalString(options.filename, 'options.filename'); + if (options.filename === undefined) + options.filename = '(unnamed)'; + + assert.object(formats[format], 'formats[format]'); + + try { + var k = formats[format].read(data, options); + assert.ok(k instanceof PrivateKey, 'key is not a private key'); + if (!k.comment) + k.comment = options.filename; + return (k); + } catch (e) { + if (e.name === 'KeyEncryptedError') + throw (e); + throw (new KeyParseError(options.filename, format, e)); + } +}; + +PrivateKey.isPrivateKey = function (obj, ver) { + return (utils.isCompatible(obj, PrivateKey, ver)); +}; + +PrivateKey.generate = function (type, options) { + if (options === undefined) + options = {}; + assert.object(options, 'options'); + + switch (type) { + case 'ecdsa': + if (options.curve === undefined) + options.curve = 'nistp256'; + assert.string(options.curve, 'options.curve'); + return (generateECDSA(options.curve)); + case 'ed25519': + return (generateED25519()); + default: + throw (new Error('Key generation not supported with key ' + + 'type "' + type + '"')); + } +}; + +/* + * API versions for PrivateKey: + * [1,0] -- initial ver + * [1,1] -- added auto, pkcs[18], openssh/ssh-private formats + * [1,2] -- added defaultHashAlgorithm + * [1,3] -- added derive, ed, createDH + * [1,4] -- first tagged version + * [1,5] -- changed ed25519 part names and format + */ +PrivateKey.prototype._sshpkApiVersion = [1, 5]; + +PrivateKey._oldVersionDetect = function (obj) { + assert.func(obj.toPublic); + assert.func(obj.createSign); + if (obj.derive) + return ([1, 3]); + if (obj.defaultHashAlgorithm) + return ([1, 2]); + if (obj.formats['auto']) + return ([1, 1]); + return ([1, 0]); +}; + + +/***/ }), +/* 34 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.wrapLifecycle = exports.run = exports.install = exports.Install = undefined; + +var _extends2; + +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(21)); +} + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let install = exports.install = (() => { + var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, lockfile) { + yield wrapLifecycle(config, flags, (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const install = new Install(flags, config, reporter, lockfile); + yield install.init(); + })); + }); + + return function install(_x7, _x8, _x9, _x10) { + return _ref29.apply(this, arguments); + }; +})(); + +let run = exports.run = (() => { + var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + let lockfile; + let error = 'installCommandRenamed'; + if (flags.lockfile === false) { + lockfile = new (_lockfile || _load_lockfile()).default(); + } else { + lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder, reporter); + } + + if (args.length) { + const exampleArgs = args.slice(); + + if (flags.saveDev) { + exampleArgs.push('--dev'); + } + if (flags.savePeer) { + exampleArgs.push('--peer'); + } + if (flags.saveOptional) { + exampleArgs.push('--optional'); + } + if (flags.saveExact) { + exampleArgs.push('--exact'); + } + if (flags.saveTilde) { + exampleArgs.push('--tilde'); + } + let command = 'add'; + if (flags.global) { + error = 'globalFlagRemoved'; + command = 'global add'; + } + throw new (_errors || _load_errors()).MessageError(reporter.lang(error, `yarn ${command} ${exampleArgs.join(' ')}`)); + } + + yield install(config, reporter, flags, lockfile); + }); + + return function run(_x11, _x12, _x13, _x14) { + return _ref31.apply(this, arguments); + }; +})(); + +let wrapLifecycle = exports.wrapLifecycle = (() => { + var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, flags, factory) { + yield config.executeLifecycleScript('preinstall'); + + yield factory(); + + // npm behaviour, seems kinda funky but yay compatibility + yield config.executeLifecycleScript('install'); + yield config.executeLifecycleScript('postinstall'); + + if (!config.production) { + if (!config.disablePrepublish) { + yield config.executeLifecycleScript('prepublish'); + } + yield config.executeLifecycleScript('prepare'); + } + }); + + return function wrapLifecycle(_x15, _x16, _x17) { + return _ref32.apply(this, arguments); + }; +})(); + +exports.hasWrapper = hasWrapper; +exports.setFlags = setFlags; + +var _objectPath; + +function _load_objectPath() { + return _objectPath = _interopRequireDefault(__webpack_require__(304)); +} + +var _hooks; + +function _load_hooks() { + return _hooks = __webpack_require__(374); +} + +var _index; + +function _load_index() { + return _index = _interopRequireDefault(__webpack_require__(220)); +} + +var _errors; + +function _load_errors() { + return _errors = __webpack_require__(6); +} + +var _integrityChecker; + +function _load_integrityChecker() { + return _integrityChecker = _interopRequireDefault(__webpack_require__(208)); +} + +var _lockfile; + +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(19)); +} + +var _lockfile2; + +function _load_lockfile2() { + return _lockfile2 = __webpack_require__(19); +} + +var _packageFetcher; + +function _load_packageFetcher() { + return _packageFetcher = _interopRequireWildcard(__webpack_require__(210)); +} + +var _packageInstallScripts; + +function _load_packageInstallScripts() { + return _packageInstallScripts = _interopRequireDefault(__webpack_require__(557)); +} + +var _packageCompatibility; + +function _load_packageCompatibility() { + return _packageCompatibility = _interopRequireWildcard(__webpack_require__(209)); +} + +var _packageResolver; + +function _load_packageResolver() { + return _packageResolver = _interopRequireDefault(__webpack_require__(366)); +} + +var _packageLinker; + +function _load_packageLinker() { + return _packageLinker = _interopRequireDefault(__webpack_require__(211)); +} + +var _index2; + +function _load_index2() { + return _index2 = __webpack_require__(57); +} + +var _index3; + +function _load_index3() { + return _index3 = __webpack_require__(78); +} + +var _autoclean; + +function _load_autoclean() { + return _autoclean = __webpack_require__(354); +} + +var _constants; + +function _load_constants() { + return _constants = _interopRequireWildcard(__webpack_require__(8)); +} + +var _normalizePattern; + +function _load_normalizePattern() { + return _normalizePattern = __webpack_require__(37); +} + +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(4)); +} + +var _map; + +function _load_map() { + return _map = _interopRequireDefault(__webpack_require__(29)); +} + +var _yarnVersion; + +function _load_yarnVersion() { + return _yarnVersion = __webpack_require__(120); +} + +var _generatePnpMap; + +function _load_generatePnpMap() { + return _generatePnpMap = __webpack_require__(579); +} + +var _workspaceLayout; + +function _load_workspaceLayout() { + return _workspaceLayout = _interopRequireDefault(__webpack_require__(90)); +} + +var _resolutionMap; + +function _load_resolutionMap() { + return _resolutionMap = _interopRequireDefault(__webpack_require__(214)); +} + +var _guessName; + +function _load_guessName() { + return _guessName = _interopRequireDefault(__webpack_require__(169)); +} + +var _audit; + +function _load_audit() { + return _audit = _interopRequireDefault(__webpack_require__(353)); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const deepEqual = __webpack_require__(631); + +const emoji = __webpack_require__(302); +const invariant = __webpack_require__(9); +const path = __webpack_require__(0); +const semver = __webpack_require__(22); +const uuid = __webpack_require__(119); +const ssri = __webpack_require__(65); + +const ONE_DAY = 1000 * 60 * 60 * 24; + +/** + * Try and detect the installation method for Yarn and provide a command to update it with. + */ + +function getUpdateCommand(installationMethod) { + if (installationMethod === 'tar') { + return `curl --compressed -o- -L ${(_constants || _load_constants()).YARN_INSTALLER_SH} | bash`; + } + + if (installationMethod === 'homebrew') { + return 'brew upgrade yarn'; + } + + if (installationMethod === 'deb') { + return 'sudo apt-get update && sudo apt-get install yarn'; + } + + if (installationMethod === 'rpm') { + return 'sudo yum install yarn'; + } + + if (installationMethod === 'npm') { + return 'npm install --global yarn'; + } + + if (installationMethod === 'chocolatey') { + return 'choco upgrade yarn'; + } + + if (installationMethod === 'apk') { + return 'apk update && apk add -u yarn'; + } + + if (installationMethod === 'portage') { + return 'sudo emerge --sync && sudo emerge -au sys-apps/yarn'; + } + + return null; +} + +function getUpdateInstaller(installationMethod) { + // Windows + if (installationMethod === 'msi') { + return (_constants || _load_constants()).YARN_INSTALLER_MSI; + } + + return null; +} + +function normalizeFlags(config, rawFlags) { + const flags = { + // install + har: !!rawFlags.har, + ignorePlatform: !!rawFlags.ignorePlatform, + ignoreEngines: !!rawFlags.ignoreEngines, + ignoreScripts: !!rawFlags.ignoreScripts, + ignoreOptional: !!rawFlags.ignoreOptional, + force: !!rawFlags.force, + flat: !!rawFlags.flat, + lockfile: rawFlags.lockfile !== false, + pureLockfile: !!rawFlags.pureLockfile, + updateChecksums: !!rawFlags.updateChecksums, + skipIntegrityCheck: !!rawFlags.skipIntegrityCheck, + frozenLockfile: !!rawFlags.frozenLockfile, + linkDuplicates: !!rawFlags.linkDuplicates, + checkFiles: !!rawFlags.checkFiles, + audit: !!rawFlags.audit, + + // add + peer: !!rawFlags.peer, + dev: !!rawFlags.dev, + optional: !!rawFlags.optional, + exact: !!rawFlags.exact, + tilde: !!rawFlags.tilde, + ignoreWorkspaceRootCheck: !!rawFlags.ignoreWorkspaceRootCheck, + + // outdated, update-interactive + includeWorkspaceDeps: !!rawFlags.includeWorkspaceDeps, + + // add, remove, update + workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false + }; + + if (config.getOption('ignore-scripts')) { + flags.ignoreScripts = true; + } + + if (config.getOption('ignore-platform')) { + flags.ignorePlatform = true; + } + + if (config.getOption('ignore-engines')) { + flags.ignoreEngines = true; + } + + if (config.getOption('ignore-optional')) { + flags.ignoreOptional = true; + } + + if (config.getOption('force')) { + flags.force = true; + } + + return flags; +} + +class Install { + constructor(flags, config, reporter, lockfile) { + this.rootManifestRegistries = []; + this.rootPatternsToOrigin = (0, (_map || _load_map()).default)(); + this.lockfile = lockfile; + this.reporter = reporter; + this.config = config; + this.flags = normalizeFlags(config, flags); + this.resolutions = (0, (_map || _load_map()).default)(); // Legacy resolutions field used for flat install mode + this.resolutionMap = new (_resolutionMap || _load_resolutionMap()).default(config); // Selective resolutions for nested dependencies + this.resolver = new (_packageResolver || _load_packageResolver()).default(config, lockfile, this.resolutionMap); + this.integrityChecker = new (_integrityChecker || _load_integrityChecker()).default(config); + this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver); + this.scripts = new (_packageInstallScripts || _load_packageInstallScripts()).default(config, this.resolver, this.flags.force); + } + + /** + * Create a list of dependency requests from the current directories manifests. + */ + + fetchRequestFromCwd(excludePatterns = [], ignoreUnusedPatterns = false) { + var _this = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const patterns = []; + const deps = []; + let resolutionDeps = []; + const manifest = {}; + + const ignorePatterns = []; + const usedPatterns = []; + let workspaceLayout; + + // some commands should always run in the context of the entire workspace + const cwd = _this.flags.includeWorkspaceDeps || _this.flags.workspaceRootIsCwd ? _this.config.lockfileFolder : _this.config.cwd; + + // non-workspaces are always root, otherwise check for workspace root + const cwdIsRoot = !_this.config.workspaceRootFolder || _this.config.lockfileFolder === cwd; + + // exclude package names that are in install args + const excludeNames = []; + for (var _iterator = excludePatterns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const pattern = _ref; + + if ((0, (_index3 || _load_index3()).getExoticResolver)(pattern)) { + excludeNames.push((0, (_guessName || _load_guessName()).default)(pattern)); + } else { + // extract the name + const parts = (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern); + excludeNames.push(parts.name); + } + } + + const stripExcluded = function stripExcluded(manifest) { + for (var _iterator2 = excludeNames, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref2; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref2 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref2 = _i2.value; + } + + const exclude = _ref2; + + if (manifest.dependencies && manifest.dependencies[exclude]) { + delete manifest.dependencies[exclude]; + } + if (manifest.devDependencies && manifest.devDependencies[exclude]) { + delete manifest.devDependencies[exclude]; + } + if (manifest.optionalDependencies && manifest.optionalDependencies[exclude]) { + delete manifest.optionalDependencies[exclude]; + } + } + }; + + for (var _iterator3 = Object.keys((_index2 || _load_index2()).registries), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; + } + + const registry = _ref3; + + const filename = (_index2 || _load_index2()).registries[registry].filename; + + const loc = path.join(cwd, filename); + if (!(yield (_fs || _load_fs()).exists(loc))) { + continue; + } + + _this.rootManifestRegistries.push(registry); + + const projectManifestJson = yield _this.config.readJson(loc); + yield (0, (_index || _load_index()).default)(projectManifestJson, cwd, _this.config, cwdIsRoot); + + Object.assign(_this.resolutions, projectManifestJson.resolutions); + Object.assign(manifest, projectManifestJson); + + _this.resolutionMap.init(_this.resolutions); + for (var _iterator4 = Object.keys(_this.resolutionMap.resolutionsByPackage), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref4; + + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref4 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref4 = _i4.value; + } + + const packageName = _ref4; + + const optional = (_objectPath || _load_objectPath()).default.has(manifest.optionalDependencies, packageName) && _this.flags.ignoreOptional; + for (var _iterator8 = _this.resolutionMap.resolutionsByPackage[packageName], _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref9; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref9 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref9 = _i8.value; + } + + const _ref8 = _ref9; + const pattern = _ref8.pattern; + + resolutionDeps = [...resolutionDeps, { registry, pattern, optional, hint: 'resolution' }]; + } + } + + const pushDeps = function pushDeps(depType, manifest, { hint, optional }, isUsed) { + if (ignoreUnusedPatterns && !isUsed) { + return; + } + // We only take unused dependencies into consideration to get deterministic hoisting. + // Since flat mode doesn't care about hoisting and everything is top level and specified then we can safely + // leave these out. + if (_this.flags.flat && !isUsed) { + return; + } + const depMap = manifest[depType]; + for (const name in depMap) { + if (excludeNames.indexOf(name) >= 0) { + continue; + } + + let pattern = name; + if (!_this.lockfile.getLocked(pattern)) { + // when we use --save we save the dependency to the lockfile with just the name rather than the + // version combo + pattern += '@' + depMap[name]; + } + + // normalization made sure packages are mentioned only once + if (isUsed) { + usedPatterns.push(pattern); + } else { + ignorePatterns.push(pattern); + } + + _this.rootPatternsToOrigin[pattern] = depType; + patterns.push(pattern); + deps.push({ pattern, registry, hint, optional, workspaceName: manifest.name, workspaceLoc: manifest._loc }); + } + }; + + if (cwdIsRoot) { + pushDeps('dependencies', projectManifestJson, { hint: null, optional: false }, true); + pushDeps('devDependencies', projectManifestJson, { hint: 'dev', optional: false }, !_this.config.production); + pushDeps('optionalDependencies', projectManifestJson, { hint: 'optional', optional: true }, true); + } + + if (_this.config.workspaceRootFolder) { + const workspaceLoc = cwdIsRoot ? loc : path.join(_this.config.lockfileFolder, filename); + const workspacesRoot = path.dirname(workspaceLoc); + + let workspaceManifestJson = projectManifestJson; + if (!cwdIsRoot) { + // the manifest we read before was a child workspace, so get the root + workspaceManifestJson = yield _this.config.readJson(workspaceLoc); + yield (0, (_index || _load_index()).default)(workspaceManifestJson, workspacesRoot, _this.config, true); + } + + const workspaces = yield _this.config.resolveWorkspaces(workspacesRoot, workspaceManifestJson); + workspaceLayout = new (_workspaceLayout || _load_workspaceLayout()).default(workspaces, _this.config); + + // add virtual manifest that depends on all workspaces, this way package hoisters and resolvers will work fine + const workspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.dependencies); + for (var _iterator5 = Object.keys(workspaces), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref5; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref5 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref5 = _i5.value; + } + + const workspaceName = _ref5; + + const workspaceManifest = workspaces[workspaceName].manifest; + workspaceDependencies[workspaceName] = workspaceManifest.version; + + // include dependencies from all workspaces + if (_this.flags.includeWorkspaceDeps) { + pushDeps('dependencies', workspaceManifest, { hint: null, optional: false }, true); + pushDeps('devDependencies', workspaceManifest, { hint: 'dev', optional: false }, !_this.config.production); + pushDeps('optionalDependencies', workspaceManifest, { hint: 'optional', optional: true }, true); + } + } + const virtualDependencyManifest = { + _uid: '', + name: `workspace-aggregator-${uuid.v4()}`, + version: '1.0.0', + _registry: 'npm', + _loc: workspacesRoot, + dependencies: workspaceDependencies, + devDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.devDependencies), + optionalDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.optionalDependencies), + private: workspaceManifestJson.private, + workspaces: workspaceManifestJson.workspaces + }; + workspaceLayout.virtualManifestName = virtualDependencyManifest.name; + const virtualDep = {}; + virtualDep[virtualDependencyManifest.name] = virtualDependencyManifest.version; + workspaces[virtualDependencyManifest.name] = { loc: workspacesRoot, manifest: virtualDependencyManifest }; + + // ensure dependencies that should be excluded are stripped from the correct manifest + stripExcluded(cwdIsRoot ? virtualDependencyManifest : workspaces[projectManifestJson.name].manifest); + + pushDeps('workspaces', { workspaces: virtualDep }, { hint: 'workspaces', optional: false }, true); + + const implicitWorkspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceDependencies); + + for (var _iterator6 = (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref6; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref6 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref6 = _i6.value; + } + + const type = _ref6; + + for (var _iterator7 = Object.keys(projectManifestJson[type] || {}), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref7; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref7 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref7 = _i7.value; + } + + const dependencyName = _ref7; + + delete implicitWorkspaceDependencies[dependencyName]; + } + } + + pushDeps('dependencies', { dependencies: implicitWorkspaceDependencies }, { hint: 'workspaces', optional: false }, true); + } + + break; + } + + // inherit root flat flag + if (manifest.flat) { + _this.flags.flat = true; + } + + return { + requests: [...resolutionDeps, ...deps], + patterns, + manifest, + usedPatterns, + ignorePatterns, + workspaceLayout + }; + })(); + } + + /** + * TODO description + */ + + prepareRequests(requests) { + return requests; + } + + preparePatterns(patterns) { + return patterns; + } + preparePatternsForLinking(patterns, cwdManifest, cwdIsRoot) { + return patterns; + } + + prepareManifests() { + var _this2 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const manifests = yield _this2.config.getRootManifests(); + return manifests; + })(); + } + + bailout(patterns, workspaceLayout) { + var _this3 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // We don't want to skip the audit - it could yield important errors + if (_this3.flags.audit) { + return false; + } + // PNP is so fast that the integrity check isn't pertinent + if (_this3.config.plugnplayEnabled) { + return false; + } + if (_this3.flags.skipIntegrityCheck || _this3.flags.force) { + return false; + } + const lockfileCache = _this3.lockfile.cache; + if (!lockfileCache) { + return false; + } + const lockfileClean = _this3.lockfile.parseResultType === 'success'; + const match = yield _this3.integrityChecker.check(patterns, lockfileCache, _this3.flags, workspaceLayout); + if (_this3.flags.frozenLockfile && (!lockfileClean || match.missingPatterns.length > 0)) { + throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('frozenLockfileError')); + } + + const haveLockfile = yield (_fs || _load_fs()).exists(path.join(_this3.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME)); + + const lockfileIntegrityPresent = !_this3.lockfile.hasEntriesExistWithoutIntegrity(); + const integrityBailout = lockfileIntegrityPresent || !_this3.config.autoAddIntegrity; + + if (match.integrityMatches && haveLockfile && lockfileClean && integrityBailout) { + _this3.reporter.success(_this3.reporter.lang('upToDate')); + return true; + } + + if (match.integrityFileMissing && haveLockfile) { + // Integrity file missing, force script installations + _this3.scripts.setForce(true); + return false; + } + + if (match.hardRefreshRequired) { + // e.g. node version doesn't match, force script installations + _this3.scripts.setForce(true); + return false; + } + + if (!patterns.length && !match.integrityFileMissing) { + _this3.reporter.success(_this3.reporter.lang('nothingToInstall')); + yield _this3.createEmptyManifestFolders(); + yield _this3.saveLockfileAndIntegrity(patterns, workspaceLayout); + return true; + } + + return false; + })(); + } + + /** + * Produce empty folders for all used root manifests. + */ + + createEmptyManifestFolders() { + var _this4 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (_this4.config.modulesFolder) { + // already created + return; + } + + for (var _iterator9 = _this4.rootManifestRegistries, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref10; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref10 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref10 = _i9.value; + } + + const registryName = _ref10; + const folder = _this4.config.registries[registryName].folder; + + yield (_fs || _load_fs()).mkdirp(path.join(_this4.config.lockfileFolder, folder)); + } + })(); + } + + /** + * TODO description + */ + + markIgnored(patterns) { + for (var _iterator10 = patterns, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref11; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref11 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref11 = _i10.value; + } + + const pattern = _ref11; + + const manifest = this.resolver.getStrictResolvedPattern(pattern); + const ref = manifest._reference; + invariant(ref, 'expected package reference'); + + // just mark the package as ignored. if the package is used by a required package, the hoister + // will take care of that. + ref.ignore = true; + } + } + + /** + * helper method that gets only recent manifests + * used by global.ls command + */ + getFlattenedDeps() { + var _this5 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _ref12 = yield _this5.fetchRequestFromCwd(); + + const depRequests = _ref12.requests, + rawPatterns = _ref12.patterns; + + + yield _this5.resolver.init(depRequests, {}); + + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this5.resolver.getManifests(), _this5.config); + _this5.resolver.updateManifests(manifests); + + return _this5.flatten(rawPatterns); + })(); + } + + /** + * TODO description + */ + + init() { + var _this6 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.checkUpdate(); + + // warn if we have a shrinkwrap + if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_SHRINKWRAP_FILENAME))) { + _this6.reporter.warn(_this6.reporter.lang('shrinkwrapWarning')); + } + + // warn if we have an npm lockfile + if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_LOCK_FILENAME))) { + _this6.reporter.warn(_this6.reporter.lang('npmLockfileWarning')); + } + + if (_this6.config.plugnplayEnabled) { + _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L1')); + _this6.reporter.info(_this6.reporter.lang('plugnplaySuggestV2L2')); + } + + let flattenedTopLevelPatterns = []; + const steps = []; + + var _ref13 = yield _this6.fetchRequestFromCwd(); + + const depRequests = _ref13.requests, + rawPatterns = _ref13.patterns, + ignorePatterns = _ref13.ignorePatterns, + workspaceLayout = _ref13.workspaceLayout, + manifest = _ref13.manifest; + + let topLevelPatterns = []; + + const artifacts = yield _this6.integrityChecker.getArtifacts(); + if (artifacts) { + _this6.linker.setArtifacts(artifacts); + _this6.scripts.setArtifacts(artifacts); + } + + if ((_packageCompatibility || _load_packageCompatibility()).shouldCheck(manifest, _this6.flags)) { + steps.push((() => { + var _ref14 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + _this6.reporter.step(curr, total, _this6.reporter.lang('checkingManifest'), emoji.get('mag')); + yield _this6.checkCompatibility(); + }); + + return function (_x, _x2) { + return _ref14.apply(this, arguments); + }; + })()); + } + + const audit = new (_audit || _load_audit()).default(_this6.config, _this6.reporter, { groups: (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES }); + let auditFoundProblems = false; + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('resolveStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.reporter.lang('resolvingPackages'), emoji.get('mag')); + yield _this6.resolver.init(_this6.prepareRequests(depRequests), { + isFlat: _this6.flags.flat, + isFrozen: _this6.flags.frozenLockfile, + workspaceLayout + }); + topLevelPatterns = _this6.preparePatterns(rawPatterns); + flattenedTopLevelPatterns = yield _this6.flatten(topLevelPatterns); + return { bailout: !_this6.flags.audit && (yield _this6.bailout(topLevelPatterns, workspaceLayout)) }; + })); + }); + + if (_this6.flags.audit) { + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('auditStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.reporter.lang('auditRunning'), emoji.get('mag')); + if (_this6.flags.offline) { + _this6.reporter.warn(_this6.reporter.lang('auditOffline')); + return { bailout: false }; + } + const preparedManifests = yield _this6.prepareManifests(); + // $FlowFixMe - Flow considers `m` in the map operation to be "mixed", so does not recognize `m.object` + const mergedManifest = Object.assign({}, ...Object.values(preparedManifests).map(function (m) { + return m.object; + })); + const auditVulnerabilityCounts = yield audit.performAudit(mergedManifest, _this6.lockfile, _this6.resolver, _this6.linker, topLevelPatterns); + auditFoundProblems = auditVulnerabilityCounts.info || auditVulnerabilityCounts.low || auditVulnerabilityCounts.moderate || auditVulnerabilityCounts.high || auditVulnerabilityCounts.critical; + return { bailout: yield _this6.bailout(topLevelPatterns, workspaceLayout) }; + })); + }); + } + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('fetchStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.markIgnored(ignorePatterns); + _this6.reporter.step(curr, total, _this6.reporter.lang('fetchingPackages'), emoji.get('truck')); + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this6.resolver.getManifests(), _this6.config); + _this6.resolver.updateManifests(manifests); + yield (_packageCompatibility || _load_packageCompatibility()).check(_this6.resolver.getManifests(), _this6.config, _this6.flags.ignoreEngines); + })); + }); + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('linkStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // remove integrity hash to make this operation atomic + yield _this6.integrityChecker.removeIntegrityFile(); + _this6.reporter.step(curr, total, _this6.reporter.lang('linkingDependencies'), emoji.get('link')); + flattenedTopLevelPatterns = _this6.preparePatternsForLinking(flattenedTopLevelPatterns, manifest, _this6.config.lockfileFolder === _this6.config.cwd); + yield _this6.linker.init(flattenedTopLevelPatterns, workspaceLayout, { + linkDuplicates: _this6.flags.linkDuplicates, + ignoreOptional: _this6.flags.ignoreOptional + }); + })); + }); + + if (_this6.config.plugnplayEnabled) { + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('pnpStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const pnpPath = `${_this6.config.lockfileFolder}/${(_constants || _load_constants()).PNP_FILENAME}`; + + const code = yield (0, (_generatePnpMap || _load_generatePnpMap()).generatePnpMap)(_this6.config, flattenedTopLevelPatterns, { + resolver: _this6.resolver, + reporter: _this6.reporter, + targetPath: pnpPath, + workspaceLayout + }); + + try { + const file = yield (_fs || _load_fs()).readFile(pnpPath); + if (file === code) { + return; + } + } catch (error) {} + + yield (_fs || _load_fs()).writeFile(pnpPath, code); + yield (_fs || _load_fs()).chmod(pnpPath, 0o755); + })); + }); + } + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('buildStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.flags.force ? _this6.reporter.lang('rebuildingPackages') : _this6.reporter.lang('buildingFreshPackages'), emoji.get('hammer')); + + if (_this6.config.ignoreScripts) { + _this6.reporter.warn(_this6.reporter.lang('ignoredScripts')); + } else { + yield _this6.scripts.init(flattenedTopLevelPatterns); + } + })); + }); + + if (_this6.flags.har) { + steps.push((() => { + var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + const formattedDate = new Date().toISOString().replace(/:/g, '-'); + const filename = `yarn-install_${formattedDate}.har`; + _this6.reporter.step(curr, total, _this6.reporter.lang('savingHar', filename), emoji.get('black_circle_for_record')); + yield _this6.config.requestManager.saveHar(filename); + }); + + return function (_x3, _x4) { + return _ref21.apply(this, arguments); + }; + })()); + } + + if (yield _this6.shouldClean()) { + steps.push((() => { + var _ref22 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + _this6.reporter.step(curr, total, _this6.reporter.lang('cleaningModules'), emoji.get('recycle')); + yield (0, (_autoclean || _load_autoclean()).clean)(_this6.config, _this6.reporter); + }); + + return function (_x5, _x6) { + return _ref22.apply(this, arguments); + }; + })()); + } + + let currentStep = 0; + for (var _iterator11 = steps, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref23; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref23 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref23 = _i11.value; + } + + const step = _ref23; + + const stepResult = yield step(++currentStep, steps.length); + if (stepResult && stepResult.bailout) { + if (_this6.flags.audit) { + audit.summary(); + } + if (auditFoundProblems) { + _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); + } + _this6.maybeOutputUpdate(); + return flattenedTopLevelPatterns; + } + } + + // fin! + if (_this6.flags.audit) { + audit.summary(); + } + if (auditFoundProblems) { + _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); + } + yield _this6.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); + yield _this6.persistChanges(); + _this6.maybeOutputUpdate(); + _this6.config.requestManager.clearCache(); + return flattenedTopLevelPatterns; + })(); + } + + checkCompatibility() { + var _this7 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _ref24 = yield _this7.fetchRequestFromCwd(); + + const manifest = _ref24.manifest; + + yield (_packageCompatibility || _load_packageCompatibility()).checkOne(manifest, _this7.config, _this7.flags.ignoreEngines); + })(); + } + + persistChanges() { + var _this8 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // get all the different registry manifests in this folder + const manifests = yield _this8.config.getRootManifests(); + + if (yield _this8.applyChanges(manifests)) { + yield _this8.config.saveRootManifests(manifests); + } + })(); + } + + applyChanges(manifests) { + let hasChanged = false; + + if (this.config.plugnplayPersist) { + const object = manifests.npm.object; + + + if (typeof object.installConfig !== 'object') { + object.installConfig = {}; + } + + if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { + object.installConfig.pnp = true; + hasChanged = true; + } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { + delete object.installConfig.pnp; + hasChanged = true; + } + + if (Object.keys(object.installConfig).length === 0) { + delete object.installConfig; + } + } + + return Promise.resolve(hasChanged); + } + + /** + * Check if we should run the cleaning step. + */ + + shouldClean() { + return (_fs || _load_fs()).exists(path.join(this.config.lockfileFolder, (_constants || _load_constants()).CLEAN_FILENAME)); + } + + /** + * TODO + */ + + flatten(patterns) { + var _this9 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (!_this9.flags.flat) { + return patterns; + } + + const flattenedPatterns = []; + + for (var _iterator12 = _this9.resolver.getAllDependencyNamesByLevelOrder(patterns), _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref25; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref25 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref25 = _i12.value; + } + + const name = _ref25; + + const infos = _this9.resolver.getAllInfoForPackageName(name).filter(function (manifest) { + const ref = manifest._reference; + invariant(ref, 'expected package reference'); + return !ref.ignore; + }); + + if (infos.length === 0) { + continue; + } + + if (infos.length === 1) { + // single version of this package + // take out a single pattern as multiple patterns may have resolved to this package + flattenedPatterns.push(_this9.resolver.patternsByPackage[name][0]); + continue; + } + + const options = infos.map(function (info) { + const ref = info._reference; + invariant(ref, 'expected reference'); + return { + // TODO `and is required by {PARENT}`, + name: _this9.reporter.lang('manualVersionResolutionOption', ref.patterns.join(', '), info.version), + + value: info.version + }; + }); + const versions = infos.map(function (info) { + return info.version; + }); + let version; + + const resolutionVersion = _this9.resolutions[name]; + if (resolutionVersion && versions.indexOf(resolutionVersion) >= 0) { + // use json `resolution` version + version = resolutionVersion; + } else { + version = yield _this9.reporter.select(_this9.reporter.lang('manualVersionResolution', name), _this9.reporter.lang('answer'), options); + _this9.resolutions[name] = version; + } + + flattenedPatterns.push(_this9.resolver.collapseAllVersionsOfPackage(name, version)); + } + + // save resolutions to their appropriate root manifest + if (Object.keys(_this9.resolutions).length) { + const manifests = yield _this9.config.getRootManifests(); + + for (const name in _this9.resolutions) { + const version = _this9.resolutions[name]; + + const patterns = _this9.resolver.patternsByPackage[name]; + if (!patterns) { + continue; + } + + let manifest; + for (var _iterator13 = patterns, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref26; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref26 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref26 = _i13.value; + } + + const pattern = _ref26; + + manifest = _this9.resolver.getResolvedPattern(pattern); + if (manifest) { + break; + } + } + invariant(manifest, 'expected manifest'); + + const ref = manifest._reference; + invariant(ref, 'expected reference'); + + const object = manifests[ref.registry].object; + object.resolutions = object.resolutions || {}; + object.resolutions[name] = version; + } + + yield _this9.config.saveRootManifests(manifests); + } + + return flattenedPatterns; + })(); + } + + /** + * Remove offline tarballs that are no longer required + */ + + pruneOfflineMirror(lockfile) { + var _this10 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const mirror = _this10.config.getOfflineMirrorPath(); + if (!mirror) { + return; + } + + const requiredTarballs = new Set(); + for (const dependency in lockfile) { + const resolved = lockfile[dependency].resolved; + if (resolved) { + const basename = path.basename(resolved.split('#')[0]); + if (dependency[0] === '@' && basename[0] !== '@') { + requiredTarballs.add(`${dependency.split('/')[0]}-${basename}`); + } + requiredTarballs.add(basename); + } + } + + const mirrorFiles = yield (_fs || _load_fs()).walk(mirror); + for (var _iterator14 = mirrorFiles, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref27; + + if (_isArray14) { + if (_i14 >= _iterator14.length) break; + _ref27 = _iterator14[_i14++]; + } else { + _i14 = _iterator14.next(); + if (_i14.done) break; + _ref27 = _i14.value; + } + + const file = _ref27; + + const isTarball = path.extname(file.basename) === '.tgz'; + // if using experimental-pack-script-packages-in-mirror flag, don't unlink prebuilt packages + const hasPrebuiltPackage = file.relative.startsWith('prebuilt/'); + if (isTarball && !hasPrebuiltPackage && !requiredTarballs.has(file.basename)) { + yield (_fs || _load_fs()).unlink(file.absolute); + } + } + })(); + } + + /** + * Save updated integrity and lockfiles. + */ + + saveLockfileAndIntegrity(patterns, workspaceLayout) { + var _this11 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const resolvedPatterns = {}; + Object.keys(_this11.resolver.patterns).forEach(function (pattern) { + if (!workspaceLayout || !workspaceLayout.getManifestByPattern(pattern)) { + resolvedPatterns[pattern] = _this11.resolver.patterns[pattern]; + } + }); + + // TODO this code is duplicated in a few places, need a common way to filter out workspace patterns from lockfile + patterns = patterns.filter(function (p) { + return !workspaceLayout || !workspaceLayout.getManifestByPattern(p); + }); + + const lockfileBasedOnResolver = _this11.lockfile.getLockfile(resolvedPatterns); + + if (_this11.config.pruneOfflineMirror) { + yield _this11.pruneOfflineMirror(lockfileBasedOnResolver); + } + + // write integrity hash + if (!_this11.config.plugnplayEnabled) { + yield _this11.integrityChecker.save(patterns, lockfileBasedOnResolver, _this11.flags, workspaceLayout, _this11.scripts.getArtifacts()); + } + + // --no-lockfile or --pure-lockfile or --frozen-lockfile + if (_this11.flags.lockfile === false || _this11.flags.pureLockfile || _this11.flags.frozenLockfile) { + return; + } + + const lockFileHasAllPatterns = patterns.every(function (p) { + return _this11.lockfile.getLocked(p); + }); + const lockfilePatternsMatch = Object.keys(_this11.lockfile.cache || {}).every(function (p) { + return lockfileBasedOnResolver[p]; + }); + const resolverPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { + const manifest = _this11.lockfile.getLocked(pattern); + return manifest && manifest.resolved === lockfileBasedOnResolver[pattern].resolved && deepEqual(manifest.prebuiltVariants, lockfileBasedOnResolver[pattern].prebuiltVariants); + }); + const integrityPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { + const existingIntegrityInfo = lockfileBasedOnResolver[pattern].integrity; + if (!existingIntegrityInfo) { + // if this entry does not have an integrity, no need to re-write the lockfile because of it + return true; + } + const manifest = _this11.lockfile.getLocked(pattern); + if (manifest && manifest.integrity) { + const manifestIntegrity = ssri.stringify(manifest.integrity); + return manifestIntegrity === existingIntegrityInfo; + } + return false; + }); + + // remove command is followed by install with force, lockfile will be rewritten in any case then + if (!_this11.flags.force && _this11.lockfile.parseResultType === 'success' && lockFileHasAllPatterns && lockfilePatternsMatch && resolverPatternsAreSameAsInLockfile && integrityPatternsAreSameAsInLockfile && patterns.length) { + return; + } + + // build lockfile location + const loc = path.join(_this11.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME); + + // write lockfile + const lockSource = (0, (_lockfile2 || _load_lockfile2()).stringify)(lockfileBasedOnResolver, false, _this11.config.enableLockfileVersions); + yield (_fs || _load_fs()).writeFilePreservingEol(loc, lockSource); + + _this11._logSuccessSaveLockfile(); + })(); + } + + _logSuccessSaveLockfile() { + this.reporter.success(this.reporter.lang('savedLockfile')); + } + + /** + * Load the dependency graph of the current install. Only does package resolving and wont write to the cwd. + */ + hydrate(ignoreUnusedPatterns) { + var _this12 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const request = yield _this12.fetchRequestFromCwd([], ignoreUnusedPatterns); + const depRequests = request.requests, + rawPatterns = request.patterns, + ignorePatterns = request.ignorePatterns, + workspaceLayout = request.workspaceLayout; + + + yield _this12.resolver.init(depRequests, { + isFlat: _this12.flags.flat, + isFrozen: _this12.flags.frozenLockfile, + workspaceLayout + }); + yield _this12.flatten(rawPatterns); + _this12.markIgnored(ignorePatterns); + + // fetch packages, should hit cache most of the time + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this12.resolver.getManifests(), _this12.config); + _this12.resolver.updateManifests(manifests); + yield (_packageCompatibility || _load_packageCompatibility()).check(_this12.resolver.getManifests(), _this12.config, _this12.flags.ignoreEngines); + + // expand minimal manifests + for (var _iterator15 = _this12.resolver.getManifests(), _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref28; + + if (_isArray15) { + if (_i15 >= _iterator15.length) break; + _ref28 = _iterator15[_i15++]; + } else { + _i15 = _iterator15.next(); + if (_i15.done) break; + _ref28 = _i15.value; + } + + const manifest = _ref28; + + const ref = manifest._reference; + invariant(ref, 'expected reference'); + const type = ref.remote.type; + // link specifier won't ever hit cache + + let loc = ''; + if (type === 'link') { + continue; + } else if (type === 'workspace') { + if (!ref.remote.reference) { + continue; + } + loc = ref.remote.reference; + } else { + loc = _this12.config.generateModuleCachePath(ref); + } + const newPkg = yield _this12.config.readManifest(loc); + yield _this12.resolver.updateManifest(ref, newPkg); + } + + return request; + })(); + } + + /** + * Check for updates every day and output a nag message if there's a newer version. + */ + + checkUpdate() { + if (this.config.nonInteractive) { + // don't show upgrade dialog on CI or non-TTY terminals + return; + } + + // don't check if disabled + if (this.config.getOption('disable-self-update-check')) { + return; + } + + // only check for updates once a day + const lastUpdateCheck = Number(this.config.getOption('lastUpdateCheck')) || 0; + if (lastUpdateCheck && Date.now() - lastUpdateCheck < ONE_DAY) { + return; + } + + // don't bug for updates on tagged releases + if ((_yarnVersion || _load_yarnVersion()).version.indexOf('-') >= 0) { + return; + } + + this._checkUpdate().catch(() => { + // swallow errors + }); + } + + _checkUpdate() { + var _this13 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + let latestVersion = yield _this13.config.requestManager.request({ + url: (_constants || _load_constants()).SELF_UPDATE_VERSION_URL + }); + invariant(typeof latestVersion === 'string', 'expected string'); + latestVersion = latestVersion.trim(); + if (!semver.valid(latestVersion)) { + return; + } + + // ensure we only check for updates periodically + _this13.config.registries.yarn.saveHomeConfig({ + lastUpdateCheck: Date.now() + }); + + if (semver.gt(latestVersion, (_yarnVersion || _load_yarnVersion()).version)) { + const installationMethod = yield (0, (_yarnVersion || _load_yarnVersion()).getInstallationMethod)(); + _this13.maybeOutputUpdate = function () { + _this13.reporter.warn(_this13.reporter.lang('yarnOutdated', latestVersion, (_yarnVersion || _load_yarnVersion()).version)); + + const command = getUpdateCommand(installationMethod); + if (command) { + _this13.reporter.info(_this13.reporter.lang('yarnOutdatedCommand')); + _this13.reporter.command(command); + } else { + const installer = getUpdateInstaller(installationMethod); + if (installer) { + _this13.reporter.info(_this13.reporter.lang('yarnOutdatedInstaller', installer)); + } + } + }; + } + })(); + } + + /** + * Method to override with a possible upgrade message. + */ + + maybeOutputUpdate() {} +} + +exports.Install = Install; +function hasWrapper(commander, args) { + return true; +} + +function setFlags(commander) { + commander.description('Yarn install is used to install all dependencies for a project.'); + commander.usage('install [flags]'); + commander.option('-A, --audit', 'Run vulnerability audit on installed packages'); + commander.option('-g, --global', 'DEPRECATED'); + commander.option('-S, --save', 'DEPRECATED - save package to your `dependencies`'); + commander.option('-D, --save-dev', 'DEPRECATED - save package to your `devDependencies`'); + commander.option('-P, --save-peer', 'DEPRECATED - save package to your `peerDependencies`'); + commander.option('-O, --save-optional', 'DEPRECATED - save package to your `optionalDependencies`'); + commander.option('-E, --save-exact', 'DEPRECATED'); + commander.option('-T, --save-tilde', 'DEPRECATED'); +} + +/***/ }), +/* 35 */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(52); +module.exports = function (it) { + if (!isObject(it)) throw TypeError(it + ' is not an object!'); + return it; +}; + + +/***/ }), +/* 36 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return SubjectSubscriber; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subject; }); +/* unused harmony export AnonymousSubject */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Observable__ = __webpack_require__(12); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Subscriber__ = __webpack_require__(7); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(25); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__ = __webpack_require__(189); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__ = __webpack_require__(422); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__ = __webpack_require__(321); +/** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */ + + + + + + + +var SubjectSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SubjectSubscriber, _super); + function SubjectSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + return _this; + } + return SubjectSubscriber; +}(__WEBPACK_IMPORTED_MODULE_2__Subscriber__["a" /* Subscriber */])); + +var Subject = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subject, _super); + function Subject() { + var _this = _super.call(this) || this; + _this.observers = []; + _this.closed = false; + _this.isStopped = false; + _this.hasError = false; + _this.thrownError = null; + return _this; + } + Subject.prototype[__WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { + return new SubjectSubscriber(this); + }; + Subject.prototype.lift = function (operator) { + var subject = new AnonymousSubject(this, this); + subject.operator = operator; + return subject; + }; + Subject.prototype.next = function (value) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + if (!this.isStopped) { + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].next(value); + } + } + }; + Subject.prototype.error = function (err) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + this.hasError = true; + this.thrownError = err; + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].error(err); + } + this.observers.length = 0; + }; + Subject.prototype.complete = function () { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].complete(); + } + this.observers.length = 0; + }; + Subject.prototype.unsubscribe = function () { + this.isStopped = true; + this.closed = true; + this.observers = null; + }; + Subject.prototype._trySubscribe = function (subscriber) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + else { + return _super.prototype._trySubscribe.call(this, subscriber); + } + }; + Subject.prototype._subscribe = function (subscriber) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + else if (this.hasError) { + subscriber.error(this.thrownError); + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + else if (this.isStopped) { + subscriber.complete(); + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + else { + this.observers.push(subscriber); + return new __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__["a" /* SubjectSubscription */](this, subscriber); + } + }; + Subject.prototype.asObservable = function () { + var observable = new __WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */](); + observable.source = this; + return observable; + }; + Subject.create = function (destination, source) { + return new AnonymousSubject(destination, source); + }; + return Subject; +}(__WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */])); + +var AnonymousSubject = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](AnonymousSubject, _super); + function AnonymousSubject(destination, source) { + var _this = _super.call(this) || this; + _this.destination = destination; + _this.source = source; + return _this; + } + AnonymousSubject.prototype.next = function (value) { + var destination = this.destination; + if (destination && destination.next) { + destination.next(value); + } + }; + AnonymousSubject.prototype.error = function (err) { + var destination = this.destination; + if (destination && destination.error) { + this.destination.error(err); + } + }; + AnonymousSubject.prototype.complete = function () { + var destination = this.destination; + if (destination && destination.complete) { + this.destination.complete(); + } + }; + AnonymousSubject.prototype._subscribe = function (subscriber) { + var source = this.source; + if (source) { + return this.source.subscribe(subscriber); + } + else { + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + }; + return AnonymousSubject; +}(Subject)); + +//# sourceMappingURL=Subject.js.map + + +/***/ }), +/* 37 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.normalizePattern = normalizePattern; + +/** + * Explode and normalize a pattern into its name and range. + */ + +function normalizePattern(pattern) { + let hasVersion = false; + let range = 'latest'; + let name = pattern; + + // if we're a scope then remove the @ and add it back later + let isScoped = false; + if (name[0] === '@') { + isScoped = true; + name = name.slice(1); + } + + // take first part as the name + const parts = name.split('@'); + if (parts.length > 1) { + name = parts.shift(); + range = parts.join('@'); + + if (range) { + hasVersion = true; + } else { + range = '*'; + } + } + + // add back @ scope suffix + if (isScoped) { + name = `@${name}`; + } + + return { name, range, hasVersion }; +} + +/***/ }), +/* 38 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(module) {var __WEBPACK_AMD_DEFINE_RESULT__;/** + * @license + * Lodash + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '4.17.10'; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Error message constants. */ + var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', + FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** Used to compose bitmasks for cloning. */ + var CLONE_DEEP_FLAG = 1, + CLONE_FLAT_FLAG = 2, + CLONE_SYMBOLS_FLAG = 4; + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + + /** Used to compose bitmasks for function metadata. */ + var WRAP_BIND_FLAG = 1, + WRAP_BIND_KEY_FLAG = 2, + WRAP_CURRY_BOUND_FLAG = 4, + WRAP_CURRY_FLAG = 8, + WRAP_CURRY_RIGHT_FLAG = 16, + WRAP_PARTIAL_FLAG = 32, + WRAP_PARTIAL_RIGHT_FLAG = 64, + WRAP_ARY_FLAG = 128, + WRAP_REARG_FLAG = 256, + WRAP_FLIP_FLAG = 512; + + /** Used as default options for `_.truncate`. */ + var DEFAULT_TRUNC_LENGTH = 30, + DEFAULT_TRUNC_OMISSION = '...'; + + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 1, + LAZY_MAP_FLAG = 2, + LAZY_WHILE_FLAG = 3; + + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** Used to associate wrap methods with their bit flags. */ + var wrapFlags = [ + ['ary', WRAP_ARY_FLAG], + ['bind', WRAP_BIND_FLAG], + ['bindKey', WRAP_BIND_KEY_FLAG], + ['curry', WRAP_CURRY_FLAG], + ['curryRight', WRAP_CURRY_RIGHT_FLAG], + ['flip', WRAP_FLIP_FLAG], + ['partial', WRAP_PARTIAL_FLAG], + ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], + ['rearg', WRAP_REARG_FLAG] + ]; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + asyncTag = '[object AsyncFunction]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + domExcTag = '[object DOMException]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + nullTag = '[object Null]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + proxyTag = '[object Proxy]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + undefinedTag = '[object Undefined]', + weakMapTag = '[object WeakMap]', + weakSetTag = '[object WeakSet]'; + + var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match empty string literals in compiled template source. */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, + reUnescapedHtml = /[&<>"']/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match template delimiters. */ + var reEscape = /<%-([\s\S]+?)%>/g, + reEvaluate = /<%([\s\S]+?)%>/g, + reInterpolate = /<%=([\s\S]+?)%>/g; + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, + reHasRegExpChar = RegExp(reRegExpChar.source); + + /** Used to match leading and trailing whitespace. */ + var reTrim = /^\s+|\s+$/g, + reTrimStart = /^\s+/, + reTrimEnd = /\s+$/; + + /** Used to match wrap detail comments. */ + var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, + reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, + reSplitDetails = /,? & /; + + /** Used to match words composed of alphanumeric characters. */ + var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** + * Used to match + * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). + */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; + + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; + + /** Used to match Latin Unicode letters (excluding mathematical operators). */ + var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; + + /** Used to ensure capturing order of template delimiters. */ + var reNoMatch = /($^)/; + + /** Used to match unescaped characters in compiled string literals. */ + var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + + /** Used to compose unicode character classes. */ + var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsDingbatRange = '\\u2700-\\u27bf', + rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', + rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', + rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', + rsPunctuationRange = '\\u2000-\\u206f', + rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', + rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', + rsVarRange = '\\ufe0e\\ufe0f', + rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + + /** Used to compose unicode capture groups. */ + var rsApos = "['\u2019]", + rsAstral = '[' + rsAstralRange + ']', + rsBreak = '[' + rsBreakRange + ']', + rsCombo = '[' + rsComboRange + ']', + rsDigits = '\\d+', + rsDingbat = '[' + rsDingbatRange + ']', + rsLower = '[' + rsLowerRange + ']', + rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsUpper = '[' + rsUpperRange + ']', + rsZWJ = '\\u200d'; + + /** Used to compose unicode regexes. */ + var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', + rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', + rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', + rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', + reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange + ']?', + rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])', + rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + + /** Used to match apostrophes. */ + var reApos = RegExp(rsApos, 'g'); + + /** + * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and + * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). + */ + var reComboMark = RegExp(rsCombo, 'g'); + + /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ + var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + + /** Used to match complex or compound words. */ + var reUnicodeWord = RegExp([ + rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', + rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', + rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, + rsUpper + '+' + rsOptContrUpper, + rsOrdUpper, + rsOrdLower, + rsDigits, + rsEmoji + ].join('|'), 'g'); + + /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ + var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + + /** Used to detect strings that need a more robust regexp to match words. */ + var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; + + /** Used to assign default `context` object properties. */ + var contextProps = [ + 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', + 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', + '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' + ]; + + /** Used to make template sourceURLs easier to identify. */ + var templateCounter = -1; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag] = + typedArrayTags[objectTag] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag] = + typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = + cloneableTags[boolTag] = cloneableTags[dateTag] = + cloneableTags[float32Tag] = cloneableTags[float64Tag] = + cloneableTags[int8Tag] = cloneableTags[int16Tag] = + cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[setTag] = + cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[weakMapTag] = false; + + /** Used to map Latin Unicode letters to basic Latin letters. */ + var deburredLetters = { + // Latin-1 Supplement block. + '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', + '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', + '\xc7': 'C', '\xe7': 'c', + '\xd0': 'D', '\xf0': 'd', + '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', + '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', + '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xd1': 'N', '\xf1': 'n', + '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', + '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', + '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', + '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', + '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', + '\xc6': 'Ae', '\xe6': 'ae', + '\xde': 'Th', '\xfe': 'th', + '\xdf': 'ss', + // Latin Extended-A block. + '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', + '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', + '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', + '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', + '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', + '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', + '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', + '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', + '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', + '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', + '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', + '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', + '\u0134': 'J', '\u0135': 'j', + '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', + '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', + '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', + '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', + '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', + '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', + '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', + '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', + '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', + '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', + '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', + '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', + '\u0163': 't', '\u0165': 't', '\u0167': 't', + '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', + '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', + '\u0174': 'W', '\u0175': 'w', + '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', + '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', + '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', + '\u0132': 'IJ', '\u0133': 'ij', + '\u0152': 'Oe', '\u0153': 'oe', + '\u0149': "'n", '\u017f': 's' + }; + + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + }; + + /** Used to escape characters for inclusion in compiled string literals. */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + /** Built-in method references without a dependency on `root`. */ + var freeParseFloat = parseFloat, + freeParseInt = parseInt; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} + }()); + + /* Node.js helper references. */ + var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, + nodeIsDate = nodeUtil && nodeUtil.isDate, + nodeIsMap = nodeUtil && nodeUtil.isMap, + nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, + nodeIsSet = nodeUtil && nodeUtil.isSet, + nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + + /*--------------------------------------------------------------------------*/ + + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /** + * A specialized version of `baseAggregator` for arrays. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function arrayAggregator(array, setter, iteratee, accumulator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + var value = array[index]; + setter(accumulator, value, iteratee(value), array); + } + return accumulator; + } + + /** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.forEachRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEachRight(array, iteratee) { + var length = array == null ? 0 : array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + + /** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; + } + + /** + * This function is like `arrayIncludes` except that it accepts a comparator. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @param {Function} comparator The comparator invoked per element. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } + } + return false; + } + + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * A specialized version of `_.reduce` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the first element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, + length = array == null ? 0 : array.length; + + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.reduceRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the last element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initAccum) { + var length = array == null ? 0 : array.length; + if (initAccum && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Gets the size of an ASCII `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + var asciiSize = baseProperty('length'); + + /** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function asciiToArray(string) { + return string.split(''); + } + + /** + * Splits an ASCII `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function asciiWords(string) { + return string.match(reAsciiWord) || []; + } + + /** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); + } + + /** + * This function is like `baseIndexOf` except that it accepts a comparator. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @param {Function} comparator The comparator invoked per element. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOfWith(array, value, fromIndex, comparator) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (comparator(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ + function baseIsNaN(value) { + return value !== value; + } + + /** + * The base implementation of `_.mean` and `_.meanBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the mean. + */ + function baseMean(array, iteratee) { + var length = array == null ? 0 : array.length; + return length ? (baseSum(array, iteratee) / length) : NAN; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.propertyOf` without support for deep paths. + * + * @private + * @param {Object} object The object to query. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyOf(object) { + return function(key) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight`, without support + * for iteratee shorthands, which iterates over `collection` using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initAccum Specify using the first or last element of + * `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initAccum + ? (initAccum = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.sortBy` which uses `comparer` to define the + * sort order of `array` and replaces criteria objects with their corresponding + * values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * The base implementation of `_.sum` and `_.sumBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function baseSum(array, iteratee) { + var result, + index = -1, + length = array.length; + + while (++index < length) { + var current = iteratee(array[index]); + if (current !== undefined) { + result = result === undefined ? current : (result + current); + } + } + return result; + } + + /** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ + function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; + } + + /** + * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array + * of key-value pairs for `object` corresponding to the property names of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the key-value pairs. + */ + function baseToPairs(object, props) { + return arrayMap(props, function(key) { + return [key, object[key]]; + }); + } + + /** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ + function baseUnary(func) { + return function(value) { + return func(value); + }; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + return arrayMap(props, function(key) { + return object[key]; + }); + } + + /** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + + /** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ + function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ + function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Gets the number of `placeholder` occurrences in `array`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} placeholder The placeholder to search for. + * @returns {number} Returns the placeholder count. + */ + function countHolders(array, placeholder) { + var length = array.length, + result = 0; + + while (length--) { + if (array[length] === placeholder) { + ++result; + } + } + return result; + } + + /** + * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A + * letters to basic Latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ + var deburrLetter = basePropertyOf(deburredLetters); + + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + var escapeHtmlChar = basePropertyOf(htmlEscapes); + + /** + * Used by `_.template` to escape characters for inclusion in compiled string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; + } + + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + + /** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ + function hasUnicode(string) { + return reHasUnicode.test(string); + } + + /** + * Checks if `string` contains a word composed of Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a word is found, else `false`. + */ + function hasUnicodeWord(string) { + return reHasUnicodeWord.test(string); + } + + /** + * Converts `iterator` to an array. + * + * @private + * @param {Object} iterator The iterator to convert. + * @returns {Array} Returns the converted array. + */ + function iteratorToArray(iterator) { + var data, + result = []; + + while (!(data = iterator.next()).done) { + result.push(data.value); + } + return result; + } + + /** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ + function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; + } + + /** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ + function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value === placeholder || value === PLACEHOLDER) { + array[index] = PLACEHOLDER; + result[resIndex++] = index; + } + } + return result; + } + + /** + * Gets the value at `key`, unless `key` is "__proto__". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function safeGet(object, key) { + return key == '__proto__' + ? undefined + : object[key]; + } + + /** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ + function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; + } + + /** + * Converts `set` to its value-value pairs. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the value-value pairs. + */ + function setToPairs(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = [value, value]; + }); + return result; + } + + /** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * A specialized version of `_.lastIndexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictLastIndexOf(array, value, fromIndex) { + var index = fromIndex + 1; + while (index--) { + if (array[index] === value) { + return index; + } + } + return index; + } + + /** + * Gets the number of symbols in `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the string size. + */ + function stringSize(string) { + return hasUnicode(string) + ? unicodeSize(string) + : asciiSize(string); + } + + /** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); + } + + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + var unescapeHtmlChar = basePropertyOf(htmlUnescapes); + + /** + * Gets the size of a Unicode `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + function unicodeSize(string) { + var result = reUnicode.lastIndex = 0; + while (reUnicode.test(string)) { + ++result; + } + return result; + } + + /** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function unicodeToArray(string) { + return string.match(reUnicode) || []; + } + + /** + * Splits a Unicode `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function unicodeWords(string) { + return string.match(reUnicodeWord) || []; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a new pristine `lodash` function using the `context` object. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Util + * @param {Object} [context=root] The context object. + * @returns {Function} Returns a new `lodash` function. + * @example + * + * _.mixin({ 'foo': _.constant('foo') }); + * + * var lodash = _.runInContext(); + * lodash.mixin({ 'bar': lodash.constant('bar') }); + * + * _.isFunction(_.foo); + * // => true + * _.isFunction(_.bar); + * // => false + * + * lodash.isFunction(lodash.foo); + * // => false + * lodash.isFunction(lodash.bar); + * // => true + * + * // Create a suped-up `defer` in Node.js. + * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; + */ + var runInContext = (function runInContext(context) { + context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); + + /** Built-in constructor references. */ + var Array = context.Array, + Date = context.Date, + Error = context.Error, + Function = context.Function, + Math = context.Math, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** Used for built-in method references. */ + var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; + + /** Used to detect overreaching core-js shims. */ + var coreJsData = context['__core-js_shared__']; + + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Used to infer the `Object` constructor. */ + var objectCtorString = funcToString.call(Object); + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = root._; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Built-in value references. */ + var Buffer = moduleExports ? context.Buffer : undefined, + Symbol = context.Symbol, + Uint8Array = context.Uint8Array, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice, + spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, + symIterator = Symbol ? Symbol.iterator : undefined, + symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); + + /** Mocked built-ins. */ + var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, + ctxNow = Date && Date.now !== root.Date.now && Date.now, + ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil, + nativeFloor = Math.floor, + nativeGetSymbols = Object.getOwnPropertySymbols, + nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeIsFinite = context.isFinite, + nativeJoin = arrayProto.join, + nativeKeys = overArg(Object.keys, Object), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = Date.now, + nativeParseInt = context.parseInt, + nativeRandom = Math.random, + nativeReverse = arrayProto.reverse; + + /* Built-in method references that are verified to be native. */ + var DataView = getNative(context, 'DataView'), + Map = getNative(context, 'Map'), + Promise = getNative(context, 'Promise'), + Set = getNative(context, 'Set'), + WeakMap = getNative(context, 'WeakMap'), + nativeCreate = getNative(Object, 'create'); + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /** Used to detect maps, sets, and weakmaps. */ + var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit method + * chain sequences. Methods that operate on and return arrays, collections, + * and functions can be chained together. Methods that retrieve a single value + * or may return a primitive value will automatically end the chain sequence + * and return the unwrapped value. Otherwise, the value must be unwrapped + * with `_#value`. + * + * Explicit chain sequences, which must be unwrapped with `_#value`, may be + * enabled using `_.chain`. + * + * The execution of chained methods is lazy, that is, it's deferred until + * `_#value` is implicitly or explicitly called. + * + * Lazy evaluation allows several methods to support shortcut fusion. + * Shortcut fusion is an optimization to merge iteratee calls; this avoids + * the creation of intermediate arrays and can greatly reduce the number of + * iteratee executions. Sections of a chain sequence qualify for shortcut + * fusion if the section is applied to an array and iteratees accept only + * one argument. The heuristic for whether a section qualifies for shortcut + * fusion is subject to change. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, + * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, + * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, + * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, + * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, + * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, + * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, + * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, + * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, + * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, + * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, + * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, + * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, + * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, + * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, + * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, + * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, + * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, + * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, + * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, + * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, + * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, + * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, + * `zipObject`, `zipObjectDeep`, and `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, + * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, + * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, + * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, + * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, + * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, + * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, + * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, + * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, + * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, + * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, + * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, + * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, + * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, + * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, + * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, + * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, + * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, + * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, + * `upperFirst`, `value`, and `words` + * + * @name _ + * @constructor + * @category Seq + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2, 3]); + * + * // Returns an unwrapped value. + * wrapped.reduce(_.add); + * // => 6 + * + * // Returns a wrapped value. + * var squares = wrapped.map(square); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return wrapperClone(value); + } + } + return new LodashWrapper(value); + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; + }()); + + /** + * The function whose prototype chain sequence wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } + + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable explicit method chain sequences. + */ + function LodashWrapper(value, chainAll) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__chain__ = !!chainAll; + this.__index__ = 0; + this.__values__ = undefined; + } + + /** + * By default, the template delimiters used by lodash are like those in + * embedded Ruby (ERB) as well as ES2015 template strings. Change the + * following template settings to use alternative delimiters. + * + * @static + * @memberOf _ + * @type {Object} + */ + lodash.templateSettings = { + + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'escape': reEscape, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'evaluate': reEvaluate, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'interpolate': reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type {string} + */ + 'variable': '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type {Object} + */ + 'imports': { + + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type {Function} + */ + '_': lodash + } + }; + + // Ensure wrappers are instances of `baseLodash`. + lodash.prototype = baseLodash.prototype; + lodash.prototype.constructor = lodash; + + LodashWrapper.prototype = baseCreate(baseLodash.prototype); + LodashWrapper.prototype.constructor = LodashWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @constructor + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__dir__ = 1; + this.__filtered__ = false; + this.__iteratees__ = []; + this.__takeCount__ = MAX_ARRAY_LENGTH; + this.__views__ = []; + } + + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var result = new LazyWrapper(this.__wrapped__); + result.__actions__ = copyArray(this.__actions__); + result.__dir__ = this.__dir__; + result.__filtered__ = this.__filtered__; + result.__iteratees__ = copyArray(this.__iteratees__); + result.__takeCount__ = this.__takeCount__; + result.__views__ = copyArray(this.__views__); + return result; + } + + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.__filtered__) { + var result = new LazyWrapper(this); + result.__dir__ = -1; + result.__filtered__ = true; + } else { + result = this.clone(); + result.__dir__ *= -1; + } + return result; + } + + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.__wrapped__.value(), + dir = this.__dir__, + isArr = isArray(array), + isRight = dir < 0, + arrLength = isArr ? array.length : 0, + view = getView(0, arrLength, this.__views__), + start = view.start, + end = view.end, + length = end - start, + index = isRight ? end : (start - 1), + iteratees = this.__iteratees__, + iterLength = iteratees.length, + resIndex = 0, + takeCount = nativeMin(length, this.__takeCount__); + + if (!isArr || (!isRight && arrLength == length && takeCount == length)) { + return baseWrapperValue(array, this.__actions__); + } + var result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + type = data.type, + computed = iteratee(value); + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + result[resIndex++] = value; + } + return result; + } + + // Ensure `LazyWrapper` is an instance of `baseLodash`. + LazyWrapper.prototype = baseCreate(baseLodash.prototype); + LazyWrapper.prototype.constructor = LazyWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; + } + + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; + } + + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + } + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; + } + + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; + } + + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return getMapData(this, key).get(key); + } + + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return getMapData(this, key).has(key); + } + + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } + + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } + } + + /** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ + function setCacheHas(value) { + return this.__data__.has(value); + } + + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; + } + + /** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ + function stackClear() { + this.__data__ = new ListCache; + this.size = 0; + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function stackGet(key) { + return this.__data__.get(key); + } + + /** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function stackHas(key) { + return this.__data__.has(key); + } + + /** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ + function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; + } + + // Add methods to `Stack`. + Stack.prototype.clear = stackClear; + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.has = stackHas; + Stack.prototype.set = stackSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ + function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; + } + + /** + * A specialized version of `_.sample` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @returns {*} Returns the random element. + */ + function arraySample(array) { + var length = array.length; + return length ? array[baseRandom(0, length - 1)] : undefined; + } + + /** + * A specialized version of `_.sampleSize` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function arraySampleSize(array, n) { + return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); + } + + /** + * A specialized version of `_.shuffle` for arrays. + * + * @private + * @param {Array} array The array to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function arrayShuffle(array) { + return shuffleSelf(copyArray(array)); + } + + /** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + + /** + * Aggregates elements of `collection` on `accumulator` with keys transformed + * by `iteratee` and values set by `setter`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function baseAggregator(collection, setter, iteratee, accumulator) { + baseEach(collection, function(value, key, collection) { + setter(accumulator, value, iteratee(value), collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); + } + + /** + * The base implementation of `_.assignIn` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssignIn(object, source) { + return object && copyObject(source, keysIn(source), object); + } + + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } + + /** + * The base implementation of `_.at` without support for individual paths. + * + * @private + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths to pick. + * @returns {Array} Returns the picked elements. + */ + function baseAt(object, paths) { + var index = -1, + length = paths.length, + result = Array(length), + skip = object == null; + + while (++index < length) { + result[index] = skip ? undefined : get(object, paths[index]); + } + return result; + } + + /** + * The base implementation of `_.clamp` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + */ + function baseClamp(number, lower, upper) { + if (number === number) { + if (upper !== undefined) { + number = number <= upper ? number : upper; + } + if (lower !== undefined) { + number = number >= lower ? number : lower; + } + } + return number; + } + + /** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} bitmask The bitmask flags. + * 1 - Deep clone + * 2 - Flatten inherited properties + * 4 - Clone symbols + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, bitmask, customizer, key, object, stack) { + var result, + isDeep = bitmask & CLONE_DEEP_FLAG, + isFlat = bitmask & CLONE_FLAT_FLAG, + isFull = bitmask & CLONE_SYMBOLS_FLAG; + + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); + } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; + + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); + } + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = (isFlat || isFunc) ? {} : initCloneObject(value); + if (!isDeep) { + return isFlat + ? copySymbolsIn(value, baseAssignIn(result, value)) + : copySymbols(value, baseAssign(result, value)); + } + } else { + if (!cloneableTags[tag]) { + return object ? value : {}; + } + result = initCloneByTag(value, tag, isDeep); + } + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); + + if (isSet(value)) { + value.forEach(function(subValue) { + result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); + }); + + return result; + } + + if (isMap(value)) { + value.forEach(function(subValue, key) { + result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + + return result; + } + + var keysFunc = isFull + ? (isFlat ? getAllKeysIn : getAllKeys) + : (isFlat ? keysIn : keys); + + var props = isArr ? undefined : keysFunc(value); + arrayEach(props || value, function(subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + return result; + } + + /** + * The base implementation of `_.conforms` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property predicates to conform to. + * @returns {Function} Returns the new spec function. + */ + function baseConforms(source) { + var props = keys(source); + return function(object) { + return baseConformsTo(object, source, props); + }; + } + + /** + * The base implementation of `_.conformsTo` which accepts `props` to check. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + */ + function baseConformsTo(object, source, props) { + var length = props.length; + if (object == null) { + return !length; + } + object = Object(object); + while (length--) { + var key = props[length], + predicate = source[key], + value = object[key]; + + if ((value === undefined && !(key in object)) || !predicate(value)) { + return false; + } + } + return true; + } + + /** + * The base implementation of `_.delay` and `_.defer` which accepts `args` + * to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Array} args The arguments to provide to `func`. + * @returns {number|Object} Returns the timer id or timeout object. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, args); }, wait); + } + + /** + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + isCommon = true, + length = array.length, + result = [], + valuesLength = values.length; + + if (!length) { + return result; + } + if (iteratee) { + values = arrayMap(values, baseUnary(iteratee)); + } + if (comparator) { + includes = arrayIncludesWith; + isCommon = false; + } + else if (values.length >= LARGE_ARRAY_SIZE) { + includes = cacheHas; + isCommon = false; + values = new SetCache(values); + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee == null ? value : iteratee(value); + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === computed) { + continue outer; + } + } + result.push(value); + } + else if (!includes(values, computed, comparator)) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.forEachRight` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEachRight = createBaseEach(baseForOwnRight, true); + + /** + * The base implementation of `_.every` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of methods like `_.max` and `_.min` which accepts a + * `comparator` to determine the extremum value. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The iteratee invoked per iteration. + * @param {Function} comparator The comparator used to compare values. + * @returns {*} Returns the extremum value. + */ + function baseExtremum(array, iteratee, comparator) { + var index = -1, + length = array.length; + + while (++index < length) { + var value = array[index], + current = iteratee(value); + + if (current != null && (computed === undefined + ? (current === current && !isSymbol(current)) + : comparator(current, computed) + )) { + var computed = current, + result = value; + } + } + return result; + } + + /** + * The base implementation of `_.fill` without an iteratee call guard. + * + * @private + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + */ + function baseFill(array, value, start, end) { + var length = array.length; + + start = toInteger(start); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (end === undefined || end > length) ? length : toInteger(end); + if (end < 0) { + end += length; + } + end = start > end ? 0 : toLength(end); + while (start < end) { + array[start++] = value; + } + return array; + } + + /** + * The base implementation of `_.filter` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with support for restricting flattening. + * + * @private + * @param {Array} array The array to flatten. + * @param {number} depth The maximum recursion depth. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, depth, predicate, isStrict, result) { + var index = -1, + length = array.length; + + predicate || (predicate = isFlattenable); + result || (result = []); + + while (++index < length) { + var value = array[index]; + if (depth > 0 && predicate(value)) { + if (depth > 1) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, depth - 1, predicate, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseForRight = createBaseFor(true); + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `_.forOwnRight` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return object && baseForRight(object, iteratee, keys); + } + + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from `props`. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the function names. + */ + function baseFunctions(object, props) { + return arrayFilter(props, function(key) { + return isFunction(object[key]); + }); + } + + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ + function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); + } + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * The base implementation of `_.gt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + */ + function baseGt(value, other) { + return value > other; + } + + /** + * The base implementation of `_.has` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHas(object, key) { + return object != null && hasOwnProperty.call(object, key); + } + + /** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHasIn(object, key) { + return object != null && key in Object(object); + } + + /** + * The base implementation of `_.inRange` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to check. + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + */ + function baseInRange(number, start, end) { + return number >= nativeMin(start, end) && number < nativeMax(start, end); + } + + /** + * The base implementation of methods like `_.intersection`, without support + * for iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of shared values. + */ + function baseIntersection(arrays, iteratee, comparator) { + var includes = comparator ? arrayIncludesWith : arrayIncludes, + length = arrays[0].length, + othLength = arrays.length, + othIndex = othLength, + caches = Array(othLength), + maxLength = Infinity, + result = []; + + while (othIndex--) { + var array = arrays[othIndex]; + if (othIndex && iteratee) { + array = arrayMap(array, baseUnary(iteratee)); + } + maxLength = nativeMin(array.length, maxLength); + caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) + ? new SetCache(othIndex && array) + : undefined; + } + array = arrays[0]; + + var index = -1, + seen = caches[0]; + + outer: + while (++index < length && result.length < maxLength) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (!(seen + ? cacheHas(seen, computed) + : includes(result, computed, comparator) + )) { + othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if (!(cache + ? cacheHas(cache, computed) + : includes(arrays[othIndex], computed, comparator)) + ) { + continue outer; + } + } + if (seen) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.invert` and `_.invertBy` which inverts + * `object` with values transformed by `iteratee` and set by `setter`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform values. + * @param {Object} accumulator The initial inverted object. + * @returns {Function} Returns `accumulator`. + */ + function baseInverter(object, setter, iteratee, accumulator) { + baseForOwn(object, function(value, key, object) { + setter(accumulator, iteratee(value), key, object); + }); + return accumulator; + } + + /** + * The base implementation of `_.invoke` without support for individual + * method arguments. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function baseInvoke(object, path, args) { + path = castPath(path, object); + object = parent(object, path); + var func = object == null ? object : object[toKey(last(path))]; + return func == null ? undefined : apply(func, object, args); + } + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** + * The base implementation of `_.isArrayBuffer` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + */ + function baseIsArrayBuffer(value) { + return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; + } + + /** + * The base implementation of `_.isDate` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + */ + function baseIsDate(value) { + return isObjectLike(value) && baseGetTag(value) == dateTag; + } + + /** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag : getTag(object), + othTag = othIsArr ? arrayTag : getTag(other); + + objTag = objTag == argsTag ? objectTag : objTag; + othTag = othTag == argsTag ? objectTag : othTag; + + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG)) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); + } + + /** + * The base implementation of `_.isMap` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + */ + function baseIsMap(value) { + return isObjectLike(value) && getTag(value) == mapTag; + } + + /** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) + : result + )) { + return false; + } + } + } + return true; + } + + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + + /** + * The base implementation of `_.isRegExp` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + */ + function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; + } + + /** + * The base implementation of `_.isSet` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + */ + function baseIsSet(value) { + return isObjectLike(value) && getTag(value) == setTag; + } + + /** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ + function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; + } + + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); + } + + /** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.lt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + */ + function baseLt(value, other) { + return value < other; + } + + /** + * The base implementation of `_.map` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } + + /** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; + } + + /** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); + }; + } + + /** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + if (isObject(srcValue)) { + stack || (stack = new Stack); + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); + } + + /** + * The base implementation of `_.nth` which doesn't coerce arguments. + * + * @private + * @param {Array} array The array to query. + * @param {number} n The index of the element to return. + * @returns {*} Returns the nth element of `array`. + */ + function baseNth(array, n) { + var length = array.length; + if (!length) { + return; + } + n += n < 0 ? length : 0; + return isIndex(n, length) ? array[n] : undefined; + } + + /** + * The base implementation of `_.orderBy` without param guards. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {string[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseOrderBy(collection, iteratees, orders) { + var index = -1; + iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); + + var result = baseMap(collection, function(value, key, collection) { + var criteria = arrayMap(iteratees, function(iteratee) { + return iteratee(value); + }); + return { 'criteria': criteria, 'index': ++index, 'value': value }; + }); + + return baseSortBy(result, function(object, other) { + return compareMultiple(object, other, orders); + }); + } + + /** + * The base implementation of `_.pick` without support for individual + * property identifiers. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. + */ + function basePick(object, paths) { + return basePickBy(object, paths, function(value, path) { + return hasIn(object, path); + }); + } + + /** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; + } + + /** + * The base implementation of `_.pullAllBy` without support for iteratee + * shorthands. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + */ + function basePullAll(array, values, iteratee, comparator) { + var indexOf = comparator ? baseIndexOfWith : baseIndexOf, + index = -1, + length = values.length, + seen = array; + + if (array === values) { + values = copyArray(values); + } + if (iteratee) { + seen = arrayMap(array, baseUnary(iteratee)); + } + while (++index < length) { + var fromIndex = 0, + value = values[index], + computed = iteratee ? iteratee(value) : value; + + while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { + if (seen !== array) { + splice.call(seen, fromIndex, 1); + } + splice.call(array, fromIndex, 1); + } + } + return array; + } + + /** + * The base implementation of `_.pullAt` without support for individual + * indexes or capturing the removed elements. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns `array`. + */ + function basePullAt(array, indexes) { + var length = array ? indexes.length : 0, + lastIndex = length - 1; + + while (length--) { + var index = indexes[length]; + if (length == lastIndex || index !== previous) { + var previous = index; + if (isIndex(index)) { + splice.call(array, index, 1); + } else { + baseUnset(array, index); + } + } + } + return array; + } + + /** + * The base implementation of `_.random` without support for returning + * floating-point numbers. + * + * @private + * @param {number} lower The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the random number. + */ + function baseRandom(lower, upper) { + return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); + } + + /** + * The base implementation of `_.range` and `_.rangeRight` which doesn't + * coerce arguments. + * + * @private + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @param {number} step The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the range of numbers. + */ + function baseRange(start, end, step, fromRight) { + var index = -1, + length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); + + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; + } + return result; + } + + /** + * The base implementation of `_.repeat` which doesn't coerce arguments. + * + * @private + * @param {string} string The string to repeat. + * @param {number} n The number of times to repeat the string. + * @returns {string} Returns the repeated string. + */ + function baseRepeat(string, n) { + var result = ''; + if (!string || n < 1 || n > MAX_SAFE_INTEGER) { + return result; + } + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = nativeFloor(n / 2); + if (n) { + string += string; + } + } while (n); + + return result; + } + + /** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** + * The base implementation of `_.sample`. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + */ + function baseSample(collection) { + return arraySample(values(collection)); + } + + /** + * The base implementation of `_.sampleSize` without param guards. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function baseSampleSize(collection, n) { + var array = values(collection); + return shuffleSelf(array, baseClamp(n, 0, array.length)); + } + + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } + + /** + * The base implementation of `setData` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); + }; + + /** + * The base implementation of `_.shuffle`. + * + * @private + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function baseShuffle(collection) { + return shuffleSelf(values(collection)); + } + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.some` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } + + /** + * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which + * performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndex(array, value, retHighest) { + var low = 0, + high = array == null ? low : array.length; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if (computed !== null && !isSymbol(computed) && + (retHighest ? (computed <= value) : (computed < value))) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return baseSortedIndexBy(array, value, identity, retHighest); + } + + /** + * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` + * which invokes `iteratee` for `value` and each element of `array` to compute + * their sort ranking. The iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The iteratee invoked per element. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array == null ? 0 : array.length, + valIsNaN = value !== value, + valIsNull = value === null, + valIsSymbol = isSymbol(value), + valIsUndefined = value === undefined; + + while (low < high) { + var mid = nativeFloor((low + high) / 2), + computed = iteratee(array[mid]), + othIsDefined = computed !== undefined, + othIsNull = computed === null, + othIsReflexive = computed === computed, + othIsSymbol = isSymbol(computed); + + if (valIsNaN) { + var setLow = retHighest || othIsReflexive; + } else if (valIsUndefined) { + setLow = othIsReflexive && (retHighest || othIsDefined); + } else if (valIsNull) { + setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); + } else if (valIsSymbol) { + setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); + } else if (othIsNull || othIsSymbol) { + setLow = false; + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + + /** + * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseSortedUniq(array, iteratee) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + if (!index || !eq(computed, seen)) { + var seen = computed; + result[resIndex++] = value === 0 ? 0 : value; + } + } + return result; + } + + /** + * The base implementation of `_.toNumber` which doesn't ensure correct + * conversions of binary, hexadecimal, or octal string values. + * + * @private + * @param {*} value The value to process. + * @returns {number} Returns the number. + */ + function baseToNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + return +value; + } + + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * The base implementation of `_.uniqBy` without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseUniq(array, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + length = array.length, + isCommon = true, + result = [], + seen = result; + + if (comparator) { + isCommon = false; + includes = arrayIncludesWith; + } + else if (length >= LARGE_ARRAY_SIZE) { + var set = iteratee ? null : createSet(array); + if (set) { + return setToArray(set); + } + isCommon = false; + includes = cacheHas; + seen = new SetCache; + } + else { + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (!includes(seen, computed, comparator)) { + if (seen !== result) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.unset`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The property path to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + */ + function baseUnset(object, path) { + path = castPath(path, object); + object = parent(object, path); + return object == null || delete object[toKey(last(path))]; + } + + /** + * The base implementation of `_.update`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to update. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseUpdate(object, path, updater, customizer) { + return baseSet(object, path, updater(baseGet(object, path)), customizer); + } + + /** + * The base implementation of methods like `_.dropWhile` and `_.takeWhile` + * without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to query. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [isDrop] Specify dropping elements instead of taking them. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the slice of `array`. + */ + function baseWhile(array, predicate, isDrop, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length) && + predicate(array[index], index, array)) {} + + return isDrop + ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) + : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to perform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + return arrayReduce(actions, function(result, action) { + return action.func.apply(action.thisArg, arrayPush([result], action.args)); + }, result); + } + + /** + * The base implementation of methods like `_.xor`, without support for + * iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of values. + */ + function baseXor(arrays, iteratee, comparator) { + var length = arrays.length; + if (length < 2) { + return length ? baseUniq(arrays[0]) : []; + } + var index = -1, + result = Array(length); + + while (++index < length) { + var array = arrays[index], + othIndex = -1; + + while (++othIndex < length) { + if (othIndex != index) { + result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); + } + } + } + return baseUniq(baseFlatten(result, 1), iteratee, comparator); + } + + /** + * This base implementation of `_.zipObject` which assigns values using `assignFunc`. + * + * @private + * @param {Array} props The property identifiers. + * @param {Array} values The property values. + * @param {Function} assignFunc The function to assign values. + * @returns {Object} Returns the new object. + */ + function baseZipObject(props, values, assignFunc) { + var index = -1, + length = props.length, + valsLength = values.length, + result = {}; + + while (++index < length) { + var value = index < valsLength ? values[index] : undefined; + assignFunc(result, props[index], value); + } + return result; + } + + /** + * Casts `value` to an empty array if it's not an array like object. + * + * @private + * @param {*} value The value to inspect. + * @returns {Array|Object} Returns the cast array-like object. + */ + function castArrayLikeObject(value) { + return isArrayLikeObject(value) ? value : []; + } + + /** + * Casts `value` to `identity` if it's not a function. + * + * @private + * @param {*} value The value to inspect. + * @returns {Function} Returns cast function. + */ + function castFunction(value) { + return typeof value == 'function' ? value : identity; + } + + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); + } + + /** + * A `baseRest` alias which can be replaced with `identity` by module + * replacement plugins. + * + * @private + * @type {Function} + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + var castRest = baseRest; + + /** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ + function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); + } + + /** + * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). + * + * @private + * @param {number|Object} id The timer id or timeout object of the timer to clear. + */ + var clearTimeout = ctxClearTimeout || function(id) { + return root.clearTimeout(id); + }; + + /** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ + function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; + } + + /** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ + function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); + } + + /** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ + function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; + } + + /** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ + function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); + } + + /** + * Compares values to sort them in ascending order. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ + function compareAscending(value, other) { + if (value !== other) { + var valIsDefined = value !== undefined, + valIsNull = value === null, + valIsReflexive = value === value, + valIsSymbol = isSymbol(value); + + var othIsDefined = other !== undefined, + othIsNull = other === null, + othIsReflexive = other === other, + othIsSymbol = isSymbol(other); + + if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || + (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || + (valIsNull && othIsDefined && othIsReflexive) || + (!valIsDefined && othIsReflexive) || + !valIsReflexive) { + return 1; + } + if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || + (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || + (othIsNull && valIsDefined && valIsReflexive) || + (!othIsDefined && valIsReflexive) || + !othIsReflexive) { + return -1; + } + } + return 0; + } + + /** + * Used by `_.orderBy` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, + * specify an order of "desc" for descending or "asc" for ascending sort order + * of corresponding values. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]|string[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; + + while (++index < length) { + var result = compareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * (order == 'desc' ? -1 : 1); + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersLength = holders.length, + leftIndex = -1, + leftLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(leftLength + rangeLength), + isUncurried = !isCurried; + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + } + while (rangeLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersIndex = -1, + holdersLength = holders.length, + rightIndex = -1, + rightLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(rangeLength + rightLength), + isUncurried = !isCurried; + + while (++argsIndex < rangeLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + } + return result; + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; + } + + /** + * Copies own symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); + } + + /** + * Copies own and inherited symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbolsIn(source, object) { + return copyObject(source, getSymbolsIn(source), object); + } + + /** + * Creates a function like `_.groupBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} [initializer] The accumulator object initializer. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee) { + var func = isArray(collection) ? arrayAggregator : baseAggregator, + accumulator = initializer ? initializer() : {}; + + return func(collection, setter, getIteratee(iteratee, 2), accumulator); + }; + } + + /** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); + } + + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { + return eachFunc(collection, iteratee); + } + var length = collection.length, + index = fromRight ? length : -1, + iterable = Object(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } + + /** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` to invoke it with the optional `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createBind(func, bitmask, thisArg) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, arguments); + } + return wrapper; + } + + /** + * Creates a function like `_.lowerFirst`. + * + * @private + * @param {string} methodName The name of the `String` case method to use. + * @returns {Function} Returns the new case function. + */ + function createCaseFirst(methodName) { + return function(string) { + string = toString(string); + + var strSymbols = hasUnicode(string) + ? stringToArray(string) + : undefined; + + var chr = strSymbols + ? strSymbols[0] + : string.charAt(0); + + var trailing = strSymbols + ? castSlice(strSymbols, 1).join('') + : string.slice(1); + + return chr[methodName]() + trailing; + }; + } + + /** + * Creates a function like `_.camelCase`. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ + function createCompounder(callback) { + return function(string) { + return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); + }; + } + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtor(Ctor) { + return function() { + // Use a `switch` statement to work with class constructors. See + // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: return new Ctor; + case 1: return new Ctor(args[0]); + case 2: return new Ctor(args[0], args[1]); + case 3: return new Ctor(args[0], args[1], args[2]); + case 4: return new Ctor(args[0], args[1], args[2], args[3]); + case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); + case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a function that wraps `func` to enable currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {number} arity The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createCurry(func, bitmask, arity) { + var Ctor = createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length, + placeholder = getHolder(wrapper); + + while (index--) { + args[index] = arguments[index]; + } + var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) + ? [] + : replaceHolders(args, placeholder); + + length -= holders.length; + if (length < arity) { + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, undefined, + args, holders, undefined, undefined, arity - length); + } + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return apply(fn, this, args); + } + return wrapper; + } + + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} findIndexFunc The function to find the collection index. + * @returns {Function} Returns the new find function. + */ + function createFind(findIndexFunc) { + return function(collection, predicate, fromIndex) { + var iterable = Object(collection); + if (!isArrayLike(collection)) { + var iteratee = getIteratee(predicate, 3); + collection = keys(collection); + predicate = function(key) { return iteratee(iterable[key], key, iterable); }; + } + var index = findIndexFunc(collection, predicate, fromIndex); + return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; + }; + } + + /** + * Creates a `_.flow` or `_.flowRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new flow function. + */ + function createFlow(fromRight) { + return flatRest(function(funcs) { + var length = funcs.length, + index = length, + prereq = LodashWrapper.prototype.thru; + + if (fromRight) { + funcs.reverse(); + } + while (index--) { + var func = funcs[index]; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (prereq && !wrapper && getFuncName(func) == 'wrapper') { + var wrapper = new LodashWrapper([], true); + } + } + index = wrapper ? index : length; + while (++index < length) { + func = funcs[index]; + + var funcName = getFuncName(func), + data = funcName == 'wrapper' ? getData(func) : undefined; + + if (data && isLaziable(data[0]) && + data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && + !data[4].length && data[9] == 1 + ) { + wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); + } else { + wrapper = (func.length == 1 && isLaziable(func)) + ? wrapper[funcName]() + : wrapper.thru(func); + } + } + return function() { + var args = arguments, + value = args[0]; + + if (wrapper && args.length == 1 && isArray(value)) { + return wrapper.plant(value).value(); + } + var index = 0, + result = length ? funcs[index].apply(this, args) : value; + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + }); + } + + /** + * Creates a function that wraps `func` to invoke it with optional `this` + * binding of `thisArg`, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided + * to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & WRAP_ARY_FLAG, + isBind = bitmask & WRAP_BIND_FLAG, + isBindKey = bitmask & WRAP_BIND_KEY_FLAG, + isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), + isFlip = bitmask & WRAP_FLIP_FLAG, + Ctor = isBindKey ? undefined : createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length; + + while (index--) { + args[index] = arguments[index]; + } + if (isCurried) { + var placeholder = getHolder(wrapper), + holdersCount = countHolders(args, placeholder); + } + if (partials) { + args = composeArgs(args, partials, holders, isCurried); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight, isCurried); + } + length -= holdersCount; + if (isCurried && length < arity) { + var newHolders = replaceHolders(args, placeholder); + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, thisArg, + args, newHolders, argPos, ary, arity - length + ); + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + length = args.length; + if (argPos) { + args = reorder(args, argPos); + } else if (isFlip && length > 1) { + args.reverse(); + } + if (isAry && ary < length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtor(fn); + } + return fn.apply(thisBinding, args); + } + return wrapper; + } + + /** + * Creates a function like `_.invertBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} toIteratee The function to resolve iteratees. + * @returns {Function} Returns the new inverter function. + */ + function createInverter(setter, toIteratee) { + return function(object, iteratee) { + return baseInverter(object, setter, toIteratee(iteratee), {}); + }; + } + + /** + * Creates a function that performs a mathematical operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @param {number} [defaultValue] The value used for `undefined` arguments. + * @returns {Function} Returns the new mathematical operation function. + */ + function createMathOperation(operator, defaultValue) { + return function(value, other) { + var result; + if (value === undefined && other === undefined) { + return defaultValue; + } + if (value !== undefined) { + result = value; + } + if (other !== undefined) { + if (result === undefined) { + return other; + } + if (typeof value == 'string' || typeof other == 'string') { + value = baseToString(value); + other = baseToString(other); + } else { + value = baseToNumber(value); + other = baseToNumber(other); + } + result = operator(value, other); + } + return result; + }; + } + + /** + * Creates a function like `_.over`. + * + * @private + * @param {Function} arrayFunc The function to iterate over iteratees. + * @returns {Function} Returns the new over function. + */ + function createOver(arrayFunc) { + return flatRest(function(iteratees) { + iteratees = arrayMap(iteratees, baseUnary(getIteratee())); + return baseRest(function(args) { + var thisArg = this; + return arrayFunc(iteratees, function(iteratee) { + return apply(iteratee, thisArg, args); + }); + }); + }); + } + + /** + * Creates the padding for `string` based on `length`. The `chars` string + * is truncated if the number of characters exceeds `length`. + * + * @private + * @param {number} length The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padding for `string`. + */ + function createPadding(length, chars) { + chars = chars === undefined ? ' ' : baseToString(chars); + + var charsLength = chars.length; + if (charsLength < 2) { + return charsLength ? baseRepeat(chars, length) : chars; + } + var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); + return hasUnicode(chars) + ? castSlice(stringToArray(result), 0, length).join('') + : result.slice(0, length); + } + + /** + * Creates a function that wraps `func` to invoke it with the `this` binding + * of `thisArg` and `partials` prepended to the arguments it receives. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to + * the new function. + * @returns {Function} Returns the new wrapped function. + */ + function createPartial(func, bitmask, thisArg, partials) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(leftLength + argsLength), + fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return apply(fn, isBind ? thisArg : this, args); + } + return wrapper; + } + + /** + * Creates a `_.range` or `_.rangeRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new range function. + */ + function createRange(fromRight) { + return function(start, end, step) { + if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { + end = step = undefined; + } + // Ensure the sign of `-0` is preserved. + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); + return baseRange(start, end, step, fromRight); + }; + } + + /** + * Creates a function that performs a relational operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @returns {Function} Returns the new relational operation function. + */ + function createRelationalOperation(operator) { + return function(value, other) { + if (!(typeof value == 'string' && typeof other == 'string')) { + value = toNumber(value); + other = toNumber(other); + } + return operator(value, other); + }; + } + + /** + * Creates a function that wraps `func` to continue currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} wrapFunc The function to create the `func` wrapper. + * @param {*} placeholder The placeholder value. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { + var isCurry = bitmask & WRAP_CURRY_FLAG, + newHolders = isCurry ? holders : undefined, + newHoldersRight = isCurry ? undefined : holders, + newPartials = isCurry ? partials : undefined, + newPartialsRight = isCurry ? undefined : partials; + + bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); + + if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { + bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); + } + var newData = [ + func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, + newHoldersRight, argPos, ary, arity + ]; + + var result = wrapFunc.apply(undefined, newData); + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return setWrapToString(result, func, bitmask); + } + + /** + * Creates a function like `_.round`. + * + * @private + * @param {string} methodName The name of the `Math` method to use when rounding. + * @returns {Function} Returns the new round function. + */ + function createRound(methodName) { + var func = Math[methodName]; + return function(number, precision) { + number = toNumber(number); + precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); + if (precision) { + // Shift with exponential notation to avoid floating-point issues. + // See [MDN](https://mdn.io/round#Examples) for more details. + var pair = (toString(number) + 'e').split('e'), + value = func(pair[0] + 'e' + (+pair[1] + precision)); + + pair = (toString(value) + 'e').split('e'); + return +(pair[0] + 'e' + (+pair[1] - precision)); + } + return func(number); + }; + } + + /** + * Creates a set object of `values`. + * + * @private + * @param {Array} values The values to add to the set. + * @returns {Object} Returns the new set. + */ + var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { + return new Set(values); + }; + + /** + * Creates a `_.toPairs` or `_.toPairsIn` function. + * + * @private + * @param {Function} keysFunc The function to get the keys of a given object. + * @returns {Function} Returns the new pairs function. + */ + function createToPairs(keysFunc) { + return function(object) { + var tag = getTag(object); + if (tag == mapTag) { + return mapToArray(object); + } + if (tag == setTag) { + return setToPairs(object); + } + return baseToPairs(object, keysFunc(object)); + }; + } + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * 512 - `_.flip` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); + partials = holders = undefined; + } + ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); + arity = arity === undefined ? arity : toInteger(arity); + length -= holders ? holders.length : 0; + + if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = undefined; + } + var data = isBindKey ? undefined : getData(func); + + var newData = [ + func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, + argPos, ary, arity + ]; + + if (data) { + mergeData(newData, data); + } + func = newData[0]; + bitmask = newData[1]; + thisArg = newData[2]; + partials = newData[3]; + holders = newData[4]; + arity = newData[9] = newData[9] === undefined + ? (isBindKey ? 0 : func.length) + : nativeMax(newData[9] - length, 0); + + if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { + bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); + } + if (!bitmask || bitmask == WRAP_BIND_FLAG) { + var result = createBind(func, bitmask, thisArg); + } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { + result = createCurry(func, bitmask, arity); + } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { + result = createPartial(func, bitmask, thisArg, partials); + } else { + result = createHybrid.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setWrapToString(setter(result, newData), func, bitmask); + } + + /** + * Used by `_.defaults` to customize its `_.assignIn` use to assign properties + * of source objects to the destination object for all destination properties + * that resolve to `undefined`. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to assign. + * @param {Object} object The parent object of `objValue`. + * @returns {*} Returns the value to assign. + */ + function customDefaultsAssignIn(objValue, srcValue, key, object) { + if (objValue === undefined || + (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { + return srcValue; + } + return objValue; + } + + /** + * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source + * objects into destination objects that are passed thru. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to merge. + * @param {Object} object The parent object of `objValue`. + * @param {Object} source The parent object of `srcValue`. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + * @returns {*} Returns the value to assign. + */ + function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { + if (isObject(objValue) && isObject(srcValue)) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, objValue); + baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); + stack['delete'](srcValue); + } + return objValue; + } + + /** + * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain + * objects. + * + * @private + * @param {*} value The value to inspect. + * @param {string} key The key of the property to inspect. + * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. + */ + function customOmitClone(value) { + return isPlainObject(value) ? undefined : value; + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag: + case dateTag: + case numberTag: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag: + return object.name == other.name && object.message == other.message; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag: + var convert = mapToArray; + + case setTag: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseRest` which flattens the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); + } + + /** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); + } + + /** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = (func.name + ''), + array = realNames[result], + length = hasOwnProperty.call(realNames, result) ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } + + /** + * Gets the argument placeholder value for `func`. + * + * @private + * @param {Function} func The function to inspect. + * @returns {*} Returns the placeholder value. + */ + function getHolder(func) { + var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; + return object.placeholder; + } + + /** + * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, + * this function returns the custom method, otherwise it returns `baseIteratee`. + * If arguments are provided, the chosen function is invoked with them and + * its result is returned. + * + * @private + * @param {*} [value] The value to convert to an iteratee. + * @param {number} [arity] The arity of the created iteratee. + * @returns {Function} Returns the chosen function or its result. + */ + function getIteratee() { + var result = lodash.iteratee || iteratee; + result = result === iteratee ? baseIteratee : result; + return arguments.length ? result(arguments[0], arguments[1]) : result; + } + + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + + /** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; + } + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + /** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable.call(object, symbol); + }); + }; + + /** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; + }; + + /** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + var getTag = baseGetTag; + + // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. + if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; + } + } + return result; + }; + } + + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} transforms The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms.length; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': start += size; break; + case 'dropRight': end -= size; break; + case 'take': end = nativeMin(end, start + size); break; + case 'takeRight': start = nativeMax(start, end - size); break; + } + } + return { 'start': start, 'end': end }; + } + + /** + * Extracts wrapper details from the `source` body comment. + * + * @private + * @param {string} source The source to inspect. + * @returns {Array} Returns the wrapper details. + */ + function getWrapDetails(source) { + var match = source.match(reWrapDetails); + return match ? match[1].split(reSplitDetails) : []; + } + + /** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case dataViewTag: + return cloneDataView(object, isDeep); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + return cloneTypedArray(object, isDeep); + + case mapTag: + return new Ctor; + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + return cloneRegExp(object); + + case setTag: + return new Ctor; + + case symbolTag: + return cloneSymbol(object); + } + } + + /** + * Inserts wrapper `details` in a comment at the top of the `source` body. + * + * @private + * @param {string} source The source to modify. + * @returns {Array} details The details to insert. + * @returns {string} Returns the modified source. + */ + function insertWrapDetails(source, details) { + var length = details.length; + if (!length) { + return source; + } + var lastIndex = length - 1; + details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; + details = details.join(length > 2 ? ', ' : ' '); + return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); + } + + /** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenable(value) { + return isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); + } + + /** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; + } + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } + + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } + + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, + * else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func), + other = lodash[funcName]; + + if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { + return false; + } + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } + + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** + * Checks if `func` is capable of being masked. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `func` is maskable, else `false`. + */ + var isMaskable = coreJsData ? isFunction : stubFalse; + + /** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; + } + + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers used to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and + * `_.rearg` modify function arguments, making the order in which they are + * executed important, preventing the merging of metadata. However, we make + * an exception for a safe combined case where curried functions have `_.ary` + * and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); + + var isCombo = + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || + ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & WRAP_BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : value; + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = value; + } + // Use source `ary` if it's smaller. + if (srcBitmask & WRAP_ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + /** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; + } + + /** + * Gets the parent value at `path` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path to get the parent value of. + * @returns {*} Returns the parent value. + */ + function parent(object, path) { + return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = copyArray(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity + * function to avoid garbage collection pauses in V8. See + * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = shortOut(baseSetData); + + /** + * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @returns {number|Object} Returns the timer id or timeout object. + */ + var setTimeout = ctxSetTimeout || function(func, wait) { + return root.setTimeout(func, wait); + }; + + /** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * Sets the `toString` method of `wrapper` to mimic the source of `reference` + * with wrapper details in a comment at the top of the source body. + * + * @private + * @param {Function} wrapper The function to modify. + * @param {Function} reference The reference function. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Function} Returns `wrapper`. + */ + function setWrapToString(wrapper, reference, bitmask) { + var source = (reference + ''); + return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); + } + + /** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ + function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; + } + + /** + * A specialized version of `_.shuffle` which mutates and sets the size of `array`. + * + * @private + * @param {Array} array The array to shuffle. + * @param {number} [size=array.length] The size of `array`. + * @returns {Array} Returns `array`. + */ + function shuffleSelf(array, size) { + var index = -1, + length = array.length, + lastIndex = length - 1; + + size = size === undefined ? length : size; + while (++index < size) { + var rand = baseRandom(index, lastIndex), + value = array[rand]; + + array[rand] = array[index]; + array[index] = value; + } + array.length = size; + return array; + } + + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); + + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; + } + + /** + * Updates wrapper `details` based on `bitmask` flags. + * + * @private + * @returns {Array} details The details to modify. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Array} Returns `details`. + */ + function updateWrapDetails(details, bitmask) { + arrayEach(wrapFlags, function(pair) { + var value = '_.' + pair[0]; + if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { + details.push(value); + } + }); + return details.sort(); + } + + /** + * Creates a clone of `wrapper`. + * + * @private + * @param {Object} wrapper The wrapper to clone. + * @returns {Object} Returns the cloned wrapper. + */ + function wrapperClone(wrapper) { + if (wrapper instanceof LazyWrapper) { + return wrapper.clone(); + } + var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); + result.__actions__ = copyArray(wrapper.__actions__); + result.__index__ = wrapper.__index__; + result.__values__ = wrapper.__values__; + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `array` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to process. + * @param {number} [size=1] The length of each chunk + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the new array of chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { + size = 1; + } else { + size = nativeMax(toInteger(size), 0); + } + var length = array == null ? 0 : array.length; + if (!length || size < 1) { + return []; + } + var index = 0, + resIndex = 0, + result = Array(nativeCeil(length / size)); + + while (index < length) { + result[resIndex++] = baseSlice(array, index, (index += size)); + } + return result; + } + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * Creates a new array concatenating `array` with any additional arrays + * and/or values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to concatenate. + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var other = _.concat(array, 2, [3], [[4]]); + * + * console.log(other); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + function concat() { + var length = arguments.length; + if (!length) { + return []; + } + var args = Array(length - 1), + array = arguments[0], + index = length; + + while (index--) { + args[index - 1] = arguments[index]; + } + return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); + } + + /** + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * **Note:** Unlike `_.pullAll`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.without, _.xor + * @example + * + * _.difference([2, 1], [2, 3]); + * // => [1] + */ + var difference = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `iteratee` which + * is invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * **Note:** Unlike `_.pullAllBy`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2] + * + * // The `_.property` iteratee shorthand. + * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var differenceBy = baseRest(function(array, values) { + var iteratee = last(values); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `comparator` + * which is invoked to compare elements of `array` to `values`. The order and + * references of result values are determined by the first array. The comparator + * is invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.pullAllWith`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * + * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); + * // => [{ 'x': 2, 'y': 1 }] + */ + var differenceWith = baseRest(function(array, values) { + var comparator = last(values); + if (isArrayLikeObject(comparator)) { + comparator = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) + : []; + }); + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function dropRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.dropRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney'] + * + * // The `_.matches` iteratee shorthand. + * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropRightWhile(users, ['active', false]); + * // => objects for ['barney'] + * + * // The `_.property` iteratee shorthand. + * _.dropRightWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true, true) + : []; + } + + /** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.dropWhile(users, function(o) { return !o.active; }); + * // => objects for ['pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.dropWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropWhile(users, ['active', false]); + * // => objects for ['pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.dropWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true) + : []; + } + + /** + * Fills elements of `array` with `value` from `start` up to, but not + * including, `end`. + * + * **Note:** This method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Array + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.fill(array, 'a'); + * console.log(array); + * // => ['a', 'a', 'a'] + * + * _.fill(Array(3), 2); + * // => [2, 2, 2] + * + * _.fill([4, 6, 8, 10], '*', 1, 3); + * // => [4, '*', '*', 10] + */ + function fill(array, value, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { + start = 0; + end = length; + } + return baseFill(array, value, start, end); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, function(o) { return o.user == 'barney'; }); + * // => 0 + * + * // The `_.matches` iteratee shorthand. + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findIndex(users, ['active', false]); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.findIndex(users, 'active'); + * // => 2 + */ + function findIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, getIteratee(predicate, 3), index); + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); + * // => 2 + * + * // The `_.matches` iteratee shorthand. + * _.findLastIndex(users, { 'user': 'barney', 'active': true }); + * // => 0 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastIndex(users, ['active', false]); + * // => 2 + * + * // The `_.property` iteratee shorthand. + * _.findLastIndex(users, 'active'); + * // => 0 + */ + function findLastIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, getIteratee(predicate, 3), index, true); + } + + /** + * Flattens `array` a single level deep. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, [3, [4]], 5]]); + * // => [1, 2, [3, [4]], 5] + */ + function flatten(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; + } + + /** + * Recursively flattens `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, [3, [4]], 5]]); + * // => [1, 2, 3, 4, 5] + */ + function flattenDeep(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; + } + + /** + * Recursively flatten `array` up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Array + * @param {Array} array The array to flatten. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * var array = [1, [2, [3, [4]], 5]]; + * + * _.flattenDepth(array, 1); + * // => [1, 2, [3, [4]], 5] + * + * _.flattenDepth(array, 2); + * // => [1, 2, 3, [4], 5] + */ + function flattenDepth(array, depth) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(array, depth); + } + + /** + * The inverse of `_.toPairs`; this method returns an object composed + * from key-value `pairs`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} pairs The key-value pairs. + * @returns {Object} Returns the new object. + * @example + * + * _.fromPairs([['a', 1], ['b', 2]]); + * // => { 'a': 1, 'b': 2 } + */ + function fromPairs(pairs) { + var index = -1, + length = pairs == null ? 0 : pairs.length, + result = {}; + + while (++index < length) { + var pair = pairs[index]; + result[pair[0]] = pair[1]; + } + return result; + } + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias first + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.head([1, 2, 3]); + * // => 1 + * + * _.head([]); + * // => undefined + */ + function head(array) { + return (array && array.length) ? array[0] : undefined; + } + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the + * offset from the end of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // Search from the `fromIndex`. + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + function indexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseIndexOf(array, value, index); + } + + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 0, -1) : []; + } + + /** + * Creates an array of unique values that are included in all given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersection([2, 1], [2, 3]); + * // => [2] + */ + var intersection = baseRest(function(arrays) { + var mapped = arrayMap(arrays, castArrayLikeObject); + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `iteratee` + * which is invoked for each element of each `arrays` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [2.1] + * + * // The `_.property` iteratee shorthand. + * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }] + */ + var intersectionBy = baseRest(function(arrays) { + var iteratee = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + if (iteratee === last(mapped)) { + iteratee = undefined; + } else { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `comparator` + * which is invoked to compare elements of `arrays`. The order and references + * of result values are determined by the first array. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.intersectionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }] + */ + var intersectionWith = baseRest(function(arrays) { + var comparator = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + comparator = typeof comparator == 'function' ? comparator : undefined; + if (comparator) { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, undefined, comparator) + : []; + }); + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + function join(array, separator) { + return array == null ? '' : nativeJoin.call(array, separator); + } + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array == null ? 0 : array.length; + return length ? array[length - 1] : undefined; + } + + /** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 1, 2], 2); + * // => 3 + * + * // Search from the `fromIndex`. + * _.lastIndexOf([1, 2, 1, 2], 2, 2); + * // => 1 + */ + function lastIndexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); + } + return value === value + ? strictLastIndexOf(array, value, index) + : baseFindIndex(array, baseIsNaN, index, true); + } + + /** + * Gets the element at index `n` of `array`. If `n` is negative, the nth + * element from the end is returned. + * + * @static + * @memberOf _ + * @since 4.11.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=0] The index of the element to return. + * @returns {*} Returns the nth element of `array`. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * + * _.nth(array, 1); + * // => 'b' + * + * _.nth(array, -2); + * // => 'c'; + */ + function nth(array, n) { + return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; + } + + /** + * Removes all given values from `array` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` + * to remove elements from an array by predicate. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pull(array, 'a', 'c'); + * console.log(array); + * // => ['b', 'b'] + */ + var pull = baseRest(pullAll); + + /** + * This method is like `_.pull` except that it accepts an array of values to remove. + * + * **Note:** Unlike `_.difference`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pullAll(array, ['a', 'c']); + * console.log(array); + * // => ['b', 'b'] + */ + function pullAll(array, values) { + return (array && array.length && values && values.length) + ? basePullAll(array, values) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `iteratee` which is + * invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The iteratee is invoked with one argument: (value). + * + * **Note:** Unlike `_.differenceBy`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; + * + * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); + * console.log(array); + * // => [{ 'x': 2 }] + */ + function pullAllBy(array, values, iteratee) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, getIteratee(iteratee, 2)) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `comparator` which + * is invoked to compare elements of `array` to `values`. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.differenceWith`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; + * + * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); + * console.log(array); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] + */ + function pullAllWith(array, values, comparator) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, undefined, comparator) + : array; + } + + /** + * Removes elements from `array` corresponding to `indexes` and returns an + * array of removed elements. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * var pulled = _.pullAt(array, [1, 3]); + * + * console.log(array); + * // => ['a', 'c'] + * + * console.log(pulled); + * // => ['b', 'd'] + */ + var pullAt = flatRest(function(array, indexes) { + var length = array == null ? 0 : array.length, + result = baseAt(array, indexes); + + basePullAt(array, arrayMap(indexes, function(index) { + return isIndex(index, length) ? +index : index; + }).sort(compareAscending)); + + return result; + }); + + /** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is invoked + * with three arguments: (value, index, array). + * + * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` + * to pull elements from an array by value. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { + * return n % 2 == 0; + * }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ + function remove(array, predicate) { + var result = []; + if (!(array && array.length)) { + return result; + } + var index = -1, + indexes = [], + length = array.length; + + predicate = getIteratee(predicate, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + indexes.push(index); + } + } + basePullAt(array, indexes); + return result; + } + + /** + * Reverses `array` so that the first element becomes the last, the second + * element becomes the second to last, and so on. + * + * **Note:** This method mutates `array` and is based on + * [`Array#reverse`](https://mdn.io/Array/reverse). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.reverse(array); + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function reverse(array) { + return array == null ? array : nativeReverse.call(array); + } + + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of + * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are + * returned. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + else { + start = start == null ? 0 : toInteger(start); + end = end === undefined ? length : toInteger(end); + } + return baseSlice(array, start, end); + } + + /** + * Uses a binary search to determine the lowest index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + */ + function sortedIndex(array, value) { + return baseSortedIndex(array, value); + } + + /** + * This method is like `_.sortedIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); + * // => 0 + */ + function sortedIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); + } + + /** + * This method is like `_.indexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedIndexOf([4, 5, 5, 5, 6], 5); + * // => 1 + */ + function sortedIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value); + if (index < length && eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 5, 5, 5, 6], 5); + * // => 4 + */ + function sortedLastIndex(array, value) { + return baseSortedIndex(array, value, true); + } + + /** + * This method is like `_.sortedLastIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 1 + * + * // The `_.property` iteratee shorthand. + * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); + * // => 1 + */ + function sortedLastIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); + } + + /** + * This method is like `_.lastIndexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); + * // => 3 + */ + function sortedLastIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value, true) - 1; + if (eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.uniq` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniq([1, 1, 2]); + * // => [1, 2] + */ + function sortedUniq(array) { + return (array && array.length) + ? baseSortedUniq(array) + : []; + } + + /** + * This method is like `_.uniqBy` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); + * // => [1.1, 2.3] + */ + function sortedUniqBy(array, iteratee) { + return (array && array.length) + ? baseSortedUniq(array, getIteratee(iteratee, 2)) + : []; + } + + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.tail([1, 2, 3]); + * // => [2, 3] + */ + function tail(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 1, length) : []; + } + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + if (!(array && array.length)) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.takeRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeRightWhile(users, ['active', false]); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.takeRightWhile(users, 'active'); + * // => [] + */ + function takeRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), false, true) + : []; + } + + /** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.takeWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matches` iteratee shorthand. + * _.takeWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeWhile(users, ['active', false]); + * // => objects for ['barney', 'fred'] + * + * // The `_.property` iteratee shorthand. + * _.takeWhile(users, 'active'); + * // => [] + */ + function takeWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3)) + : []; + } + + /** + * Creates an array of unique values, in order, from all given arrays using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([2], [1, 2]); + * // => [2, 1] + */ + var union = baseRest(function(arrays) { + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); + }); + + /** + * This method is like `_.union` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which uniqueness is computed. Result values are chosen from the first + * array in which the value occurs. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.unionBy([2.1], [1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + var unionBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.union` except that it accepts `comparator` which + * is invoked to compare elements of `arrays`. Result values are chosen from + * the first array in which the value occurs. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.unionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var unionWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); + }); + + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurrence of each element + * is kept. The order of result values is determined by the order they occur + * in the array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + */ + function uniq(array) { + return (array && array.length) ? baseUniq(array) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The order of result values is determined by the + * order they occur in the array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([2.1, 1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniqBy(array, iteratee) { + return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `comparator` which + * is invoked to compare elements of `array`. The order of result values is + * determined by the order they occur in the array.The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.uniqWith(objects, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] + */ + function uniqWith(array, comparator) { + comparator = typeof comparator == 'function' ? comparator : undefined; + return (array && array.length) ? baseUniq(array, undefined, comparator) : []; + } + + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-zip + * configuration. + * + * @static + * @memberOf _ + * @since 1.2.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + * + * _.unzip(zipped); + * // => [['a', 'b'], [1, 2], [true, false]] + */ + function unzip(array) { + if (!(array && array.length)) { + return []; + } + var length = 0; + array = arrayFilter(array, function(group) { + if (isArrayLikeObject(group)) { + length = nativeMax(group.length, length); + return true; + } + }); + return baseTimes(length, function(index) { + return arrayMap(array, baseProperty(index)); + }); + } + + /** + * This method is like `_.unzip` except that it accepts `iteratee` to specify + * how regrouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @param {Function} [iteratee=_.identity] The function to combine + * regrouped values. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip([1, 2], [10, 20], [100, 200]); + * // => [[1, 10, 100], [2, 20, 200]] + * + * _.unzipWith(zipped, _.add); + * // => [3, 30, 300] + */ + function unzipWith(array, iteratee) { + if (!(array && array.length)) { + return []; + } + var result = unzip(array); + if (iteratee == null) { + return result; + } + return arrayMap(result, function(group) { + return apply(iteratee, undefined, group); + }); + } + + /** + * Creates an array excluding all given values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.pull`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.xor + * @example + * + * _.without([2, 1, 2, 3], 1, 2); + * // => [3] + */ + var without = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, values) + : []; + }); + + /** + * Creates an array of unique values that is the + * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) + * of the given arrays. The order of result values is determined by the order + * they occur in the arrays. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.without + * @example + * + * _.xor([2, 1], [2, 3]); + * // => [1, 3] + */ + var xor = baseRest(function(arrays) { + return baseXor(arrayFilter(arrays, isArrayLikeObject)); + }); + + /** + * This method is like `_.xor` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which by which they're compared. The order of result values is determined + * by the order they occur in the arrays. The iteratee is invoked with one + * argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2, 3.4] + * + * // The `_.property` iteratee shorthand. + * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var xorBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.xor` except that it accepts `comparator` which is + * invoked to compare elements of `arrays`. The order of result values is + * determined by the order they occur in the arrays. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.xorWith(objects, others, _.isEqual); + * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var xorWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); + }); + + /** + * Creates an array of grouped elements, the first of which contains the + * first elements of the given arrays, the second of which contains the + * second elements of the given arrays, and so on. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + */ + var zip = baseRest(unzip); + + /** + * This method is like `_.fromPairs` except that it accepts two arrays, + * one of property identifiers and one of corresponding values. + * + * @static + * @memberOf _ + * @since 0.4.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['a', 'b'], [1, 2]); + * // => { 'a': 1, 'b': 2 } + */ + function zipObject(props, values) { + return baseZipObject(props || [], values || [], assignValue); + } + + /** + * This method is like `_.zipObject` except that it supports property paths. + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); + * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } + */ + function zipObjectDeep(props, values) { + return baseZipObject(props || [], values || [], baseSet); + } + + /** + * This method is like `_.zip` except that it accepts `iteratee` to specify + * how grouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @param {Function} [iteratee=_.identity] The function to combine + * grouped values. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { + * return a + b + c; + * }); + * // => [111, 222] + */ + var zipWith = baseRest(function(arrays) { + var length = arrays.length, + iteratee = length > 1 ? arrays[length - 1] : undefined; + + iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; + return unzipWith(arrays, iteratee); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` wrapper instance that wraps `value` with explicit method + * chain sequences enabled. The result of such sequences must be unwrapped + * with `_#value`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Seq + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _ + * .chain(users) + * .sortBy('age') + * .map(function(o) { + * return o.user + ' is ' + o.age; + * }) + * .head() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; + } + + /** + * This method invokes `interceptor` and returns `value`. The interceptor + * is invoked with one argument; (value). The purpose of this method is to + * "tap into" a method chain sequence in order to modify intermediate results. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { + * // Mutate input array. + * array.pop(); + * }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor) { + interceptor(value); + return value; + } + + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * The purpose of this method is to "pass thru" values replacing intermediate + * results in a method chain sequence. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _(' abc ') + * .chain() + * .trim() + * .thru(function(value) { + * return [value]; + * }) + * .value(); + * // => ['abc'] + */ + function thru(value, interceptor) { + return interceptor(value); + } + + /** + * This method is the wrapper version of `_.at`. + * + * @name at + * @memberOf _ + * @since 1.0.0 + * @category Seq + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _(object).at(['a[0].b.c', 'a[1]']).value(); + * // => [3, 4] + */ + var wrapperAt = flatRest(function(paths) { + var length = paths.length, + start = length ? paths[0] : 0, + value = this.__wrapped__, + interceptor = function(object) { return baseAt(object, paths); }; + + if (length > 1 || this.__actions__.length || + !(value instanceof LazyWrapper) || !isIndex(start)) { + return this.thru(interceptor); + } + value = value.slice(start, +start + (length ? 1 : 0)); + value.__actions__.push({ + 'func': thru, + 'args': [interceptor], + 'thisArg': undefined + }); + return new LodashWrapper(value, this.__chain__).thru(function(array) { + if (length && !array.length) { + array.push(undefined); + } + return array; + }); + }); + + /** + * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. + * + * @name chain + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // A sequence without explicit chaining. + * _(users).head(); + * // => { 'user': 'barney', 'age': 36 } + * + * // A sequence with explicit chaining. + * _(users) + * .chain() + * .head() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } + + /** + * Executes the chain sequence and returns the wrapped result. + * + * @name commit + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).push(3); + * + * console.log(array); + * // => [1, 2] + * + * wrapped = wrapped.commit(); + * console.log(array); + * // => [1, 2, 3] + * + * wrapped.last(); + * // => 3 + * + * console.log(array); + * // => [1, 2, 3] + */ + function wrapperCommit() { + return new LodashWrapper(this.value(), this.__chain__); + } + + /** + * Gets the next value on a wrapped object following the + * [iterator protocol](https://mdn.io/iteration_protocols#iterator). + * + * @name next + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the next iterator value. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped.next(); + * // => { 'done': false, 'value': 1 } + * + * wrapped.next(); + * // => { 'done': false, 'value': 2 } + * + * wrapped.next(); + * // => { 'done': true, 'value': undefined } + */ + function wrapperNext() { + if (this.__values__ === undefined) { + this.__values__ = toArray(this.value()); + } + var done = this.__index__ >= this.__values__.length, + value = done ? undefined : this.__values__[this.__index__++]; + + return { 'done': done, 'value': value }; + } + + /** + * Enables the wrapper to be iterable. + * + * @name Symbol.iterator + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the wrapper object. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped[Symbol.iterator]() === wrapped; + * // => true + * + * Array.from(wrapped); + * // => [1, 2] + */ + function wrapperToIterator() { + return this; + } + + /** + * Creates a clone of the chain sequence planting `value` as the wrapped value. + * + * @name plant + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @param {*} value The value to plant. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2]).map(square); + * var other = wrapped.plant([3, 4]); + * + * other.value(); + * // => [9, 16] + * + * wrapped.value(); + * // => [1, 4] + */ + function wrapperPlant(value) { + var result, + parent = this; + + while (parent instanceof baseLodash) { + var clone = wrapperClone(parent); + clone.__index__ = 0; + clone.__values__ = undefined; + if (result) { + previous.__wrapped__ = clone; + } else { + result = clone; + } + var previous = clone; + parent = parent.__wrapped__; + } + previous.__wrapped__ = value; + return result; + } + + /** + * This method is the wrapper version of `_.reverse`. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + var wrapped = value; + if (this.__actions__.length) { + wrapped = new LazyWrapper(this); + } + wrapped = wrapped.reverse(); + wrapped.__actions__.push({ + 'func': thru, + 'args': [reverse], + 'thisArg': undefined + }); + return new LodashWrapper(wrapped, this.__chain__); + } + return this.thru(reverse); + } + + /** + * Executes the chain sequence to resolve the unwrapped value. + * + * @name value + * @memberOf _ + * @since 0.1.0 + * @alias toJSON, valueOf + * @category Seq + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the number of times the key was returned by `iteratee`. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': 1, '6': 2 } + * + * // The `_.property` iteratee shorthand. + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + ++result[key]; + } else { + baseAssignValue(result, key, 1); + } + }); + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * **Note:** This method returns `true` for + * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because + * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of + * elements of empty collections. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.every(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, guard) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * **Note:** Unlike `_.remove`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.reject + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.filter(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.filter(users, { 'age': 36, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.filter(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.filter(users, 'active'); + * // => objects for ['barney'] + */ + function filter(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.find(users, function(o) { return o.age < 40; }); + * // => object for 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.find(users, { 'age': 1, 'active': true }); + * // => object for 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.find(users, ['active', false]); + * // => object for 'fred' + * + * // The `_.property` iteratee shorthand. + * _.find(users, 'active'); + * // => object for 'barney' + */ + var find = createFind(findIndex); + + /** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=collection.length-1] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { + * return n % 2 == 1; + * }); + * // => 3 + */ + var findLast = createFind(findLastIndex); + + /** + * Creates a flattened array of values by running each element in `collection` + * thru `iteratee` and flattening the mapped results. The iteratee is invoked + * with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [n, n]; + * } + * + * _.flatMap([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMap(collection, iteratee) { + return baseFlatten(map(collection, iteratee), 1); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDeep([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMapDeep(collection, iteratee) { + return baseFlatten(map(collection, iteratee), INFINITY); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDepth([1, 2], duplicate, 2); + * // => [[1, 1], [2, 2]] + */ + function flatMapDepth(collection, iteratee, depth) { + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(map(collection, iteratee), depth); + } + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" + * property are iterated like arrays. To avoid this behavior use `_.forIn` + * or `_.forOwn` for object iteration. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias each + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEachRight + * @example + * + * _.forEach([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `1` then `2`. + * + * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forEach(collection, iteratee) { + var func = isArray(collection) ? arrayEach : baseEach; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @alias eachRight + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEach + * @example + * + * _.forEachRight([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `2` then `1`. + */ + function forEachRight(collection, iteratee) { + var func = isArray(collection) ? arrayEachRight : baseEachRight; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The order of grouped values + * is determined by the order they occur in `collection`. The corresponding + * value of each key is an array of elements responsible for generating the + * key. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': [4.2], '6': [6.1, 6.3] } + * + * // The `_.property` iteratee shorthand. + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + baseAssignValue(result, key, [value]); + } + }); + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * is used for equality comparisons. If `fromIndex` is negative, it's used as + * the offset from the end of `collection`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + function includes(collection, value, fromIndex, guard) { + collection = isArrayLike(collection) ? collection : values(collection); + fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; + + var length = collection.length; + if (fromIndex < 0) { + fromIndex = nativeMax(length + fromIndex, 0); + } + return isString(collection) + ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) + : (!!length && baseIndexOf(collection, value, fromIndex) > -1); + } + + /** + * Invokes the method at `path` of each element in `collection`, returning + * an array of the results of each invoked method. Any additional arguments + * are provided to each invoked method. If `path` is a function, it's invoked + * for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke each method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invokeMap([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + var invokeMap = baseRest(function(collection, path, args) { + var index = -1, + isFunc = typeof path == 'function', + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value) { + result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); + }); + return result; + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the last element responsible for generating the key. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var array = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.keyBy(array, function(o) { + * return String.fromCharCode(o.code); + * }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.keyBy(array, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + */ + var keyBy = createAggregator(function(result, value, key) { + baseAssignValue(result, key, value); + }); + + /** + * Creates an array of values by running each element in `collection` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, + * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, + * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, + * `template`, `trim`, `trimEnd`, `trimStart`, and `words` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n; + * } + * + * _.map([4, 8], square); + * // => [16, 64] + * + * _.map({ 'a': 4, 'b': 8 }, square); + * // => [16, 64] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // The `_.property` iteratee shorthand. + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee) { + var func = isArray(collection) ? arrayMap : baseMap; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.sortBy` except that it allows specifying the sort + * orders of the iteratees to sort by. If `orders` is unspecified, all values + * are sorted in ascending order. Otherwise, specify an order of "desc" for + * descending or "asc" for ascending sort order of corresponding values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] + * The iteratees to sort by. + * @param {string[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // Sort by `user` in ascending order and by `age` in descending order. + * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + */ + function orderBy(collection, iteratees, orders, guard) { + if (collection == null) { + return []; + } + if (!isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + orders = guard ? undefined : orders; + if (!isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseOrderBy(collection, iteratees, orders); + } + + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, the second of which + * contains elements `predicate` returns falsey for. The predicate is + * invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.partition(users, function(o) { return o.active; }); + * // => objects for [['fred'], ['barney', 'pebbles']] + * + * // The `_.matches` iteratee shorthand. + * _.partition(users, { 'age': 1, 'active': false }); + * // => objects for [['pebbles'], ['barney', 'fred']] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.partition(users, ['active', false]); + * // => objects for [['barney', 'pebbles'], ['fred']] + * + * // The `_.property` iteratee shorthand. + * _.partition(users, 'active'); + * // => objects for [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `collection` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, + * and `sortBy` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduceRight + * @example + * + * _.reduce([1, 2], function(sum, n) { + * return sum + n; + * }, 0); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * return result; + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) + */ + function reduce(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduce : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); + } + + /** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduce + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * + * _.reduceRight(array, function(flattened, other) { + * return flattened.concat(other); + * }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduceRight : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); + } + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.filter + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * _.reject(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.reject(users, { 'age': 40, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.reject(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.reject(users, 'active'); + * // => objects for ['barney'] + */ + function reject(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, negate(getIteratee(predicate, 3))); + } + + /** + * Gets a random element from `collection`. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + */ + function sample(collection) { + var func = isArray(collection) ? arraySample : baseSample; + return func(collection); + } + + /** + * Gets `n` random elements at unique keys from `collection` up to the + * size of `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @param {number} [n=1] The number of elements to sample. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the random elements. + * @example + * + * _.sampleSize([1, 2, 3], 2); + * // => [3, 1] + * + * _.sampleSize([1, 2, 3], 4); + * // => [2, 3, 1] + */ + function sampleSize(collection, n, guard) { + if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + var func = isArray(collection) ? arraySampleSize : baseSampleSize; + return func(collection, n); + } + + /** + * Creates an array of shuffled values, using a version of the + * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ + function shuffle(collection) { + var func = isArray(collection) ? arrayShuffle : baseShuffle; + return func(collection); + } + + /** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable string keyed properties for objects. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * _.size([1, 2, 3]); + * // => 3 + * + * _.size({ 'a': 1, 'b': 2 }); + * // => 2 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + if (collection == null) { + return 0; + } + if (isArrayLike(collection)) { + return isString(collection) ? stringSize(collection) : collection.length; + } + var tag = getTag(collection); + if (tag == mapTag || tag == setTag) { + return collection.size; + } + return baseKeys(collection).length; + } + + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * Iteration is stopped once `predicate` returns truthy. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.some(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.some(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.some(users, 'active'); + * // => true + */ + function some(collection, predicate, guard) { + var func = isArray(collection) ? arraySome : baseSome; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection thru each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratees are invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {...(Function|Function[])} [iteratees=[_.identity]] + * The iteratees to sort by. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.sortBy(users, [function(o) { return o.user; }]); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * + * _.sortBy(users, ['user', 'age']); + * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] + */ + var sortBy = baseRest(function(collection, iteratees) { + if (collection == null) { + return []; + } + var length = iteratees.length; + if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { + iteratees = []; + } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { + iteratees = [iteratees[0]]; + } + return baseOrderBy(collection, baseFlatten(iteratees, 1), []); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now = ctxNow || function() { + return root.Date.now(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it's called `n` or more times. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => Logs 'done saving!' after the two async saves have completed. + */ + function after(n, func) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that invokes `func`, with up to `n` arguments, + * ignoring any additional arguments. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ + function ary(func, n, guard) { + n = guard ? undefined : n; + n = (func && n == null) ? func.length : n; + return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); + } + + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it's called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery(element).on('click', _.before(5, addContactToList)); + * // => Allows adding up to 4 contacts to the list. + */ + function before(n, func) { + var result; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; + } + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and `partials` prepended to the arguments it receives. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * function greet(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // Bound with placeholders. + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = baseRest(function(func, thisArg, partials) { + var bitmask = WRAP_BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bind)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(func, bitmask, thisArg, partials, holders); + }); + + /** + * Creates a function that invokes the method at `object[key]` with `partials` + * prepended to the arguments it receives. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. See + * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Function + * @param {Object} object The object to invoke the method on. + * @param {string} key The key of the method. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // Bound with placeholders. + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ + var bindKey = baseRest(function(object, key, partials) { + var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bindKey)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(key, bitmask, object, partials, holders); + }); + + /** + * Creates a function that accepts arguments of `func` and either invokes + * `func` returning its result, if at least `arity` number of arguments have + * been provided, or returns a function that accepts the remaining `func` + * arguments, and so on. The arity of `func` may be specified if `func.length` + * is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ + function curry(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curry.placeholder; + return result; + } + + /** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ + function curryRight(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryRight.placeholder; + return result; + } + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; + + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } + + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } + + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(now()); + } + + function debounced() { + var time = now(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // => Logs 'deferred' after one millisecond. + */ + var defer = baseRest(function(func, args) { + return baseDelay(func, 1, args); + }); + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { + * console.log(text); + * }, 1000, 'later'); + * // => Logs 'later' after one second. + */ + var delay = baseRest(function(func, wait, args) { + return baseDelay(func, toNumber(wait) || 0, args); + }); + + /** + * Creates a function that invokes `func` with arguments reversed. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to flip arguments for. + * @returns {Function} Returns the new flipped function. + * @example + * + * var flipped = _.flip(function() { + * return _.toArray(arguments); + * }); + * + * flipped('a', 'b', 'c', 'd'); + * // => ['d', 'c', 'b', 'a'] + */ + function flip(func) { + return createWrap(func, WRAP_FLIP_FLAG); + } + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; + } + + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; + } + + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // => `createApplication` is invoked once + */ + function once(func) { + return before(2, func); + } + + /** + * Creates a function that invokes `func` with its arguments transformed. + * + * @static + * @since 4.0.0 + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms=[_.identity]] + * The argument transforms. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var func = _.overArgs(function(x, y) { + * return [x, y]; + * }, [square, doubled]); + * + * func(9, 3); + * // => [81, 6] + * + * func(10, 5); + * // => [100, 10] + */ + var overArgs = castRest(function(func, transforms) { + transforms = (transforms.length == 1 && isArray(transforms[0])) + ? arrayMap(transforms[0], baseUnary(getIteratee())) + : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); + + var funcsLength = transforms.length; + return baseRest(function(args) { + var index = -1, + length = nativeMin(args.length, funcsLength); + + while (++index < length) { + args[index] = transforms[index].call(this, args[index]); + } + return apply(func, this, args); + }); + }); + + /** + * Creates a function that invokes `func` with `partials` prepended to the + * arguments it receives. This method is like `_.bind` except it does **not** + * alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 0.2.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // Partially applied with placeholders. + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + var partial = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partial)); + return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); + }); + + /** + * This method is like `_.partial` except that partially applied arguments + * are appended to the arguments it receives. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // Partially applied with placeholders. + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ + var partialRight = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partialRight)); + return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); + }); + + /** + * Creates a function that invokes `func` with arguments arranged according + * to the specified `indexes` where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, [2, 0, 1]); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + */ + var rearg = flatRest(function(func, indexes) { + return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); + }); + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as + * an array. + * + * **Note:** This method is based on the + * [rest parameter](https://mdn.io/rest_parameters). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.rest(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function rest(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start === undefined ? start : toInteger(start); + return baseRest(func, start); + } + + /** + * Creates a function that invokes `func` with the `this` binding of the + * create function and an array of arguments much like + * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). + * + * **Note:** This method is based on the + * [spread operator](https://mdn.io/spread_operator). + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Function + * @param {Function} func The function to spread arguments over. + * @param {number} [start=0] The start position of the spread. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.spread(function(who, what) { + * return who + ' says ' + what; + * }); + * + * say(['fred', 'hello']); + * // => 'fred says hello' + * + * var numbers = Promise.all([ + * Promise.resolve(40), + * Promise.resolve(36) + * ]); + * + * numbers.then(_.spread(function(x, y) { + * return x + y; + * })); + * // => a Promise of 76 + */ + function spread(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start == null ? 0 : nativeMax(toInteger(start), 0); + return baseRest(function(args) { + var array = args[start], + otherArgs = castSlice(args, 0, start); + + if (array) { + arrayPush(otherArgs, array); + } + return apply(func, this, otherArgs); + }); + } + + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); + } + + /** + * Creates a function that accepts up to one argument, ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.unary(parseInt)); + * // => [6, 8, 10] + */ + function unary(func) { + return ary(func, 1); + } + + /** + * Creates a function that provides `value` to `wrapper` as its first + * argument. Any additional arguments provided to the function are appended + * to those provided to the `wrapper`. The wrapper is invoked with the `this` + * binding of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {*} value The value to wrap. + * @param {Function} [wrapper=identity] The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

fred, barney, & pebbles

' + */ + function wrap(value, wrapper) { + return partial(castFunction(wrapper), value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Casts `value` as an array if it's not one. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Lang + * @param {*} value The value to inspect. + * @returns {Array} Returns the cast array. + * @example + * + * _.castArray(1); + * // => [1] + * + * _.castArray({ 'a': 1 }); + * // => [{ 'a': 1 }] + * + * _.castArray('abc'); + * // => ['abc'] + * + * _.castArray(null); + * // => [null] + * + * _.castArray(undefined); + * // => [undefined] + * + * _.castArray(); + * // => [] + * + * var array = [1, 2, 3]; + * console.log(_.castArray(array) === array); + * // => true + */ + function castArray() { + if (!arguments.length) { + return []; + } + var value = arguments[0]; + return isArray(value) ? value : [value]; + } + + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @see _.cloneDeep + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + function clone(value) { + return baseClone(value, CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.clone` except that it accepts `customizer` which + * is invoked to produce the cloned value. If `customizer` returns `undefined`, + * cloning is handled by the method instead. The `customizer` is invoked with + * up to four arguments; (value [, index|key, object, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the cloned value. + * @see _.cloneDeepWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(false); + * } + * } + * + * var el = _.cloneWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 0 + */ + function cloneWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @see _.clone + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ + function cloneDeep(value) { + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.cloneWith` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the deep cloned value. + * @see _.cloneWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(true); + * } + * } + * + * var el = _.cloneDeepWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 20 + */ + function cloneDeepWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * Checks if `object` conforms to `source` by invoking the predicate + * properties of `source` with the corresponding property values of `object`. + * + * **Note:** This method is equivalent to `_.conforms` when `source` is + * partially applied. + * + * @static + * @memberOf _ + * @since 4.14.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); + * // => true + * + * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); + * // => false + */ + function conformsTo(object, source) { + return source == null || baseConformsTo(object, source, keys(source)); + } + + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } + + /** + * Checks if `value` is greater than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + * @see _.lt + * @example + * + * _.gt(3, 1); + * // => true + * + * _.gt(3, 3); + * // => false + * + * _.gt(1, 3); + * // => false + */ + var gt = createRelationalOperation(baseGt); + + /** + * Checks if `value` is greater than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than or equal to + * `other`, else `false`. + * @see _.lte + * @example + * + * _.gte(3, 1); + * // => true + * + * _.gte(3, 3); + * // => true + * + * _.gte(1, 3); + * // => false + */ + var gte = createRelationalOperation(function(value, other) { + return value >= other; + }); + + /** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; + + /** + * Checks if `value` is classified as an `ArrayBuffer` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + * @example + * + * _.isArrayBuffer(new ArrayBuffer(2)); + * // => true + * + * _.isArrayBuffer(new Array(2)); + * // => false + */ + var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); + } + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || + (isObjectLike(value) && baseGetTag(value) == boolTag); + } + + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = nativeIsBuffer || stubFalse; + + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; + + /** + * Checks if `value` is likely a DOM element. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); + } + + /** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if (isArrayLike(value) && + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { + return !value.length; + } + var tag = getTag(value); + if (tag == mapTag || tag == setTag) { + return !value.size; + } + if (isPrototype(value)) { + return !baseKeys(value).length; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * This method is like `_.isEqual` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with up to + * six arguments: (objValue, othValue [, index|key, object, other, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, othValue) { + * if (isGreeting(objValue) && isGreeting(othValue)) { + * return true; + * } + * } + * + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqualWith(array, other, customizer); + * // => true + */ + function isEqualWith(value, other, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + var result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; + } + + /** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ + function isError(value) { + if (!isObjectLike(value)) { + return false; + } + var tag = baseGetTag(value); + return tag == errorTag || tag == domExcTag || + (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); + } + + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on + * [`Number.isFinite`](https://mdn.io/Number/isFinite). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(3); + * // => true + * + * _.isFinite(Number.MIN_VALUE); + * // => true + * + * _.isFinite(Infinity); + * // => false + * + * _.isFinite('3'); + * // => false + */ + function isFinite(value) { + return typeof value == 'number' && nativeIsFinite(value); + } + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } + + /** + * Checks if `value` is an integer. + * + * **Note:** This method is based on + * [`Number.isInteger`](https://mdn.io/Number/isInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an integer, else `false`. + * @example + * + * _.isInteger(3); + * // => true + * + * _.isInteger(Number.MIN_VALUE); + * // => false + * + * _.isInteger(Infinity); + * // => false + * + * _.isInteger('3'); + * // => false + */ + function isInteger(value) { + return typeof value == 'number' && value == toInteger(value); + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** + * Checks if `value` is classified as a `Map` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + * @example + * + * _.isMap(new Map); + * // => true + * + * _.isMap(new WeakMap); + * // => false + */ + var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; + + /** + * Performs a partial deep comparison between `object` and `source` to + * determine if `object` contains equivalent property values. + * + * **Note:** This method is equivalent to `_.matches` when `source` is + * partially applied. + * + * Partial comparisons will match empty array and empty object `source` + * values against any array or object value, respectively. See `_.isEqual` + * for a list of supported value comparisons. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.isMatch(object, { 'b': 2 }); + * // => true + * + * _.isMatch(object, { 'b': 1 }); + * // => false + */ + function isMatch(object, source) { + return object === source || baseIsMatch(object, source, getMatchData(source)); + } + + /** + * This method is like `_.isMatch` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with five + * arguments: (objValue, srcValue, index|key, object, source). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, srcValue) { + * if (isGreeting(objValue) && isGreeting(srcValue)) { + * return true; + * } + * } + * + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatchWith(object, source, customizer); + * // => true + */ + function isMatchWith(object, source, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseIsMatch(object, source, getMatchData(source), customizer); + } + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is a pristine native function. + * + * **Note:** This method can't reliably detect native functions in the presence + * of the core-js package because core-js circumvents this kind of detection. + * Despite multiple requests, the core-js maintainer has made it clear: any + * attempt to fix the detection will be obstructed. As a result, we're left + * with little choice but to throw an error. Unfortunately, this also affects + * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), + * which rely on core-js. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (isMaskable(value)) { + throw new Error(CORE_ERROR_TEXT); + } + return baseIsNative(value); + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is `null` or `undefined`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is nullish, else `false`. + * @example + * + * _.isNil(null); + * // => true + * + * _.isNil(void 0); + * // => true + * + * _.isNil(NaN); + * // => false + */ + function isNil(value) { + return value == null; + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; + } + + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + + /** + * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 + * double precision number which isn't the result of a rounded unsafe integer. + * + * **Note:** This method is based on + * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. + * @example + * + * _.isSafeInteger(3); + * // => true + * + * _.isSafeInteger(Number.MIN_VALUE); + * // => false + * + * _.isSafeInteger(Infinity); + * // => false + * + * _.isSafeInteger('3'); + * // => false + */ + function isSafeInteger(value) { + return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is classified as a `Set` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + * @example + * + * _.isSet(new Set); + * // => true + * + * _.isSet(new WeakSet); + * // => false + */ + var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); + } + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + + /** + * Checks if `value` is `undefined`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return value === undefined; + } + + /** + * Checks if `value` is classified as a `WeakMap` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. + * @example + * + * _.isWeakMap(new WeakMap); + * // => true + * + * _.isWeakMap(new Map); + * // => false + */ + function isWeakMap(value) { + return isObjectLike(value) && getTag(value) == weakMapTag; + } + + /** + * Checks if `value` is classified as a `WeakSet` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. + * @example + * + * _.isWeakSet(new WeakSet); + * // => true + * + * _.isWeakSet(new Set); + * // => false + */ + function isWeakSet(value) { + return isObjectLike(value) && baseGetTag(value) == weakSetTag; + } + + /** + * Checks if `value` is less than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + * @see _.gt + * @example + * + * _.lt(1, 3); + * // => true + * + * _.lt(3, 3); + * // => false + * + * _.lt(3, 1); + * // => false + */ + var lt = createRelationalOperation(baseLt); + + /** + * Checks if `value` is less than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than or equal to + * `other`, else `false`. + * @see _.gte + * @example + * + * _.lte(1, 3); + * // => true + * + * _.lte(3, 3); + * // => true + * + * _.lte(3, 1); + * // => false + */ + var lte = createRelationalOperation(function(value, other) { + return value <= other; + }); + + /** + * Converts `value` to an array. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * _.toArray({ 'a': 1, 'b': 2 }); + * // => [1, 2] + * + * _.toArray('abc'); + * // => ['a', 'b', 'c'] + * + * _.toArray(1); + * // => [] + * + * _.toArray(null); + * // => [] + */ + function toArray(value) { + if (!value) { + return []; + } + if (isArrayLike(value)) { + return isString(value) ? stringToArray(value) : copyArray(value); + } + if (symIterator && value[symIterator]) { + return iteratorToArray(value[symIterator]()); + } + var tag = getTag(value), + func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); + + return func(value); + } + + /** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ + function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } + + /** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ + function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; + } + + /** + * Converts `value` to an integer suitable for use as the length of an + * array-like object. + * + * **Note:** This method is based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toLength(3.2); + * // => 3 + * + * _.toLength(Number.MIN_VALUE); + * // => 0 + * + * _.toLength(Infinity); + * // => 4294967295 + * + * _.toLength('3.2'); + * // => 3 + */ + function toLength(value) { + return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; + } + + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return copyObject(value, keysIn(value)); + } + + /** + * Converts `value` to a safe integer. A safe integer can be compared and + * represented correctly. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toSafeInteger(3.2); + * // => 3 + * + * _.toSafeInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toSafeInteger(Infinity); + * // => 9007199254740991 + * + * _.toSafeInteger('3.2'); + * // => 3 + */ + function toSafeInteger(value) { + return value + ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) + : (value === 0 ? value : 0); + } + + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString(value) { + return value == null ? '' : baseToString(value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable string keyed properties of source objects to the + * destination object. Source objects are applied from left to right. + * Subsequent sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is loosely based on + * [`Object.assign`](https://mdn.io/Object/assign). + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assignIn + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assign({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'c': 3 } + */ + var assign = createAssigner(function(object, source) { + if (isPrototype(source) || isArrayLike(source)) { + copyObject(source, keys(source), object); + return; + } + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + assignValue(object, key, source[key]); + } + } + }); + + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assign + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assignIn({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } + */ + var assignIn = createAssigner(function(object, source) { + copyObject(source, keysIn(source), object); + }); + + /** + * This method is like `_.assignIn` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extendWith + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignInWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keysIn(source), object, customizer); + }); + + /** + * This method is like `_.assign` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignInWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keys(source), object, customizer); + }); + + /** + * Creates an array of values corresponding to `paths` of `object`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Array} Returns the picked values. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _.at(object, ['a[0].b.c', 'a[1]']); + * // => [3, 4] + */ + var at = flatRest(baseAt); + + /** + * Creates an object that inherits from the `prototype` object. If a + * `properties` object is given, its own enumerable string keyed properties + * are assigned to the created object. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties == null ? result : baseAssign(result, properties); + } + + /** + * Assigns own and inherited enumerable string keyed properties of source + * objects to the destination object for all destination properties that + * resolve to `undefined`. Source objects are applied from left to right. + * Once a property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaultsDeep + * @example + * + * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var defaults = baseRest(function(object, sources) { + object = Object(object); + + var index = -1; + var length = sources.length; + var guard = length > 2 ? sources[2] : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + length = 1; + } + + while (++index < length) { + var source = sources[index]; + var props = keysIn(source); + var propsIndex = -1; + var propsLength = props.length; + + while (++propsIndex < propsLength) { + var key = props[propsIndex]; + var value = object[key]; + + if (value === undefined || + (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { + object[key] = source[key]; + } + } + } + + return object; + }); + + /** + * This method is like `_.defaults` except that it recursively assigns + * default properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaults + * @example + * + * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); + * // => { 'a': { 'b': 2, 'c': 3 } } + */ + var defaultsDeep = baseRest(function(args) { + args.push(undefined, customDefaultsMerge); + return apply(mergeWith, undefined, args); + }); + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); + } + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(o) { return o.age < 40; }); + * // => returns 'pebbles' assuming `_.findKey` returns 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.findLastKey(users, { 'age': 36, 'active': true }); + * // => 'barney' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + function findLastKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); + } + + /** + * Iterates over own and inherited enumerable string keyed properties of an + * object and invokes `iteratee` for each property. The iteratee is invoked + * with three arguments: (value, key, object). Iteratee functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forInRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). + */ + function forIn(object, iteratee) { + return object == null + ? object + : baseFor(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forIn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. + */ + function forInRight(object, iteratee) { + return object == null + ? object + : baseForRight(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * Iterates over own enumerable string keyed properties of an object and + * invokes `iteratee` for each property. The iteratee is invoked with three + * arguments: (value, key, object). Iteratee functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwnRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forOwn(object, iteratee) { + return object && baseForOwn(object, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwnRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. + */ + function forOwnRight(object, iteratee) { + return object && baseForOwnRight(object, getIteratee(iteratee, 3)); + } + + /** + * Creates an array of function property names from own enumerable properties + * of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functionsIn + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functions(new Foo); + * // => ['a', 'b'] + */ + function functions(object) { + return object == null ? [] : baseFunctions(object, keys(object)); + } + + /** + * Creates an array of function property names from own and inherited + * enumerable properties of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functions + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functionsIn(new Foo); + * // => ['a', 'b', 'c'] + */ + function functionsIn(object) { + return object == null ? [] : baseFunctions(object, keysIn(object)); + } + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; + } + + /** + * Checks if `path` is a direct property of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = { 'a': { 'b': 2 } }; + * var other = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b'); + * // => true + * + * _.has(object, ['a', 'b']); + * // => true + * + * _.has(other, 'a'); + * // => false + */ + function has(object, path) { + return object != null && hasPath(object, path, baseHas); + } + + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); + } + + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite + * property assignments of previous values. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Object + * @param {Object} object The object to invert. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invert(object); + * // => { '1': 'c', '2': 'b' } + */ + var invert = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + result[value] = key; + }, constant(identity)); + + /** + * This method is like `_.invert` except that the inverted object is generated + * from the results of running each element of `object` thru `iteratee`. The + * corresponding inverted value of each inverted key is an array of keys + * responsible for generating the inverted value. The iteratee is invoked + * with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Object + * @param {Object} object The object to invert. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invertBy(object); + * // => { '1': ['a', 'c'], '2': ['b'] } + * + * _.invertBy(object, function(value) { + * return 'group' + value; + * }); + * // => { 'group1': ['a', 'c'], 'group2': ['b'] } + */ + var invertBy = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + }, getIteratee); + + /** + * Invokes the method at `path` of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + * @example + * + * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; + * + * _.invoke(object, 'a[0].b.c.slice', 1, 3); + * // => [2, 3] + */ + var invoke = baseRest(baseInvoke); + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); + } + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + } + + /** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ + function mapKeys(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; + } + + /** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ + function mapValues(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; + } + + /** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ + var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); + }); + + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined`, merging is handled by the + * method instead. The `customizer` is invoked with six arguments: + * (objValue, srcValue, key, object, source, stack). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * if (_.isArray(objValue)) { + * return objValue.concat(srcValue); + * } + * } + * + * var object = { 'a': [1], 'b': [2] }; + * var other = { 'a': [3], 'b': [4] }; + * + * _.mergeWith(object, other, customizer); + * // => { 'a': [1, 3], 'b': [2, 4] } + */ + var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { + baseMerge(object, source, srcIndex, customizer); + }); + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable property paths of `object` that are not omitted. + * + * **Note:** This method is considerably slower than `_.pick`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to omit. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omit(object, ['a', 'c']); + * // => { 'b': '2' } + */ + var omit = flatRest(function(object, paths) { + var result = {}; + if (object == null) { + return result; + } + var isDeep = false; + paths = arrayMap(paths, function(path) { + path = castPath(path, object); + isDeep || (isDeep = path.length > 1); + return path; + }); + copyObject(object, getAllKeysIn(object), result); + if (isDeep) { + result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); + } + var length = paths.length; + while (length--) { + baseUnset(result, paths[length]); + } + return result; + }); + + /** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + function omitBy(object, predicate) { + return pickBy(object, negate(getIteratee(predicate))); + } + + /** + * Creates an object composed of the picked `object` properties. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } + */ + var pick = flatRest(function(object, paths) { + return object == null ? {} : basePick(object, paths); + }); + + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = getIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); + } + + /** + * This method is like `_.get` except that if the resolved value is a + * function it's invoked with the `this` binding of its parent object and + * its result is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to resolve. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; + * + * _.result(object, 'a[0].b.c1'); + * // => 3 + * + * _.result(object, 'a[0].b.c2'); + * // => 4 + * + * _.result(object, 'a[0].b.c3', 'default'); + * // => 'default' + * + * _.result(object, 'a[0].b.c3', _.constant('default')); + * // => 'default' + */ + function result(object, path, defaultValue) { + path = castPath(path, object); + + var index = -1, + length = path.length; + + // Ensure the loop is entered when path is empty. + if (!length) { + length = 1; + object = undefined; + } + while (++index < length) { + var value = object == null ? undefined : object[toKey(path[index])]; + if (value === undefined) { + index = length; + value = defaultValue; + } + object = isFunction(value) ? value.call(object) : value; + } + return object; + } + + /** + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.set(object, 'a[0].b.c', 4); + * console.log(object.a[0].b.c); + * // => 4 + * + * _.set(object, ['x', '0', 'y', 'z'], 5); + * console.log(object.x[0].y.z); + * // => 5 + */ + function set(object, path, value) { + return object == null ? object : baseSet(object, path, value); + } + + /** + * This method is like `_.set` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.setWith(object, '[0][1]', 'a', Object); + * // => { '0': { '1': 'a' } } + */ + function setWith(object, path, value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseSet(object, path, value, customizer); + } + + /** + * Creates an array of own enumerable string keyed-value pairs for `object` + * which can be consumed by `_.fromPairs`. If `object` is a map or set, its + * entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entries + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairs(new Foo); + * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) + */ + var toPairs = createToPairs(keys); + + /** + * Creates an array of own and inherited enumerable string keyed-value pairs + * for `object` which can be consumed by `_.fromPairs`. If `object` is a map + * or set, its entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entriesIn + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairsIn(new Foo); + * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) + */ + var toPairsIn = createToPairs(keysIn); + + /** + * An alternative to `_.reduce`; this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own + * enumerable string keyed properties thru `iteratee`, with each invocation + * potentially mutating the `accumulator` object. If `accumulator` is not + * provided, a new object with the same `[[Prototype]]` will be used. The + * iteratee is invoked with four arguments: (accumulator, value, key, object). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @returns {*} Returns the accumulated value. + * @example + * + * _.transform([2, 3, 4], function(result, n) { + * result.push(n *= n); + * return n % 2 == 0; + * }, []); + * // => [4, 9] + * + * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } + */ + function transform(object, iteratee, accumulator) { + var isArr = isArray(object), + isArrLike = isArr || isBuffer(object) || isTypedArray(object); + + iteratee = getIteratee(iteratee, 4); + if (accumulator == null) { + var Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor : []; + } + else if (isObject(object)) { + accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + } + else { + accumulator = {}; + } + } + (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { + return iteratee(accumulator, value, index, object); + }); + return accumulator; + } + + /** + * Removes the property at `path` of `object`. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 7 } }] }; + * _.unset(object, 'a[0].b.c'); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + * + * _.unset(object, ['a', '0', 'b', 'c']); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + */ + function unset(object, path) { + return object == null ? true : baseUnset(object, path); + } + + /** + * This method is like `_.set` except that accepts `updater` to produce the + * value to set. Use `_.updateWith` to customize `path` creation. The `updater` + * is invoked with one argument: (value). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.update(object, 'a[0].b.c', function(n) { return n * n; }); + * console.log(object.a[0].b.c); + * // => 9 + * + * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); + * console.log(object.x[0].y.z); + * // => 0 + */ + function update(object, path, updater) { + return object == null ? object : baseUpdate(object, path, castFunction(updater)); + } + + /** + * This method is like `_.update` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.updateWith(object, '[0][1]', _.constant('a'), Object); + * // => { '0': { '1': 'a' } } + */ + function updateWith(object, path, updater, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); + } + + /** + * Creates an array of the own enumerable string keyed property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return object == null ? [] : baseValues(object, keys(object)); + } + + /** + * Creates an array of the own and inherited enumerable string keyed property + * values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.valuesIn(new Foo); + * // => [1, 2, 3] (iteration order is not guaranteed) + */ + function valuesIn(object) { + return object == null ? [] : baseValues(object, keysIn(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Clamps `number` within the inclusive `lower` and `upper` bounds. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Number + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + * @example + * + * _.clamp(-10, -5, 5); + * // => -5 + * + * _.clamp(10, -5, 5); + * // => 5 + */ + function clamp(number, lower, upper) { + if (upper === undefined) { + upper = lower; + lower = undefined; + } + if (upper !== undefined) { + upper = toNumber(upper); + upper = upper === upper ? upper : 0; + } + if (lower !== undefined) { + lower = toNumber(lower); + lower = lower === lower ? lower : 0; + } + return baseClamp(toNumber(number), lower, upper); + } + + /** + * Checks if `n` is between `start` and up to, but not including, `end`. If + * `end` is not specified, it's set to `start` with `start` then set to `0`. + * If `start` is greater than `end` the params are swapped to support + * negative ranges. + * + * @static + * @memberOf _ + * @since 3.3.0 + * @category Number + * @param {number} number The number to check. + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + * @see _.range, _.rangeRight + * @example + * + * _.inRange(3, 2, 4); + * // => true + * + * _.inRange(4, 8); + * // => true + * + * _.inRange(4, 2); + * // => false + * + * _.inRange(2, 2); + * // => false + * + * _.inRange(1.2, 2); + * // => true + * + * _.inRange(5.2, 4); + * // => false + * + * _.inRange(-3, -2, -6); + * // => true + */ + function inRange(number, start, end) { + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + number = toNumber(number); + return baseInRange(number, start, end); + } + + /** + * Produces a random number between the inclusive `lower` and `upper` bounds. + * If only one argument is provided a number between `0` and the given number + * is returned. If `floating` is `true`, or either `lower` or `upper` are + * floats, a floating-point number is returned instead of an integer. + * + * **Note:** JavaScript follows the IEEE-754 standard for resolving + * floating-point values which can produce unexpected results. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Number + * @param {number} [lower=0] The lower bound. + * @param {number} [upper=1] The upper bound. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(lower, upper, floating) { + if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { + upper = floating = undefined; + } + if (floating === undefined) { + if (typeof upper == 'boolean') { + floating = upper; + upper = undefined; + } + else if (typeof lower == 'boolean') { + floating = lower; + lower = undefined; + } + } + if (lower === undefined && upper === undefined) { + lower = 0; + upper = 1; + } + else { + lower = toFinite(lower); + if (upper === undefined) { + upper = lower; + lower = 0; + } else { + upper = toFinite(upper); + } + } + if (lower > upper) { + var temp = lower; + lower = upper; + upper = temp; + } + if (floating || lower % 1 || upper % 1) { + var rand = nativeRandom(); + return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); + } + return baseRandom(lower, upper); + } + + /*------------------------------------------------------------------------*/ + + /** + * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the camel cased string. + * @example + * + * _.camelCase('Foo Bar'); + * // => 'fooBar' + * + * _.camelCase('--foo-bar--'); + * // => 'fooBar' + * + * _.camelCase('__FOO_BAR__'); + * // => 'fooBar' + */ + var camelCase = createCompounder(function(result, word, index) { + word = word.toLowerCase(); + return result + (index ? capitalize(word) : word); + }); + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * _.capitalize('FRED'); + * // => 'Fred' + */ + function capitalize(string) { + return upperFirst(toString(string).toLowerCase()); + } + + /** + * Deburrs `string` by converting + * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) + * letters to basic Latin letters and removing + * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to deburr. + * @returns {string} Returns the deburred string. + * @example + * + * _.deburr('déjà vu'); + * // => 'deja vu' + */ + function deburr(string) { + string = toString(string); + return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); + } + + /** + * Checks if `string` ends with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=string.length] The position to search up to. + * @returns {boolean} Returns `true` if `string` ends with `target`, + * else `false`. + * @example + * + * _.endsWith('abc', 'c'); + * // => true + * + * _.endsWith('abc', 'b'); + * // => false + * + * _.endsWith('abc', 'b', 2); + * // => true + */ + function endsWith(string, target, position) { + string = toString(string); + target = baseToString(target); + + var length = string.length; + position = position === undefined + ? length + : baseClamp(toInteger(position), 0, length); + + var end = position; + position -= target.length; + return position >= 0 && string.slice(position, end) == target; + } + + /** + * Converts the characters "&", "<", ">", '"', and "'" in `string` to their + * corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional + * characters use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't need escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. See + * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * When working with HTML you should always + * [quote attribute values](http://wonko.com/post/html-escaping) to reduce + * XSS vectors. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function escape(string) { + string = toString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; + } + + /** + * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", + * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https://lodash\.com/\)' + */ + function escapeRegExp(string) { + string = toString(string); + return (string && reHasRegExpChar.test(string)) + ? string.replace(reRegExpChar, '\\$&') + : string; + } + + /** + * Converts `string` to + * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the kebab cased string. + * @example + * + * _.kebabCase('Foo Bar'); + * // => 'foo-bar' + * + * _.kebabCase('fooBar'); + * // => 'foo-bar' + * + * _.kebabCase('__FOO_BAR__'); + * // => 'foo-bar' + */ + var kebabCase = createCompounder(function(result, word, index) { + return result + (index ? '-' : '') + word.toLowerCase(); + }); + + /** + * Converts `string`, as space separated words, to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the lower cased string. + * @example + * + * _.lowerCase('--Foo-Bar--'); + * // => 'foo bar' + * + * _.lowerCase('fooBar'); + * // => 'foo bar' + * + * _.lowerCase('__FOO_BAR__'); + * // => 'foo bar' + */ + var lowerCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + word.toLowerCase(); + }); + + /** + * Converts the first character of `string` to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.lowerFirst('Fred'); + * // => 'fred' + * + * _.lowerFirst('FRED'); + * // => 'fRED' + */ + var lowerFirst = createCaseFirst('toLowerCase'); + + /** + * Pads `string` on the left and right sides if it's shorter than `length`. + * Padding characters are truncated if they can't be evenly divided by `length`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.pad('abc', 8); + * // => ' abc ' + * + * _.pad('abc', 8, '_-'); + * // => '_-abc_-_' + * + * _.pad('abc', 3); + * // => 'abc' + */ + function pad(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + if (!length || strLength >= length) { + return string; + } + var mid = (length - strLength) / 2; + return ( + createPadding(nativeFloor(mid), chars) + + string + + createPadding(nativeCeil(mid), chars) + ); + } + + /** + * Pads `string` on the right side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padEnd('abc', 6); + * // => 'abc ' + * + * _.padEnd('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padEnd('abc', 3); + * // => 'abc' + */ + function padEnd(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (string + createPadding(length - strLength, chars)) + : string; + } + + /** + * Pads `string` on the left side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padStart('abc', 6); + * // => ' abc' + * + * _.padStart('abc', 6, '_-'); + * // => '_-_abc' + * + * _.padStart('abc', 3); + * // => 'abc' + */ + function padStart(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (createPadding(length - strLength, chars) + string) + : string; + } + + /** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a + * hexadecimal, in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the + * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category String + * @param {string} string The string to convert. + * @param {number} [radix=10] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {number} Returns the converted integer. + * @example + * + * _.parseInt('08'); + * // => 8 + * + * _.map(['6', '08', '10'], _.parseInt); + * // => [6, 8, 10] + */ + function parseInt(string, radix, guard) { + if (guard || radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); + } + + /** + * Repeats the given string `n` times. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=1] The number of times to repeat the string. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the repeated string. + * @example + * + * _.repeat('*', 3); + * // => '***' + * + * _.repeat('abc', 2); + * // => 'abcabc' + * + * _.repeat('abc', 0); + * // => '' + */ + function repeat(string, n, guard) { + if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + return baseRepeat(toString(string), n); + } + + /** + * Replaces matches for `pattern` in `string` with `replacement`. + * + * **Note:** This method is based on + * [`String#replace`](https://mdn.io/String/replace). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to modify. + * @param {RegExp|string} pattern The pattern to replace. + * @param {Function|string} replacement The match replacement. + * @returns {string} Returns the modified string. + * @example + * + * _.replace('Hi Fred', 'Fred', 'Barney'); + * // => 'Hi Barney' + */ + function replace() { + var args = arguments, + string = toString(args[0]); + + return args.length < 3 ? string : string.replace(args[1], args[2]); + } + + /** + * Converts `string` to + * [snake case](https://en.wikipedia.org/wiki/Snake_case). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the snake cased string. + * @example + * + * _.snakeCase('Foo Bar'); + * // => 'foo_bar' + * + * _.snakeCase('fooBar'); + * // => 'foo_bar' + * + * _.snakeCase('--FOO-BAR--'); + * // => 'foo_bar' + */ + var snakeCase = createCompounder(function(result, word, index) { + return result + (index ? '_' : '') + word.toLowerCase(); + }); + + /** + * Splits `string` by `separator`. + * + * **Note:** This method is based on + * [`String#split`](https://mdn.io/String/split). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to split. + * @param {RegExp|string} separator The separator pattern to split by. + * @param {number} [limit] The length to truncate results to. + * @returns {Array} Returns the string segments. + * @example + * + * _.split('a-b-c', '-', 2); + * // => ['a', 'b'] + */ + function split(string, separator, limit) { + if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { + separator = limit = undefined; + } + limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; + if (!limit) { + return []; + } + string = toString(string); + if (string && ( + typeof separator == 'string' || + (separator != null && !isRegExp(separator)) + )) { + separator = baseToString(separator); + if (!separator && hasUnicode(string)) { + return castSlice(stringToArray(string), 0, limit); + } + } + return string.split(separator, limit); + } + + /** + * Converts `string` to + * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). + * + * @static + * @memberOf _ + * @since 3.1.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the start cased string. + * @example + * + * _.startCase('--foo-bar--'); + * // => 'Foo Bar' + * + * _.startCase('fooBar'); + * // => 'Foo Bar' + * + * _.startCase('__FOO_BAR__'); + * // => 'FOO BAR' + */ + var startCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + upperFirst(word); + }); + + /** + * Checks if `string` starts with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=0] The position to search from. + * @returns {boolean} Returns `true` if `string` starts with `target`, + * else `false`. + * @example + * + * _.startsWith('abc', 'a'); + * // => true + * + * _.startsWith('abc', 'b'); + * // => false + * + * _.startsWith('abc', 'b', 1); + * // => true + */ + function startsWith(string, target, position) { + string = toString(string); + position = position == null + ? 0 + : baseClamp(toInteger(position), 0, string.length); + + target = baseToString(target); + return string.slice(position, position + target.length) == target; + } + + /** + * Creates a compiled template function that can interpolate data properties + * in "interpolate" delimiters, HTML-escape interpolated data properties in + * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data + * properties may be accessed as free variables in the template. If a setting + * object is given, it takes precedence over `_.templateSettings` values. + * + * **Note:** In the development build `_.template` utilizes + * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * for easier debugging. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The template string. + * @param {Object} [options={}] The options object. + * @param {RegExp} [options.escape=_.templateSettings.escape] + * The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] + * The "evaluate" delimiter. + * @param {Object} [options.imports=_.templateSettings.imports] + * An object to import into the template as free variables. + * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] + * The "interpolate" delimiter. + * @param {string} [options.sourceURL='lodash.templateSources[n]'] + * The sourceURL of the compiled template. + * @param {string} [options.variable='obj'] + * The data object variable name. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the compiled template function. + * @example + * + * // Use the "interpolate" delimiter to create a compiled template. + * var compiled = _.template('hello <%= user %>!'); + * compiled({ 'user': 'fred' }); + * // => 'hello fred!' + * + * // Use the HTML "escape" delimiter to escape data property values. + * var compiled = _.template('<%- value %>'); + * compiled({ 'value': ' + diff --git a/integration/bazel/yarn.lock b/integration/bazel/yarn.lock index 8c23c3dc0f..6645352d2a 100644 --- a/integration/bazel/yarn.lock +++ b/integration/bazel/yarn.lock @@ -10,7 +10,7 @@ dependencies: "@microsoft/api-extractor" "^7.3.9" shelljs "0.8.2" - tsickle "^0.37.1" + tsickle "^0.38.0" "@angular/cdk@8.0.1": version "8.0.1" @@ -28,7 +28,7 @@ version "9.0.0-rc.1" dependencies: canonical-path "1.0.0" - chokidar "^2.1.1" + chokidar "^3.0.0" convert-source-map "^1.5.1" dependency-graph "^0.7.2" magic-string "^0.25.0" @@ -63,73 +63,61 @@ "@angular/router@file:../../dist/packages-dist/router": version "9.0.0-rc.1" -"@bazel/bazel-darwin_x64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-1.1.0.tgz#9402ecadfaf0383bc366ef5b37b933e0d0e804fc" - integrity sha512-/dnpkjqnl2Qrcy+qFerOe+lV9QZ2HoUHtTplQgRxa+OH8AtQ7mcopdJ9/3Y10GqgT2Kp+AR6G99R59/Si+BOMg== +"@bazel/bazel-darwin_x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-2.0.0.tgz#bd678069216dd470c6816a22c405f21e7f048038" + integrity sha512-I/pP+B+2xfY0g+OEpEcVnk8rizuC761pAzBOQjP3b+gz3AzeRgm05CpcSY7tfPIppMSYoy3uTZJ1XlwgUg7IQQ== -"@bazel/bazel-linux_x64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-1.1.0.tgz#98d75240e3e9ff5ba14fa48d6241d5d741e89926" - integrity sha512-yDR1URphRQTkXYjl4U2NLmbGR8ar8imhytK3txZZqlPf5pfWI/7wa7gSg0H4VbRRLIGAy/nD2eXZpgSj1eUiqA== +"@bazel/bazel-linux_x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-2.0.0.tgz#2c76e3301e9178a90ec3ad00649e89b953eda0b7" + integrity sha512-iOr45G+511IbP7e+ISriG97WpfCAVXekTrTgL5mGg3NDBFCVNs350VquHAvmlXAoP5+IEug2pCOlkdEl4bLl8g== -"@bazel/bazel-win32_x64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-1.1.0.tgz#e9c80a8c6495834ee7fc6184c425284d1151ac38" - integrity sha512-mj3ujcifKO+hjAjHvLoutYxzs90YWuc/fYJuVaEQrk4YFrRW5g70OpjN74zzBHRstObOjSZ3cOj+HDB19SIFKw== +"@bazel/bazel-win32_x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-2.0.0.tgz#f12ac0738d2eac0fd255f099776194807cedfe50" + integrity sha512-5qs2qoa/paG/YYEM0yvrwuJIShoPVK2FX+Oz9jEWAQJsmU4drHA9Aq+gbBOirEFLmvYhleZ9XORCwu/5uAo8vA== "@bazel/bazel@file:../../node_modules/@bazel/bazel": - version "1.1.0" + version "2.0.0" dependencies: "@bazel/hide-bazel-files" latest optionalDependencies: - "@bazel/bazel-darwin_x64" "1.1.0" - "@bazel/bazel-linux_x64" "1.1.0" - "@bazel/bazel-win32_x64" "1.1.0" + "@bazel/bazel-darwin_x64" "2.0.0" + "@bazel/bazel-linux_x64" "2.0.0" + "@bazel/bazel-win32_x64" "2.0.0" "@bazel/hide-bazel-files@latest": version "0.38.3" resolved "https://registry.yarnpkg.com/@bazel/hide-bazel-files/-/hide-bazel-files-0.38.3.tgz#e98231d3d360d51860d9c1a7c3345b40dab4cf81" integrity sha512-o+dNkfDm3qxWQ8h/04cWuTcjR7qnjZi3pQGv4aklVb16oPWx2jF8BzbkwvWuIkdbOl9VnqYP0vaHzwQVJRRcIA== -"@bazel/karma@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.40.0.tgz#5d6b669355d173dea02e9b5d21ff41db91ceb3fd" - integrity sha512-xRbUU3vg2KUmCTYBkHsvdDEy6vhtmWICiE/s0vikb4c3lCY5UtY/Y9fmoflhNHjOgjnncEFS8J4uMaWn5rZmhg== +"@bazel/karma@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.2.2.tgz#545c0f86f921229879511a9a0b2edba1329a1fb8" + integrity sha512-jUTv6DKoLkU3VUIFHCTnRU94qbOBPRZYbg7//2AnzHAS77SQyIAEUG5xU/W26+kle+sj7nBMavlMOxLjsrpMFA== dependencies: - jasmine-core "2.8.0" - karma "~4.1.0" - karma-chrome-launcher "2.2.0" - karma-firefox-launcher "1.1.0" - karma-jasmine "2.0.1" - karma-requirejs "1.1.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" + tmp "0.1.0" -"@bazel/protractor@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-0.40.0.tgz#0c64ddbf5a063417f43520ec1fed5cbc485792cf" - integrity sha512-qio8c8ie6Ajwu6hEs3vYf5+18JvrYH/6bv2b5YcE7HnyQZKGeJCDyTUErIUkCHwq8RsIqpsgxtCj69xmUxZXbw== - dependencies: - protractor "^5.4.2" +"@bazel/protractor@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.2.2.tgz#33bd58dfbfa33f1ec4b037ef5d4edc5de130aa2b" + integrity sha512-PgE/VAwgvtlFPKdCR1o2ofZyc4khLeEu+nztzuohZ1MqD5Yn5tx6QGhOAhLDLNCim1DRqRXct7LerAy1VNm5iA== -"@bazel/rollup@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-0.40.0.tgz#8ee08e1967c1ff7d549ce81b676872fa7e45afdb" - integrity sha512-7ZKzOIfHm0lEc3G/o2ykCZQlc7xcKSHiwIV4GIeaYJIbFUnO/L0cmaWzxOhdlr7NFfTdXcltTFnCrG7wlaad9A== +"@bazel/rollup@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.2.2.tgz#f5522ac308c41c6e11cbbdf3f0300a1db885410d" + integrity sha512-TGdL06eO8ARHEGVYdwA4MXoVM/V8EeFhi2DAMK+VrN609B7/CvtukdlT9KnuAONo5W7mttPzyuCgsvkaADrNOA== -"@bazel/terser@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-0.40.0.tgz#e31c76c32055a6bdffc711b05b530ae8df7ed1d5" - integrity sha512-XSnoLnB9i+RTJ4T1Tyrq0NMcIStzb9LQ1szMBOkJY4mBTRRNpf8Qnq+k5Vu9YY/dNIKVWtowNYBSWHzxxcL05g== +"@bazel/terser@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.2.2.tgz#a245e345028fd0e15b76b67da1a60c0d9635c76f" + integrity sha512-IsHxbSjbNesSjIQDRpm1tDPwiHadTQIIIOUgtQQN1hDlzmDufTNvqGpB+34MeSLNzn2KVHObqYbYs6LVpW1a8A== -"@bazel/typescript@0.40.0": - version "0.40.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.40.0.tgz#4f70d1365ee28fb8c1fd430a25034b74deecada9" - integrity sha512-826LXZYVlvcf9zNNcywzGprMUgCFqcwCeM/VLp+xG8/q6idJpqCBxABfJy2U6iZ8qIg5+wlxgYkOcmAZBfKMfA== +"@bazel/typescript@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.2.2.tgz#9acb8e07d1bd2b5d9c7afd01b434687b277f9dcb" + integrity sha512-qEkkkLOsKvcTvyToiMLVTU67iEHTOzVUIJGDo3+7g8vRL4OqG9EWk0ooNzVLWZ129Caz9TyVyleh1RhuReJWOw== dependencies: protobufjs "6.8.8" semver "5.6.0" @@ -289,11 +277,6 @@ resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a" integrity sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA== -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.4: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -307,7 +290,7 @@ acorn@^7.1.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== -adm-zip@^0.4.9, adm-zip@~0.4.3: +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== @@ -354,26 +337,13 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -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== +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== 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" + normalize-path "^3.0.0" + picomatch "^2.0.4" argparse@~1.0.9: version "1.0.10" @@ -382,21 +352,6 @@ argparse@~1.0.9: 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" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -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-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -409,11 +364,6 @@ array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= -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" @@ -436,22 +386,12 @@ 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= -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.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== -async@^2.1.2, async@^2.6.2: +async@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== @@ -474,9 +414,9 @@ aws-sign2@~0.7.0: 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== + version "1.9.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" + integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== backo2@1.0.2: version "1.0.2" @@ -498,18 +438,10 @@ base64id@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" +basic-auth@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" + integrity sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ= bcrypt-pbkdf@^1.0.0: version "1.0.2" @@ -525,10 +457,10 @@ better-assert@~1.0.0: dependencies: callsite "1.0.0" -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== blob@0.0.5: version "0.0.5" @@ -571,21 +503,12 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 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" + fill-range "^7.0.1" browserstack@^1.5.1: version "1.5.3" @@ -627,21 +550,6 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -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" @@ -673,39 +581,20 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chokidar@^2.0.3, chokidar@^2.1.1: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== +chokidar@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" + integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.2.0" optionalDependencies: - fsevents "^1.2.7" - -chownr@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" - integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== - -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" + fsevents "~2.1.1" cliui@^4.0.0: version "4.1.0" @@ -721,20 +610,7 @@ code-point-at@^1.0.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" - -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - -colors@^1.1.0: +colors@^1.1.0, colors@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== @@ -766,11 +642,6 @@ component-emitter@1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" @@ -791,11 +662,6 @@ connect@^3.6.0: parseurl "~1.3.3" utils-merge "1.0.1" -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= - content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -813,22 +679,12 @@ cookie@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.2.0: - version "2.6.10" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.10.tgz#8a5b8391f8cc7013da703411ce5b585706300d7f" - integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA== - 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= -corser@~2.0.0: +corser@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= @@ -861,7 +717,7 @@ date-format@^2.0.0: resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf" integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +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== @@ -899,11 +755,6 @@ decode-uri-component@^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-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -911,28 +762,6 @@ define-properties@^1.1.2, define-properties@^1.1.3: dependencies: object-keys "^1.0.12" -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" @@ -951,11 +780,6 @@ delayed-stream@~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" @@ -966,11 +790,6 @@ dependency-graph@^0.7.2: resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== -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= - di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" @@ -994,7 +813,7 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -ecstatic@^3.0.0: +ecstatic@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48" integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog== @@ -1072,25 +891,25 @@ ent@~2.2.0: integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= es-abstract@^1.5.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.15.0.tgz#8884928ec7e40a79e3c9bc812d37d10c8b24cc57" - integrity sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ== + version "1.16.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.2.tgz#4e874331645e9925edef141e74fc4bd144669d34" + integrity sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA== dependencies: - es-to-primitive "^1.2.0" + es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.0" + has-symbols "^1.0.1" is-callable "^1.1.4" is-regex "^1.0.4" - object-inspect "^1.6.0" + object-inspect "^1.7.0" object-keys "^1.1.1" string.prototype.trimleft "^2.1.0" string.prototype.trimright "^2.1.0" -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" is-date-object "^1.0.1" @@ -1146,53 +965,11 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -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" - -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== -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" @@ -1213,15 +990,12 @@ 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= -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= +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" + to-regex-range "^5.0.1" finalhandler@1.1.2: version "1.1.2" @@ -1255,11 +1029,6 @@ follow-redirects@^1.0.0: dependencies: debug "^3.0.0" -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= - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -1274,20 +1043,6 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -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" - -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-extra@^7.0.1, fs-extra@~7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -1297,45 +1052,21 @@ fs-extra@^7.0.1, fs-extra@~7.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - 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.2.7: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== - dependencies: - nan "^2.12.1" - node-pre-gyp "^0.12.0" +fsevents@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -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@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -1348,11 +1079,6 @@ get-stream@^4.0.0: 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" @@ -1360,15 +1086,14 @@ getpass@^0.1.1: dependencies: assert-plus "^1.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= +glob-parent@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" + integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" + is-glob "^4.0.1" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3: +glob@^7.0.0, glob@^7.1.3: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== @@ -1380,6 +1105,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.0.3, glob@^7.0.6, glob@^7.1.1: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + 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" + globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" @@ -1392,7 +1129,7 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.2.2" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== @@ -1429,46 +1166,10 @@ has-cors@1.1.0: resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - -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" +has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== has@^1.0.1, has@^1.0.3: version "1.0.3" @@ -1493,7 +1194,7 @@ http-errors@1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -http-proxy@^1.13.0, http-proxy@^1.8.1: +http-proxy@^1.13.0, http-proxy@^1.17.0: version "1.18.0" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== @@ -1502,19 +1203,21 @@ http-proxy@^1.13.0, http-proxy@^1.8.1: follow-redirects "^1.0.0" requires-port "^1.0.0" -http-server@0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" - integrity sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w== +http-server@0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.12.0.tgz#316b450603c0454d4a462d97a3132808a9858563" + integrity sha512-imGLDSTT1BZ0QG1rBFnaZ6weK5jeisUnCxZQI1cpYTdz0luPUM5e3s+WU5zRWEkiI6DQxL2p54oeKrDlzO6bRw== dependencies: - colors "1.0.3" - corser "~2.0.0" - ecstatic "^3.0.0" - http-proxy "^1.8.1" - opener "~1.4.0" - optimist "0.6.x" - portfinder "^1.0.13" - union "~0.4.3" + basic-auth "^1.0.3" + colors "^1.3.3" + corser "^2.0.1" + ecstatic "^3.3.2" + http-proxy "^1.17.0" + opener "^1.5.1" + optimist "~0.6.1" + portfinder "^1.0.20" + secure-compare "3.0.1" + union "~0.5.0" http-signature@~1.2.0: version "1.2.0" @@ -1526,27 +1229,20 @@ http-signature@~1.2.0: sshpk "^1.7.0" https-proxy-agent@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz#271ea8e90f836ac9f119daccd39c19ff7dfb0793" - integrity sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg== + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== dependencies: agent-base "^4.3.0" debug "^3.1.0" -iconv-lite@0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24: 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" -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - 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" @@ -1565,7 +1261,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1575,7 +1271,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4, ini@~1.3.0: +ini@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -1590,87 +1286,24 @@ invert-kv@^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== -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= +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 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-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== + binary-extensions "^2.0.0" is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== -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-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= -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-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@^2.1.0, is-extglob@^2.1.1: +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= @@ -1687,14 +1320,7 @@ is-fullwidth-code-point@^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@^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: +is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -1706,12 +1332,10 @@ is-module@^1.0.0: resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= -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@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-path-cwd@^1.0.0: version "1.0.0" @@ -1732,13 +1356,6 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.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-reference@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.4.tgz#3f95849886ddb70256a3e6d062b1a68c13c51427" @@ -1759,32 +1376,32 @@ is-stream@^1.1.0: integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== dependencies: - has-symbols "^1.0.0" + has-symbols "^1.0.1" 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-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: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +is-wsl@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" + integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isbinaryfile@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" @@ -1797,33 +1414,21 @@ isexe@^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, 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@^3.3: version "3.5.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.5.0.tgz#132c23e645af96d85c8bca13c8758b18429fc1e4" integrity sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA== +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" @@ -1880,7 +1485,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jszip@^3.1.3, jszip@^3.1.5: +jszip@^3.1.3: version "3.2.2" resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.2.2.tgz#b143816df7e106a9597a94c77493385adca5bd1d" integrity sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA== @@ -1890,18 +1495,19 @@ jszip@^3.1.3, jszip@^3.1.5: readable-stream "~2.3.6" set-immediate-shim "~1.0.1" -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== +karma-chrome-launcher@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz#805a586799a4d05f4e54f72a204979f3f3066738" + integrity sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg== dependencies: - fs-access "^1.0.0" which "^1.2.1" -karma-firefox-launcher@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-1.1.0.tgz#2c47030452f04531eb7d13d4fc7669630bb93339" - integrity sha512-LbZ5/XlIXLeQ3cqnCbYLn+rOVhuMIK9aZwlP6eOLGzWdo1UVp7t6CN3DP4SafiRLjexKwHeKHDm0c38Mtd3VxA== +karma-firefox-launcher@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-1.2.0.tgz#64fe03dd10300f9754d48f9ebfbf31f6c94a200c" + integrity sha512-j9Zp8M8+VLq1nI/5xZGfzeaEPtGQ/vk3G+Y8vpmFWLvKLNZ2TDjD6cu2dUu7lDbu1HXNgatsAX4jgCZTkR9qhQ== + dependencies: + is-wsl "^2.1.0" karma-jasmine@2.0.1: version "2.0.1" @@ -1915,15 +1521,6 @@ 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@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: - 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" resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz#91322c77f8f13d46fed062b042e1009d4c4505d8" @@ -1931,18 +1528,17 @@ karma-sourcemap-loader@0.3.7: dependencies: graceful-fs "^4.1.2" -karma@~4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/karma/-/karma-4.1.0.tgz#d07387c9743a575b40faf73e8a3eb5421c2193e1" - integrity sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw== +karma@4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/karma/-/karma-4.4.1.tgz#6d9aaab037a31136dc074002620ee11e8c2e32ab" + integrity sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A== dependencies: bluebird "^3.3.0" body-parser "^1.16.1" - braces "^2.3.2" - chokidar "^2.0.3" + braces "^3.0.2" + chokidar "^3.0.0" colors "^1.1.0" connect "^3.6.0" - core-js "^2.2.0" di "^0.0.1" dom-serialize "^2.2.0" flatted "^2.0.0" @@ -1950,7 +1546,7 @@ karma@~4.1.0: graceful-fs "^4.1.2" http-proxy "^1.13.0" isbinaryfile "^3.0.0" - lodash "^4.17.11" + lodash "^4.17.14" log4js "^4.0.0" mime "^2.3.1" minimatch "^3.0.2" @@ -1964,30 +1560,6 @@ karma@~4.1.0: tmp "0.0.33" useragent "2.3.0" -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@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" @@ -2020,7 +1592,7 @@ lodash.isequal@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= -lodash@^4.16.6, lodash@^4.17.11, lodash@^4.17.14, lodash@~4.17.15: +lodash@^4.17.14, lodash@~4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -2063,18 +1635,6 @@ map-age-cleaner@^0.1.1: 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-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" - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -2089,36 +1649,17 @@ mem@^4.0.0: mimic-fn "^2.0.0" p-is-promise "^2.0.0" -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" - -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== +mime-db@1.42.0: + version "1.42.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" + integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + version "2.1.25" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" + integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== dependencies: - mime-db "1.40.0" + mime-db "1.42.0" mime@^1.6.0: version "1.6.0" @@ -2157,30 +1698,7 @@ minimist@~0.0.1: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -2197,37 +1715,6 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - -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.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -2238,55 +1725,11 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== - 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-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-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== - -npm-packlist@^1.1.6: - version "1.4.6" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4" - integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg== - 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" @@ -2294,21 +1737,6 @@ npm-run-path@^2.0.0: 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" - -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= - 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" @@ -2319,7 +1747,7 @@ oauth-sign@~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: +object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -2329,32 +1757,16 @@ object-component@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-inspect@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" - integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -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.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" @@ -2363,13 +1775,6 @@ object.getownpropertydescriptors@^2.0.3: define-properties "^1.1.2" es-abstract "^1.5.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" @@ -2384,12 +1789,12 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -opener@~1.4.0: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= +opener@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" + integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== -optimist@0.6.x, optimist@^0.6.1, optimist@~0.6.0: +optimist@^0.6.1, optimist@~0.6.0, optimist@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= @@ -2397,11 +1802,6 @@ optimist@0.6.x, optimist@^0.6.1, optimist@~0.6.0: minimist "~0.0.1" wordwrap "~0.0.2" -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@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" @@ -2411,19 +1811,11 @@ os-locale@^3.1.0: lcid "^2.0.0" mem "^4.0.0" -os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: +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.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-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -2487,16 +1879,6 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -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-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@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -2527,6 +1909,11 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picomatch@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.1.1.tgz#ecdfbea7704adb5fe6fb47f9866c4c0e15e905c5" + integrity sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA== + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -2544,7 +1931,7 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= -portfinder@^1.0.13: +portfinder@^1.0.20: version "1.0.25" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== @@ -2553,11 +1940,6 @@ portfinder@^1.0.13: debug "^3.1.1" mkdirp "^0.5.1" -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= - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -2582,7 +1964,7 @@ protobufjs@6.8.8: "@types/node" "^10.1.0" long "^4.0.0" -protractor@^5.4.2: +protractor@5.4.2: version "5.4.2" resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.4.2.tgz#329efe37f48b2141ab9467799be2d4d12eb48c13" integrity sha512-zlIj64Cr6IOWP7RwxVeD8O4UskLYPoyIcg0HboWJL9T79F1F0VWtKkGTr/9GN6BKL+/Q/GmM7C9kFVCfDbP5sA== @@ -2651,10 +2033,10 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== -qs@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" - integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ= +qs@^6.4.0: + version "6.9.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9" + integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA== qs@~6.5.2: version "6.5.2" @@ -2676,17 +2058,7 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -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" - -readable-stream@^2.0.2, readable-stream@^2.0.6, 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== @@ -2699,14 +2071,12 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== +readdirp@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" + integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" + picomatch "^2.0.4" rechoir@^0.6.2: version "0.6.2" @@ -2725,29 +2095,6 @@ reflect-metadata@^0.1.2: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== -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" - -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.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - request@^2.87.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" @@ -2784,10 +2131,10 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -requirejs@2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.5.tgz#617b9acbbcb336540ef4914d790323a8d4b861b0" - integrity sha512-svnO+aNcR/an9Dpi44C7KSAy5fFGLtmPbaaCeQaklUz8BQhS64tWWIIlvEA5jrWICzlO/X9KSzSeXFnZdBu8nw== +requirejs@2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" + integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== requires-port@^1.0.0: version "1.0.0" @@ -2813,17 +2160,12 @@ resolve@^1.1.6, resolve@^1.11.0, resolve@^1.11.1: 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== - rfdc@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2" integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug== -rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.3: +rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -2867,10 +2209,10 @@ rollup-pluginutils@^2.0.1, rollup-pluginutils@^2.8.1: dependencies: estree-walker "^0.6.1" -rollup@1.25.2: - version "1.25.2" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.25.2.tgz#739f508bd8f7ece52bb6c1fcda83466af82b7f6d" - integrity sha512-+7z6Wab/L45QCPcfpuTZKwKiB0tynj05s/+s2U3F2Bi7rOLPr9UcjUwO7/xpjlPNXA/hwnth6jBExFRGyf3tMg== +rollup@1.27.5: + version "1.27.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.27.5.tgz#d100fb0ffd8353575cb2057152547b9abfddfe59" + integrity sha512-8rfVdzuTg2kt8ObD9LNJpEwUN7B6lsl3sHc5fddtgICpLjpYeSf4m2+RftBzcCaBTMi1iYX3Ez8zFT4Gj2nJjg== dependencies: "@types/estree" "*" "@types/node" "*" @@ -2891,29 +2233,11 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: 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== -sauce-connect-launcher@^1.2.4: - version "1.2.7" - resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.2.7.tgz#c7f8b3d4eb354d07a9922b4cd67356f527192556" - integrity sha512-v07+QhFrxgz3seMFuRSonu3gW1s6DbcLQlFhjsRrmKUauzPbbudHdnn91WYgEwhoZVdPNzeZpAEJwcQyd9xnTA== - dependencies: - adm-zip "~0.4.3" - async "^2.1.2" - https-proxy-agent "^2.2.1" - lodash "^4.16.6" - rimraf "^2.5.4" - saucelabs@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.5.0.tgz#9405a73c360d449b232839919a86c396d379fd9d" @@ -2921,11 +2245,16 @@ saucelabs@^1.5.0: dependencies: https-proxy-agent "^2.2.1" -sax@>=0.6.0, sax@^1.2.4: +sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +secure-compare@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/secure-compare/-/secure-compare-3.0.1.tgz#f1a0329b308b221fae37b9974f3d578d0ca999e3" + integrity sha1-8aAymzCLIh+uN7mXTz1XjQypmeM= + 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" @@ -2936,16 +2265,6 @@ selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: tmp "0.0.30" xml2js "^0.4.17" -selenium-webdriver@^4.0.0-alpha.1: - version "4.0.0-alpha.5" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.5.tgz#e4683b3dbf827d70df09a7e43bf02ebad20fa7c1" - integrity sha512-hktl3DSrhzM59yLhWzDGHIX9o56DvA+cVK7Dw6FcJR6qQ4CGzkaHeXQPcdrslkWMTeq0Ci9AmCxq0EMOvm2Rkg== - dependencies: - jszip "^3.1.5" - rimraf "^2.6.3" - tmp "0.0.30" - xml2js "^0.4.19" - semver@5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -2961,7 +2280,7 @@ semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -set-blocking@^2.0.0, 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= @@ -2971,16 +2290,6 @@ set-immediate-shim@~1.0.1: resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - setprototypeof@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" @@ -3012,40 +2321,10 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -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= + version "1.1.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" + integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== socket.io-client@2.1.1: version "2.1.1" @@ -3142,13 +2421,6 @@ sourcemap-codec@^1.4.4: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9" integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg== -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.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -3169,14 +2441,6 @@ sshpk@^1.7.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.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -3202,7 +2466,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.1: +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== @@ -3268,33 +2532,15 @@ strip-eof@^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@^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= -tar@^4: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - -terser@4.3.9: - version "4.3.9" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.9.tgz#e4be37f80553d02645668727777687dad26bbca8" - integrity sha512-NFGMpHjlzmyOtPL+fDw3G7+6Ueh/sz4mkaUYa4lJCxOPTNzd0Uj0aZJOmsDYoSQyfuVoWDMSWTPU3huyOm2zdA== +terser@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.0.tgz#22c46b4817cf4c9565434bfe6ad47336af259ac3" + integrity sha512-oDG16n2WKm27JO8h4y/w3iqBGAOSCtq7k8dRmrn4Wf9NouL0b2WpMHGChFGZq4nFAQy1FsNJrVQHfurXOSTmOA== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -3314,35 +2560,24 @@ tmp@0.0.33, tmp@0.0.x: dependencies: os-tmpdir "~1.0.2" +tmp@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" + integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw== + dependencies: + rimraf "^2.6.3" + 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-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= +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 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" + is-number "^7.0.0" toidentifier@1.0.0: version "1.0.0" @@ -3357,10 +2592,10 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" -tsickle@^0.37.1: - version "0.37.1" - resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.37.1.tgz#2f8a87c1b15766e866457bd06fb6c0e0d84eed09" - integrity sha512-0GwgOJEnsmRsrONXCvcbAWY0CvdqF3UugPVoupUpA8Ul0qCPTuqqq0ou/hLqtKZOyyulzCP6MYRjb9/J1g9bJg== +tsickle@^0.38.0: + version "0.38.0" + resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.38.0.tgz#89f5952c9bb3ba0b36dc384975e23cf90e584822" + integrity sha512-k7kI6afBuLd2jIrj9JR8lKhEkp99sFVRKQbHeaHQkdvDaH5AvzwqA/qX+aNj28OfuAsWryOKAZoXm24l7JelEw== tslib@^1.7.1, tslib@^1.8.1, tslib@^1.9.0: version "1.10.0" @@ -3397,10 +2632,10 @@ type-is@~1.6.17: media-typer "0.3.0" mime-types "~2.1.24" -typescript@3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" - integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== +typescript@3.7.4: + version "3.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19" + integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw== typescript@~3.5.3: version "3.5.3" @@ -3412,22 +2647,12 @@ ultron@~1.1.0: 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.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== +union@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/union/-/union-0.5.0.tgz#b2c11be84f60538537b846edb9ba266ba0090075" + integrity sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA== dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -union@~0.4.3: - version "0.4.6" - resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" - integrity sha1-GY+9rrolTniLDvy2MLwR8kopWeA= - dependencies: - qs "~2.3.3" + qs "^6.4.0" universalify@^0.1.0: version "0.1.2" @@ -3439,19 +2664,6 @@ unpipe@1.0.0, unpipe@~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.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -3469,11 +2681,6 @@ url-join@^2.0.5: resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= -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" @@ -3561,13 +2768,6 @@ which@^1.2.1, which@^1.2.9: 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@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" @@ -3595,7 +2795,7 @@ ws@~3.3.1: safe-buffer "~5.1.0" ultron "~1.1.0" -xml2js@^0.4.17, xml2js@^0.4.19: +xml2js@^0.4.17: version "0.4.22" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.22.tgz#4fa2d846ec803237de86f30aa9b5f70b6600de02" integrity sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw== @@ -3624,11 +2824,6 @@ yallist@^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.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - yargs-parser@^13.0.0: version "13.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" diff --git a/integration/cli-hello-world-ivy-i18n/angular.json b/integration/cli-hello-world-ivy-i18n/angular.json index 5c960650cf..e0d1ab2635 100644 --- a/integration/cli-hello-world-ivy-i18n/angular.json +++ b/integration/cli-hello-world-ivy-i18n/angular.json @@ -84,6 +84,12 @@ "configurations": { "production": { "browserTarget": "cli-hello-world-ivy-i18n:build:production" + }, + "fr": { + "browserTarget": "cli-hello-world-ivy-i18n:build:production,fr" + }, + "de": { + "browserTarget": "cli-hello-world-ivy-i18n:build:production,de" } } }, @@ -140,11 +146,11 @@ "protractorConfig": "e2e/protractor.conf.js" }, "fr": { - "devServerTarget": "", + "devServerTarget": "cli-hello-world-ivy-i18n:serve:fr", "specs": ["./fr/app.e2e-spec.ts"] }, "de": { - "devServerTarget": "", + "devServerTarget": "cli-hello-world-ivy-i18n:serve:de", "specs": ["./de/app.e2e-spec.ts"] } } diff --git a/integration/cli-hello-world-ivy-i18n/package.json b/integration/cli-hello-world-ivy-i18n/package.json index 313cee7245..ab090899c4 100644 --- a/integration/cli-hello-world-ivy-i18n/package.json +++ b/integration/cli-hello-world-ivy-i18n/package.json @@ -11,7 +11,7 @@ "update-webdriver": "webdriver-manager update --gecko=false --standalone=false $CI_CHROMEDRIVER_VERSION_ARG", "start": "ng serve", "pretest": "ng version", - "test": "ng e2e --prod && ng xi18n && yarn translate && ng build --configuration production,fr && ng build --configuration production,de && run-p -r \"serve dist/fr\" \"ng e2e --configuration=fr\" && run-p -r \"serve dist/de\" \"ng e2e --configuration=de\"", + "test": "ng e2e --prod && ng xi18n && yarn translate && ng e2e --configuration fr && ng e2e --configuration de", "translate": "cp src/locale/messages.xlf src/locale/messages.fr.xlf && cp src/locale/messages.xlf src/locale/messages.de.xlf && sed -i.bak -e 's/source>/target>/g' -e 's/Hello/Bonjour/' src/locale/messages.fr.xlf && sed -i.bak -e 's/source>/target>/g' -e 's/Hello/Hallo/' src/locale/messages.de.xlf", "serve": "serve --no-clipboard --listen 4200" }, diff --git a/integration/ngcc/debug-test.sh b/integration/ngcc/debug-test.sh index fc9aca7945..d7ed06be59 100755 --- a/integration/ngcc/debug-test.sh +++ b/integration/ngcc/debug-test.sh @@ -15,7 +15,7 @@ node $(pwd)/../../scripts/build-packages-dist.js # Workaround https://github.com/yarnpkg/yarn/issues/2165 # Yarn will cache file://dist URIs and not update Angular code -readonly cache=../.yarn_local_cache +export readonly cache=../.yarn_local_cache function rm_cache { rm -rf $cache } diff --git a/integration/ngcc/mock-ngcc-version-marker.js b/integration/ngcc/mock-ngcc-version-marker.js new file mode 100644 index 0000000000..e72c998e5c --- /dev/null +++ b/integration/ngcc/mock-ngcc-version-marker.js @@ -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 + */ + +/** + * **Usage:** + * ```sh + * node mock-ngcc-version-marker + * + * # Example: + * # node mock-ngcc-version-marker @angular/material/button 3.0.0 + * ``` + * + * Ngcc marks entry-points as processed by adding marker properties in their `package.json`. It uses + * a version as a marker in order to be able to distinguish entry-points processed by a different + * ngcc version (e.g. an older version after an update) and perform the necessary clean-up. + * + * This script replaces the ngcc version marker in an entry-point's `package.json` to make it appear + * as if it were processed by a different version of ngcc. This allows testing the clean-up logic + * without the overhead of actually installing a different ngcc version, compiling the dependencies, + * then installing the current version and compiling again. + */ + +const {writeFileSync} = require('fs'); +const {basename} = require('path'); + +const entryPointName = process.argv[2]; +const mockNgccVersion = process.argv[3]; +const actualNgccVersion = require('@angular/compiler-cli/package.json').version; + +if (!entryPointName || !mockNgccVersion) { + throw new Error( + 'Missing required argument(s).\n' + + `Usage: node ${basename(__filename)} \n`); +} + +const entryPointPkgJsonPath = require.resolve(`${entryPointName}/package.json`); +const entryPointPkgJson = require(entryPointPkgJsonPath); +const processedMarkers = entryPointPkgJson.__processed_by_ivy_ngcc__; + +Object.keys(processedMarkers).forEach(key => processedMarkers[key] = mockNgccVersion); +writeFileSync(entryPointPkgJsonPath, JSON.stringify(entryPointPkgJson, null, 2)); + +console.log( + `Successfully mocked ngcc version marker in '${entryPointName}': ` + + `${actualNgccVersion} --> ${mockNgccVersion}`); diff --git a/integration/ngcc/package.json b/integration/ngcc/package.json index f3cb039f52..9df0ea3e3f 100644 --- a/integration/ngcc/package.json +++ b/integration/ngcc/package.json @@ -13,6 +13,7 @@ "@angular/material": "9.0.0-rc.4", "@angular/platform-browser": "file:../../dist/packages-dist/platform-browser", "@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic", + "@angular/platform-server": "file:../../dist/packages-dist/platform-server", "@angular/router": "file:../../dist/packages-dist/router", "@types/node": "file:../../node_modules/@types/node", "rxjs": "file:../../node_modules/rxjs", diff --git a/integration/ngcc/test.sh b/integration/ngcc/test.sh index e17972a122..70ce608866 100755 --- a/integration/ngcc/test.sh +++ b/integration/ngcc/test.sh @@ -3,7 +3,7 @@ # Do not immediately exit on error to allow the `assertSucceeded` function to handle the error. # # NOTE: -# Each statement should be followed by an `assertSucceeded`/`assertFailed` or `exit 1` statement. +# Each statement should be followed by an `assert*` or `exit 1` statement. set +e -x PATH=$PATH:$(npm bin) @@ -22,6 +22,26 @@ function assertSucceeded { fi } +function assertEquals { + local value1=$1; + local value2=$2; + + if [[ "$value1" != "$value2" ]]; then + echo "FAIL: Expected '$value1' to equal '$value2'." + exit 1; + fi +} + +function assertNotEquals { + local value1=$1; + local value2=$2; + + if [[ "$value1" == "$value2" ]]; then + echo "FAIL: Expected '$value1' not to equal '$value2'." + exit 1; + fi +} + ngcc --help assertSucceeded "Expected 'ngcc --help' to succeed." @@ -140,6 +160,39 @@ assertSucceeded "Expected 'ngcc' to log 'Compiling'." assertSucceeded "Expected 'ngcc' to not add trailing commas to factory function parameters in UMD." +# Can it correctly clean up and re-compile when dependencies are already compiled by a different version? + readonly actualNgccVersion=`node --print "require('@angular/compiler-cli/package.json').version"` + readonly mockNgccVersion="3.0.0" + + # Mock the ngcc version marker on a package to make it appear as if it is compiled by a different ngcc version. + node mock-ngcc-version-marker @angular/material/button $mockNgccVersion + assertSucceeded "Expected to successfully mock the 'ngcc' version marker in '@angular/material/button'." + assertEquals $mockNgccVersion `node --print "require('@angular/material/button/package.json').__processed_by_ivy_ngcc__.main"` + assertEquals 1 `cat node_modules/@angular/material/button/button.d.ts | grep 'import \* as ɵngcc0' | wc -l` + + # Re-compile packages (which requires cleaning up those compiled by a different ngcc version). + # (Use sync mode to ensure all tasks share the same `CachedFileSystem` instance.) + ngcc --no-async --properties main + assertSucceeded "Expected 'ngcc' to successfully re-compile the packages." + + # Ensure previously compiled packages were correctly cleaned up (i.e. no multiple + # `import ... ɵngcc0` statements) and re-compiled by the current ngcc version. + assertEquals $actualNgccVersion `node --print "require('@angular/material/button/package.json').__processed_by_ivy_ngcc__.main"` + assertEquals 1 `cat node_modules/@angular/material/button/button.d.ts | grep 'import \* as ɵngcc0' | wc -l` + + +# Can it compile `@angular/platform-server` in UMD + typings without errors? +# (The CLI prefers the `main` property (which maps to UMD) over `module` when compiling `@angular/platform-server`. +# See https://github.com/angular/angular-cli/blob/e36853338/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/server.ts#L34) + rm -rf node_modules/@angular/platform-server && \ + yarn install --cache-folder $cache --check-files && \ + test -d node_modules/@angular/platform-server + assertSucceeded "Expected to re-install '@angular/platform-server'." + + ngcc --properties main --target @angular/platform-server + assertSucceeded "Expected 'ngcc' to successfully compile '@angular/platform-server' (main)." + + # Can it be safely run again (as a noop)? # And check that it logged skipping compilation as expected ngcc -l debug | grep 'Skipping' diff --git a/integration/ngcc/yarn.lock b/integration/ngcc/yarn.lock index d701229ecb..2e1b49e367 100644 --- a/integration/ngcc/yarn.lock +++ b/integration/ngcc/yarn.lock @@ -19,9 +19,10 @@ version "9.0.0-rc.1" dependencies: canonical-path "1.0.0" - chokidar "^2.1.1" + chokidar "^3.0.0" convert-source-map "^1.5.1" dependency-graph "^0.7.2" + fs-extra "4.0.2" magic-string "^0.25.0" minimist "^1.2.0" reflect-metadata "^0.1.2" @@ -49,6 +50,12 @@ "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": version "9.0.0-rc.1" +"@angular/platform-server@file:../../dist/packages-dist/platform-server": + version "9.0.0-rc.1" + dependencies: + domino "^2.1.2" + xhr2 "^0.1.4" + "@angular/router@file:../../dist/packages-dist/router": version "9.0.0-rc.1" @@ -148,6 +155,14 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -242,11 +257,6 @@ async-each@^1.0.0: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" integrity sha1-GdOGodntxufByF04iu28xW0zYC0= -async-each@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735" - integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg== - async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -342,6 +352,11 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14" integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg== +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + blob@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" @@ -371,7 +386,7 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -braces@^2.3.0, braces@^2.3.1, braces@^2.3.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== @@ -387,6 +402,13 @@ braces@^2.3.0, braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + browser-sync-client@^2.26.2: version "2.26.2" resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.26.2.tgz#dd0070c80bdc6d9021e89f7837ee70ed0a8acf91" @@ -554,24 +576,20 @@ chokidar@^2.0.4: optionalDependencies: fsevents "^1.2.2" -chokidar@^2.1.1: - version "2.1.5" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" - integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== +chokidar@^3.0.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" + integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.3.0" optionalDependencies: - fsevents "^1.2.7" + fsevents "~2.1.2" chownr@^1.0.1: version "1.1.1" @@ -853,6 +871,11 @@ dev-ip@^1.0.1: resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0" integrity sha1-p2o+0YVb56ASu4rBbLgPPADcKPA= +domino@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.4.tgz#78922e7fab7c610f35792b6c745b7962d342e9c4" + integrity sha512-l70mlQ7IjPKC8kT7GljQXJZmt5OqFL+RE91ik5y5WWQtsd9wP8R7gpFnNu96fK5MqAAZRXfLLsnzKtkty5fWGQ== + easy-extender@^2.3.4: version "2.3.4" resolved "https://registry.yarnpkg.com/easy-extender/-/easy-extender-2.3.4.tgz#298789b64f9aaba62169c77a2b3b64b4c9589b8f" @@ -1108,6 +1131,13 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" @@ -1190,6 +1220,15 @@ fs-extra@3.0.1: jsonfile "^3.0.0" universalify "^0.1.0" +fs-extra@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" + integrity sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s= + 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" @@ -1210,13 +1249,10 @@ fsevents@^1.2.2: nan "^2.9.2" node-pre-gyp "^0.10.0" -fsevents@^1.2.7: - 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" +fsevents@~2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== gauge@~2.7.3: version "2.7.4" @@ -1284,6 +1320,13 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" + integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== + dependencies: + is-glob "^4.0.1" + glob@^7.0.3, glob@^7.0.5, glob@^7.0.6: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -1477,7 +1520,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, 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= @@ -1523,6 +1566,13 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.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" @@ -1634,6 +1684,13 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-number-like@^1.0.3: version "1.0.8" resolved "https://registry.yarnpkg.com/is-number-like/-/is-number-like-1.0.8.tgz#2e129620b50891042e44e9bbbb30593e75cfbbe3" @@ -1660,6 +1717,11 @@ is-number@^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-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + 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" @@ -1799,6 +1861,13 @@ jsonfile@^3.0.0: optionalDependencies: graceful-fs "^4.1.6" +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" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2178,7 +2247,7 @@ normalize-path@^2.0.1, normalize-path@^2.1.1: dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -2468,6 +2537,11 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picomatch@^2.0.4, picomatch@^2.0.7: + version "2.2.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" + integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -2509,7 +2583,7 @@ process-nextick-args@~2.0.0: integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== "protractor@file:../../node_modules/protractor": - version "5.4.2" + version "5.4.3" dependencies: "@types/q" "^0.0.32" "@types/selenium-webdriver" "^3.0.0" @@ -2629,7 +2703,7 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readdirp@^2.0.0, readdirp@^2.2.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== @@ -2638,6 +2712,13 @@ readdirp@^2.0.0, readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" +readdirp@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" + integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== + dependencies: + picomatch "^2.0.7" + reflect-metadata@^0.1.2: version "0.1.12" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" @@ -3265,6 +3346,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.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" @@ -3306,7 +3394,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= "typescript@file:../../node_modules/typescript": - version "3.6.4" + version "3.7.4" ua-parser-js@0.7.17: version "0.7.17" @@ -3351,11 +3439,6 @@ upath@^1.0.5: resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== -upath@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" - integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== - urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -3479,6 +3562,11 @@ ws@~3.3.1: safe-buffer "~5.1.0" ultron "~1.1.0" +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" diff --git a/integration/run_tests.sh b/integration/run_tests.sh index dac52b3bb4..86688fefa7 100755 --- a/integration/run_tests.sh +++ b/integration/run_tests.sh @@ -38,7 +38,7 @@ fi # Workaround https://github.com/yarnpkg/yarn/issues/2165 # Yarn will cache file://dist URIs and not update Angular code -readonly cache=.yarn_local_cache +export readonly cache=.yarn_local_cache function rm_cache { rm -rf $cache } diff --git a/integration/typings_test_ts36/package.json b/integration/typings_test_ts36/package.json index 58d97e198e..4f5f64ed01 100644 --- a/integration/typings_test_ts36/package.json +++ b/integration/typings_test_ts36/package.json @@ -19,7 +19,7 @@ "@angular/router": "file:../../dist/packages-dist/router", "@angular/service-worker": "file:../../dist/packages-dist/service-worker", "@angular/upgrade": "file:../../dist/packages-dist/upgrade", - "@types/jasmine": "2.5.41", + "@types/jasmine": "file:../../node_modules/@types/jasmine", "rxjs": "file:../../node_modules/rxjs", "typescript": "3.6.4", "zone.js": "file:../../dist/zone.js-dist/zone.js" diff --git a/integration/typings_test_ts36/tsconfig.json b/integration/typings_test_ts36/tsconfig.json index c815868e51..a7522d1cff 100644 --- a/integration/typings_test_ts36/tsconfig.json +++ b/integration/typings_test_ts36/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { + "strict": true, + "skipLibCheck": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, "module": "commonjs", @@ -15,7 +17,6 @@ "es2015.promise" ], "types": [], - "strictNullChecks": true }, "files": [ "include-all.ts", diff --git a/integration/typings_test_ts36/yarn.lock b/integration/typings_test_ts36/yarn.lock index 6108b8b8a6..cf27763dd7 100644 --- a/integration/typings_test_ts36/yarn.lock +++ b/integration/typings_test_ts36/yarn.lock @@ -61,10 +61,8 @@ "@angular/upgrade@file:../../dist/packages-dist/upgrade": version "9.0.0-rc.1" -"@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/jasmine@file:../../node_modules/@types/jasmine": + version "2.8.8" abbrev@1: version "1.1.1" diff --git a/integration/typings_test_ts37/include-all.ts b/integration/typings_test_ts37/include-all.ts new file mode 100644 index 0000000000..116ba30903 --- /dev/null +++ b/integration/typings_test_ts37/include-all.ts @@ -0,0 +1,77 @@ +/** + * @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 animations from '@angular/animations'; +import * as animationsBrowser from '@angular/animations/browser'; +import * as animationsBrowserTesting from '@angular/animations/browser/testing'; +import * as common from '@angular/common'; +import * as commonHttp from '@angular/common/http'; +import * as commonTesting from '@angular/common/testing'; +import * as commonHttpTesting from '@angular/common/testing'; +import * as compiler from '@angular/compiler'; +import * as compilerTesting from '@angular/compiler/testing'; +import * as core from '@angular/core'; +import * as coreTesting from '@angular/core/testing'; +import * as elements from '@angular/elements'; +import * as forms from '@angular/forms'; +// Current plan for Angular 8 is to stop building the @angular/http package +// import * as http from '@angular/http'; +// import * as httpTesting from '@angular/http/testing'; +import * as platformBrowser from '@angular/platform-browser'; +import * as platformBrowserDynamic from '@angular/platform-browser-dynamic'; +import * as platformBrowserDynamicTesting from '@angular/platform-browser-dynamic/testing'; +import * as platformBrowserAnimations from '@angular/platform-browser/animations'; +import * as platformBrowserTesting from '@angular/platform-browser/testing'; +import * as platformServer from '@angular/platform-server'; +import * as platformServerTesting from '@angular/platform-server/testing'; +import * as platformWebworker from '@angular/platform-webworker'; +import * as platformWebworkerDynamic from '@angular/platform-webworker-dynamic'; +import * as router from '@angular/router'; +import * as routerTesting from '@angular/router/testing'; +import * as routerUpgrade from '@angular/router/upgrade'; +import * as serviceWorker from '@angular/service-worker'; +import * as upgrade from '@angular/upgrade'; +import * as upgradeStatic from '@angular/upgrade/static'; +import * as upgradeTesting from '@angular/upgrade/static/testing'; + +export default { + animations, + animationsBrowser, + animationsBrowserTesting, + common, + commonTesting, + commonHttp, + commonHttpTesting, + compiler, + compilerTesting, + core, + coreTesting, + elements, + forms, + // See above + // http, + // httpTesting, + platformBrowser, + platformBrowserTesting, + platformBrowserDynamic, + platformBrowserDynamicTesting, + platformBrowserAnimations, + platformServer, + platformServerTesting, + platformWebworker, + platformWebworkerDynamic, + router, + routerTesting, + routerUpgrade, + serviceWorker, + upgrade, + upgradeStatic, + upgradeTesting, +}; diff --git a/integration/typings_test_ts37/package.json b/integration/typings_test_ts37/package.json new file mode 100644 index 0000000000..7e9fee12c9 --- /dev/null +++ b/integration/typings_test_ts37/package.json @@ -0,0 +1,30 @@ +{ + "name": "angular-integration", + "description": "Assert that users with TypeScript 3.7 can type-check an Angular application", + "version": "0.0.0", + "license": "MIT", + "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/elements": "file:../../dist/packages-dist/elements", + "@angular/forms": "file:../../dist/packages-dist/forms", + "@angular/platform-browser": "file:../../dist/packages-dist/platform-browser", + "@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic", + "@angular/platform-server": "file:../../dist/packages-dist/platform-server", + "@angular/platform-webworker": "file:../../dist/packages-dist/platform-webworker", + "@angular/platform-webworker-dynamic": "file:../../dist/packages-dist/platform-webworker-dynamic", + "@angular/router": "file:../../dist/packages-dist/router", + "@angular/service-worker": "file:../../dist/packages-dist/service-worker", + "@angular/upgrade": "file:../../dist/packages-dist/upgrade", + "@types/jasmine": "file:../../node_modules/@types/jasmine", + "rxjs": "file:../../node_modules/rxjs", + "typescript": "3.7.4", + "zone.js": "file:../../dist/zone.js-dist/zone.js" + }, + "scripts": { + "test": "tsc" + } +} diff --git a/integration/typings_test_ts37/tsconfig.json b/integration/typings_test_ts37/tsconfig.json new file mode 100644 index 0000000000..b220b236d5 --- /dev/null +++ b/integration/typings_test_ts37/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "strict": true, + "skipLibCheck": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "module": "commonjs", + "moduleResolution": "node", + "outDir": "../../dist/typings_test_ts37/", + "rootDir": ".", + "target": "es5", + "lib": [ + "es5", + "dom", + "es2015.collection", + "es2015.iterable", + "es2015.promise" + ], + "types": [], + }, + "files": [ + "include-all.ts", + "node_modules/@types/jasmine/index.d.ts" + ] +} diff --git a/integration/typings_test_ts37/yarn.lock b/integration/typings_test_ts37/yarn.lock new file mode 100644 index 0000000000..66d1842ebd --- /dev/null +++ b/integration/typings_test_ts37/yarn.lock @@ -0,0 +1,1332 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@angular/animations@file:../../dist/packages-dist/animations": + version "9.0.0-rc.1" + +"@angular/common@file:../../dist/packages-dist/common": + version "9.0.0-rc.1" + +"@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": + version "9.0.0-rc.1" + dependencies: + canonical-path "1.0.0" + chokidar "^2.1.1" + 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" + semver "^6.3.0" + source-map "^0.6.1" + yargs "13.1.0" + +"@angular/compiler@file:../../dist/packages-dist/compiler": + version "9.0.0-rc.1" + +"@angular/core@file:../../dist/packages-dist/core": + version "9.0.0-rc.1" + +"@angular/elements@file:../../dist/packages-dist/elements": + version "9.0.0-rc.1" + +"@angular/forms@file:../../dist/packages-dist/forms": + version "9.0.0-rc.1" + +"@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": + version "9.0.0-rc.1" + +"@angular/platform-browser@file:../../dist/packages-dist/platform-browser": + version "9.0.0-rc.1" + +"@angular/platform-server@file:../../dist/packages-dist/platform-server": + version "9.0.0-rc.1" + dependencies: + domino "^2.1.2" + xhr2 "^0.1.4" + +"@angular/platform-webworker-dynamic@file:../../dist/packages-dist/platform-webworker-dynamic": + version "9.0.0-rc.1" + +"@angular/platform-webworker@file:../../dist/packages-dist/platform-webworker": + version "9.0.0-rc.1" + +"@angular/router@file:../../dist/packages-dist/router": + version "9.0.0-rc.1" + +"@angular/service-worker@file:../../dist/packages-dist/service-worker": + version "9.0.0-rc.1" + +"@angular/upgrade@file:../../dist/packages-dist/upgrade": + version "9.0.0-rc.1" + +"@types/jasmine@file:../../node_modules/@types/jasmine": + version "2.8.8" + +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.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +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" + +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.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-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= + +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.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +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" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +braces@^2.3.1, braces@^2.3.2: + 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" + +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@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +canonical-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" + integrity sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg== + +chokidar@^2.1.1: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +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@^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" + +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" + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +convert-source-map@^1.5.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +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-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= + +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" + +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" + +decamelize@^1.2.0: + 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= + +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" + +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== + +domino@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.4.tgz#78922e7fab7c610f35792b6c745b7962d342e9c4" + integrity sha512-l70mlQ7IjPKC8kT7GljQXJZmt5OqFL+RE91ik5y5WWQtsd9wP8R7gpFnNu96fK5MqAAZRXfLLsnzKtkty5fWGQ== + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +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" + +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" + +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" + +file-uri-to-path@1.0.0: + 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== + +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" + +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" + +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= + +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" + +fsevents@^1.2.7: + version "1.2.11" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3" + integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stream@^4.0.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= + +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" + +graceful-fs@^4.1.11: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + +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" + +inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +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== + +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-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-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-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@^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-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@^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.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +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-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-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-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: + 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= + +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@^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" + +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" + +magic-string@^0.25.0: + version "0.25.5" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.5.tgz#694fa8c6b9a51d83cc4a72c5b6883a7cfa890e40" + integrity sha512-vIO/BOm9odBHBAGwv0gZPLJeO9IpwliiIc0uPeAW93rrFMJ/R3M665IAEfOU/IW3kD4S9AtEn76lfTn1Yif+9A== + dependencies: + sourcemap-codec "^1.4.4" + +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-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" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +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" + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +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" + +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== + +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-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +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" + +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= + +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.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" + +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" + +os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +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@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== + dependencies: + p-try "^2.0.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-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +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-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@^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-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= + +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= + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +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" + +readable-stream@^2.0.2: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + 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" + +readdirp@^2.2.1: + 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" + +reflect-metadata@^0.1.2: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +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" + +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.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +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@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +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= + +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== + +"rxjs@file:../../node_modules/rxjs": + version "6.5.3" + dependencies: + tslib "^1.9.0" + +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" + +semver@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +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@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.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= + +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= + +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-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.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" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + 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: + 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.4: + version "1.4.7" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.7.tgz#5b2cd184e3fe51fd30ba049f7f62bf499b4f73ae" + integrity sha512-RuN23NzhAOuUtaivhcrjXx1OPXsFeH9m5sI373/U7+tGLKihjUyboZAzOadytMjnqHp1f45RGk1IzDKCpDpSYA== + +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" + +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" + +string-width@^1.0.1: + 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.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-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string_decoder@~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.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-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= + +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" + +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +typescript@3.7.4: + version "3.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19" + integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +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.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +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= + +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= + +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" + +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= + +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== + +yargs-parser@^13.0.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.1.0.tgz#b2729ce4bfc0c584939719514099d8a916ad2301" + integrity sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg== + dependencies: + cliui "^4.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.0.0" + +"zone.js@file:../../dist/zone.js-dist/zone.js": + version "0.10.2" diff --git a/karma-js.conf.js b/karma-js.conf.js index a36a34ba6e..5f431c3c9f 100644 --- a/karma-js.conf.js +++ b/karma-js.conf.js @@ -152,9 +152,6 @@ module.exports = function(config) { set: () => {}, }); - // When running under Bazel with karma_web_test, SAUCE_TUNNEL_IDENTIFIER and KARMA_WEB_TEST_MODE - // will only be available if they are part of the Bazel action environment. More details in the - // "scripts/saucelabs/run-bazel-via-tunnel.sh" script. if (process.env['SAUCE_TUNNEL_IDENTIFIER']) { console.log(`SAUCE_TUNNEL_IDENTIFIER: ${process.env.SAUCE_TUNNEL_IDENTIFIER}`); diff --git a/modules/benchmarks/README.md b/modules/benchmarks/README.md index 2acb18b650..a6d01d208f 100644 --- a/modules/benchmarks/README.md +++ b/modules/benchmarks/README.md @@ -23,3 +23,23 @@ yarn bazel test modules/benchmarks/... 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. + +## Specifying benchmark options + +There are options that can be specified in order to control how a given benchmark target +runs. The following options can be set through [test environment variables](https://docs.bazel.build/versions/master/command-line-reference.html#flag--test_env): + +* `PERF_SAMPLE_SIZE`: Benchpress performs measurements until `scriptTime` predictively no longer + decreases. It does this by using a simple linear regression with the amount of samples specified. + Defaults to `20` samples. +* `PERF_FORCE_GC`: If set to `true`, `@angular/benchpress` will run run the garbage collector + before and after performing measurements. Benchpress will measure and report the garbage + collection time. +* `PERF_DRYRUN`: If set to `true`, no results are printed and stored in a `json` file. Also + benchpress only performs a single measurement (unlike with the simple linear regression). + +Here is an example command that sets the `PERF_DRYRUN` option: + +```bash +yarn bazel test modules/benchmarks/src/tree/baseline:perf --test_env=PERF_DRYRUN=true +``` \ No newline at end of file diff --git a/modules/benchmarks/benchmark_test.bzl b/modules/benchmarks/benchmark_test.bzl index 1c48ea441c..a6d6442004 100644 --- a/modules/benchmarks/benchmark_test.bzl +++ b/modules/benchmarks/benchmark_test.bzl @@ -3,10 +3,11 @@ load("//tools:defaults.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". + that sets up "@angular/benchpress". Benchmark test targets will not run on CI + unless explicitly requested. """ -def benchmark_test(name, server, deps, tags = []): +def benchmark_test(name, server, tags = [], **kwargs): protractor_web_test_suite( name = name, configuration = "//:protractor-perf.conf.js", @@ -15,8 +16,14 @@ def benchmark_test(name, server, deps, tags = []): ], on_prepare = "//modules/benchmarks:start-server.js", server = server, - tags = tags, - deps = [ - "@npm//yargs", - ] + deps, + # Benchmark targets should not run on CI by default. + tags = tags + [ + "manual", + "no-remote-exec", + ], + test_suite_tags = [ + "manual", + "no-remote-exec", + ], + **kwargs ) diff --git a/modules/benchmarks/e2e_test.bzl b/modules/benchmarks/e2e_test.bzl new file mode 100644 index 0000000000..0f405654dc --- /dev/null +++ b/modules/benchmarks/e2e_test.bzl @@ -0,0 +1,15 @@ +load("//tools:defaults.bzl", "protractor_web_test_suite") + +""" + Macro that can be used to define a e2e test in `modules/benchmarks`. Targets created through + this macro differentiate from a "benchmark_test" as they will run on CI and do not run + with `@angular/benchpress`. +""" + +def e2e_test(name, server, **kwargs): + protractor_web_test_suite( + name = name, + on_prepare = "//modules/benchmarks:start-server.js", + server = server, + **kwargs + ) diff --git a/modules/benchmarks/src/class_bindings/BUILD.bazel b/modules/benchmarks/src/class_bindings/BUILD.bazel index 7e7241c655..da310ba857 100644 --- a/modules/benchmarks/src/class_bindings/BUILD.bazel +++ b/modules/benchmarks/src/class_bindings/BUILD.bazel @@ -7,7 +7,7 @@ ng_module( name = "application_lib", srcs = glob( ["**/*.ts"], - exclude = ["**/*.spec.ts"], + exclude = ["**/*.perf-spec.ts"], ), generate_ve_shims = True, deps = [ @@ -22,7 +22,7 @@ ng_module( ts_library( name = "perf_lib", testonly = 1, - srcs = ["benchmark_perf.spec.ts"], + srcs = ["class_bindings.perf-spec.ts"], deps = [ "//modules/e2e_util", "@npm//protractor", diff --git a/modules/benchmarks/src/class_bindings/benchmark_perf.spec.ts b/modules/benchmarks/src/class_bindings/class_bindings.perf-spec.ts similarity index 95% rename from modules/benchmarks/src/class_bindings/benchmark_perf.spec.ts rename to modules/benchmarks/src/class_bindings/class_bindings.perf-spec.ts index 4dba88ccc2..f4c5991b01 100644 --- a/modules/benchmarks/src/class_bindings/benchmark_perf.spec.ts +++ b/modules/benchmarks/src/class_bindings/class_bindings.perf-spec.ts @@ -9,7 +9,7 @@ import {$, browser} from 'protractor'; import {runBenchmark} from '../../../e2e_util/perf_util'; -describe('benchmarks', () => { +describe('class bindings perf', () => { it('should work for update', done => { browser.rootEl = '#root'; diff --git a/modules/benchmarks/src/expanding_rows/BUILD.bazel b/modules/benchmarks/src/expanding_rows/BUILD.bazel index 68bc4a9b4a..20f72503e8 100644 --- a/modules/benchmarks/src/expanding_rows/BUILD.bazel +++ b/modules/benchmarks/src/expanding_rows/BUILD.bazel @@ -7,7 +7,7 @@ ng_module( name = "application_lib", srcs = glob( ["**/*.ts"], - exclude = ["**/*.spec.ts"], + exclude = ["**/*.perf-spec.ts"], ), generate_ve_shims = True, deps = [ @@ -23,7 +23,7 @@ ng_module( ts_library( name = "perf_lib", testonly = 1, - srcs = ["benchmark_perf.spec.ts"], + srcs = ["expanding_rows.perf-spec.ts"], deps = [ "//modules/e2e_util", "@npm//protractor", diff --git a/modules/benchmarks/src/expanding_rows/benchmark_perf.spec.ts b/modules/benchmarks/src/expanding_rows/expanding_rows.perf-spec.ts similarity index 100% rename from modules/benchmarks/src/expanding_rows/benchmark_perf.spec.ts rename to modules/benchmarks/src/expanding_rows/expanding_rows.perf-spec.ts diff --git a/modules/benchmarks/src/js-web-frameworks/BUILD.bazel b/modules/benchmarks/src/js-web-frameworks/BUILD.bazel index d319d9b297..8ffae59af6 100644 --- a/modules/benchmarks/src/js-web-frameworks/BUILD.bazel +++ b/modules/benchmarks/src/js-web-frameworks/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//visibility:public"]) ts_library( name = "perf_lib", testonly = True, - srcs = ["perf.spec.ts"], + srcs = ["js-web-frameworks.perf-spec.ts"], deps = [ "//modules/e2e_util", "@npm//protractor", diff --git a/modules/benchmarks/src/js-web-frameworks/perf.spec.ts b/modules/benchmarks/src/js-web-frameworks/js-web-frameworks.perf-spec.ts similarity index 100% rename from modules/benchmarks/src/js-web-frameworks/perf.spec.ts rename to modules/benchmarks/src/js-web-frameworks/js-web-frameworks.perf-spec.ts diff --git a/modules/benchmarks/src/largeform/BUILD.bazel b/modules/benchmarks/src/largeform/BUILD.bazel index 37cf09c97d..a6eb8b4679 100644 --- a/modules/benchmarks/src/largeform/BUILD.bazel +++ b/modules/benchmarks/src/largeform/BUILD.bazel @@ -3,13 +3,23 @@ package(default_visibility = ["//modules/benchmarks:__subpackages__"]) load("//tools:defaults.bzl", "ts_library") ts_library( - name = "tests_lib", + name = "perf_tests_lib", testonly = 1, - srcs = ["largeform_perf.spec.ts"], + srcs = ["largeform.perf-spec.ts"], + tsconfig = "//modules/benchmarks:tsconfig-e2e.json", + deps = [ + "//modules/e2e_util", + "@npm//protractor", + ], +) + +ts_library( + name = "e2e_tests_lib", + testonly = 1, + srcs = ["largeform.e2e-spec.ts"], tsconfig = "//modules/benchmarks:tsconfig-e2e.json", deps = [ "//modules/e2e_util", - "@npm//@types/jasminewd2", "@npm//protractor", ], ) diff --git a/modules/benchmarks/src/largeform/largeform.e2e-spec.ts b/modules/benchmarks/src/largeform/largeform.e2e-spec.ts new file mode 100644 index 0000000000..5cd7516a27 --- /dev/null +++ b/modules/benchmarks/src/largeform/largeform.e2e-spec.ts @@ -0,0 +1,29 @@ +/** + * @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 {$, By, element} from 'protractor'; + +import {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + +describe('largeform benchmark', () => { + + afterEach(verifyNoBrowserErrors); + + it('should work for ng2', async() => { + openBrowser({ + url: '/', + params: [{name: 'copies', value: 1}], + ignoreBrowserSynchronization: true, + }); + await $('#createDom').click(); + expect(await element.all(By.css('input[name=value0]')).get(0).getAttribute('value')) + .toBe('someValue0'); + await $('#destroyDom').click(); + expect(await element.all(By.css('input[name=value0]')).count()).toBe(0); + }); +}); diff --git a/modules/benchmarks/src/largeform/largeform_perf.spec.ts b/modules/benchmarks/src/largeform/largeform.perf-spec.ts similarity index 69% rename from modules/benchmarks/src/largeform/largeform_perf.spec.ts rename to modules/benchmarks/src/largeform/largeform.perf-spec.ts index 1210745425..b297d0455f 100644 --- a/modules/benchmarks/src/largeform/largeform_perf.spec.ts +++ b/modules/benchmarks/src/largeform/largeform.perf-spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {$, By, element} from 'protractor'; +import {$} from 'protractor'; -import {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; +import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; import {runBenchmark} from '../../../e2e_util/perf_util'; interface Worker { @@ -29,19 +29,6 @@ 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 => { diff --git a/modules/benchmarks/src/largeform/ng2/BUILD.bazel b/modules/benchmarks/src/largeform/ng2/BUILD.bazel index 17795aef4f..51db615c78 100644 --- a/modules/benchmarks/src/largeform/ng2/BUILD.bazel +++ b/modules/benchmarks/src/largeform/ng2/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ng_module", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -38,5 +39,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/largeform:tests_lib"], + deps = ["//modules/benchmarks/src/largeform:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/largeform:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/largetable/BUILD.bazel b/modules/benchmarks/src/largetable/BUILD.bazel index cc00b3f5b8..43be9bd533 100644 --- a/modules/benchmarks/src/largetable/BUILD.bazel +++ b/modules/benchmarks/src/largetable/BUILD.bazel @@ -9,9 +9,20 @@ ts_library( ) ts_library( - name = "perf_lib", + name = "perf_tests_lib", testonly = 1, - srcs = ["largetable_perf.spec.ts"], + srcs = ["largetable.perf-spec.ts"], + deps = [ + "//modules/e2e_util", + "@npm//protractor", + ], +) + +ts_library( + name = "e2e_tests_lib", + testonly = 1, + srcs = ["largetable.e2e-spec.ts"], + tsconfig = "//modules/benchmarks:tsconfig-e2e.json", deps = [ "//modules/e2e_util", "@npm//protractor", diff --git a/modules/benchmarks/src/largetable/baseline/BUILD.bazel b/modules/benchmarks/src/largetable/baseline/BUILD.bazel index 598023d11e..8c8398db7e 100644 --- a/modules/benchmarks/src/largetable/baseline/BUILD.bazel +++ b/modules/benchmarks/src/largetable/baseline/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -24,5 +25,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/largetable:perf_lib"], + deps = ["//modules/benchmarks/src/largetable:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/largetable/incremental_dom/BUILD.bazel b/modules/benchmarks/src/largetable/incremental_dom/BUILD.bazel index 101abd7747..6d63f067d3 100644 --- a/modules/benchmarks/src/largetable/incremental_dom/BUILD.bazel +++ b/modules/benchmarks/src/largetable/incremental_dom/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -27,5 +28,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/largetable:perf_lib"], + deps = ["//modules/benchmarks/src/largetable:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/largetable/iv/BUILD.bazel b/modules/benchmarks/src/largetable/iv/BUILD.bazel index 4b2719162a..841a298e6c 100644 --- a/modules/benchmarks/src/largetable/iv/BUILD.bazel +++ b/modules/benchmarks/src/largetable/iv/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -13,5 +14,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/largetable:perf_lib"], + deps = ["//modules/benchmarks/src/largetable:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/largetable/largetable.e2e-spec.ts b/modules/benchmarks/src/largetable/largetable.e2e-spec.ts new file mode 100644 index 0000000000..2e3f1a0e76 --- /dev/null +++ b/modules/benchmarks/src/largetable/largetable.e2e-spec.ts @@ -0,0 +1,29 @@ +/** + * @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 {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; + +describe('largetable benchmark', () => { + afterEach(verifyNoBrowserErrors); + + it(`should render the table`, () => { + openBrowser({ + url: '', + ignoreBrowserSynchronization: true, + 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() as any).toEqual(''); + }); +}); diff --git a/modules/benchmarks/src/largetable/largetable_perf.spec.ts b/modules/benchmarks/src/largetable/largetable.perf-spec.ts similarity index 81% rename from modules/benchmarks/src/largetable/largetable_perf.spec.ts rename to modules/benchmarks/src/largetable/largetable.perf-spec.ts index 6e9bdfe788..de90152786 100644 --- a/modules/benchmarks/src/largetable/largetable_perf.spec.ts +++ b/modules/benchmarks/src/largetable/largetable.perf-spec.ts @@ -7,8 +7,6 @@ */ import {$} from 'protractor'; - -import {openBrowser} from '../../../e2e_util/e2e_util'; import {runBenchmark, verifyNoBrowserErrors} from '../../../e2e_util/perf_util'; interface Worker { @@ -48,20 +46,6 @@ describe('largetable benchmark perf', () => { afterEach(verifyNoBrowserErrors); - it(`should render the table for ${testPackageName}`, () => { - openBrowser({ - url: '', - ignoreBrowserSynchronization: true, - 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() as any).toEqual(''); - }); - [CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => { describe(worker.id, () => { it(`should run benchmark for ${testPackageName}`, done => { diff --git a/modules/benchmarks/src/largetable/ng2/BUILD.bazel b/modules/benchmarks/src/largetable/ng2/BUILD.bazel index c45828fb28..b52ad6b173 100644 --- a/modules/benchmarks/src/largetable/ng2/BUILD.bazel +++ b/modules/benchmarks/src/largetable/ng2/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -40,5 +41,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":prodserver", - deps = ["//modules/benchmarks/src/largetable:perf_lib"], + deps = ["//modules/benchmarks/src/largetable:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":prodserver", + deps = ["//modules/benchmarks/src/largetable:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/largetable/ng2_switch/BUILD.bazel b/modules/benchmarks/src/largetable/ng2_switch/BUILD.bazel index ca73d1c71a..555ecab562 100644 --- a/modules/benchmarks/src/largetable/ng2_switch/BUILD.bazel +++ b/modules/benchmarks/src/largetable/ng2_switch/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ng_module", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -36,5 +37,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/largetable:perf_lib"], + deps = ["//modules/benchmarks/src/largetable:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/largetable:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/largetable/render3/BUILD.bazel b/modules/benchmarks/src/largetable/render3/BUILD.bazel index 14def7df43..ab6f33646d 100644 --- a/modules/benchmarks/src/largetable/render3/BUILD.bazel +++ b/modules/benchmarks/src/largetable/render3/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") ng_module( name = "largetable_lib", @@ -43,5 +44,12 @@ benchmark_test( name = "perf", server = ":devserver", tags = ["ivy-only"], - deps = ["//modules/benchmarks/src/largetable:perf_lib"], + deps = ["//modules/benchmarks/src/largetable:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + tags = ["ivy-only"], + deps = ["//modules/benchmarks/src/largetable:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/styling/BUILD.bazel b/modules/benchmarks/src/styling/BUILD.bazel new file mode 100644 index 0000000000..4a77b559f2 --- /dev/null +++ b/modules/benchmarks/src/styling/BUILD.bazel @@ -0,0 +1,14 @@ +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "tests_lib", + testonly = True, + srcs = ["styling_perf.spec.ts"], + tsconfig = "//modules/benchmarks:tsconfig-e2e.json", + deps = [ + "//modules/e2e_util", + "@npm//protractor", + ], +) diff --git a/modules/benchmarks/src/styling/ng2/BUILD.bazel b/modules/benchmarks/src/styling/ng2/BUILD.bazel new file mode 100644 index 0000000000..4f077ae02b --- /dev/null +++ b/modules/benchmarks/src/styling/ng2/BUILD.bazel @@ -0,0 +1,39 @@ +load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle", "ts_devserver") +load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") + +package(default_visibility = ["//modules/benchmarks:__subpackages__"]) + +ng_module( + name = "ng2", + srcs = glob(["*.ts"]), + generate_ve_shims = True, + tsconfig = "//modules/benchmarks:tsconfig-build.json", + deps = [ + "//modules/benchmarks/src:util_lib", + "//packages/core", + "//packages/platform-browser", + ], +) + +ng_rollup_bundle( + name = "bundle", + entry_point = ":index_aot.ts", + deps = [ + ":ng2", + "@npm//rxjs", + ], +) + +ts_devserver( + name = "prodserver", + bootstrap = ["//packages/zone.js/dist:zone.js"], + port = 4200, + static_files = ["index.html"], + deps = [":bundle.min_debug.es2015.js"], +) + +benchmark_test( + name = "perf", + server = ":prodserver", + deps = ["//modules/benchmarks/src/styling:tests_lib"], +) diff --git a/modules/benchmarks/src/styling/ng2/index.html b/modules/benchmarks/src/styling/ng2/index.html new file mode 100644 index 0000000000..e54fe08367 --- /dev/null +++ b/modules/benchmarks/src/styling/ng2/index.html @@ -0,0 +1,49 @@ + + + + + + + + + + +

Styling bindings benchmark

+

+ + + + + + + + + +

+ +
+ Loading... +
+ + + + + + \ No newline at end of file diff --git a/modules/benchmarks/src/styling/ng2/index_aot.ts b/modules/benchmarks/src/styling/ng2/index_aot.ts new file mode 100644 index 0000000000..e9064fe144 --- /dev/null +++ b/modules/benchmarks/src/styling/ng2/index_aot.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 {enableProdMode} from '@angular/core'; +import {platformBrowser} from '@angular/platform-browser'; + +import {init} from './init'; +import {StylingModuleNgFactory} from './styling.ngfactory'; + +enableProdMode(); +platformBrowser().bootstrapModuleFactory(StylingModuleNgFactory).then(init); diff --git a/modules/benchmarks/src/styling/ng2/init.ts b/modules/benchmarks/src/styling/ng2/init.ts new file mode 100644 index 0000000000..e7816d80f8 --- /dev/null +++ b/modules/benchmarks/src/styling/ng2/init.ts @@ -0,0 +1,73 @@ +/** + * @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, NgModuleRef} from '@angular/core'; +import {bindAction, profile} from '../../util'; +import {StylingModule} from './styling'; + +const empty = []; +const items = []; +for (let i = 0; i < 2000; i++) { + items.push(i); +} + + +export function init(moduleRef: NgModuleRef) { + const injector = moduleRef.injector; + const appRef = injector.get(ApplicationRef); + const componentRef = appRef.components[0]; + const component = componentRef.instance; + const componentHostEl = componentRef.location.nativeElement; + const select = document.querySelector('#scenario-select') !as HTMLSelectElement; + + function create(tplRefIdx: number) { + component.tplRefIdx = tplRefIdx; + component.data = items; + appRef.tick(); + } + + function destroy() { + component.data = empty; + appRef.tick(); + } + + function update() { + component.exp = component.exp === 'bar' ? 'baz' : 'bar'; + appRef.tick(); + } + + function detectChanges() { appRef.tick(); } + + function modifyExternally() { + const buttonEls = componentHostEl.querySelectorAll('button') as HTMLButtonElement[]; + buttonEls.forEach((buttonEl: HTMLButtonElement) => { + const cl = buttonEl.classList; + if (cl.contains('external')) { + cl.remove('external'); + } else { + cl.add('external'); + } + }); + } + + bindAction('#create', () => create(select.selectedIndex)); + bindAction('#update', update); + bindAction('#detect_changes', detectChanges); + bindAction('#destroy', destroy); + bindAction('#profile_update', profile(() => { + for (let i = 0; i < 10; i++) { + update(); + } + }, () => {}, 'update and detect changes')); + bindAction('#profile_detect_changes', profile(() => { + for (let i = 0; i < 10; i++) { + detectChanges(); + } + }, () => {}, 'noop detect changes')); + bindAction('#modify', modifyExternally); +} diff --git a/modules/benchmarks/src/styling/ng2/styling.ts b/modules/benchmarks/src/styling/ng2/styling.ts new file mode 100644 index 0000000000..b669654ae7 --- /dev/null +++ b/modules/benchmarks/src/styling/ng2/styling.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 {Component, NgModule, TemplateRef} from '@angular/core'; +import {BrowserModule} from '@angular/platform-browser'; + +@Component({ + selector: 'styling-bindings', + template: ` + + + + + + + + + + + + +
+ +
+ ` +}) +export class StylingComponent { + data: number[] = []; + exp: string = 'bar'; + tplRefIdx: number = 0; + staticStyle = {width: '10px'}; + + getTplRef(...tplRefs): TemplateRef { return tplRefs[this.tplRefIdx]; } +} + +@NgModule({ + imports: [BrowserModule], + declarations: [StylingComponent], + bootstrap: [StylingComponent], +}) +export class StylingModule { +} \ No newline at end of file diff --git a/modules/benchmarks/src/styling/styling_perf.spec.ts b/modules/benchmarks/src/styling/styling_perf.spec.ts new file mode 100644 index 0000000000..5592e17da5 --- /dev/null +++ b/modules/benchmarks/src/styling/styling_perf.spec.ts @@ -0,0 +1,121 @@ +/** + * @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 {$, by, element} from 'protractor'; +import {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; +import {runBenchmark} from '../../../e2e_util/perf_util'; + +/** List of possible scenarios that should be tested. */ +const SCENARIOS = [ + {optionIndex: 0, id: 'no_styling_involved'}, + {optionIndex: 1, id: 'static_class'}, + {optionIndex: 2, id: 'static_class_with_interpolation'}, + {optionIndex: 3, id: 'class_binding'}, + {optionIndex: 4, id: 'static_class_and_class_binding'}, + {optionIndex: 5, id: 'static_class_and_ngclass_binding'}, + {optionIndex: 6, id: 'static_class_and_ngstyle_binding_and_style_binding'}, + {optionIndex: 7, id: 'static_style'}, + {optionIndex: 8, id: 'style_property_bindings'}, + {optionIndex: 9, id: 'static_style_and_property_binding'}, + {optionIndex: 10, id: 'ng_style_with_units'}, +]; + +describe('styling benchmark spec', () => { + afterEach(verifyNoBrowserErrors); + + it('should render and interact to update and detect changes', async() => { + openBrowser({url: '/', ignoreBrowserSynchronization: true}); + create(); + const items = element.all(by.css('styling-bindings button')); + expect(await items.count()).toBe(2000); + expect(await items.first().getAttribute('title')).toBe('bar'); + update(); + expect(await items.first().getAttribute('title')).toBe('baz'); + }); + + it('should render and run noop change detection', async() => { + openBrowser({url: '/', ignoreBrowserSynchronization: true}); + create(); + const items = element.all(by.css('styling-bindings button')); + expect(await items.count()).toBe(2000); + expect(await items.first().getAttribute('title')).toBe('bar'); + detectChanges(); + expect(await items.first().getAttribute('title')).toBe('bar'); + }); + + // Create benchmarks for each possible test scenario. + SCENARIOS.forEach(({optionIndex, id}) => { + describe(id, () => { + it('should run create benchmark', done => { + runStylingBenchmark(`styling.${id}.create`, { + work: () => create(), + prepare: () => { + selectScenario(optionIndex); + destroy(); + }, + }).then(done, done.fail); + }); + + it('should run update benchmark', done => { + runStylingBenchmark(`styling.${id}.update`, { + work: () => update(), + prepare: () => { + selectScenario(optionIndex); + create(); + }, + }).then(done, done.fail); + }); + + it('should run detect changes benchmark', done => { + runStylingBenchmark(`styling.${id}.noop_cd`, { + work: () => detectChanges(), + prepare: () => { + selectScenario(optionIndex); + create(); + }, + }).then(done, done.fail); + }); + }); + }); +}); + +function selectScenario(optionIndex: number) { + // Switch to the current scenario by clicking the corresponding option. + element.all(by.tagName('option')).get(optionIndex).click(); +} + +function create() { + $('#create').click(); +} + +function destroy() { + $('#destroy').click(); +} + +function update() { + $('#update').click(); +} + +function detectChanges() { + $('#detect_changes').click(); +} + +/** + * Runs the styling benchmark with the given id and worker. The worker describes + * the actions that should run for preparation and measurement. + */ +function runStylingBenchmark(id: string, worker: {prepare: () => void, work: () => void}) { + return runBenchmark({ + id, + url: '/', + params: [], + ignoreBrowserSynchronization: true, + prepare: worker.prepare, + work: worker.work + }); +} diff --git a/modules/benchmarks/src/tree/BUILD.bazel b/modules/benchmarks/src/tree/BUILD.bazel index 3a7c4d5f01..f8a0865772 100644 --- a/modules/benchmarks/src/tree/BUILD.bazel +++ b/modules/benchmarks/src/tree/BUILD.bazel @@ -11,7 +11,7 @@ ts_library( ts_library( name = "test_utils_lib", testonly = 1, - srcs = ["tree_perf_test_utils.ts"], + srcs = ["test_utils.ts"], deps = [ "//modules/e2e_util", "@npm//protractor", @@ -19,9 +19,9 @@ ts_library( ) ts_library( - name = "perf_lib", + name = "perf_tests_lib", testonly = 1, - srcs = ["tree_perf.spec.ts"], + srcs = ["tree.perf-spec.ts"], deps = [ ":test_utils_lib", "@npm//protractor", @@ -29,9 +29,29 @@ ts_library( ) ts_library( - name = "perf_detect_changes_lib", + name = "e2e_tests_lib", testonly = 1, - srcs = ["tree_perf_detect_changes.spec.ts"], + srcs = ["tree.e2e-spec.ts"], + deps = [ + ":test_utils_lib", + "@npm//protractor", + ], +) + +ts_library( + name = "detect_changes_perf_tests_lib", + testonly = 1, + srcs = ["tree_detect_changes.perf-spec.ts"], + deps = [ + ":test_utils_lib", + "@npm//protractor", + ], +) + +ts_library( + name = "detect_changes_e2e_tests_lib", + testonly = 1, + srcs = ["tree_detect_changes.e2e-spec.ts"], deps = [ ":test_utils_lib", "@npm//protractor", diff --git a/modules/benchmarks/src/tree/baseline/BUILD.bazel b/modules/benchmarks/src/tree/baseline/BUILD.bazel index a984c896b8..7a6b37ef3d 100644 --- a/modules/benchmarks/src/tree/baseline/BUILD.bazel +++ b/modules/benchmarks/src/tree/baseline/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -24,5 +25,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/tree:perf_lib"], + deps = ["//modules/benchmarks/src/tree:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/tree/incremental_dom/BUILD.bazel b/modules/benchmarks/src/tree/incremental_dom/BUILD.bazel index a4cf28a9bb..b99a6d5839 100644 --- a/modules/benchmarks/src/tree/incremental_dom/BUILD.bazel +++ b/modules/benchmarks/src/tree/incremental_dom/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -28,5 +29,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/tree:perf_lib"], + deps = ["//modules/benchmarks/src/tree:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/tree/iv/BUILD.bazel b/modules/benchmarks/src/tree/iv/BUILD.bazel index 762eb1af0b..f7efff307a 100644 --- a/modules/benchmarks/src/tree/iv/BUILD.bazel +++ b/modules/benchmarks/src/tree/iv/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -14,7 +15,16 @@ benchmark_test( name = "perf", server = ":devserver", deps = [ - "//modules/benchmarks/src/tree:perf_detect_changes_lib", - "//modules/benchmarks/src/tree:perf_lib", + "//modules/benchmarks/src/tree:detect_changes_perf_tests_lib", + "//modules/benchmarks/src/tree:perf_tests_lib", + ], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:detect_changes_e2e_tests_lib", + "//modules/benchmarks/src/tree:e2e_tests_lib", ], ) diff --git a/modules/benchmarks/src/tree/ng1/BUILD.bazel b/modules/benchmarks/src/tree/ng1/BUILD.bazel index 87c9dcf3e9..b9d4a71f66 100644 --- a/modules/benchmarks/src/tree/ng1/BUILD.bazel +++ b/modules/benchmarks/src/tree/ng1/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -26,7 +27,16 @@ benchmark_test( name = "perf", server = ":devserver", deps = [ - "//modules/benchmarks/src/tree:perf_detect_changes_lib", - "//modules/benchmarks/src/tree:perf_lib", + "//modules/benchmarks/src/tree:detect_changes_perf_tests_lib", + "//modules/benchmarks/src/tree:perf_tests_lib", + ], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:detect_changes_e2e_tests_lib", + "//modules/benchmarks/src/tree:e2e_tests_lib", ], ) diff --git a/modules/benchmarks/src/tree/ng2/BUILD.bazel b/modules/benchmarks/src/tree/ng2/BUILD.bazel index fb4c652fac..9765e5b1ea 100644 --- a/modules/benchmarks/src/tree/ng2/BUILD.bazel +++ b/modules/benchmarks/src/tree/ng2/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -41,7 +42,16 @@ benchmark_test( name = "perf", server = ":prodserver", deps = [ - "//modules/benchmarks/src/tree:perf_detect_changes_lib", - "//modules/benchmarks/src/tree:perf_lib", + "//modules/benchmarks/src/tree:detect_changes_perf_tests_lib", + "//modules/benchmarks/src/tree:perf_tests_lib", + ], +) + +e2e_test( + name = "e2e", + server = ":prodserver", + deps = [ + "//modules/benchmarks/src/tree:detect_changes_e2e_tests_lib", + "//modules/benchmarks/src/tree:e2e_tests_lib", ], ) diff --git a/modules/benchmarks/src/tree/ng2_next/BUILD.bazel b/modules/benchmarks/src/tree/ng2_next/BUILD.bazel index 1157a1ef7e..a678099e4d 100644 --- a/modules/benchmarks/src/tree/ng2_next/BUILD.bazel +++ b/modules/benchmarks/src/tree/ng2_next/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -32,7 +33,16 @@ benchmark_test( name = "perf", server = ":devserver", deps = [ - "//modules/benchmarks/src/tree:perf_detect_changes_lib", - "//modules/benchmarks/src/tree:perf_lib", + "//modules/benchmarks/src/tree:detect_changes_perf_tests_lib", + "//modules/benchmarks/src/tree:perf_tests_lib", + ], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:detect_changes_e2e_tests_lib", + "//modules/benchmarks/src/tree:e2e_tests_lib", ], ) diff --git a/modules/benchmarks/src/tree/ng2_static/BUILD.bazel b/modules/benchmarks/src/tree/ng2_static/BUILD.bazel index 42857ef098..99167f1cb1 100644 --- a/modules/benchmarks/src/tree/ng2_static/BUILD.bazel +++ b/modules/benchmarks/src/tree/ng2_static/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -35,5 +36,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/tree:perf_lib"], + deps = ["//modules/benchmarks/src/tree:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/tree/ng2_switch/BUILD.bazel b/modules/benchmarks/src/tree/ng2_switch/BUILD.bazel index 4963ab9841..4c1e8cb933 100644 --- a/modules/benchmarks/src/tree/ng2_switch/BUILD.bazel +++ b/modules/benchmarks/src/tree/ng2_switch/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ng_module", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -36,5 +37,11 @@ ts_devserver( benchmark_test( name = "perf", server = ":devserver", - deps = ["//modules/benchmarks/src/tree:perf_lib"], + deps = ["//modules/benchmarks/src/tree:perf_tests_lib"], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = ["//modules/benchmarks/src/tree:e2e_tests_lib"], ) diff --git a/modules/benchmarks/src/tree/render3/BUILD.bazel b/modules/benchmarks/src/tree/render3/BUILD.bazel index 4864135e35..ecfad4e8b9 100644 --- a/modules/benchmarks/src/tree/render3/BUILD.bazel +++ b/modules/benchmarks/src/tree/render3/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//modules/benchmarks:__subpackages__"]) load("//tools:defaults.bzl", "ng_module", "ng_rollup_bundle", "ts_devserver") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") ng_module( name = "tree_lib", @@ -41,7 +42,17 @@ benchmark_test( server = ":devserver", tags = ["ivy-only"], deps = [ - "//modules/benchmarks/src/tree:perf_detect_changes_lib", - "//modules/benchmarks/src/tree:perf_lib", + "//modules/benchmarks/src/tree:detect_changes_perf_tests_lib", + "//modules/benchmarks/src/tree:perf_tests_lib", + ], +) + +e2e_test( + name = "e2e", + server = ":devserver", + tags = ["ivy-only"], + deps = [ + "//modules/benchmarks/src/tree:detect_changes_e2e_tests_lib", + "//modules/benchmarks/src/tree:e2e_tests_lib", ], ) diff --git a/modules/benchmarks/src/tree/render3_function/BUILD.bazel b/modules/benchmarks/src/tree/render3_function/BUILD.bazel index 3a9145142c..da9ec7ecb2 100644 --- a/modules/benchmarks/src/tree/render3_function/BUILD.bazel +++ b/modules/benchmarks/src/tree/render3_function/BUILD.bazel @@ -1,5 +1,6 @@ load("//tools:defaults.bzl", "ts_devserver", "ts_library") load("//modules/benchmarks:benchmark_test.bzl", "benchmark_test") +load("//modules/benchmarks:e2e_test.bzl", "e2e_test") package(default_visibility = ["//modules/benchmarks:__subpackages__"]) @@ -30,7 +31,16 @@ benchmark_test( name = "perf", server = ":devserver", deps = [ - "//modules/benchmarks/src/tree:perf_detect_changes_lib", - "//modules/benchmarks/src/tree:perf_lib", + "//modules/benchmarks/src/tree:detect_changes_perf_tests_lib", + "//modules/benchmarks/src/tree:perf_tests_lib", + ], +) + +e2e_test( + name = "e2e", + server = ":devserver", + deps = [ + "//modules/benchmarks/src/tree:detect_changes_e2e_tests_lib", + "//modules/benchmarks/src/tree:e2e_tests_lib", ], ) diff --git a/modules/benchmarks/src/tree/render3_function/index.ts b/modules/benchmarks/src/tree/render3_function/index.ts index 4a9f9394c4..32be3be0b8 100644 --- a/modules/benchmarks/src/tree/render3_function/index.ts +++ b/modules/benchmarks/src/tree/render3_function/index.ts @@ -25,7 +25,7 @@ export class TreeFunction { type: TreeFunction, selectors: [['tree']], decls: 5, - vars: 1, + vars: 2, template: function(rf: ɵRenderFlags, ctx: TreeFunction) { // bit of a hack TreeTpl(rf, ctx.data); @@ -34,6 +34,7 @@ export class TreeFunction { }); } +const TreeFunctionCmpDef = TreeFunction.ɵcmp as{decls: number, vars: number}; export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { if (rf & ɵRenderFlags.Create) { ɵɵelementStart(0, 'tree'); @@ -54,7 +55,7 @@ export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { ɵɵcontainerRefreshStart(3); { if (ctx.left != null) { - let rf0 = ɵɵembeddedViewStart(0, 5, 1); + let rf0 = ɵɵembeddedViewStart(0, 5, 2); { TreeTpl(rf0, ctx.left); } ɵɵembeddedViewEnd(); } @@ -63,7 +64,7 @@ export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { ɵɵcontainerRefreshStart(4); { if (ctx.right != null) { - let rf0 = ɵɵembeddedViewStart(0, 5, 1); + let rf0 = ɵɵembeddedViewStart(0, TreeFunctionCmpDef.decls, TreeFunctionCmpDef.vars); { TreeTpl(rf0, ctx.right); } ɵɵembeddedViewEnd(); } diff --git a/modules/benchmarks/src/tree/tree_perf_test_utils.ts b/modules/benchmarks/src/tree/test_utils.ts similarity index 100% rename from modules/benchmarks/src/tree/tree_perf_test_utils.ts rename to modules/benchmarks/src/tree/test_utils.ts diff --git a/modules/benchmarks/src/tree/tree.e2e-spec.ts b/modules/benchmarks/src/tree/tree.e2e-spec.ts new file mode 100644 index 0000000000..0f9c2963cf --- /dev/null +++ b/modules/benchmarks/src/tree/tree.e2e-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} from './test_utils'; + +describe('tree benchmark', () => { + it('should work for createDestroy', () => { + openTreeBenchmark(); + $('#createDom').click(); + expect($('#root').getText()).toContain('1'); + $('#destroyDom').click(); + expect($('#root').getText() as any).toEqual(''); + }); + + it('should work for update', () => { + openTreeBenchmark(); + $('#createDom').click(); + $('#createDom').click(); + expect($('#root').getText()).toContain('A'); + }); +}); diff --git a/modules/benchmarks/src/tree/tree_perf.spec.ts b/modules/benchmarks/src/tree/tree.perf-spec.ts similarity index 71% rename from modules/benchmarks/src/tree/tree_perf.spec.ts rename to modules/benchmarks/src/tree/tree.perf-spec.ts index 1b4881c5e3..74d02e019f 100644 --- a/modules/benchmarks/src/tree/tree_perf.spec.ts +++ b/modules/benchmarks/src/tree/tree.perf-spec.ts @@ -7,27 +7,9 @@ */ import {$} from 'protractor'; -import {openTreeBenchmark, runTreeBenchmark} from './tree_perf_test_utils'; - -describe('benchmark render', () => { - it('should work for createDestroy', () => { - openTreeBenchmark(); - $('#createDom').click(); - expect($('#root').getText()).toContain('0'); - $('#destroyDom').click(); - expect($('#root').getText() as any).toEqual(''); - }); - - it('should work for update', () => { - openTreeBenchmark(); - $('#createDom').click(); - $('#createDom').click(); - expect($('#root').getText()).toContain('A'); - }); -}); - -describe('benchmarks', () => { +import {runTreeBenchmark} from './test_utils'; +describe('tree benchmark perf', () => { it('should work for createOnly', done => { runTreeBenchmark({ // This cannot be called "createOnly" because the actual destroy benchmark diff --git a/modules/benchmarks/src/tree/tree_detect_changes.e2e-spec.ts b/modules/benchmarks/src/tree/tree_detect_changes.e2e-spec.ts new file mode 100644 index 0000000000..b85d8a71c5 --- /dev/null +++ b/modules/benchmarks/src/tree/tree_detect_changes.e2e-spec.ts @@ -0,0 +1,19 @@ +/** + * @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} from './test_utils'; + +describe('tree benchmark detect changes', () => { + it('should work for detectChanges', () => { + openTreeBenchmark(); + $('#detectChanges').click(); + expect($('#numberOfChecks').getText()).toContain('10'); + }); +}); diff --git a/modules/benchmarks/src/tree/tree_perf_detect_changes.spec.ts b/modules/benchmarks/src/tree/tree_detect_changes.perf-spec.ts similarity index 58% rename from modules/benchmarks/src/tree/tree_perf_detect_changes.spec.ts rename to modules/benchmarks/src/tree/tree_detect_changes.perf-spec.ts index 9b744d2bac..822491e619 100644 --- a/modules/benchmarks/src/tree/tree_perf_detect_changes.spec.ts +++ b/modules/benchmarks/src/tree/tree_detect_changes.perf-spec.ts @@ -7,17 +7,9 @@ */ import {$} from 'protractor'; -import {openTreeBenchmark, runTreeBenchmark} from './tree_perf_test_utils'; +import {runTreeBenchmark} from './test_utils'; -describe('benchmark render', () => { - it('should work for detectChanges', () => { - openTreeBenchmark(); - $('#detectChanges').click(); - expect($('#numberOfChecks').getText()).toContain('10'); - }); -}); - -describe('benchmarks', () => { +describe('tree benchmark detect changes perf', () => { it('should work for detectChanges', async() => { await runTreeBenchmark({ id: 'detectChanges', diff --git a/modules/benchmarks/tsconfig-e2e.json b/modules/benchmarks/tsconfig-e2e.json index ed38112bb4..aa1068feae 100644 --- a/modules/benchmarks/tsconfig-e2e.json +++ b/modules/benchmarks/tsconfig-e2e.json @@ -1,6 +1,6 @@ { "compilerOptions": { "lib": ["es2015"], - "types": ["node", "jasminewd2"] + "types": ["node", "jasmine"] } } diff --git a/modules/benchmarks/tsconfig.json b/modules/benchmarks/tsconfig.json new file mode 100644 index 0000000000..2a5b97245d --- /dev/null +++ b/modules/benchmarks/tsconfig.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "module": "commonjs", + "moduleResolution": "node", + "outDir": "../../dist/all/", + "noImplicitAny": true, + "noFallthroughCasesInSwitch": true, + "paths": { + "selenium-webdriver": ["../../node_modules/@types/selenium-webdriver/index.d.ts"], + "rxjs/*": ["../../node_modules/rxjs/*"], + "@angular/*": ["../../packages/*"], + "zone.js/*": ["../../packages/zone.js/*"], + "e2e_util/*": ["../e2e_util/*"] + }, + "rootDir": ".", + "inlineSourceMap": true, + "lib": ["es5", "DOM", "ScriptHost"], + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "target": "es5", + "types": ["angular", "jasmine"] + }, + "angularCompilerOptions": { + "skipTemplateCodegen": true + }, + "rules": { + "no-floating-promises": true, + "no-unused-expression": true, + "no-unused-variable": true + } +} diff --git a/modules/e2e_util/e2e_util.ts b/modules/e2e_util/e2e_util.ts index d0e9c1e8fd..f9d3ffeff5 100644 --- a/modules/e2e_util/e2e_util.ts +++ b/modules/e2e_util/e2e_util.ts @@ -8,28 +8,10 @@ /* tslint:disable:no-console */ import {browser} from 'protractor'; - -const yargs = require('yargs'); import * as webdriver from 'selenium-webdriver'; -let cmdArgs: {'bundles': boolean}; - declare var expect: any; -export function readCommandLine(extraOptions?: {[key: string]: any}) { - const options: {[key: string]: any} = { - 'bundles': {describe: 'Whether to use the angular bundles or not.', default: false} - }; - if (extraOptions) { - for (const key in extraOptions) { - options[key] = extraOptions[key]; - } - } - - cmdArgs = yargs.usage('Angular e2e test options.').options(options).help('ng-help').wrap(40).argv; - return cmdArgs; -} - export function openBrowser(config: { url: string, params?: {name: string, value: any}[], @@ -38,13 +20,10 @@ export function openBrowser(config: { if (config.ignoreBrowserSynchronization) { browser.ignoreSynchronization = true; } - let params = config.params || []; - if (!params.some((param) => param.name === 'bundles')) { - params = params.concat([{name: 'bundles', value: cmdArgs.bundles}]); - } - const urlParams: string[] = []; - params.forEach((param) => { urlParams.push(param.name + '=' + param.value); }); + if (config.params) { + config.params.forEach((param) => urlParams.push(param.name + '=' + param.value)); + } const url = encodeURI(config.url + '?' + urlParams.join('&')); browser.get(url); if (config.ignoreBrowserSynchronization) { diff --git a/modules/e2e_util/perf_util.ts b/modules/e2e_util/perf_util.ts index 2b6b85ee6a..c2970e02a8 100644 --- a/modules/e2e_util/perf_util.ts +++ b/modules/e2e_util/perf_util.ts @@ -11,20 +11,16 @@ const nodeUuid = require('node-uuid'); import * as fs from 'fs-extra'; import {SeleniumWebDriverAdapter, Options, JsonFileReporter, Validator, RegressionSlopeValidator, ConsoleReporter, SizeValidator, MultiReporter, MultiMetric, Runner, StaticProvider} from '@angular/benchpress'; -import {readCommandLine as readE2eCommandLine, openBrowser} from './e2e_util'; +import {openBrowser} from './e2e_util'; -let cmdArgs: {'sample-size': number, 'force-gc': boolean, 'dryrun': boolean, 'bundles': boolean}; -let runner: Runner; +// Note: Keep the `modules/benchmarks/README.md` file in sync with the supported options. +const globalOptions = { + sampleSize: process.env.PERF_SAMPLE_SIZE || 20, + forceGc: process.env.PERF_FORCE_GC === 'true', + dryRun: process.env.PERF_DRYRUN === 'true', +}; -export function readCommandLine() { - cmdArgs = readE2eCommandLine({ - 'sample-size': {describe: 'Used for perf: sample size.', default: 20}, - 'force-gc': {describe: 'Used for perf: force gc.', default: false, type: 'boolean'}, - 'dryrun': {describe: 'If true, only run performance benchmarks once.', default: false}, - 'bundles': {describe: 'Whether to use the angular bundles or not.', default: false} - }); - runner = createBenchpressRunner(); -} +const runner = createBenchpressRunner(); export function runBenchmark(config: { id: string, @@ -40,15 +36,14 @@ export function runBenchmark(config: { if (config.setup) { config.setup(); } - if (!cmdArgs) readCommandLine(); - const description: {[key: string]: any} = {'bundles': cmdArgs.bundles}; - config.params.forEach((param) => { description[param.name] = param.value; }); + const description: {[key: string]: any} = {}; + config.params.forEach((param) => description[param.name] = param.value); return runner.sample({ id: config.id, execute: config.work, prepare: config.prepare, microMetrics: config.microMetrics, - providers: [{provide: Options.SAMPLE_DESCRIPTION, useValue: description}] + providers: [{provide: Options.SAMPLE_DESCRIPTION, useValue: {}}] }); } @@ -61,14 +56,14 @@ function createBenchpressRunner(): Runner { fs.ensureDirSync(resultsFolder); const providers: StaticProvider[] = [ SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS, - {provide: Options.FORCE_GC, useValue: cmdArgs['force-gc']}, + {provide: Options.FORCE_GC, useValue: globalOptions.forceGc}, {provide: Options.DEFAULT_DESCRIPTION, useValue: {'runId': runId}}, JsonFileReporter.PROVIDERS, {provide: JsonFileReporter.PATH, useValue: resultsFolder} ]; - if (!cmdArgs['dryrun']) { + if (!globalOptions.dryRun) { providers.push({provide: Validator, useExisting: RegressionSlopeValidator}); providers.push( - {provide: RegressionSlopeValidator.SAMPLE_SIZE, useValue: cmdArgs['sample-size']}); + {provide: RegressionSlopeValidator.SAMPLE_SIZE, useValue: globalOptions.sampleSize}); providers.push(MultiReporter.provideWith([ConsoleReporter, JsonFileReporter])); } else { providers.push({provide: Validator, useExisting: SizeValidator}); diff --git a/modules/playground/src/http/BUILD.bazel b/modules/playground/src/http/BUILD.bazel index 3aced90ee0..a4e36e30b7 100644 --- a/modules/playground/src/http/BUILD.bazel +++ b/modules/playground/src/http/BUILD.bazel @@ -7,8 +7,8 @@ ng_module( srcs = glob(["**/*.ts"]), tsconfig = "//modules/playground:tsconfig-build.json", deps = [ + "//packages/common/http", "//packages/core", - "//packages/http", "//packages/platform-browser", "//packages/platform-browser-dynamic", "@npm//rxjs", diff --git a/modules/playground/src/http/app/http_comp.ts b/modules/playground/src/http/app/http_comp.ts index 4a1be633d0..719e52b433 100644 --- a/modules/playground/src/http/app/http_comp.ts +++ b/modules/playground/src/http/app/http_comp.ts @@ -6,9 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +import {HttpClient} from '@angular/common/http'; import {Component} from '@angular/core'; -import {Http, Response} from '@angular/http'; -import {map} from 'rxjs/operators'; @Component({ selector: 'http-app', @@ -23,9 +22,7 @@ import {map} from 'rxjs/operators'; }) export class HttpCmp { people: Object[]; - constructor(http: Http) { - http.get('./people.json') - .pipe(map((res: Response) => res.json())) - .subscribe((people: Array) => this.people = people); + constructor(http: HttpClient) { + http.get('./people.json').subscribe((people: Array) => this.people = people); } } diff --git a/modules/playground/src/http/index.ts b/modules/playground/src/http/index.ts index 19672e8b54..4ddec0a89b 100644 --- a/modules/playground/src/http/index.ts +++ b/modules/playground/src/http/index.ts @@ -6,14 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ +import {HttpClientModule} from '@angular/common/http'; import {NgModule} from '@angular/core'; -import {HttpModule} from '@angular/http'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {HttpCmp} from './app/http_comp'; -@NgModule({declarations: [HttpCmp], bootstrap: [HttpCmp], imports: [BrowserModule, HttpModule]}) +@NgModule( + {declarations: [HttpCmp], bootstrap: [HttpCmp], imports: [BrowserModule, HttpClientModule]}) export class ExampleModule { } diff --git a/modules/playground/src/jsonp/BUILD.bazel b/modules/playground/src/jsonp/BUILD.bazel index 0a399f0273..f9807ef4de 100644 --- a/modules/playground/src/jsonp/BUILD.bazel +++ b/modules/playground/src/jsonp/BUILD.bazel @@ -7,8 +7,8 @@ ng_module( srcs = glob(["**/*.ts"]), tsconfig = "//modules/playground:tsconfig-build.json", deps = [ + "//packages/common/http", "//packages/core", - "//packages/http", "//packages/platform-browser", "//packages/platform-browser-dynamic", ], diff --git a/modules/playground/src/jsonp/app/jsonp_comp.ts b/modules/playground/src/jsonp/app/jsonp_comp.ts index 46e111acf7..6559378fd7 100644 --- a/modules/playground/src/jsonp/app/jsonp_comp.ts +++ b/modules/playground/src/jsonp/app/jsonp_comp.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ +import {HttpClient} from '@angular/common/http'; import {Component} from '@angular/core'; -import {Jsonp} from '@angular/http'; @Component({ selector: 'jsonp-app', @@ -22,7 +22,7 @@ import {Jsonp} from '@angular/http'; }) export class JsonpCmp { people: Object; - constructor(jsonp: Jsonp) { - jsonp.get('./people.json?callback=JSONP_CALLBACK').subscribe(res => this.people = res.json()); + constructor(http: HttpClient) { + http.jsonp('./people.json', 'callback').subscribe((res: Object) => this.people = res); } } diff --git a/modules/playground/src/jsonp/index.ts b/modules/playground/src/jsonp/index.ts index c9e6501b8a..0a4fc469b9 100644 --- a/modules/playground/src/jsonp/index.ts +++ b/modules/playground/src/jsonp/index.ts @@ -6,14 +6,18 @@ * found in the LICENSE file at https://angular.io/license */ +import {HttpClientJsonpModule, HttpClientModule} from '@angular/common/http'; import {NgModule} from '@angular/core'; -import {JsonpModule} from '@angular/http'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {JsonpCmp} from './app/jsonp_comp'; -@NgModule({bootstrap: [JsonpCmp], declarations: [JsonpCmp], imports: [BrowserModule, JsonpModule]}) +@NgModule({ + bootstrap: [JsonpCmp], + declarations: [JsonpCmp], + imports: [BrowserModule, HttpClientModule, HttpClientJsonpModule] +}) export class ExampleModule { } diff --git a/modules/playground/src/jsonp/people.json b/modules/playground/src/jsonp/people.json index 764beb25d7..9d4b4de2ad 100644 --- a/modules/playground/src/jsonp/people.json +++ b/modules/playground/src/jsonp/people.json @@ -1,2 +1,2 @@ // This can only be requested once due to constant method name :( -__ng_jsonp__.__req0.finished([{"name":"caitp"}]) +ng_jsonp_callback_0([{"name":"caitp"}]) diff --git a/package.json b/package.json index ac09ab70ea..4a0ddb490c 100644 --- a/package.json +++ b/package.json @@ -30,27 +30,29 @@ "list-fixme-ivy-targets": "bazel query --output=label 'attr(\"tags\", \"\\[.*fixme-ivy.*\\]\", //...) except kind(\"sh_binary\", //...) except kind(\"devmode_js_sources\", //...)' | sort", "bazel": "bazel", "//circleci-win-comment": "See the test-win circleci job for why these are needed. If they are not needed anymore, remove them.", - "circleci-win-ve": "bazel test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-browser:chromium-local //packages/compiler-cli/...", - "circleci-win-ivy": "bazel test --config=ivy --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot,-browser:chromium-local //packages/compiler-cli/..." + "circleci-win-ve": "bazel test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only,-browser:chromium-local //packages/compiler-cli/... //tools/ts-api-guardian/...", + "circleci-win-ivy": "bazel test --config=ivy --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot,-browser:chromium-local //packages/compiler-cli/... //tools/ts-api-guardian/..." }, "// 1": "dependencies are used locally and by bazel", "dependencies": { - "@angular-devkit/architect": "^0.900.0-rc.3", - "@angular-devkit/build-optimizer": "^0.900.0-rc.3", - "@angular-devkit/core": "^9.0.0-rc.3", - "@angular-devkit/schematics": "^9.0.0-rc.3", + "@angular-devkit/architect": "0.900.0-rc.10", + "@angular-devkit/build-optimizer": "0.900.0-rc.10", + "@angular-devkit/core": "9.0.0-rc.10", + "@angular-devkit/schematics": "9.0.0-rc.10", "@angular/bazel": "file:./tools/npm/@angular_bazel", - "@babel/core": "^7.6.4", - "@bazel/jasmine": "0.42.2", - "@bazel/karma": "0.42.2", - "@bazel/protractor": "0.42.2", - "@bazel/rollup": "0.42.2", - "@bazel/terser": "0.42.2", - "@bazel/typescript": "0.42.2", + "@babel/core": "7.8.3", + "@babel/generator": "7.8.3", + "@bazel/jasmine": "1.2.2", + "@bazel/karma": "1.2.2", + "@bazel/protractor": "1.2.2", + "@bazel/rollup": "1.2.2", + "@bazel/terser": "1.2.2", + "@bazel/typescript": "1.2.2", "@microsoft/api-extractor": "^7.3.9", - "@schematics/angular": "^9.0.0-rc.3", + "@schematics/angular": "9.0.0-rc.8", "@types/angular": "^1.6.47", "@types/babel__core": "^7.1.3", + "@types/babel__generator": "^7.6.1", "@types/base64-js": "1.2.5", "@types/bluebird": "^3.5.27", "@types/chai": "^4.1.2", @@ -82,7 +84,7 @@ "canonical-path": "1.0.0", "chai": "^4.1.2", "chalk": "^2.3.1", - "chokidar": "^2.1.1", + "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", "core-js": "^2.4.1", "dependency-graph": "^0.7.2", @@ -120,21 +122,21 @@ "source-map-support": "0.5.9", "systemjs": "0.18.10", "terser": "^4.4.0", - "tsickle": "0.37.1", + "tsickle": "0.38.0", "tslib": "^1.10.0", "tslint": "5.7.0", - "typescript": "~3.6.4", + "typescript": "~3.7.4", "xhr2": "0.1.4", "yargs": "13.1.0" }, "// 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": { - "@angular-devkit/build-angular": "^0.900.0-rc.3", - "@angular/cli": "^9.0.0-rc.3", - "@bazel/bazel": "1.1.0", + "@angular-devkit/build-angular": "0.900.0-rc.11", + "@angular/cli": "9.0.0-rc.11", + "@bazel/bazel": "2.0.0", "@bazel/buildifier": "^0.29.0", - "@bazel/ibazel": "^0.10.3", + "@bazel/ibazel": "^0.11.1", "@types/minimist": "^1.2.0", "@yarnpkg/lockfile": "^1.1.0", "browserstacktunnel-wrapper": "2.0.1", @@ -158,7 +160,7 @@ "jpm": "1.3.1", "karma-browserstack-launcher": "^1.3.0", "karma-sauce-launcher": "^2.0.2", - "madge": "0.5.0", + "madge": "^3.6.0", "mutation-observer": "^1.0.3", "rewire": "2.5.2", "sauce-connect": "https://saucelabs.com/downloads/sc-4.5.1-linux.tar.gz", diff --git a/packages/animations/browser/src/render/transition_animation_engine.ts b/packages/animations/browser/src/render/transition_animation_engine.ts index b3ec5bc052..f3ef0f80bc 100644 --- a/packages/animations/browser/src/render/transition_animation_engine.ts +++ b/packages/animations/browser/src/render/transition_animation_engine.ts @@ -437,11 +437,14 @@ export class AnimationTransitionNamespace { if (containsPotentialParentTransition) { engine.markElementAsRemoved(this.id, element, false, context); } else { - // we do this after the flush has occurred such - // that the callbacks can be fired - engine.afterFlush(() => this.clearElementCache(element)); - engine.destroyInnerAnimations(element); - engine._onRemovalComplete(element, context); + const removalFlag = element[REMOVAL_FLAG]; + if (!removalFlag || removalFlag === NULL_REMOVAL_STATE) { + // we do this after the flush has occurred such + // that the callbacks can be fired + engine.afterFlush(() => this.clearElementCache(element)); + engine.destroyInnerAnimations(element); + engine._onRemovalComplete(element, context); + } } } diff --git a/packages/animations/browser/test/BUILD.bazel b/packages/animations/browser/test/BUILD.bazel index 4d46b7c1ae..79b21d2ef2 100644 --- a/packages/animations/browser/test/BUILD.bazel +++ b/packages/animations/browser/test/BUILD.bazel @@ -1,4 +1,17 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/animations/browser/index.js", + deps = ["//packages/animations/browser"], +) + +circular_dependency_test( + name = "testing_circular_deps_test", + entry_point = "angular/packages/animations/browser/testing/index.js", + deps = ["//packages/animations/browser/testing"], +) ts_library( name = "test_lib", @@ -16,10 +29,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/animations/test/BUILD.bazel b/packages/animations/test/BUILD.bazel index 2b5e4e288b..8153e436ab 100644 --- a/packages/animations/test/BUILD.bazel +++ b/packages/animations/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/animations/index.js", + deps = ["//packages/animations"], +) ts_library( name = "test_lib", @@ -13,10 +20,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/bazel/BUILD.bazel b/packages/bazel/BUILD.bazel index fa89f8aa0f..a9f6c52534 100644 --- a/packages/bazel/BUILD.bazel +++ b/packages/bazel/BUILD.bazel @@ -1,6 +1,6 @@ -load("//tools:defaults.bzl", "npm_package") +load("//tools:defaults.bzl", "pkg_npm") -npm_package( +pkg_npm( name = "npm_package", srcs = glob( ["*"], @@ -14,10 +14,10 @@ npm_package( "//packages/bazel/src/schematics:package_assets", "//packages/bazel/third_party/github.com/bazelbuild/bazel/src/main/protobuf:package_assets", ], - packages = [ + nested_packages = [ "//packages/bazel/docs", ], - replacements = { + substitutions = { "(#|\/\/)\\s+BEGIN-DEV-ONLY[\\w\W]+?(#|\/\/)\\s+END-DEV-ONLY": "", "//packages/bazel/": "//", "angular/packages/bazel/": "npm_angular_bazel/", diff --git a/packages/bazel/package.bzl b/packages/bazel/package.bzl index 7880fe62b2..182fc3e903 100644 --- a/packages/bazel/package.bzl +++ b/packages/bazel/package.bzl @@ -29,19 +29,26 @@ def rules_angular_dev_dependencies(): _maybe( http_archive, name = "bazel_toolchains", - sha256 = "3c1299efcf64a4ecf4f6def7564db28879ad2870632144d77932e7910686d3f3", - strip_prefix = "bazel-toolchains-1.1.2", - url = "https://github.com/bazelbuild/bazel-toolchains/archive/1.1.2.tar.gz", + sha256 = "a653c9d318e42b14c0ccd7ac50c4a2a276c0db1e39743ab88b5aa2f0bc9cf607", + strip_prefix = "bazel-toolchains-2.0.2", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/releases/download/2.0.2/bazel-toolchains-2.0.2.tar.gz", + "https://github.com/bazelbuild/bazel-toolchains/releases/download/2.0.2/bazel-toolchains-2.0.2.tar.gz", + ], ) ############################################# # Dependencies for generating documentation # ############################################# - http_archive( + _maybe( + http_archive, name = "io_bazel_rules_sass", - sha256 = "4f05239080175a3f4efa8982d2b7775892d656bb47e8cf56914d5f9441fb5ea6", - url = "https://github.com/bazelbuild/rules_sass/archive/86ca977cf2a8ed481859f83a286e164d07335116.zip", - strip_prefix = "rules_sass-86ca977cf2a8ed481859f83a286e164d07335116", + sha256 = "77e241148f26d5dbb98f96fe0029d8f221c6cb75edbb83e781e08ac7f5322c5f", + strip_prefix = "rules_sass-1.24.0", + urls = [ + "https://github.com/bazelbuild/rules_sass/archive/1.24.0.zip", + "https://mirror.bazel.build/github.com/bazelbuild/rules_sass/archive/1.24.0.zip", + ], ) http_archive( diff --git a/packages/bazel/package.json b/packages/bazel/package.json index 4781f93cd3..59a3acd95f 100644 --- a/packages/bazel/package.json +++ b/packages/bazel/package.json @@ -28,13 +28,13 @@ "dependencies": { "@microsoft/api-extractor": "^7.3.9", "shelljs": "0.8.2", - "tsickle": "^0.37.1" + "tsickle": "^0.38.0" }, "peerDependencies": { "@angular/compiler-cli": "0.0.0-PLACEHOLDER", - "@bazel/typescript": "0.*", + "@bazel/typescript": ">=1.0.0", "terser": "^4.3.1", - "typescript": ">=3.6 <3.7", + "typescript": ">=3.6 <3.8", "rollup": ">=1.20.0", "rollup-plugin-commonjs": ">=9.0.0", "rollup-plugin-node-resolve": ">=4.2.0", diff --git a/packages/bazel/src/BUILD.bazel b/packages/bazel/src/BUILD.bazel index 7a7b73b51a..b26742aae4 100644 --- a/packages/bazel/src/BUILD.bazel +++ b/packages/bazel/src/BUILD.bazel @@ -19,7 +19,6 @@ nodejs_binary( name = "modify_tsconfig", data = ["modify_tsconfig.js"], entry_point = ":modify_tsconfig.js", - install_source_map_support = False, node_modules = ":empty_node_modules", visibility = ["//visibility:public"], ) diff --git a/packages/bazel/src/builders/files/WORKSPACE.template b/packages/bazel/src/builders/files/WORKSPACE.template index 2bec84e090..98d2730e39 100644 --- a/packages/bazel/src/builders/files/WORKSPACE.template +++ b/packages/bazel/src/builders/files/WORKSPACE.template @@ -15,8 +15,8 @@ workspace( load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -RULES_NODEJS_VERSION = "0.40.0" -RULES_NODEJS_SHA256 = "9901bc17138a79135048fb0c107ee7a56e91815ec6594c08cb9a17b80276d62b" +RULES_NODEJS_VERSION = "1.2.2" +RULES_NODEJS_SHA256 = "6bcef105e75cac3c5f8212e0d0431b6ec1aaa1963e093b0091474ab98ecf29d2" http_archive( name = "build_bazel_rules_nodejs", sha256 = RULES_NODEJS_SHA256, @@ -24,13 +24,16 @@ http_archive( ) # Rules for compiling sass -RULES_SASS_VERSION = "86ca977cf2a8ed481859f83a286e164d07335116" -RULES_SASS_SHA256 = "4f05239080175a3f4efa8982d2b7775892d656bb47e8cf56914d5f9441fb5ea6" +RULES_SASS_VERSION = "1.24.0" +RULES_SASS_SHA256 = "77e241148f26d5dbb98f96fe0029d8f221c6cb75edbb83e781e08ac7f5322c5f" http_archive( name = "io_bazel_rules_sass", sha256 = RULES_SASS_SHA256, - url = "https://github.com/bazelbuild/rules_sass/archive/%s.zip" % RULES_SASS_VERSION, strip_prefix = "rules_sass-%s" % RULES_SASS_VERSION, + urls = [ + "https://github.com/bazelbuild/rules_sass/archive/%s.zip" % RULES_SASS_VERSION, + "https://mirror.bazel.build/github.com/bazelbuild/rules_sass/archive/%s.zip" % RULES_SASS_VERSION, + ], ) #################################### @@ -51,14 +54,14 @@ Try running `yarn bazel` instead. # Setup the Node repositories. We need a NodeJS version that is more recent than v10.15.0 # because "selenium-webdriver" which is required for "ng e2e" cannot be installed. -# TODO: remove the custom repositories once "rules_nodejs" supports v10.16.0 by default. +# TODO: remove the custom repositories once "rules_nodejs" supports v12.14.1 by default. node_repositories( node_repositories = { - "10.16.0-darwin_amd64": ("node-v10.16.0-darwin-x64.tar.gz", "node-v10.16.0-darwin-x64", "6c009df1b724026d84ae9a838c5b382662e30f6c5563a0995532f2bece39fa9c"), - "10.16.0-linux_amd64": ("node-v10.16.0-linux-x64.tar.xz", "node-v10.16.0-linux-x64", "1827f5b99084740234de0c506f4dd2202a696ed60f76059696747c34339b9d48"), - "10.16.0-windows_amd64": ("node-v10.16.0-win-x64.zip", "node-v10.16.0-win-x64", "aa22cb357f0fb54ccbc06b19b60e37eefea5d7dd9940912675d3ed988bf9a059"), + "12.14.1-darwin_amd64": ("node-v12.14.1-darwin-x64.tar.gz", "node-v12.14.1-darwin-x64", "0be10a28737527a1e5e3784d3ad844d742fe8b0718acd701fd48f718fd3af78f"), + "12.14.1-linux_amd64": ("node-v12.14.1-linux-x64.tar.xz", "node-v12.14.1-linux-x64", "07cfcaa0aa9d0fcb6e99725408d9e0b07be03b844701588e3ab5dbc395b98e1b"), + "12.14.1-windows_amd64": ("node-v12.14.1-win-x64.zip", "node-v12.14.1-win-x64", "1f96ccce3ba045ecea3f458e189500adb90b8bc1a34de5d82fc10a5bf66ce7e3"), }, - node_version = "10.16.0", + node_version = "12.14.1", ) yarn_install( diff --git a/packages/bazel/src/builders/files/src/BUILD.bazel.template b/packages/bazel/src/builders/files/src/BUILD.bazel.template index 442e9ffa8b..8ebbfee9aa 100644 --- a/packages/bazel/src/builders/files/src/BUILD.bazel.template +++ b/packages/bazel/src/builders/files/src/BUILD.bazel.template @@ -1,9 +1,10 @@ package(default_visibility = ["//visibility:public"]) +load("@build_bazel_rules_nodejs//:index.bzl", "pkg_web") +load("@npm//history-server:index.bzl", "history_server") +load("@npm//html-insert-assets:index.bzl", "html_insert_assets") load("@npm_angular_bazel//:index.bzl", "ng_module") load("@npm_bazel_karma//:index.bzl", "karma_web_test_suite") -load("@build_bazel_rules_nodejs//internal/web_package:web_package.bzl", "web_package") -load("@npm//history-server:index.bzl", "history_server") load("@npm_bazel_rollup//:index.bzl", "rollup_bundle") load("@npm_bazel_terser//:index.bzl", "terser_minified") load("@npm_bazel_typescript//:index.bzl", "ts_devserver", "ts_library") @@ -64,18 +65,38 @@ terser_minified( src = ":bundle", ) -web_package( +html_insert_assets( + name = "asset_injected_index_html", + outs = ["_/index.html"], + args = [ + "--html", + "$(execpath :index.html)", + "--out", + "$@", + "--roots", + "$(RULEDIR)", + "--assets", + "$(execpath :global_stylesheet.css)", + "$(execpath @npm//:node_modules/zone.js/dist/zone.min.js)", + "bundle.min.js", + ], + data = [ + ":index.html", + ":global_stylesheet.css", + "@npm//:node_modules/zone.js/dist/zone.min.js", + ], +) + +pkg_web( name = "prodapp", - assets = [ - # do not sort + additional_root_paths = ["src/_"], + srcs = [ "@npm//:node_modules/zone.js/dist/zone.min.js", ":bundle.min", ":global_stylesheet", - ], - data = [ + ":asset_injected_index_html", "favicon.ico", ], - index_html = "index.html", ) history_server( @@ -95,6 +116,7 @@ filegroup( ts_devserver( name = "devserver", + additional_root_paths = ["src/_"], port = 4200, entry_module = "project/src/main.dev", serving_path = "/bundle.min.js", @@ -105,11 +127,9 @@ ts_devserver( static_files = [ "@npm//:node_modules/zone.js/dist/zone.min.js", ":global_stylesheet", - ], - data = [ + ":asset_injected_index_html", "favicon.ico", ], - index_html = "index.html", deps = [":src"], ) @@ -158,6 +178,5 @@ karma_web_test_suite( deps = [ ":rxjs_umd_modules", ":test_lib", - "@npm//karma-jasmine", ], ) diff --git a/packages/bazel/src/ng_package/BUILD.bazel b/packages/bazel/src/ng_package/BUILD.bazel index 6de304b664..b32752bc6a 100644 --- a/packages/bazel/src/ng_package/BUILD.bazel +++ b/packages/bazel/src/ng_package/BUILD.bazel @@ -24,7 +24,6 @@ nodejs_binary( "@npm//shelljs", ], entry_point = ":packager.ts", - install_source_map_support = False, ) nodejs_binary( @@ -36,7 +35,6 @@ nodejs_binary( "@npm//rollup-plugin-sourcemaps", ], entry_point = "@npm//:node_modules/rollup/dist/bin/rollup", - install_source_map_support = False, ) exports_files([ diff --git a/packages/bazel/src/ng_package/collect-type-definitions.bzl b/packages/bazel/src/ng_package/collect-type-definitions.bzl index 0f2f616ffa..e47d649613 100644 --- a/packages/bazel/src/ng_package/collect-type-definitions.bzl +++ b/packages/bazel/src/ng_package/collect-type-definitions.bzl @@ -8,6 +8,8 @@ This is used to find all files that will be copied into a "ng_package". """ +load("@build_bazel_rules_nodejs//:providers.bzl", "DeclarationInfo") + def _filter_typing_files(files): return [file for file in files if file.path.endswith(".d.ts")] @@ -35,7 +37,7 @@ def collect_type_definitions(ctx): # Collect all TypeScript definition files from the specified dependencies. for dep in ctx.attr.deps: - if hasattr(dep, "typescript"): - collected_files += dep.typescript.transitive_declarations.to_list() + if DeclarationInfo in dep: + collected_files += dep[DeclarationInfo].transitive_declarations.to_list() return collected_files diff --git a/packages/bazel/src/ng_package/ng_package.bzl b/packages/bazel/src/ng_package/ng_package.bzl index 88aaa759dc..48d7ec4f4e 100644 --- a/packages/bazel/src/ng_package/ng_package.bzl +++ b/packages/bazel/src/ng_package/ng_package.bzl @@ -15,9 +15,9 @@ specification of this format at https://goo.gl/jB3GVv load("@build_bazel_rules_nodejs//:providers.bzl", "JSEcmaScriptModuleInfo", "JSNamedModuleInfo", "NpmPackageInfo", "node_modules_aspect") load( - "@build_bazel_rules_nodejs//internal/npm_package:npm_package.bzl", - "NPM_PACKAGE_ATTRS", - "NPM_PACKAGE_OUTPUTS", + "@build_bazel_rules_nodejs//internal/pkg_npm:pkg_npm.bzl", + "PKG_NPM_ATTRS", + "PKG_NPM_OUTPUTS", "create_package", ) load("//packages/bazel/src:external.bzl", "FLAT_DTS_FILE_SUFFIX") @@ -623,7 +623,7 @@ def _ng_package_impl(ctx): package_dir = create_package( ctx, devfiles.to_list(), - [npm_package_directory] + ctx.files.packages, + [npm_package_directory] + ctx.files.nested_packages, ) return [DefaultInfo( files = depset([package_dir]), @@ -631,7 +631,7 @@ def _ng_package_impl(ctx): _NG_PACKAGE_DEPS_ASPECTS = [esm5_outputs_aspect, ng_package_module_mappings_aspect, node_modules_aspect] -_NG_PACKAGE_ATTRS = dict(NPM_PACKAGE_ATTRS, **{ +_NG_PACKAGE_ATTRS = dict(PKG_NPM_ATTRS, **{ "srcs": attr.label_list( doc = """JavaScript source files from the workspace. These can use ES2015 syntax and ES Modules (import/export)""", @@ -807,12 +807,12 @@ def _ng_package_outputs(name, entry_point, entry_point_name): "umd": "%s.umd.js" % basename, "umd_min": "%s.umd.min.js" % basename, } - for key in NPM_PACKAGE_OUTPUTS: - # NPM_PACKAGE_OUTPUTS is a "normal" dict-valued outputs so it looks like + for key in PKG_NPM_OUTPUTS: + # PKG_NPM_OUTPUTS is a "normal" dict-valued outputs so it looks like # "pack": "%{name}.pack", # But this is a function-valued outputs. # Bazel won't replace the %{name} token so we have to do it. - outputs[key] = NPM_PACKAGE_OUTPUTS[key].replace("%{name}", name) + outputs[key] = PKG_NPM_OUTPUTS[key].replace("%{name}", name) return outputs ng_package = rule( diff --git a/packages/bazel/src/schematics/BUILD.bazel b/packages/bazel/src/schematics/BUILD.bazel index a51a76767d..af016fc6ee 100644 --- a/packages/bazel/src/schematics/BUILD.bazel +++ b/packages/bazel/src/schematics/BUILD.bazel @@ -12,11 +12,10 @@ filegroup( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ "//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/ng-add/index.ts b/packages/bazel/src/schematics/ng-add/index.ts index 744f8dfe9b..2bf2bcbdf1 100644 --- a/packages/bazel/src/schematics/ng-add/index.ts +++ b/packages/bazel/src/schematics/ng-add/index.ts @@ -38,18 +38,27 @@ function addDevDependenciesToPackageJson(options: Schema) { // TODO: use a Record when the tsc lib setting allows us const devDependencies: [string, string][] = [ ['@angular/bazel', angularCore.version], - ['@bazel/bazel', '1.1.0'], - ['@bazel/ibazel', '^0.10.2'], - ['@bazel/karma', '0.40.0'], - ['@bazel/protractor', '0.40.0'], - ['@bazel/rollup', '0.40.0'], - ['@bazel/terser', '0.40.0'], - ['@bazel/typescript', '0.40.0'], - ['history-server', '^1.3.1'], - ['rollup', '^1.25.2'], - ['rollup-plugin-commonjs', '^10.1.0'], - ['rollup-plugin-node-resolve', '^5.2.0'], - ['terser', '^4.3.9'], + ['@bazel/bazel', '2.0.0'], + ['@bazel/ibazel', '0.10.3'], + ['@bazel/karma', '1.2.2'], + ['@bazel/protractor', '1.2.2'], + ['@bazel/rollup', '1.2.2'], + ['@bazel/terser', '1.2.2'], + ['@bazel/typescript', '1.2.2'], + ['history-server', '1.3.1'], + ['html-insert-assets', '0.2.0'], + ['karma', '4.4.1'], + ['karma-chrome-launcher', '3.1.0'], + ['karma-firefox-launcher', '1.2.0'], + ['karma-jasmine', '2.0.1'], + ['karma-requirejs', '1.1.0'], + ['karma-sourcemap-loader', '0.3.7'], + ['protractor', '5.4.2'], + ['requirejs', '2.3.6'], + ['rollup', '1.27.5'], + ['rollup-plugin-commonjs', '10.1.0'], + ['rollup-plugin-node-resolve', '5.2.0'], + ['terser', '4.4.0'], ]; for (const [name, version] of devDependencies) { diff --git a/packages/bazel/test/ng_package/example-with-ts-library/BUILD.bazel b/packages/bazel/test/ng_package/example-with-ts-library/BUILD.bazel index 35d25011f4..a4da6f6fca 100644 --- a/packages/bazel/test/ng_package/example-with-ts-library/BUILD.bazel +++ b/packages/bazel/test/ng_package/example-with-ts-library/BUILD.bazel @@ -5,7 +5,7 @@ package(default_visibility = ["//packages/bazel/test:__subpackages__"]) ts_library( name = "example", srcs = glob(["*.ts"]), - module_name = "example", + module_name = "example-with-ts-library", deps = [], ) diff --git a/packages/bazel/test/ng_package/example/BUILD.bazel b/packages/bazel/test/ng_package/example/BUILD.bazel index 67a55b7528..eb52e7f3b5 100644 --- a/packages/bazel/test/ng_package/example/BUILD.bazel +++ b/packages/bazel/test/ng_package/example/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "ng_module", "ng_package", "npm_package") +load("//tools:defaults.bzl", "ng_module", "ng_package", "pkg_npm") package(default_visibility = ["//packages/bazel/test:__subpackages__"]) @@ -26,7 +26,7 @@ ng_package( ], entry_point = ":index.ts", entry_point_name = "waffels", - packages = [ + nested_packages = [ ":arbitrary_npm_package", ], deps = [ @@ -52,7 +52,7 @@ genrule( output_to_bindir = True, ) -npm_package( +pkg_npm( name = "arbitrary_npm_package", srcs = [":arbitrary-npm-package-main.js"], ) diff --git a/packages/bazel/test/ng_package/example_package.golden b/packages/bazel/test/ng_package/example_package.golden index 8bcd68756f..e1d4aca6d1 100644 --- a/packages/bazel/test/ng_package/example_package.golden +++ b/packages/bazel/test/ng_package/example_package.golden @@ -90,7 +90,7 @@ Hello /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -339,7 +339,7 @@ Hello /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 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"; @@ -378,7 +378,7 @@ e.SecondaryModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})})); /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -625,7 +625,7 @@ e.SecondaryModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})})); /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 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"; @@ -864,7 +864,7 @@ export var a = 1; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -891,7 +891,7 @@ export { } /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -928,7 +928,7 @@ export { SecondaryModule, a }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -963,7 +963,7 @@ export { MyModule }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -1007,7 +1007,7 @@ export { SecondaryModule, a }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -1083,7 +1083,7 @@ export { MyModule }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -1105,7 +1105,7 @@ export { } /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ diff --git a/packages/bazel/test/ng_package/example_with_ts_library_package.golden b/packages/bazel/test/ng_package/example_with_ts_library_package.golden index deb7f80bb7..459aeb7f02 100644 --- a/packages/bazel/test/ng_package/example_with_ts_library_package.golden +++ b/packages/bazel/test/ng_package/example_with_ts_library_package.golden @@ -62,6 +62,9 @@ utils utils/package.json utils/testing.d.ts utils.d.ts +with-ts-library + with-ts-library/package.json +with-ts-library.d.ts --- README.md --- Angular @@ -78,7 +81,7 @@ License: MIT /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -327,7 +330,7 @@ License: MIT /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 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/portal",["exports","@angular/core"],t):t(((e=e||self).example=e.example||{},e.example.portal={}),e.ng.core)}(this,(function(e,t){"use strict"; @@ -366,7 +369,7 @@ e.PortalModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})})); /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -407,7 +410,7 @@ e.PortalModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})})); /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define("example/utils",["exports"],t):t(((e=e||self).example=e.example||{},e.example.utils={}))}(this,(function(e){"use strict"; @@ -431,14 +434,14 @@ e.dispatchFakeEvent=function t(e,n){e.dispatchEvent(n)},Object.defineProperty(e, /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define('example', ['exports'], factory) : - (global = global || self, factory(global.example = {})); + typeof define === 'function' && define.amd ? define('example-with-ts-library', ['exports'], factory) : + (global = global || self, factory(global.exampleWithTsLibrary = {})); }(this, (function (exports) { 'use strict'; /** @@ -462,10 +465,10 @@ e.dispatchFakeEvent=function t(e,n){e.dispatchEvent(n)},Object.defineProperty(e, /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define("example",["exports"],t):t((e=e||self).example={})}(this,(function(e){"use strict"; +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define("example-with-ts-library",["exports"],t):t((e=e||self).exampleWithTsLibrary={})}(this,(function(e){"use strict"; /** * @license * Copyright Google Inc. All Rights Reserved. @@ -664,7 +667,7 @@ export function dispatchFakeEvent(el, ev) { /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -685,7 +688,7 @@ export { VERSION }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -722,7 +725,7 @@ export { PortalModule, a }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -753,7 +756,7 @@ export { dispatchFakeEvent }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -774,7 +777,7 @@ export { VERSION }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -818,7 +821,7 @@ export { PortalModule, a }; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -929,7 +932,7 @@ export * from './index'; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ @@ -983,9 +986,34 @@ export declare function dispatchFakeEvent(el: HTMLElement, ev: Event): void; /** * @license Angular v0.0.0 - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ export * from './utils/index'; + +--- with-ts-library/package.json --- + +{ + "name": "example-with-ts-library", + "main": "./bundles/example-with-ts-library.umd.js", + "fesm5": "./fesm5/example-with-ts-library.js", + "fesm2015": "./fesm2015/example-with-ts-library.js", + "esm5": "../esm5/index.js", + "esm2015": "../esm2015/index.js", + "typings": "../index.d.ts", + "module": "./fesm5/example-with-ts-library.js", + "es2015": "./fesm2015/example-with-ts-library.js" +} + +--- with-ts-library.d.ts --- + +/** + * @license Angular v0.0.0 + * (c) 2010-2020 Google LLC. https://angular.io/ + * License: MIT + */ + +export * from './index'; + diff --git a/packages/benchpress/BUILD.bazel b/packages/benchpress/BUILD.bazel index 3cb0cf4dfb..e2a2add5b1 100644 --- a/packages/benchpress/BUILD.bazel +++ b/packages/benchpress/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "npm_package", "ts_library") +load("//tools:defaults.bzl", "pkg_npm", "ts_library") package(default_visibility = ["//visibility:public"]) @@ -18,7 +18,7 @@ ts_library( ], ) -npm_package( +pkg_npm( name = "npm_package", srcs = [ "README.md", diff --git a/packages/benchpress/test/BUILD.bazel b/packages/benchpress/test/BUILD.bazel index ea75062fab..6b46415e57 100644 --- a/packages/benchpress/test/BUILD.bazel +++ b/packages/benchpress/test/BUILD.bazel @@ -15,12 +15,11 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", "//packages/benchpress", "//packages/core/testing", - "//tools/testing:node", "@npm//protractor", ], ) diff --git a/packages/common/BUILD.bazel b/packages/common/BUILD.bazel index d300f29f2d..e139b85ffb 100644 --- a/packages/common/BUILD.bazel +++ b/packages/common/BUILD.bazel @@ -26,7 +26,7 @@ ng_package( "//packages/common/upgrade:package.json", ], entry_point = ":index.ts", - packages = ["//packages/common/locales:package"], + nested_packages = ["//packages/common/locales:package"], tags = [ "release-with-framework", ], diff --git a/packages/common/http/src/params.ts b/packages/common/http/src/params.ts index 0d2728f9ed..3954b49724 100755 --- a/packages/common/http/src/params.ts +++ b/packages/common/http/src/params.ts @@ -257,9 +257,15 @@ export class HttpParams { return this.keys() .map(key => { const eKey = this.encoder.encodeKey(key); + // `a: ['1']` produces `'a=1'` + // `b: []` produces `''` + // `c: ['1', '2']` produces `'c=1&c=2'` return this.map !.get(key) !.map(value => eKey + '=' + this.encoder.encodeValue(value)) .join('&'); }) + // filter out empty values because `b: []` produces `''` + // which results in `a=1&&c=1&c=2` instead of `a=1&c=1&c=2` if we don't + .filter(param => param !== '') .join('&'); } diff --git a/packages/common/http/test/BUILD.bazel b/packages/common/http/test/BUILD.bazel index 65eadfbb96..bf662c1c41 100644 --- a/packages/common/http/test/BUILD.bazel +++ b/packages/common/http/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/common/http/index.js", + deps = ["//packages/common/http"], +) ts_library( name = "test_lib", @@ -19,10 +26,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/common/http/test/params_spec.ts b/packages/common/http/test/params_spec.ts index 669959c851..9c99771043 100644 --- a/packages/common/http/test/params_spec.ts +++ b/packages/common/http/test/params_spec.ts @@ -76,5 +76,20 @@ import {HttpParams} from '@angular/common/http/src/params'; expect(body.keys()).toEqual(['a', 'b', 'c', 'd']); }); }); + + describe('toString', () => { + it('should stringify string params', () => { + const body = new HttpParams({fromObject: {a: '', b: '2', c: '3'}}); + expect(body.toString()).toBe('a=&b=2&c=3'); + }); + it('should stringify array params', () => { + const body = new HttpParams({fromObject: {a: '', b: ['21', '22'], c: '3'}}); + expect(body.toString()).toBe('a=&b=21&b=22&c=3'); + }); + it('should stringify empty array params', () => { + const body = new HttpParams({fromObject: {a: '', b: [], c: '3'}}); + expect(body.toString()).toBe('a=&c=3'); + }); + }); }); } diff --git a/packages/common/http/testing/src/backend.ts b/packages/common/http/testing/src/backend.ts index d5311fd551..75a32389b8 100644 --- a/packages/common/http/testing/src/backend.ts +++ b/packages/common/http/testing/src/backend.ts @@ -90,7 +90,19 @@ export class HttpClientTestingBackend implements HttpBackend, HttpTestingControl `Expected one matching request for criteria "${description}", found ${matches.length} requests.`); } if (matches.length === 0) { - throw new Error(`Expected one matching request for criteria "${description}", found none.`); + let message = `Expected one matching request for criteria "${description}", found none.`; + if (this.open.length > 0) { + // Show the methods and URLs of open requests in the error, for convenience. + const requests = this.open + .map(testReq => { + const url = testReq.request.urlWithParams; + const method = testReq.request.method; + return `${method} ${url}`; + }) + .join(', '); + message += ` Requests received are: ${requests}.`; + } + throw new Error(message); } return matches[0]; } diff --git a/packages/common/http/testing/test/BUILD.bazel b/packages/common/http/testing/test/BUILD.bazel index d9de470171..51763ab425 100644 --- a/packages/common/http/testing/test/BUILD.bazel +++ b/packages/common/http/testing/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/common/http/testing/index.js", + deps = ["//packages/common/http/testing"], +) ts_library( name = "test_lib", @@ -17,10 +24,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/common/http/testing/test/request_spec.ts b/packages/common/http/testing/test/request_spec.ts index ee7ba15c6f..92d78399d2 100644 --- a/packages/common/http/testing/test/request_spec.ts +++ b/packages/common/http/testing/test/request_spec.ts @@ -22,4 +22,63 @@ describe('HttpClient TestRequest', () => { expect(resp).toBeNull(); }); + + it('throws if no request matches', () => { + const mock = new HttpClientTestingBackend(); + const client = new HttpClient(mock); + + let resp: any; + client.get('/some-other-url').subscribe(body => { resp = body; }); + + try { + // expect different URL + mock.expectOne('/some-url').flush(null); + fail(); + } catch (error) { + expect(error.message) + .toBe( + 'Expected one matching request for criteria "Match URL: /some-url", found none.' + + ' Requests received are: GET /some-other-url.'); + } + }); + + it('throws if no request matches the exact parameters', () => { + const mock = new HttpClientTestingBackend(); + const client = new HttpClient(mock); + + let resp: any; + const params = {query: 'hello'}; + client.get('/some-url', {params}).subscribe(body => { resp = body; }); + + try { + // expect different query parameters + mock.expectOne('/some-url?query=world').flush(null); + fail(); + } catch (error) { + expect(error.message) + .toBe( + 'Expected one matching request for criteria "Match URL: /some-url?query=world", found none.' + + ' Requests received are: GET /some-url?query=hello.'); + } + }); + + it('throws if no request matches with several requests received', () => { + const mock = new HttpClientTestingBackend(); + const client = new HttpClient(mock); + + let resp: any; + client.get('/some-other-url?query=world').subscribe(body => { resp = body; }); + client.post('/and-another-url', {}).subscribe(body => { resp = body; }); + + try { + // expect different URL + mock.expectOne('/some-url').flush(null); + fail(); + } catch (error) { + expect(error.message) + .toBe( + 'Expected one matching request for criteria "Match URL: /some-url", found none.' + + ' Requests received are: GET /some-other-url?query=world, POST /and-another-url.'); + } + }); }); diff --git a/packages/common/locales/BUILD.bazel b/packages/common/locales/BUILD.bazel index 391e9a0acb..c887cc32ae 100644 --- a/packages/common/locales/BUILD.bazel +++ b/packages/common/locales/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "npm_package", "ts_library") +load("//tools:defaults.bzl", "pkg_npm", "ts_library") package(default_visibility = ["//visibility:public"]) @@ -10,11 +10,10 @@ ts_library( ), ) -npm_package( +pkg_npm( name = "package", srcs = glob(["global/*.js"]) + ["package.json"], - replacements = { - + substitutions = { # Workaround for `.d.ts`` containing `/// ` # which are generated in TypeScript v2.9, but not before. "/// ": "", diff --git a/packages/common/locales/af-NA.ts b/packages/common/locales/af-NA.ts index 43de220fa4..b079c4c0c8 100644 --- a/packages/common/locales/af-NA.ts +++ b/packages/common/locales/af-NA.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'Suid-Afrikaanse rand', { diff --git a/packages/common/locales/af.ts b/packages/common/locales/af.ts index 962862f8ec..e7b909a97b 100644 --- a/packages/common/locales/af.ts +++ b/packages/common/locales/af.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'Suid-Afrikaanse rand', { diff --git a/packages/common/locales/agq.ts b/packages/common/locales/agq.ts index 4de879f222..fee01d404a 100644 --- a/packages/common/locales/agq.ts +++ b/packages/common/locales/agq.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XAF', 'FCFA', 'CFA Fàlâŋ BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ak.ts b/packages/common/locales/ak.ts index 4482755a80..3a47c80b8a 100644 --- a/packages/common/locales/ak.ts +++ b/packages/common/locales/ak.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GHS', 'GH₵', 'Ghana Sidi', {'GHS': ['GH₵'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/am.ts b/packages/common/locales/am.ts index fc70806865..5a09f5d95b 100644 --- a/packages/common/locales/am.ts +++ b/packages/common/locales/am.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'ብር', 'የኢትዮጵያ ብር', { diff --git a/packages/common/locales/ar-AE.ts b/packages/common/locales/ar-AE.ts index eedcb91f47..1ba1122632 100644 --- a/packages/common/locales/ar-AE.ts +++ b/packages/common/locales/ar-AE.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'AED', 'د.إ.\u200f', 'درهم إماراتي', { diff --git a/packages/common/locales/ar-BH.ts b/packages/common/locales/ar-BH.ts index bb120ff265..fd93538458 100644 --- a/packages/common/locales/ar-BH.ts +++ b/packages/common/locales/ar-BH.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'BHD', 'د.ب.\u200f', 'دينار بحريني', { diff --git a/packages/common/locales/ar-DJ.ts b/packages/common/locales/ar-DJ.ts index 8c95558059..241ed03dae 100644 --- a/packages/common/locales/ar-DJ.ts +++ b/packages/common/locales/ar-DJ.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'DJF', 'Fdj', 'فرنك جيبوتي', { diff --git a/packages/common/locales/ar-DZ.ts b/packages/common/locales/ar-DZ.ts index aecf998960..161d2e6da6 100644 --- a/packages/common/locales/ar-DZ.ts +++ b/packages/common/locales/ar-DZ.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'DZD', 'د.ج.\u200f', 'دينار جزائري', { diff --git a/packages/common/locales/ar-EG.ts b/packages/common/locales/ar-EG.ts index 0fcb3d7a26..5ec7615375 100644 --- a/packages/common/locales/ar-EG.ts +++ b/packages/common/locales/ar-EG.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EGP', 'ج.م.\u200f', 'جنيه مصري', { diff --git a/packages/common/locales/ar-EH.ts b/packages/common/locales/ar-EH.ts index d46e40c89e..8a61bd9868 100644 --- a/packages/common/locales/ar-EH.ts +++ b/packages/common/locales/ar-EH.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MAD', 'د.م.\u200f', 'درهم مغربي', { diff --git a/packages/common/locales/ar-ER.ts b/packages/common/locales/ar-ER.ts index a6cb870306..b1d1da6c02 100644 --- a/packages/common/locales/ar-ER.ts +++ b/packages/common/locales/ar-ER.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'ERN', 'Nfk', 'ناكفا أريتري', { diff --git a/packages/common/locales/ar-IL.ts b/packages/common/locales/ar-IL.ts index d02062d1f7..53d656d611 100644 --- a/packages/common/locales/ar-IL.ts +++ b/packages/common/locales/ar-IL.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'ILS', '₪', 'شيكل إسرائيلي جديد', { diff --git a/packages/common/locales/ar-IQ.ts b/packages/common/locales/ar-IQ.ts index 0aec257bbf..7db1d614a4 100644 --- a/packages/common/locales/ar-IQ.ts +++ b/packages/common/locales/ar-IQ.ts @@ -66,6 +66,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'IQD', 'د.ع.\u200f', 'دينار عراقي', { diff --git a/packages/common/locales/ar-JO.ts b/packages/common/locales/ar-JO.ts index cfc53e49ea..e6245c20f7 100644 --- a/packages/common/locales/ar-JO.ts +++ b/packages/common/locales/ar-JO.ts @@ -54,6 +54,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'JOD', 'د.أ.\u200f', 'دينار أردني', { diff --git a/packages/common/locales/ar-KM.ts b/packages/common/locales/ar-KM.ts index 956055e839..f0ddd2f093 100644 --- a/packages/common/locales/ar-KM.ts +++ b/packages/common/locales/ar-KM.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'KMF', 'CF', 'فرنك جزر القمر', { diff --git a/packages/common/locales/ar-KW.ts b/packages/common/locales/ar-KW.ts index df34fb8d07..2490bc2137 100644 --- a/packages/common/locales/ar-KW.ts +++ b/packages/common/locales/ar-KW.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'KWD', 'د.ك.\u200f', 'دينار كويتي', { diff --git a/packages/common/locales/ar-LB.ts b/packages/common/locales/ar-LB.ts index 3fc02087cf..e30313214b 100644 --- a/packages/common/locales/ar-LB.ts +++ b/packages/common/locales/ar-LB.ts @@ -54,6 +54,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'LBP', 'ل.ل.\u200f', 'جنيه لبناني', { diff --git a/packages/common/locales/ar-LY.ts b/packages/common/locales/ar-LY.ts index cd911792f9..b4054f0284 100644 --- a/packages/common/locales/ar-LY.ts +++ b/packages/common/locales/ar-LY.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'LYD', 'د.ل.\u200f', 'دينار ليبي', { diff --git a/packages/common/locales/ar-MA.ts b/packages/common/locales/ar-MA.ts index e815c560c2..cf88bc0380 100644 --- a/packages/common/locales/ar-MA.ts +++ b/packages/common/locales/ar-MA.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MAD', 'د.م.\u200f', 'درهم مغربي', { diff --git a/packages/common/locales/ar-MR.ts b/packages/common/locales/ar-MR.ts index 0ba7ac36a6..68568ea7ae 100644 --- a/packages/common/locales/ar-MR.ts +++ b/packages/common/locales/ar-MR.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MRU', 'أ.م.', 'أوقية موريتانية', { diff --git a/packages/common/locales/ar-OM.ts b/packages/common/locales/ar-OM.ts index e6aa89d40f..b9105aaa4d 100644 --- a/packages/common/locales/ar-OM.ts +++ b/packages/common/locales/ar-OM.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'OMR', 'ر.ع.\u200f', 'ريال عماني', { diff --git a/packages/common/locales/ar-PS.ts b/packages/common/locales/ar-PS.ts index 51cf291979..392ef5b878 100644 --- a/packages/common/locales/ar-PS.ts +++ b/packages/common/locales/ar-PS.ts @@ -54,6 +54,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'ILS', '₪', 'شيكل إسرائيلي جديد', { diff --git a/packages/common/locales/ar-QA.ts b/packages/common/locales/ar-QA.ts index 42180a7bfe..edfa7c7b72 100644 --- a/packages/common/locales/ar-QA.ts +++ b/packages/common/locales/ar-QA.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'QAR', 'ر.ق.\u200f', 'ريال قطري', { diff --git a/packages/common/locales/ar-SA.ts b/packages/common/locales/ar-SA.ts index 870ba005b9..c5851068bf 100644 --- a/packages/common/locales/ar-SA.ts +++ b/packages/common/locales/ar-SA.ts @@ -50,6 +50,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '٪', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'ليس رقمًا', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SAR', 'ر.س.\u200f', 'ريال سعودي', { diff --git a/packages/common/locales/ar-SD.ts b/packages/common/locales/ar-SD.ts index c70e2dd36b..3ee16a465d 100644 --- a/packages/common/locales/ar-SD.ts +++ b/packages/common/locales/ar-SD.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SDG', 'ج.س.', 'جنيه سوداني', { diff --git a/packages/common/locales/ar-SO.ts b/packages/common/locales/ar-SO.ts index e06071df1e..f77ef52bcd 100644 --- a/packages/common/locales/ar-SO.ts +++ b/packages/common/locales/ar-SO.ts @@ -50,6 +50,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '٪', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'ليس رقمًا', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SOS', 'S', 'شلن صومالي', { diff --git a/packages/common/locales/ar-SS.ts b/packages/common/locales/ar-SS.ts index 808f590e0f..b618a2fce3 100644 --- a/packages/common/locales/ar-SS.ts +++ b/packages/common/locales/ar-SS.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SSP', '£', 'جنيه جنوب السودان', { diff --git a/packages/common/locales/ar-SY.ts b/packages/common/locales/ar-SY.ts index f0a279bc84..36f8204233 100644 --- a/packages/common/locales/ar-SY.ts +++ b/packages/common/locales/ar-SY.ts @@ -54,6 +54,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SYP', 'ل.س.\u200f', 'ليرة سورية', { diff --git a/packages/common/locales/ar-TD.ts b/packages/common/locales/ar-TD.ts index 0530ead6a9..0784611ceb 100644 --- a/packages/common/locales/ar-TD.ts +++ b/packages/common/locales/ar-TD.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'فرنك وسط أفريقي', { diff --git a/packages/common/locales/ar-TN.ts b/packages/common/locales/ar-TN.ts index 946740ef31..be07107d81 100644 --- a/packages/common/locales/ar-TN.ts +++ b/packages/common/locales/ar-TN.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TND', 'د.ت.\u200f', 'دينار تونسي', { diff --git a/packages/common/locales/ar-YE.ts b/packages/common/locales/ar-YE.ts index 73d0490e71..f2aaedd3b0 100644 --- a/packages/common/locales/ar-YE.ts +++ b/packages/common/locales/ar-YE.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'YER', 'ر.ي.\u200f', 'ريال يمني', { diff --git a/packages/common/locales/ar.ts b/packages/common/locales/ar.ts index 2282bd55ab..513a6fd014 100644 --- a/packages/common/locales/ar.ts +++ b/packages/common/locales/ar.ts @@ -53,6 +53,7 @@ export default [ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EGP', 'ج.م.\u200f', 'جنيه مصري', { diff --git a/packages/common/locales/as.ts b/packages/common/locales/as.ts index 34a2a124bb..48322812b2 100644 --- a/packages/common/locales/as.ts +++ b/packages/common/locales/as.ts @@ -63,6 +63,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'ভাৰতীয় ৰুপী', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/asa.ts b/packages/common/locales/asa.ts index b18a80eacb..044588c2a7 100644 --- a/packages/common/locales/asa.ts +++ b/packages/common/locales/asa.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'TZS', 'TSh', 'shilingi ya Tandhania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ast.ts b/packages/common/locales/ast.ts index 3e3b64cae0..3b84959468 100644 --- a/packages/common/locales/ast.ts +++ b/packages/common/locales/ast.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'ND', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/az-Cyrl.ts b/packages/common/locales/az-Cyrl.ts index 150f43d589..0352aa6566 100644 --- a/packages/common/locales/az-Cyrl.ts +++ b/packages/common/locales/az-Cyrl.ts @@ -58,6 +58,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AZN', '₼', 'AZN', {'AZN': ['₼'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/az-Latn.ts b/packages/common/locales/az-Latn.ts index 7d3186ba9d..51112d7b6e 100644 --- a/packages/common/locales/az-Latn.ts +++ b/packages/common/locales/az-Latn.ts @@ -60,6 +60,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AZN', '₼', 'Azərbaycan Manatı', { diff --git a/packages/common/locales/az.ts b/packages/common/locales/az.ts index 09b7e93e92..fd85a1420c 100644 --- a/packages/common/locales/az.ts +++ b/packages/common/locales/az.ts @@ -60,6 +60,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AZN', '₼', 'Azərbaycan Manatı', { diff --git a/packages/common/locales/bas.ts b/packages/common/locales/bas.ts index 0bb6b8fca5..4750e0f79c 100644 --- a/packages/common/locales/bas.ts +++ b/packages/common/locales/bas.ts @@ -45,6 +45,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Frǎŋ CFA (BEAC)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/be.ts b/packages/common/locales/be.ts index 6b366c191d..92f4021dfa 100644 --- a/packages/common/locales/be.ts +++ b/packages/common/locales/be.ts @@ -71,6 +71,7 @@ export default [ ['{1}, {0}', u, '{1} \'у\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BYN', 'Br', 'беларускі рубель', { diff --git a/packages/common/locales/bem.ts b/packages/common/locales/bem.ts index fa52dd9ef0..55c4c77864 100644 --- a/packages/common/locales/bem.ts +++ b/packages/common/locales/bem.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZMW', 'K', 'ZMW', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZMW': ['K', 'ZK']}, diff --git a/packages/common/locales/bez.ts b/packages/common/locales/bez.ts index b55b50f8fa..7da681ffb5 100644 --- a/packages/common/locales/bez.ts +++ b/packages/common/locales/bez.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Hutanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/bg.ts b/packages/common/locales/bg.ts index dc5f6f77d1..b27a8fd341 100644 --- a/packages/common/locales/bg.ts +++ b/packages/common/locales/bg.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '0.00 ¤', '#E0'], + 'BGN', 'лв.', 'Български лев', { diff --git a/packages/common/locales/bm.ts b/packages/common/locales/bm.ts index 013ac22ca8..f74b666500 100644 --- a/packages/common/locales/bm.ts +++ b/packages/common/locales/bm.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XOF', 'CFA', 'sefa Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/bn-IN.ts b/packages/common/locales/bn-IN.ts index 2164d29584..825d7618da 100644 --- a/packages/common/locales/bn-IN.ts +++ b/packages/common/locales/bn-IN.ts @@ -75,6 +75,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'INR', '₹', 'ভারতীয় রুপি', {'BDT': ['৳'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/bn.ts b/packages/common/locales/bn.ts index a502e785f1..bd07efe6d8 100644 --- a/packages/common/locales/bn.ts +++ b/packages/common/locales/bn.ts @@ -75,6 +75,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'BDT', '৳', 'বাংলাদেশী টাকা', {'BDT': ['৳'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/bo-IN.ts b/packages/common/locales/bo-IN.ts index 4854c278e0..9a2f999fce 100644 --- a/packages/common/locales/bo-IN.ts +++ b/packages/common/locales/bo-IN.ts @@ -82,6 +82,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'རྒྱ་གར་སྒོར་', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/bo.ts b/packages/common/locales/bo.ts index aa74ee496a..df4742b40d 100644 --- a/packages/common/locales/bo.ts +++ b/packages/common/locales/bo.ts @@ -82,6 +82,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'CNY', '¥', 'ཡུ་ཨན་', {'CNY': ['¥'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/br.ts b/packages/common/locales/br.ts index a96e489ea8..65e475aa33 100644 --- a/packages/common/locales/br.ts +++ b/packages/common/locales/br.ts @@ -52,6 +52,7 @@ export default [ ['{1} {0}', '{1}, {0}', '{1} \'da\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/brx.ts b/packages/common/locales/brx.ts index fc3e6ae6c1..0c185d1c2c 100644 --- a/packages/common/locales/brx.ts +++ b/packages/common/locales/brx.ts @@ -58,6 +58,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'रां', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/bs-Cyrl.ts b/packages/common/locales/bs-Cyrl.ts index 26ab2827b6..8beb70d4fe 100644 --- a/packages/common/locales/bs-Cyrl.ts +++ b/packages/common/locales/bs-Cyrl.ts @@ -55,6 +55,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'BAM', 'КМ', 'Конвертибилна марка', { diff --git a/packages/common/locales/bs-Latn.ts b/packages/common/locales/bs-Latn.ts index 572be503e6..7546df5525 100644 --- a/packages/common/locales/bs-Latn.ts +++ b/packages/common/locales/bs-Latn.ts @@ -54,6 +54,7 @@ export default [ ['{1} {0}', u, '{1} \'u\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BAM', 'KM', 'Bosanskohercegovačka konvertibilna marka', { diff --git a/packages/common/locales/bs.ts b/packages/common/locales/bs.ts index d105a76fbd..af85bf81b1 100644 --- a/packages/common/locales/bs.ts +++ b/packages/common/locales/bs.ts @@ -54,6 +54,7 @@ export default [ ['{1} {0}', u, '{1} \'u\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BAM', 'KM', 'Bosanskohercegovačka konvertibilna marka', { diff --git a/packages/common/locales/ca-AD.ts b/packages/common/locales/ca-AD.ts index c8df680ffa..59338ac9ed 100644 --- a/packages/common/locales/ca-AD.ts +++ b/packages/common/locales/ca-AD.ts @@ -57,6 +57,7 @@ export default [ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/ca-ES-VALENCIA.ts b/packages/common/locales/ca-ES-VALENCIA.ts index fb6f7b5002..cf5e69a6c4 100644 --- a/packages/common/locales/ca-ES-VALENCIA.ts +++ b/packages/common/locales/ca-ES-VALENCIA.ts @@ -57,6 +57,7 @@ export default [ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/ca-FR.ts b/packages/common/locales/ca-FR.ts index 4b960fc0f3..854850e878 100644 --- a/packages/common/locales/ca-FR.ts +++ b/packages/common/locales/ca-FR.ts @@ -57,6 +57,7 @@ export default [ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/ca-IT.ts b/packages/common/locales/ca-IT.ts index b4e5edd818..cc5f10954c 100644 --- a/packages/common/locales/ca-IT.ts +++ b/packages/common/locales/ca-IT.ts @@ -57,6 +57,7 @@ export default [ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/ca.ts b/packages/common/locales/ca.ts index 4b70bdeb33..6c2fd9b6bf 100644 --- a/packages/common/locales/ca.ts +++ b/packages/common/locales/ca.ts @@ -57,6 +57,7 @@ export default [ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/ccp-IN.ts b/packages/common/locales/ccp-IN.ts index b74a70d34a..193a098d25 100644 --- a/packages/common/locales/ccp-IN.ts +++ b/packages/common/locales/ccp-IN.ts @@ -87,6 +87,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'INR', '₹', '𑄃𑄨𑄚𑄴𑄘𑄨𑄠𑄚𑄴 𑄢𑄪𑄛𑄨', { diff --git a/packages/common/locales/ccp.ts b/packages/common/locales/ccp.ts index e6e1e6cf96..26e10637a7 100644 --- a/packages/common/locales/ccp.ts +++ b/packages/common/locales/ccp.ts @@ -87,6 +87,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'BDT', '৳', '𑄝𑄁𑄣𑄘𑄬𑄥𑄨 𑄑𑄬𑄋', { diff --git a/packages/common/locales/ce.ts b/packages/common/locales/ce.ts index eefd68fc93..fafe281614 100644 --- a/packages/common/locales/ce.ts +++ b/packages/common/locales/ce.ts @@ -64,6 +64,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'Терхьаш дац', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'Российн сом', {'JPY': ['JP¥', '¥'], 'RON': [u, 'лей'], 'RUB': ['₽'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ceb.ts b/packages/common/locales/ceb.ts index 8d5d0d9abf..45c92c8273 100644 --- a/packages/common/locales/ceb.ts +++ b/packages/common/locales/ceb.ts @@ -42,6 +42,7 @@ export default [ ['{1}, {0}', u, '{1} \'sa\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,#0%', '¤#,##0.00', '#E0'], + 'PHP', '₱', 'Philippine Piso', {'JPY': ['JP¥', '¥'], 'PHP': ['₱'], 'USD': ['US $', '$']}, diff --git a/packages/common/locales/cgg.ts b/packages/common/locales/cgg.ts index b48aca2751..e10e0790d0 100644 --- a/packages/common/locales/cgg.ts +++ b/packages/common/locales/cgg.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Eshiringi ya Uganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/chr.ts b/packages/common/locales/chr.ts index ac226b5c88..6a5ae4793b 100644 --- a/packages/common/locales/chr.ts +++ b/packages/common/locales/chr.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} ᎤᎾᎢ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US ᎠᏕᎳ', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/ckb-IR.ts b/packages/common/locales/ckb-IR.ts index 546e27e37d..a1d532e36c 100644 --- a/packages/common/locales/ckb-IR.ts +++ b/packages/common/locales/ckb-IR.ts @@ -49,6 +49,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'IRR', 'IRR', + 'IRR', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'rtl', plural diff --git a/packages/common/locales/ckb.ts b/packages/common/locales/ckb.ts index 2955d94424..47bb02b7ba 100644 --- a/packages/common/locales/ckb.ts +++ b/packages/common/locales/ckb.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'IQD', 'د.ع.\u200f', 'IQD', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/closure-locale.ts b/packages/common/locales/closure-locale.ts index c76162e2ff..8c7e6aa7b0 100644 --- a/packages/common/locales/closure-locale.ts +++ b/packages/common/locales/closure-locale.ts @@ -45,6 +45,7 @@ export const locale_af = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'Suid-Afrikaanse rand', { @@ -93,6 +94,7 @@ export const locale_am = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'ብር', 'የኢትዮጵያ ብር', { @@ -144,6 +146,7 @@ export const locale_ar = [ ['{1} {0}', u, u, u], ['.', ',', ';', '\u200e%\u200e', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'ليس رقمًا', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EGP', 'ج.م.\u200f', 'جنيه مصري', { @@ -239,6 +242,7 @@ export const locale_ar_DZ = [ ['{1} {0}', u, u, u], [',', '.', ';', '\u200e%\u200e', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'ليس رقمًا', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'DZD', 'د.ج.\u200f', 'دينار جزائري', { @@ -341,6 +345,7 @@ export const locale_az = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AZN', '₼', 'Azərbaycan Manatı', { @@ -401,6 +406,7 @@ export const locale_be = [ ['{1}, {0}', u, '{1} \'у\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BYN', 'Br', 'беларускі рубель', { @@ -468,6 +474,7 @@ export const locale_bg = [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '0.00 ¤', '#E0'], + 'BGN', 'лв.', 'Български лев', { @@ -573,6 +580,7 @@ export const locale_bn = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'BDT', '৳', 'বাংলাদেশী টাকা', {'BDT': ['৳'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, @@ -621,6 +629,7 @@ export const locale_br = [ ['{1} {0}', '{1}, {0}', '{1} \'da\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -690,6 +699,7 @@ export const locale_bs = [ ['{1} {0}', u, '{1} \'u\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BAM', 'KM', 'Bosanskohercegovačka konvertibilna marka', { @@ -760,6 +770,7 @@ export const locale_ca = [ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -808,6 +819,7 @@ export const locale_chr = [ ['{1}, {0}', u, '{1} ᎤᎾᎢ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US ᎠᏕᎳ', {'JPY': ['JP¥', '¥']}, @@ -857,6 +869,7 @@ export const locale_cs = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CZK', 'Kč', 'česká koruna', { @@ -930,6 +943,7 @@ export const locale_cy = [ ['{1} {0}', u, '{1} \'am\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'Punt Prydain', { @@ -987,6 +1001,7 @@ export const locale_da = [ ['{1} {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'dansk krone', { @@ -1051,6 +1066,7 @@ export const locale_de = [ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { @@ -1119,6 +1135,7 @@ export const locale_de_AT = [ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':', u, '.'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'Euro', { @@ -1190,6 +1207,7 @@ export const locale_de_CH = [ ['.', '’', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤-#,##0.00', '#E0'], 'CHF', + 'CHF', 'Schweizer Franken', { 'ATS': ['öS'], @@ -1253,6 +1271,7 @@ export const locale_el = [ ['{1}, {0}', u, '{1} - {0}', u], [',', '.', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Ευρώ', {'GRD': ['Δρχ'], 'JPY': ['JP¥', '¥'], 'THB': ['฿']}, @@ -1294,6 +1313,7 @@ export const locale_en_AU = [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', { @@ -1364,6 +1384,7 @@ export const locale_en_CA = [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CAD', '$', 'Canadian Dollar', {'CAD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, @@ -1404,6 +1425,7 @@ export const locale_en_GB = [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'British Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, @@ -1444,6 +1466,7 @@ export const locale_en_IE = [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, @@ -1484,6 +1507,7 @@ export const locale_en_IN = [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'Indian Rupee', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, @@ -1524,6 +1548,7 @@ export const locale_en_SG = [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SGD', '$', 'Singapore Dollar', {'JPY': ['JP¥', '¥'], 'SGD': ['$'], 'USD': ['US$', '$']}, @@ -1564,6 +1589,7 @@ export const locale_en_ZA = [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'South African Rand', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZAR': ['R']}, @@ -1606,6 +1632,7 @@ export const locale_es = [ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -1673,6 +1700,7 @@ export const locale_es_419 = [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], 'EUR', + 'EUR', 'euro', { 'AUD': [u, '$'], @@ -1739,6 +1767,7 @@ export const locale_es_MX = [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'MXN', '$', 'peso mexicano', { @@ -1804,6 +1833,7 @@ export const locale_es_US = [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'USD', '$', 'dólar estadounidense', { @@ -1864,6 +1894,7 @@ export const locale_et = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'AUD': ['AU$', '$'], 'EEK': ['kr'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -1908,6 +1939,7 @@ export const locale_eu = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '% #,##0', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euroa', {'ESP': ['₧'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, @@ -1955,6 +1987,7 @@ export const locale_fa = [ ['{1}،\u200f {0}', u, '{1}، ساعت {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'ناعدد', ':'], ['#,##0.###', '#,##0%', '\u200e¤ #,##0.00', '#E0'], + 'IRR', 'ریال', 'ریال ایران', { @@ -2025,6 +2058,7 @@ export const locale_fi = [ ['{1} {0}', '{1} \'klo\' {0}', u, u], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'epäluku', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -2165,6 +2199,7 @@ export const locale_fr = [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -2256,6 +2291,7 @@ export const locale_fr_CA = [ ['{1} {0}', u, '{1} \'à\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CAD', '$', 'dollar canadien', { @@ -2335,6 +2371,7 @@ export const locale_ga = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'THB': ['฿'], 'TWD': ['NT$'], 'XXX': []}, @@ -2391,6 +2428,7 @@ export const locale_gl = [ ['{0}, {1}', u, '{0} \'do\' {1}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -2441,6 +2479,7 @@ export const locale_gsw = [ ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'Schwiizer Franke', {'ATS': ['öS']}, 'ltr', @@ -2480,6 +2519,7 @@ export const locale_gu = [ ['{1} {0}', u, '{1} એ {0} વાગ્યે', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '[#E0]'], + 'INR', '₹', 'ભારતીય રૂપિયા', {'JPY': ['JP¥', '¥'], 'MUR': [u, 'રૂ.'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, @@ -2519,6 +2559,7 @@ export const locale_haw = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'USD', {'JPY': ['JP¥', '¥']}, @@ -2559,6 +2600,7 @@ export const locale_hi = [ ['{1}, {0}', u, '{1} को {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '[#E0]'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'RON': [u, 'लेई'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -2617,6 +2659,7 @@ export const locale_hr = [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'HRK', + 'HRK', 'hrvatska kuna', { 'AUD': [u, '$'], @@ -2678,6 +2721,7 @@ export const locale_hu = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'HUF', 'Ft', 'magyar forint', { @@ -2743,6 +2787,7 @@ export const locale_hy = [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'ՈչԹ', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AMD', '֏', 'հայկական դրամ', {'AMD': ['֏'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -2781,6 +2826,7 @@ export const locale_in = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'IDR', 'Rp', 'Rupiah Indonesia', { @@ -2835,6 +2881,7 @@ export const locale_is = [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'ISK', + 'ISK', 'íslensk króna', { 'AUD': [u, '$'], @@ -2888,6 +2935,7 @@ export const locale_it = [ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -2943,6 +2991,7 @@ export const locale_iw = [ ['{1}, {0}', u, '{1} בשעה {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '\u200f#,##0.00 ¤;\u200f-#,##0.00 ¤', '#E0'], + 'ILS', '₪', 'שקל חדש', {'BYN': [u, 'р'], 'CNY': ['\u200eCN¥\u200e', '¥'], 'ILP': ['ל״י'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -2977,6 +3026,7 @@ export const locale_ja = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'JPY', '¥', '日本円', {'CNY': ['元', '¥'], 'JPY': ['¥'], 'RON': [u, 'レイ'], 'XXX': []}, @@ -3016,6 +3066,7 @@ export const locale_ka = [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'არ არის რიცხვი', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GEL', '₾', 'ქართული ლარი', { @@ -3079,6 +3130,7 @@ export const locale_kk = [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'сан емес', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'KZT', '₸', 'Қазақстан теңгесі', {'JPY': ['JP¥', '¥'], 'KZT': ['₸'], 'RUB': ['₽'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -3115,6 +3167,7 @@ export const locale_km = [ ['{1}, {0}', u, '{1} នៅ​ម៉ោង {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'KHR', '៛', 'រៀល​កម្ពុជា', {'JPY': ['JP¥', '¥'], 'KHR': ['៛'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -3162,6 +3215,7 @@ export const locale_kn = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ಭಾರತೀಯ ರೂಪಾಯಿ', {'JPY': ['JP¥', '¥'], 'RON': [u, 'ಲೀ'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -3193,6 +3247,7 @@ export const locale_ko = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KRW', '₩', '대한민국 원', {'AUD': ['AU$', '$'], 'JPY': ['JP¥', '¥'], 'RON': [u, 'L'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, @@ -3240,6 +3295,7 @@ export const locale_ky = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'сан эмес', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'KGS', 'сом', 'Кыргызстан сому', { @@ -3308,6 +3364,7 @@ export const locale_ln = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'CDF', 'FC', 'Falánga ya Kongó', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, @@ -3351,6 +3408,7 @@ export const locale_lo = [ 'ບໍ່​ແມ່ນ​ໂຕ​ເລກ', ':' ], ['#,##0.###', '#,##0%', '¤#,##0.00;¤-#,##0.00', '#'], + 'LAK', '₭', 'ລາວ ກີບ', {'JPY': ['JP¥', '¥'], 'LAK': ['₭'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, @@ -3411,6 +3469,7 @@ export const locale_lt = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euras', { @@ -3494,6 +3553,7 @@ export const locale_lv = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NS', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'eiro', {'AUD': ['AU$', '$'], 'LVL': ['Ls'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -3542,6 +3602,7 @@ export const locale_mk = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MKD', 'ден.', 'Македонски денар', { @@ -3607,6 +3668,7 @@ export const locale_ml = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ഇന്ത്യൻ രൂപ', {'THB': ['฿'], 'TWD': ['NT$']}, @@ -3668,6 +3730,7 @@ export const locale_mn = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MNT', '₮', 'Монгол төгрөг', {'JPY': ['JP¥', '¥'], 'MNT': ['₮'], 'SEK': [u, 'кр'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -3713,6 +3776,7 @@ export const locale_mo = [ ['{1}, {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MDL', 'L', 'leu moldovenesc', { @@ -3772,6 +3836,7 @@ export const locale_mr = [ ['{1}, {0}', u, '{1} रोजी {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '[#E0]'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -3810,6 +3875,7 @@ export const locale_ms = [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MYR', 'RM', 'Ringgit Malaysia', { @@ -3869,6 +3935,7 @@ export const locale_mt = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'ewro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, @@ -3906,6 +3973,7 @@ export const locale_my = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'ဂဏန်းမဟုတ်သော', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MMK', 'K', 'မြန်မာ ကျပ်', { @@ -3964,6 +4032,7 @@ export const locale_ne = [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'NPR', 'नेरू', 'नेपाली रूपैयाँ', {'JPY': ['JP¥', '¥'], 'NPR': ['नेरू', 'रू'], 'THB': ['฿'], 'USD': ['US$', '$']}, @@ -4004,6 +4073,7 @@ export const locale_nl = [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'EUR', '€', 'Euro', { @@ -4061,6 +4131,7 @@ export const locale_no = [ ['{1}, {0}', u, '{1} \'kl\'. {0}', '{1} {0}'], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'NOK', 'kr', 'norske kroner', { @@ -4121,6 +4192,7 @@ export const locale_or = [ ['{1}, {0}', u, '{0} ଠାରେ {1}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ଭାରତୀୟ ଟଙ୍କା', {}, @@ -4159,6 +4231,7 @@ export const locale_pa = [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '[#E0]'], + 'INR', '₹', 'ਭਾਰਤੀ ਰੁਪਇਆ', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, @@ -4217,6 +4290,7 @@ export const locale_pl = [ ['{1}, {0}', u, '{1} {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'PLN', 'zł', 'złoty polski', { @@ -4279,6 +4353,7 @@ export const locale_pt = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'BRL', 'R$', 'Real brasileiro', { @@ -4334,6 +4409,7 @@ export const locale_pt_PT = [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -4388,6 +4464,7 @@ export const locale_ro = [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'RON', + 'RON', 'leu românesc', { 'AUD': [u, '$'], @@ -4469,6 +4546,7 @@ export const locale_ru = [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'российский рубль', { @@ -4518,6 +4596,7 @@ export const locale_sh = [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Srpski dinar', { 'AUD': [u, '$'], @@ -4575,6 +4654,7 @@ export const locale_si = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#'], + 'LKR', 'රු.', 'ශ්\u200dරී ලංකා රුපියල', { @@ -4631,6 +4711,7 @@ export const locale_sk = [ ['{1} {0}', '{1}, {0}', u, u], [',', ' ', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { @@ -4690,6 +4771,7 @@ export const locale_sl = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '−', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'evro', { @@ -4742,6 +4824,7 @@ export const locale_sq = [ ['{1}, {0}', u, '{1} \'në\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'ALL', 'Lekë', 'Leku shqiptar', { @@ -4884,6 +4967,7 @@ export const locale_sr = [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Српски динар', { 'AUD': [u, '$'], @@ -4932,6 +5016,7 @@ export const locale_sv = [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SEK', 'kr', 'svensk krona', { @@ -4999,6 +5084,7 @@ export const locale_sw = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', { @@ -5046,6 +5132,7 @@ export const locale_ta = [ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'இந்திய ரூபாய்', {'THB': ['฿'], 'TWD': ['NT$']}, @@ -5085,6 +5172,7 @@ export const locale_te = [ ['{1} {0}', u, '{1} {0}కి', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'రూపాయి', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -5126,6 +5214,7 @@ export const locale_th = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'THB', '฿', 'บาท', {'AUD': ['AU$', '$'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, @@ -5176,6 +5265,7 @@ export const locale_tl = [ ['{1}, {0}', u, '{1} \'nang\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PHP', '₱', 'Piso ng Pilipinas', {'PHP': ['₱'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -5215,6 +5305,7 @@ export const locale_tr = [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '%#,##0', '¤#,##0.00', '#E0'], + 'TRY', '₺', 'Türk Lirası', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'THB': ['฿'], 'TRY': ['₺'], 'TWD': ['NT$']}, @@ -5272,6 +5363,7 @@ export const locale_uk = [ ['{1}, {0}', u, '{1} \'о\' {0}', u], [',', ' ', ';', '%', '+', '-', 'Е', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UAH', '₴', 'українська гривня', { @@ -5330,6 +5422,7 @@ export const locale_ur = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'PKR', 'Rs', 'پاکستانی روپیہ', {'JPY': ['JP¥', '¥'], 'PKR': ['Rs'], 'THB': ['฿'], 'TWD': ['NT$']}, @@ -5376,6 +5469,7 @@ export const locale_uz = [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'son emas', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UZS', 'soʻm', 'O‘zbekiston so‘mi', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'UZS': ['soʻm']}, @@ -5428,6 +5522,7 @@ export const locale_vi = [ ['{0}, {1}', u, '{0} {1}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'VND', '₫', 'Đồng Việt Nam', { @@ -5474,6 +5569,7 @@ export const locale_zh = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { @@ -5522,6 +5618,7 @@ export const locale_zh_CN = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { @@ -5566,6 +5663,7 @@ export const locale_zh_HK = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港元', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'USD': ['US$', '$'], 'XXX': []}, @@ -5601,6 +5699,7 @@ export const locale_zh_TW = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TWD', '$', '新台幣', { @@ -5655,6 +5754,7 @@ export const locale_zu = [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'i-South African Rand', { diff --git a/packages/common/locales/cs.ts b/packages/common/locales/cs.ts index 42c4d477f9..99a2e55f75 100644 --- a/packages/common/locales/cs.ts +++ b/packages/common/locales/cs.ts @@ -56,6 +56,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CZK', 'Kč', 'česká koruna', { diff --git a/packages/common/locales/cu.ts b/packages/common/locales/cu.ts index 10358b2638..ad423a75f8 100644 --- a/packages/common/locales/cu.ts +++ b/packages/common/locales/cu.ts @@ -34,6 +34,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'RUB', '₽', 'RUB', {'JPY': ['JP¥', '¥'], 'RUB': ['₽'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/cy.ts b/packages/common/locales/cy.ts index 6899c6a6cf..46865f0c7a 100644 --- a/packages/common/locales/cy.ts +++ b/packages/common/locales/cy.ts @@ -64,6 +64,7 @@ export default [ ['{1} {0}', u, '{1} \'am\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'Punt Prydain', { diff --git a/packages/common/locales/da-GL.ts b/packages/common/locales/da-GL.ts index 3901b34845..c73b5a0075 100644 --- a/packages/common/locales/da-GL.ts +++ b/packages/common/locales/da-GL.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'dansk krone', { diff --git a/packages/common/locales/da.ts b/packages/common/locales/da.ts index 3154cd97f8..8cd14c53c8 100644 --- a/packages/common/locales/da.ts +++ b/packages/common/locales/da.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'dansk krone', { diff --git a/packages/common/locales/dav.ts b/packages/common/locales/dav.ts index 4237b9135e..f3e8e59491 100644 --- a/packages/common/locales/dav.ts +++ b/packages/common/locales/dav.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/de-AT.ts b/packages/common/locales/de-AT.ts index 9e24c6afa2..9ca2915bbf 100644 --- a/packages/common/locales/de-AT.ts +++ b/packages/common/locales/de-AT.ts @@ -58,6 +58,7 @@ export default [ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':', u, '.'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/de-BE.ts b/packages/common/locales/de-BE.ts index 451efa85f8..49ef264768 100644 --- a/packages/common/locales/de-BE.ts +++ b/packages/common/locales/de-BE.ts @@ -58,6 +58,7 @@ export default [ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/de-CH.ts b/packages/common/locales/de-CH.ts index 73ecfdae80..92fe0773e5 100644 --- a/packages/common/locales/de-CH.ts +++ b/packages/common/locales/de-CH.ts @@ -59,6 +59,7 @@ export default [ ['.', '’', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤-#,##0.00', '#E0'], 'CHF', + 'CHF', 'Schweizer Franken', { 'ATS': ['öS'], diff --git a/packages/common/locales/de-IT.ts b/packages/common/locales/de-IT.ts index 4895231996..0b573130d2 100644 --- a/packages/common/locales/de-IT.ts +++ b/packages/common/locales/de-IT.ts @@ -58,6 +58,7 @@ export default [ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/de-LI.ts b/packages/common/locales/de-LI.ts index a86657c1f7..73c1a945b3 100644 --- a/packages/common/locales/de-LI.ts +++ b/packages/common/locales/de-LI.ts @@ -59,6 +59,7 @@ export default [ ['.', '’', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'CHF', + 'CHF', 'Schweizer Franken', { 'ATS': ['öS'], diff --git a/packages/common/locales/de-LU.ts b/packages/common/locales/de-LU.ts index dbf55bfc3f..df4968ce63 100644 --- a/packages/common/locales/de-LU.ts +++ b/packages/common/locales/de-LU.ts @@ -58,6 +58,7 @@ export default [ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/de.ts b/packages/common/locales/de.ts index 1c25041b6f..d1d915ac5d 100644 --- a/packages/common/locales/de.ts +++ b/packages/common/locales/de.ts @@ -58,6 +58,7 @@ export default [ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/dje.ts b/packages/common/locales/dje.ts index df683afd86..19bf2bcb5e 100644 --- a/packages/common/locales/dje.ts +++ b/packages/common/locales/dje.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/dsb.ts b/packages/common/locales/dsb.ts index 3d71cca8dc..d495e10e3c 100644 --- a/packages/common/locales/dsb.ts +++ b/packages/common/locales/dsb.ts @@ -59,6 +59,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'AUD': [u, '$'], 'PLN': ['zł'], 'THB': ['฿']}, diff --git a/packages/common/locales/dua.ts b/packages/common/locales/dua.ts index 3dcd3a0b96..134467a5a6 100644 --- a/packages/common/locales/dua.ts +++ b/packages/common/locales/dua.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'XAF', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/dyo.ts b/packages/common/locales/dyo.ts index 64c5464d10..605b1c9707 100644 --- a/packages/common/locales/dyo.ts +++ b/packages/common/locales/dyo.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'seefa yati BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/dz.ts b/packages/common/locales/dz.ts index e9d999729e..3ff695bdbb 100644 --- a/packages/common/locales/dz.ts +++ b/packages/common/locales/dz.ts @@ -82,6 +82,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0 %', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'རྒྱ་གར་གྱི་དངུལ་ རུ་པི', { diff --git a/packages/common/locales/ebu.ts b/packages/common/locales/ebu.ts index b744055281..e49c074e07 100644 --- a/packages/common/locales/ebu.ts +++ b/packages/common/locales/ebu.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ee-TG.ts b/packages/common/locales/ee-TG.ts index 30343d2941..2fcec7c68f 100644 --- a/packages/common/locales/ee-TG.ts +++ b/packages/common/locales/ee-TG.ts @@ -43,6 +43,7 @@ export default [ ['{0} {1}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'mnn', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XOF', 'CFA', 'ɣetoɖofe afrikaga CFA franc BCEAO', { diff --git a/packages/common/locales/ee.ts b/packages/common/locales/ee.ts index 69c00db43d..fdc11ce0bb 100644 --- a/packages/common/locales/ee.ts +++ b/packages/common/locales/ee.ts @@ -43,6 +43,7 @@ export default [ ['{0} {1}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'mnn', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GHS', 'GH₵', 'ghana siɖi', { diff --git a/packages/common/locales/el-CY.ts b/packages/common/locales/el-CY.ts index 7deb5ba1e6..d083df101b 100644 --- a/packages/common/locales/el-CY.ts +++ b/packages/common/locales/el-CY.ts @@ -62,6 +62,7 @@ export default [ ['{1}, {0}', u, '{1} - {0}', u], [',', '.', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Ευρώ', {'GRD': ['Δρχ'], 'JPY': ['JP¥', '¥'], 'THB': ['฿']}, diff --git a/packages/common/locales/el.ts b/packages/common/locales/el.ts index 27434862f6..ba1e724f63 100644 --- a/packages/common/locales/el.ts +++ b/packages/common/locales/el.ts @@ -62,6 +62,7 @@ export default [ ['{1}, {0}', u, '{1} - {0}', u], [',', '.', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Ευρώ', {'GRD': ['Δρχ'], 'JPY': ['JP¥', '¥'], 'THB': ['฿']}, diff --git a/packages/common/locales/en-001.ts b/packages/common/locales/en-001.ts index 7f43fa6bbc..d22bfdb1e8 100644 --- a/packages/common/locales/en-001.ts +++ b/packages/common/locales/en-001.ts @@ -46,6 +46,7 @@ export default [ ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural diff --git a/packages/common/locales/en-150.ts b/packages/common/locales/en-150.ts index 6a28ba64e4..833a195805 100644 --- a/packages/common/locales/en-150.ts +++ b/packages/common/locales/en-150.ts @@ -46,6 +46,7 @@ export default [ ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural diff --git a/packages/common/locales/en-AE.ts b/packages/common/locales/en-AE.ts index f2dcb976de..197e7cc5f5 100644 --- a/packages/common/locales/en-AE.ts +++ b/packages/common/locales/en-AE.ts @@ -45,6 +45,7 @@ export default [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'AED', + 'AED', 'United Arab Emirates Dirham', {}, 'ltr', diff --git a/packages/common/locales/en-AG.ts b/packages/common/locales/en-AG.ts index 595aa270a9..335c5d9914 100644 --- a/packages/common/locales/en-AG.ts +++ b/packages/common/locales/en-AG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-AI.ts b/packages/common/locales/en-AI.ts index 00f6a47ae6..48a30f3d75 100644 --- a/packages/common/locales/en-AI.ts +++ b/packages/common/locales/en-AI.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-AS.ts b/packages/common/locales/en-AS.ts index 75d32d85e1..153998bfc4 100644 --- a/packages/common/locales/en-AS.ts +++ b/packages/common/locales/en-AS.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-AT.ts b/packages/common/locales/en-AT.ts index 40aec252c5..43099f2861 100644 --- a/packages/common/locales/en-AT.ts +++ b/packages/common/locales/en-AT.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-AU.ts b/packages/common/locales/en-AU.ts index 06403656e3..235caa6343 100644 --- a/packages/common/locales/en-AU.ts +++ b/packages/common/locales/en-AU.ts @@ -45,6 +45,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', { diff --git a/packages/common/locales/en-BB.ts b/packages/common/locales/en-BB.ts index d9f659adba..00f10afdeb 100644 --- a/packages/common/locales/en-BB.ts +++ b/packages/common/locales/en-BB.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BBD', '$', 'Barbadian Dollar', {'BBD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-BE.ts b/packages/common/locales/en-BE.ts index dfb0a76d94..a0408581e0 100644 --- a/packages/common/locales/en-BE.ts +++ b/packages/common/locales/en-BE.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-BI.ts b/packages/common/locales/en-BI.ts index e320e044bf..cd7ded3b6c 100644 --- a/packages/common/locales/en-BI.ts +++ b/packages/common/locales/en-BI.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BIF', 'FBu', 'Burundian Franc', {'BIF': ['FBu']}, diff --git a/packages/common/locales/en-BM.ts b/packages/common/locales/en-BM.ts index a04265cbf1..0ec7debd25 100644 --- a/packages/common/locales/en-BM.ts +++ b/packages/common/locales/en-BM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BMD', '$', 'Bermudan Dollar', {'BMD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-BS.ts b/packages/common/locales/en-BS.ts index b4fce580b0..09cb0d5fd3 100644 --- a/packages/common/locales/en-BS.ts +++ b/packages/common/locales/en-BS.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BSD', '$', 'Bahamian Dollar', {'BSD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-BW.ts b/packages/common/locales/en-BW.ts index 7f01eb8647..cdd0623ecd 100644 --- a/packages/common/locales/en-BW.ts +++ b/packages/common/locales/en-BW.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BWP', 'P', 'Botswanan Pula', {'BWP': ['P'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-BZ.ts b/packages/common/locales/en-BZ.ts index c09dea7104..ec647c00e5 100644 --- a/packages/common/locales/en-BZ.ts +++ b/packages/common/locales/en-BZ.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BZD', '$', 'Belize Dollar', {'BZD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-CA.ts b/packages/common/locales/en-CA.ts index a068af1166..b787c265e0 100644 --- a/packages/common/locales/en-CA.ts +++ b/packages/common/locales/en-CA.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CAD', '$', 'Canadian Dollar', {'CAD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-CC.ts b/packages/common/locales/en-CC.ts index e36cca923f..4f827d180e 100644 --- a/packages/common/locales/en-CC.ts +++ b/packages/common/locales/en-CC.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-CH.ts b/packages/common/locales/en-CH.ts index 12167c4520..a7b5efee39 100644 --- a/packages/common/locales/en-CH.ts +++ b/packages/common/locales/en-CH.ts @@ -45,6 +45,7 @@ export default [ ['.', '’', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤-#,##0.00', '#E0'], 'CHF', + 'CHF', 'Swiss Franc', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/en-CK.ts b/packages/common/locales/en-CK.ts index d3c81e56c8..276e8debee 100644 --- a/packages/common/locales/en-CK.ts +++ b/packages/common/locales/en-CK.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-CM.ts b/packages/common/locales/en-CM.ts index e837a10bc9..1b6e8f51c4 100644 --- a/packages/common/locales/en-CM.ts +++ b/packages/common/locales/en-CM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XAF', 'FCFA', 'Central African CFA Franc', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-CX.ts b/packages/common/locales/en-CX.ts index ca3d3a4e0e..b50c5d7c5b 100644 --- a/packages/common/locales/en-CX.ts +++ b/packages/common/locales/en-CX.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-CY.ts b/packages/common/locales/en-CY.ts index e00c8fb483..25a1b67368 100644 --- a/packages/common/locales/en-CY.ts +++ b/packages/common/locales/en-CY.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-DE.ts b/packages/common/locales/en-DE.ts index 835aff295d..2019a1e0d6 100644 --- a/packages/common/locales/en-DE.ts +++ b/packages/common/locales/en-DE.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-DG.ts b/packages/common/locales/en-DG.ts index 42a213cb3a..35929a712b 100644 --- a/packages/common/locales/en-DG.ts +++ b/packages/common/locales/en-DG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-DK.ts b/packages/common/locales/en-DK.ts index 01da74086c..849ec0c6da 100644 --- a/packages/common/locales/en-DK.ts +++ b/packages/common/locales/en-DK.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'Danish Krone', {'DKK': ['kr.', 'kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-DM.ts b/packages/common/locales/en-DM.ts index ea17391512..59988d745c 100644 --- a/packages/common/locales/en-DM.ts +++ b/packages/common/locales/en-DM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-ER.ts b/packages/common/locales/en-ER.ts index 13cd389169..f670b293bc 100644 --- a/packages/common/locales/en-ER.ts +++ b/packages/common/locales/en-ER.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ERN', 'Nfk', 'Eritrean Nakfa', {'ERN': ['Nfk'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-FI.ts b/packages/common/locales/en-FI.ts index bf46ee433d..7779b0b723 100644 --- a/packages/common/locales/en-FI.ts +++ b/packages/common/locales/en-FI.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-FJ.ts b/packages/common/locales/en-FJ.ts index 186a079678..30092419f9 100644 --- a/packages/common/locales/en-FJ.ts +++ b/packages/common/locales/en-FJ.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'FJD', '$', 'Fijian Dollar', {'FJD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-FK.ts b/packages/common/locales/en-FK.ts index 443eacb720..561d879817 100644 --- a/packages/common/locales/en-FK.ts +++ b/packages/common/locales/en-FK.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'FKP', '£', 'Falkland Islands Pound', {'FKP': ['£'], 'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-FM.ts b/packages/common/locales/en-FM.ts index 8215ee1f56..d5319875e7 100644 --- a/packages/common/locales/en-FM.ts +++ b/packages/common/locales/en-FM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-GB.ts b/packages/common/locales/en-GB.ts index e712463848..fdb1977d4c 100644 --- a/packages/common/locales/en-GB.ts +++ b/packages/common/locales/en-GB.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'British Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-GD.ts b/packages/common/locales/en-GD.ts index 8e4e1c42b3..b51502d7c1 100644 --- a/packages/common/locales/en-GD.ts +++ b/packages/common/locales/en-GD.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-GG.ts b/packages/common/locales/en-GG.ts index 155d3e6b0d..23188399df 100644 --- a/packages/common/locales/en-GG.ts +++ b/packages/common/locales/en-GG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'UK Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-GH.ts b/packages/common/locales/en-GH.ts index 1c2f746f92..2625747839 100644 --- a/packages/common/locales/en-GH.ts +++ b/packages/common/locales/en-GH.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GHS', 'GH₵', 'Ghanaian Cedi', {'GHS': ['GH₵'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-GI.ts b/packages/common/locales/en-GI.ts index 55a6b13d8b..ed3f6153d2 100644 --- a/packages/common/locales/en-GI.ts +++ b/packages/common/locales/en-GI.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GIP', '£', 'Gibraltar Pound', {'GBP': ['GB£', '£'], 'GIP': ['£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-GM.ts b/packages/common/locales/en-GM.ts index 556feb4879..8e31b8b6be 100644 --- a/packages/common/locales/en-GM.ts +++ b/packages/common/locales/en-GM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GMD', 'D', 'Gambian Dalasi', {'GMD': ['D'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-GU.ts b/packages/common/locales/en-GU.ts index 3b1458fa72..0b7507137d 100644 --- a/packages/common/locales/en-GU.ts +++ b/packages/common/locales/en-GU.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-GY.ts b/packages/common/locales/en-GY.ts index f69d7fb215..111a4f1b0a 100644 --- a/packages/common/locales/en-GY.ts +++ b/packages/common/locales/en-GY.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GYD', '$', 'Guyanaese Dollar', {'GYD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-HK.ts b/packages/common/locales/en-HK.ts index 0d5c71b4bc..a1fd494a77 100644 --- a/packages/common/locales/en-HK.ts +++ b/packages/common/locales/en-HK.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', 'Hong Kong Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-IE.ts b/packages/common/locales/en-IE.ts index a12041bcee..81560095b9 100644 --- a/packages/common/locales/en-IE.ts +++ b/packages/common/locales/en-IE.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-IL.ts b/packages/common/locales/en-IL.ts index f9eefcd078..0cc8ea8e6b 100644 --- a/packages/common/locales/en-IL.ts +++ b/packages/common/locales/en-IL.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ILS', '₪', 'Israeli New Shekel', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-IM.ts b/packages/common/locales/en-IM.ts index 0cf6305a78..8d1ef82088 100644 --- a/packages/common/locales/en-IM.ts +++ b/packages/common/locales/en-IM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'UK Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-IN.ts b/packages/common/locales/en-IN.ts index c5ac6aad3f..29447577d2 100644 --- a/packages/common/locales/en-IN.ts +++ b/packages/common/locales/en-IN.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'Indian Rupee', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-IO.ts b/packages/common/locales/en-IO.ts index fad25b4fa8..dfb9269079 100644 --- a/packages/common/locales/en-IO.ts +++ b/packages/common/locales/en-IO.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-JE.ts b/packages/common/locales/en-JE.ts index e05864e1bb..3dae50a8a1 100644 --- a/packages/common/locales/en-JE.ts +++ b/packages/common/locales/en-JE.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'UK Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-JM.ts b/packages/common/locales/en-JM.ts index 932039a175..a1349c0a6f 100644 --- a/packages/common/locales/en-JM.ts +++ b/packages/common/locales/en-JM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'JMD', '$', 'Jamaican Dollar', {'JMD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-KE.ts b/packages/common/locales/en-KE.ts index bde9edf395..efedaa87ad 100644 --- a/packages/common/locales/en-KE.ts +++ b/packages/common/locales/en-KE.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Kenyan Shilling', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-KI.ts b/packages/common/locales/en-KI.ts index 72400959dd..b9f7085e73 100644 --- a/packages/common/locales/en-KI.ts +++ b/packages/common/locales/en-KI.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-KN.ts b/packages/common/locales/en-KN.ts index 72ed0019be..41b3d9bfd8 100644 --- a/packages/common/locales/en-KN.ts +++ b/packages/common/locales/en-KN.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-KY.ts b/packages/common/locales/en-KY.ts index 49b902bb3b..787205c424 100644 --- a/packages/common/locales/en-KY.ts +++ b/packages/common/locales/en-KY.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KYD', '$', 'Cayman Islands Dollar', {'JPY': ['JP¥', '¥'], 'KYD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-LC.ts b/packages/common/locales/en-LC.ts index 9475e72937..f51a808e8d 100644 --- a/packages/common/locales/en-LC.ts +++ b/packages/common/locales/en-LC.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-LR.ts b/packages/common/locales/en-LR.ts index 749782e1fc..3b33e532de 100644 --- a/packages/common/locales/en-LR.ts +++ b/packages/common/locales/en-LR.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'Liberian Dollar', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-LS.ts b/packages/common/locales/en-LS.ts index 27a19330b6..488685b175 100644 --- a/packages/common/locales/en-LS.ts +++ b/packages/common/locales/en-LS.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'South African Rand', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZAR': ['R']}, diff --git a/packages/common/locales/en-MG.ts b/packages/common/locales/en-MG.ts index 180316aa5d..d9fb252278 100644 --- a/packages/common/locales/en-MG.ts +++ b/packages/common/locales/en-MG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MGA', 'Ar', 'Malagasy Ariary', {'JPY': ['JP¥', '¥'], 'MGA': ['Ar'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-MH.ts b/packages/common/locales/en-MH.ts index d4d6013b8c..534a5a03a0 100644 --- a/packages/common/locales/en-MH.ts +++ b/packages/common/locales/en-MH.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-MO.ts b/packages/common/locales/en-MO.ts index 00312c8eae..6630fdc02f 100644 --- a/packages/common/locales/en-MO.ts +++ b/packages/common/locales/en-MO.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MOP', 'MOP$', 'Macanese Pataca', {'JPY': ['JP¥', '¥'], 'MOP': ['MOP$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-MP.ts b/packages/common/locales/en-MP.ts index a0b1ee5517..9dad1b9834 100644 --- a/packages/common/locales/en-MP.ts +++ b/packages/common/locales/en-MP.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-MS.ts b/packages/common/locales/en-MS.ts index 3fdc17bfdd..4756763567 100644 --- a/packages/common/locales/en-MS.ts +++ b/packages/common/locales/en-MS.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-MT.ts b/packages/common/locales/en-MT.ts index d756978bc4..875941c46a 100644 --- a/packages/common/locales/en-MT.ts +++ b/packages/common/locales/en-MT.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-MU.ts b/packages/common/locales/en-MU.ts index 7c0d2d0d09..41736fbbff 100644 --- a/packages/common/locales/en-MU.ts +++ b/packages/common/locales/en-MU.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MUR', 'Rs', 'Mauritian Rupee', {'JPY': ['JP¥', '¥'], 'MUR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-MW.ts b/packages/common/locales/en-MW.ts index d5361c2d66..4866d60d6b 100644 --- a/packages/common/locales/en-MW.ts +++ b/packages/common/locales/en-MW.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MWK', 'MK', 'Malawian Kwacha', {'JPY': ['JP¥', '¥'], 'MWK': ['MK'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-MY.ts b/packages/common/locales/en-MY.ts index 19f98ce7ca..cf0dfd9249 100644 --- a/packages/common/locales/en-MY.ts +++ b/packages/common/locales/en-MY.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MYR', 'RM', 'Malaysian Ringgit', {'JPY': ['JP¥', '¥'], 'MYR': ['RM'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-NA.ts b/packages/common/locales/en-NA.ts index 7303871251..ea5b7a088b 100644 --- a/packages/common/locales/en-NA.ts +++ b/packages/common/locales/en-NA.ts @@ -45,6 +45,7 @@ export default [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'ZAR', + 'ZAR', 'South African Rand', {'JPY': ['JP¥', '¥'], 'NAD': ['$'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/en-NF.ts b/packages/common/locales/en-NF.ts index 3a41413dd8..311f739192 100644 --- a/packages/common/locales/en-NF.ts +++ b/packages/common/locales/en-NF.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-NG.ts b/packages/common/locales/en-NG.ts index 79af9e4a51..30ae886610 100644 --- a/packages/common/locales/en-NG.ts +++ b/packages/common/locales/en-NG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NGN', '₦', 'Nigerian Naira', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-NL.ts b/packages/common/locales/en-NL.ts index 027fa5b28d..c3619c53f9 100644 --- a/packages/common/locales/en-NL.ts +++ b/packages/common/locales/en-NL.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-NR.ts b/packages/common/locales/en-NR.ts index 6c58363372..2670628834 100644 --- a/packages/common/locales/en-NR.ts +++ b/packages/common/locales/en-NR.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-NU.ts b/packages/common/locales/en-NU.ts index f4094a76ff..0f86fdf083 100644 --- a/packages/common/locales/en-NU.ts +++ b/packages/common/locales/en-NU.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-NZ.ts b/packages/common/locales/en-NZ.ts index 51c053aff5..b54563af45 100644 --- a/packages/common/locales/en-NZ.ts +++ b/packages/common/locales/en-NZ.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-PG.ts b/packages/common/locales/en-PG.ts index 010879e17a..8b139e641e 100644 --- a/packages/common/locales/en-PG.ts +++ b/packages/common/locales/en-PG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PGK', 'K', 'Papua New Guinean Kina', {'JPY': ['JP¥', '¥'], 'PGK': ['K'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-PH.ts b/packages/common/locales/en-PH.ts index faf0c0cf88..bb4339971c 100644 --- a/packages/common/locales/en-PH.ts +++ b/packages/common/locales/en-PH.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PHP', '₱', 'Philippine Piso', {'JPY': ['JP¥', '¥'], 'PHP': ['₱'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-PK.ts b/packages/common/locales/en-PK.ts index b0c6421696..08880a019d 100644 --- a/packages/common/locales/en-PK.ts +++ b/packages/common/locales/en-PK.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PKR', 'Rs', 'Pakistani Rupee', {'JPY': ['JP¥', '¥'], 'PKR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-PN.ts b/packages/common/locales/en-PN.ts index 9b4b787536..ec5c656437 100644 --- a/packages/common/locales/en-PN.ts +++ b/packages/common/locales/en-PN.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-PR.ts b/packages/common/locales/en-PR.ts index 74185948c9..a18c44cf4e 100644 --- a/packages/common/locales/en-PR.ts +++ b/packages/common/locales/en-PR.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-PW.ts b/packages/common/locales/en-PW.ts index 2c506e210d..a54ca40c04 100644 --- a/packages/common/locales/en-PW.ts +++ b/packages/common/locales/en-PW.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-RW.ts b/packages/common/locales/en-RW.ts index 00334a7fbd..b53e883eaf 100644 --- a/packages/common/locales/en-RW.ts +++ b/packages/common/locales/en-RW.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'RWF', 'RF', 'Rwandan Franc', {'JPY': ['JP¥', '¥'], 'RWF': ['RF'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SB.ts b/packages/common/locales/en-SB.ts index be39c1e859..b82c20c19b 100644 --- a/packages/common/locales/en-SB.ts +++ b/packages/common/locales/en-SB.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SBD', '$', 'Solomon Islands Dollar', {'JPY': ['JP¥', '¥'], 'SBD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SC.ts b/packages/common/locales/en-SC.ts index 279afa3c86..1d5afe8bd2 100644 --- a/packages/common/locales/en-SC.ts +++ b/packages/common/locales/en-SC.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SCR', 'SR', 'Seychellois Rupee', {'JPY': ['JP¥', '¥'], 'SCR': ['SR'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SD.ts b/packages/common/locales/en-SD.ts index 01eb74fc54..185890adce 100644 --- a/packages/common/locales/en-SD.ts +++ b/packages/common/locales/en-SD.ts @@ -45,6 +45,7 @@ export default [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'SDG', + 'SDG', 'Sudanese Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/en-SE.ts b/packages/common/locales/en-SE.ts index 4980780dca..8df9747948 100644 --- a/packages/common/locales/en-SE.ts +++ b/packages/common/locales/en-SE.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', ' ', ';', '%', '+', '-', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SEK', 'kr', 'Swedish Krona', {'JPY': ['JP¥', '¥'], 'SEK': ['kr'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SG.ts b/packages/common/locales/en-SG.ts index 7265b78243..bbe53bbaea 100644 --- a/packages/common/locales/en-SG.ts +++ b/packages/common/locales/en-SG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SGD', '$', 'Singapore Dollar', {'JPY': ['JP¥', '¥'], 'SGD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SH.ts b/packages/common/locales/en-SH.ts index e84c536d22..3dff8902a9 100644 --- a/packages/common/locales/en-SH.ts +++ b/packages/common/locales/en-SH.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SHP', '£', 'St Helena Pound', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'SHP': ['£'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SI.ts b/packages/common/locales/en-SI.ts index 65f0599dce..02138cde20 100644 --- a/packages/common/locales/en-SI.ts +++ b/packages/common/locales/en-SI.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SL.ts b/packages/common/locales/en-SL.ts index 53ba9be153..e65b0ca47c 100644 --- a/packages/common/locales/en-SL.ts +++ b/packages/common/locales/en-SL.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SLL', 'Le', 'Sierra Leonean Leone', {'JPY': ['JP¥', '¥'], 'SLL': ['Le'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SS.ts b/packages/common/locales/en-SS.ts index e2c08500b6..a343796484 100644 --- a/packages/common/locales/en-SS.ts +++ b/packages/common/locales/en-SS.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SSP', '£', 'South Sudanese Pound', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'SSP': ['£'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SX.ts b/packages/common/locales/en-SX.ts index 12dfb964cb..44dfa6db5f 100644 --- a/packages/common/locales/en-SX.ts +++ b/packages/common/locales/en-SX.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ANG', 'NAf.', 'Netherlands Antillean Guilder', {'ANG': ['NAf.'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-SZ.ts b/packages/common/locales/en-SZ.ts index 3cd56a4eb8..95f12df161 100644 --- a/packages/common/locales/en-SZ.ts +++ b/packages/common/locales/en-SZ.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SZL', 'E', 'Swazi Lilangeni', {'JPY': ['JP¥', '¥'], 'SZL': ['E'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-TC.ts b/packages/common/locales/en-TC.ts index 981575828c..da1129cacb 100644 --- a/packages/common/locales/en-TC.ts +++ b/packages/common/locales/en-TC.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-TK.ts b/packages/common/locales/en-TK.ts index d68ff16ad5..d4ce8b940e 100644 --- a/packages/common/locales/en-TK.ts +++ b/packages/common/locales/en-TK.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-TO.ts b/packages/common/locales/en-TO.ts index 021d28cc9c..14d4888af5 100644 --- a/packages/common/locales/en-TO.ts +++ b/packages/common/locales/en-TO.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TOP', 'T$', 'Tongan Paʻanga', {'JPY': ['JP¥', '¥'], 'TOP': ['T$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-TT.ts b/packages/common/locales/en-TT.ts index 74b6d9f5fb..0b1389ff5e 100644 --- a/packages/common/locales/en-TT.ts +++ b/packages/common/locales/en-TT.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TTD', '$', 'Trinidad & Tobago Dollar', {'JPY': ['JP¥', '¥'], 'TTD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-TV.ts b/packages/common/locales/en-TV.ts index b8e3ea5fd9..8b494fe143 100644 --- a/packages/common/locales/en-TV.ts +++ b/packages/common/locales/en-TV.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-TZ.ts b/packages/common/locales/en-TZ.ts index 49a360c8cf..38954aa4fa 100644 --- a/packages/common/locales/en-TZ.ts +++ b/packages/common/locales/en-TZ.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Tanzanian Shilling', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-UG.ts b/packages/common/locales/en-UG.ts index 73f443087f..1fbc832d25 100644 --- a/packages/common/locales/en-UG.ts +++ b/packages/common/locales/en-UG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Ugandan Shilling', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-UM.ts b/packages/common/locales/en-UM.ts index 8deecb8f4d..d94c923887 100644 --- a/packages/common/locales/en-UM.ts +++ b/packages/common/locales/en-UM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-US-POSIX.ts b/packages/common/locales/en-US-POSIX.ts index a7963de89c..aa7d8418d0 100644 --- a/packages/common/locales/en-US-POSIX.ts +++ b/packages/common/locales/en-US-POSIX.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '0/00', 'INF', 'NaN', ':'], ['0.######', '0%', '¤ 0.00', '0.000000E+000'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-VC.ts b/packages/common/locales/en-VC.ts index 854c842c7e..6acf14a6ad 100644 --- a/packages/common/locales/en-VC.ts +++ b/packages/common/locales/en-VC.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/en-VG.ts b/packages/common/locales/en-VG.ts index 66c47a189f..cd00670f61 100644 --- a/packages/common/locales/en-VG.ts +++ b/packages/common/locales/en-VG.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en-VI.ts b/packages/common/locales/en-VI.ts index 36b0f00ca7..3d7d380c66 100644 --- a/packages/common/locales/en-VI.ts +++ b/packages/common/locales/en-VI.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/en-VU.ts b/packages/common/locales/en-VU.ts index e38277d146..b2abc6f88d 100644 --- a/packages/common/locales/en-VU.ts +++ b/packages/common/locales/en-VU.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'VUV', 'VT', 'Vanuatu Vatu', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'VUV': ['VT']}, diff --git a/packages/common/locales/en-WS.ts b/packages/common/locales/en-WS.ts index 0fa438a24f..bc82b6546d 100644 --- a/packages/common/locales/en-WS.ts +++ b/packages/common/locales/en-WS.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'WST', 'WS$', 'Samoan Tala', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'WST': ['WS$']}, diff --git a/packages/common/locales/en-ZA.ts b/packages/common/locales/en-ZA.ts index 64715c115b..e9366bd198 100644 --- a/packages/common/locales/en-ZA.ts +++ b/packages/common/locales/en-ZA.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'South African Rand', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZAR': ['R']}, diff --git a/packages/common/locales/en-ZM.ts b/packages/common/locales/en-ZM.ts index d109071afb..6696736b41 100644 --- a/packages/common/locales/en-ZM.ts +++ b/packages/common/locales/en-ZM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZMW', 'K', 'Zambian Kwacha', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZMW': ['K', 'ZK']}, diff --git a/packages/common/locales/en-ZW.ts b/packages/common/locales/en-ZW.ts index ae48b0ad5a..1642d9e0f7 100644 --- a/packages/common/locales/en-ZW.ts +++ b/packages/common/locales/en-ZW.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/en.ts b/packages/common/locales/en.ts index 785c6d08e7..2e430b5575 100644 --- a/packages/common/locales/en.ts +++ b/packages/common/locales/en.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/eo.ts b/packages/common/locales/eo.ts index 3e3eb32bca..89b7a12175 100644 --- a/packages/common/locales/eo.ts +++ b/packages/common/locales/eo.ts @@ -45,6 +45,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural diff --git a/packages/common/locales/es-419.ts b/packages/common/locales/es-419.ts index 94b8c480a6..e96db6b437 100644 --- a/packages/common/locales/es-419.ts +++ b/packages/common/locales/es-419.ts @@ -50,6 +50,7 @@ export default [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], 'EUR', + 'EUR', 'euro', { 'AUD': [u, '$'], diff --git a/packages/common/locales/es-AR.ts b/packages/common/locales/es-AR.ts index d7224d1403..0880182b7a 100644 --- a/packages/common/locales/es-AR.ts +++ b/packages/common/locales/es-AR.ts @@ -45,6 +45,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'ARS', '$', 'peso argentino', { diff --git a/packages/common/locales/es-BO.ts b/packages/common/locales/es-BO.ts index c013386f14..decfc89ba2 100644 --- a/packages/common/locales/es-BO.ts +++ b/packages/common/locales/es-BO.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'BOB', 'Bs', 'boliviano', { diff --git a/packages/common/locales/es-BR.ts b/packages/common/locales/es-BR.ts index 6bfa3f2409..9840be8aa0 100644 --- a/packages/common/locales/es-BR.ts +++ b/packages/common/locales/es-BR.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'BRL', 'R$', 'real brasileño', { diff --git a/packages/common/locales/es-BZ.ts b/packages/common/locales/es-BZ.ts index 3b6aa274bc..667c3e1949 100644 --- a/packages/common/locales/es-BZ.ts +++ b/packages/common/locales/es-BZ.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'BZD', '$', 'dólar beliceño', { diff --git a/packages/common/locales/es-CL.ts b/packages/common/locales/es-CL.ts index 3a2fd1d5c4..1f09a592c3 100644 --- a/packages/common/locales/es-CL.ts +++ b/packages/common/locales/es-CL.ts @@ -59,6 +59,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'CLP', '$', 'Peso chileno', { diff --git a/packages/common/locales/es-CO.ts b/packages/common/locales/es-CO.ts index d4e16859f3..6114251324 100644 --- a/packages/common/locales/es-CO.ts +++ b/packages/common/locales/es-CO.ts @@ -59,6 +59,7 @@ export default [ ['{1}, {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'COP', '$', 'peso colombiano', { diff --git a/packages/common/locales/es-CR.ts b/packages/common/locales/es-CR.ts index 23d9f9eb1c..23825816ad 100644 --- a/packages/common/locales/es-CR.ts +++ b/packages/common/locales/es-CR.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'CRC', '₡', 'colón costarricense', { diff --git a/packages/common/locales/es-CU.ts b/packages/common/locales/es-CU.ts index 21c46d4cd8..fad174f25b 100644 --- a/packages/common/locales/es-CU.ts +++ b/packages/common/locales/es-CU.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'CUP', '$', 'peso cubano', { diff --git a/packages/common/locales/es-DO.ts b/packages/common/locales/es-DO.ts index 7758019c2a..8856c65cf7 100644 --- a/packages/common/locales/es-DO.ts +++ b/packages/common/locales/es-DO.ts @@ -45,6 +45,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'DOP', 'RD$', 'peso dominicano', { diff --git a/packages/common/locales/es-EA.ts b/packages/common/locales/es-EA.ts index c678850239..872b284b2c 100644 --- a/packages/common/locales/es-EA.ts +++ b/packages/common/locales/es-EA.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/es-EC.ts b/packages/common/locales/es-EC.ts index 611d172e55..89164f5c8d 100644 --- a/packages/common/locales/es-EC.ts +++ b/packages/common/locales/es-EC.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'USD', '$', 'dólar estadounidense', { diff --git a/packages/common/locales/es-GQ.ts b/packages/common/locales/es-GQ.ts index b8192bc467..c7fd0a51d5 100644 --- a/packages/common/locales/es-GQ.ts +++ b/packages/common/locales/es-GQ.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'XAF', 'FCFA', 'franco CFA de África Central', { diff --git a/packages/common/locales/es-GT.ts b/packages/common/locales/es-GT.ts index 6985d8c9a1..ec0c93277c 100644 --- a/packages/common/locales/es-GT.ts +++ b/packages/common/locales/es-GT.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'GTQ', 'Q', 'quetzal', { diff --git a/packages/common/locales/es-HN.ts b/packages/common/locales/es-HN.ts index bb9ec75da4..64ce4c8157 100644 --- a/packages/common/locales/es-HN.ts +++ b/packages/common/locales/es-HN.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'HNL', 'L', 'lempira hondureño', { diff --git a/packages/common/locales/es-IC.ts b/packages/common/locales/es-IC.ts index 55a45de4da..42b4828166 100644 --- a/packages/common/locales/es-IC.ts +++ b/packages/common/locales/es-IC.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/es-MX.ts b/packages/common/locales/es-MX.ts index 8c9fa110fc..012c864944 100644 --- a/packages/common/locales/es-MX.ts +++ b/packages/common/locales/es-MX.ts @@ -45,6 +45,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'MXN', '$', 'peso mexicano', { diff --git a/packages/common/locales/es-NI.ts b/packages/common/locales/es-NI.ts index e8ceb03a20..3fb8d9549a 100644 --- a/packages/common/locales/es-NI.ts +++ b/packages/common/locales/es-NI.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'NIO', 'C$', 'córdoba nicaragüense', { diff --git a/packages/common/locales/es-PA.ts b/packages/common/locales/es-PA.ts index 4b437abf9e..18cfa5f28e 100644 --- a/packages/common/locales/es-PA.ts +++ b/packages/common/locales/es-PA.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'PAB', 'B/.', 'balboa panameño', { diff --git a/packages/common/locales/es-PE.ts b/packages/common/locales/es-PE.ts index 24535bbb7d..5577b78d8f 100644 --- a/packages/common/locales/es-PE.ts +++ b/packages/common/locales/es-PE.ts @@ -58,6 +58,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'PEN', 'S/', 'sol peruano', { diff --git a/packages/common/locales/es-PH.ts b/packages/common/locales/es-PH.ts index f7fba1bbee..19df17c04f 100644 --- a/packages/common/locales/es-PH.ts +++ b/packages/common/locales/es-PH.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'PHP', '₱', 'peso filipino', { diff --git a/packages/common/locales/es-PR.ts b/packages/common/locales/es-PR.ts index 355fec0308..327f95eeaf 100644 --- a/packages/common/locales/es-PR.ts +++ b/packages/common/locales/es-PR.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'USD', '$', 'dólar estadounidense', { diff --git a/packages/common/locales/es-PY.ts b/packages/common/locales/es-PY.ts index 35a8232a9f..09dc013495 100644 --- a/packages/common/locales/es-PY.ts +++ b/packages/common/locales/es-PY.ts @@ -50,6 +50,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'PYG', 'Gs.', 'guaraní paraguayo', { diff --git a/packages/common/locales/es-SV.ts b/packages/common/locales/es-SV.ts index d226472dfa..4ec932bf28 100644 --- a/packages/common/locales/es-SV.ts +++ b/packages/common/locales/es-SV.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'USD', '$', 'dólar estadounidense', { diff --git a/packages/common/locales/es-US.ts b/packages/common/locales/es-US.ts index 0edec6ca82..861072a0f2 100644 --- a/packages/common/locales/es-US.ts +++ b/packages/common/locales/es-US.ts @@ -45,6 +45,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'USD', '$', 'dólar estadounidense', { diff --git a/packages/common/locales/es-UY.ts b/packages/common/locales/es-UY.ts index ba9b11d5fa..fa54c2a9d7 100644 --- a/packages/common/locales/es-UY.ts +++ b/packages/common/locales/es-UY.ts @@ -58,6 +58,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'UYU', '$', 'peso uruguayo', { diff --git a/packages/common/locales/es-VE.ts b/packages/common/locales/es-VE.ts index b476164e72..fd62962ec2 100644 --- a/packages/common/locales/es-VE.ts +++ b/packages/common/locales/es-VE.ts @@ -50,6 +50,7 @@ export default [ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'VES', 'Bs.S', 'bolívar soberano', { diff --git a/packages/common/locales/es.ts b/packages/common/locales/es.ts index cedebe1ad2..1ed331b151 100644 --- a/packages/common/locales/es.ts +++ b/packages/common/locales/es.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/et.ts b/packages/common/locales/et.ts index e5006794db..3bfd9a6706 100644 --- a/packages/common/locales/et.ts +++ b/packages/common/locales/et.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'AUD': ['AU$', '$'], 'EEK': ['kr'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/eu.ts b/packages/common/locales/eu.ts index a754976292..06e18095a0 100644 --- a/packages/common/locales/eu.ts +++ b/packages/common/locales/eu.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '% #,##0', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euroa', {'ESP': ['₧'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ewo.ts b/packages/common/locales/ewo.ts index ee2d16e33f..bc35ca8437 100644 --- a/packages/common/locales/ewo.ts +++ b/packages/common/locales/ewo.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Fəláŋ CFA (BEAC)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/fa-AF.ts b/packages/common/locales/fa-AF.ts index afb9e0c596..9a2657e6e0 100644 --- a/packages/common/locales/fa-AF.ts +++ b/packages/common/locales/fa-AF.ts @@ -57,6 +57,7 @@ export default [ ['{1}،\u200f {0}', u, '{1}، ساعت {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'ناعدد', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'AFN', '؋', 'افغانی افغانستان', { diff --git a/packages/common/locales/fa.ts b/packages/common/locales/fa.ts index f4b0018a7c..b6b0925a71 100644 --- a/packages/common/locales/fa.ts +++ b/packages/common/locales/fa.ts @@ -54,6 +54,7 @@ export default [ ['{1}،\u200f {0}', u, '{1}، ساعت {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'ناعدد', ':'], ['#,##0.###', '#,##0%', '\u200e¤ #,##0.00', '#E0'], + 'IRR', 'ریال', 'ریال ایران', { diff --git a/packages/common/locales/ff-Latn-BF.ts b/packages/common/locales/ff-Latn-BF.ts index 7ce8a41e3c..eda0b3ef66 100644 --- a/packages/common/locales/ff-Latn-BF.ts +++ b/packages/common/locales/ff-Latn-BF.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-CM.ts b/packages/common/locales/ff-Latn-CM.ts index 330b7f2b21..c83958257d 100644 --- a/packages/common/locales/ff-Latn-CM.ts +++ b/packages/common/locales/ff-Latn-CM.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Mbuuɗi Seefaa BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-GH.ts b/packages/common/locales/ff-Latn-GH.ts index f61041f604..77afd7d958 100644 --- a/packages/common/locales/ff-Latn-GH.ts +++ b/packages/common/locales/ff-Latn-GH.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GHS', 'GH₵', 'GHS', {'GHS': ['GH₵'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-GM.ts b/packages/common/locales/ff-Latn-GM.ts index 318b44f233..d089897388 100644 --- a/packages/common/locales/ff-Latn-GM.ts +++ b/packages/common/locales/ff-Latn-GM.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GMD', 'D', 'Dalasi Gammbi', {'GMD': ['D'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-GN.ts b/packages/common/locales/ff-Latn-GN.ts index 95d7b6a33b..da2d45c598 100644 --- a/packages/common/locales/ff-Latn-GN.ts +++ b/packages/common/locales/ff-Latn-GN.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GNF', 'FG', 'GNF', {'GNF': ['FG'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-GW.ts b/packages/common/locales/ff-Latn-GW.ts index d1eec66a86..13884d0f11 100644 --- a/packages/common/locales/ff-Latn-GW.ts +++ b/packages/common/locales/ff-Latn-GW.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-LR.ts b/packages/common/locales/ff-Latn-LR.ts index e94be1565c..477ce47cb9 100644 --- a/packages/common/locales/ff-Latn-LR.ts +++ b/packages/common/locales/ff-Latn-LR.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'LRD', '$', 'Dolaar Liberiyaa', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-MR.ts b/packages/common/locales/ff-Latn-MR.ts index 6c02218516..129e720b50 100644 --- a/packages/common/locales/ff-Latn-MR.ts +++ b/packages/common/locales/ff-Latn-MR.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MRU', 'UM', 'Ugiyya Muritani', {'JPY': ['JP¥', '¥'], 'MRU': ['UM'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-NE.ts b/packages/common/locales/ff-Latn-NE.ts index a52a4935ed..d341bde8d1 100644 --- a/packages/common/locales/ff-Latn-NE.ts +++ b/packages/common/locales/ff-Latn-NE.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-NG.ts b/packages/common/locales/ff-Latn-NG.ts index 64e7d40713..9a67694428 100644 --- a/packages/common/locales/ff-Latn-NG.ts +++ b/packages/common/locales/ff-Latn-NG.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'NGN', '₦', 'Nayraa Nijeriyaa', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn-SL.ts b/packages/common/locales/ff-Latn-SL.ts index e62d39a68d..f5336f312b 100644 --- a/packages/common/locales/ff-Latn-SL.ts +++ b/packages/common/locales/ff-Latn-SL.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'SLL', 'Le', 'Lewoon Seraa Liyon', {'JPY': ['JP¥', '¥'], 'SLL': ['Le'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff-Latn.ts b/packages/common/locales/ff-Latn.ts index 683cfa16c7..84b89cc166 100644 --- a/packages/common/locales/ff-Latn.ts +++ b/packages/common/locales/ff-Latn.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ff.ts b/packages/common/locales/ff.ts index efe3e7fa39..ba2fbf1bc9 100644 --- a/packages/common/locales/ff.ts +++ b/packages/common/locales/ff.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/fi.ts b/packages/common/locales/fi.ts index 984b2bb0e6..ab7e2ebf19 100644 --- a/packages/common/locales/fi.ts +++ b/packages/common/locales/fi.ts @@ -67,6 +67,7 @@ export default [ ['{1} {0}', '{1} \'klo\' {0}', u, u], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'epäluku', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fil.ts b/packages/common/locales/fil.ts index 72371187c0..07f5051eb8 100644 --- a/packages/common/locales/fil.ts +++ b/packages/common/locales/fil.ts @@ -54,6 +54,7 @@ export default [ ['{1}, {0}', u, '{1} \'nang\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PHP', '₱', 'Piso ng Pilipinas', {'PHP': ['₱'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/fo-DK.ts b/packages/common/locales/fo-DK.ts index 221d5416af..c341baa2dc 100644 --- a/packages/common/locales/fo-DK.ts +++ b/packages/common/locales/fo-DK.ts @@ -61,6 +61,7 @@ export default [ ['{1}, {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'donsk króna', {'DKK': ['kr.', 'kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/fo.ts b/packages/common/locales/fo.ts index ff190dd1d6..1d957e3e0e 100644 --- a/packages/common/locales/fo.ts +++ b/packages/common/locales/fo.ts @@ -61,6 +61,7 @@ export default [ ['{1}, {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr', 'donsk króna', {'DKK': ['kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/fr-BE.ts b/packages/common/locales/fr-BE.ts index 340ba00d0d..358aa1f2ce 100644 --- a/packages/common/locales/fr-BE.ts +++ b/packages/common/locales/fr-BE.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-BF.ts b/packages/common/locales/fr-BF.ts index 580d1b48fe..3828d4dcec 100644 --- a/packages/common/locales/fr-BF.ts +++ b/packages/common/locales/fr-BF.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/fr-BI.ts b/packages/common/locales/fr-BI.ts index 0745edfa1e..19d4f620c1 100644 --- a/packages/common/locales/fr-BI.ts +++ b/packages/common/locales/fr-BI.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BIF', 'FBu', 'franc burundais', { diff --git a/packages/common/locales/fr-BJ.ts b/packages/common/locales/fr-BJ.ts index 579a2a18a3..ed7495aac2 100644 --- a/packages/common/locales/fr-BJ.ts +++ b/packages/common/locales/fr-BJ.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/fr-BL.ts b/packages/common/locales/fr-BL.ts index f47b1bdceb..a1efac52b1 100644 --- a/packages/common/locales/fr-BL.ts +++ b/packages/common/locales/fr-BL.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-CA.ts b/packages/common/locales/fr-CA.ts index c8b7d416ce..29073aa5a7 100644 --- a/packages/common/locales/fr-CA.ts +++ b/packages/common/locales/fr-CA.ts @@ -50,6 +50,7 @@ export default [ ['{1} {0}', u, '{1} \'à\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CAD', '$', 'dollar canadien', { diff --git a/packages/common/locales/fr-CD.ts b/packages/common/locales/fr-CD.ts index 5423d77fe0..780e59031b 100644 --- a/packages/common/locales/fr-CD.ts +++ b/packages/common/locales/fr-CD.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CDF', 'FC', 'franc congolais', { diff --git a/packages/common/locales/fr-CF.ts b/packages/common/locales/fr-CF.ts index bc84194751..0cf195db29 100644 --- a/packages/common/locales/fr-CF.ts +++ b/packages/common/locales/fr-CF.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/fr-CG.ts b/packages/common/locales/fr-CG.ts index c34826c8e5..e1e305ce7e 100644 --- a/packages/common/locales/fr-CG.ts +++ b/packages/common/locales/fr-CG.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/fr-CH.ts b/packages/common/locales/fr-CH.ts index 030f8a08f6..0c508471ad 100644 --- a/packages/common/locales/fr-CH.ts +++ b/packages/common/locales/fr-CH.ts @@ -48,6 +48,7 @@ export default [ [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':', '.'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'franc suisse', { 'ARS': ['$AR', '$'], diff --git a/packages/common/locales/fr-CI.ts b/packages/common/locales/fr-CI.ts index eccdb6f1cd..6dacd7f0df 100644 --- a/packages/common/locales/fr-CI.ts +++ b/packages/common/locales/fr-CI.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/fr-CM.ts b/packages/common/locales/fr-CM.ts index 0cddf0eabc..51d5f269c8 100644 --- a/packages/common/locales/fr-CM.ts +++ b/packages/common/locales/fr-CM.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/fr-DJ.ts b/packages/common/locales/fr-DJ.ts index e138c4529e..15450c97fa 100644 --- a/packages/common/locales/fr-DJ.ts +++ b/packages/common/locales/fr-DJ.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DJF', 'Fdj', 'franc djiboutien', { diff --git a/packages/common/locales/fr-DZ.ts b/packages/common/locales/fr-DZ.ts index 6d998a882f..cccbd24249 100644 --- a/packages/common/locales/fr-DZ.ts +++ b/packages/common/locales/fr-DZ.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DZD', 'DA', 'dinar algérien', { diff --git a/packages/common/locales/fr-GA.ts b/packages/common/locales/fr-GA.ts index ca609fb55f..c8e644e0b0 100644 --- a/packages/common/locales/fr-GA.ts +++ b/packages/common/locales/fr-GA.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/fr-GF.ts b/packages/common/locales/fr-GF.ts index b02f83ab31..1424c14032 100644 --- a/packages/common/locales/fr-GF.ts +++ b/packages/common/locales/fr-GF.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-GN.ts b/packages/common/locales/fr-GN.ts index c2b641ea2f..a2ff1eda0c 100644 --- a/packages/common/locales/fr-GN.ts +++ b/packages/common/locales/fr-GN.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'GNF', 'FG', 'franc guinéen', { diff --git a/packages/common/locales/fr-GP.ts b/packages/common/locales/fr-GP.ts index 04b01721bf..e1e12ad46f 100644 --- a/packages/common/locales/fr-GP.ts +++ b/packages/common/locales/fr-GP.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-GQ.ts b/packages/common/locales/fr-GQ.ts index a27adaaf26..52d979fa9d 100644 --- a/packages/common/locales/fr-GQ.ts +++ b/packages/common/locales/fr-GQ.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/fr-HT.ts b/packages/common/locales/fr-HT.ts index 294f5fb86a..a118b1608d 100644 --- a/packages/common/locales/fr-HT.ts +++ b/packages/common/locales/fr-HT.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'HTG', 'G', 'gourde haïtienne', { diff --git a/packages/common/locales/fr-KM.ts b/packages/common/locales/fr-KM.ts index 0d415298ea..27cd3a93a1 100644 --- a/packages/common/locales/fr-KM.ts +++ b/packages/common/locales/fr-KM.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'KMF', 'CF', 'franc comorien', { diff --git a/packages/common/locales/fr-LU.ts b/packages/common/locales/fr-LU.ts index bdf8b60a16..0883da7447 100644 --- a/packages/common/locales/fr-LU.ts +++ b/packages/common/locales/fr-LU.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-MA.ts b/packages/common/locales/fr-MA.ts index 9c19ce73a1..9898550f0c 100644 --- a/packages/common/locales/fr-MA.ts +++ b/packages/common/locales/fr-MA.ts @@ -48,6 +48,7 @@ export default [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'MAD', + 'MAD', 'dirham marocain', { 'ARS': ['$AR', '$'], diff --git a/packages/common/locales/fr-MC.ts b/packages/common/locales/fr-MC.ts index a328bac1ec..8ff4b099d6 100644 --- a/packages/common/locales/fr-MC.ts +++ b/packages/common/locales/fr-MC.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-MF.ts b/packages/common/locales/fr-MF.ts index b8aa6645e9..8d757d8c1f 100644 --- a/packages/common/locales/fr-MF.ts +++ b/packages/common/locales/fr-MF.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-MG.ts b/packages/common/locales/fr-MG.ts index b260e42a25..d8ad9e2e8f 100644 --- a/packages/common/locales/fr-MG.ts +++ b/packages/common/locales/fr-MG.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MGA', 'Ar', 'ariary malgache', { diff --git a/packages/common/locales/fr-ML.ts b/packages/common/locales/fr-ML.ts index 77d49b2155..064aed81f2 100644 --- a/packages/common/locales/fr-ML.ts +++ b/packages/common/locales/fr-ML.ts @@ -47,6 +47,7 @@ export default [ ['{1}, {0}', u, '{1} \'à\' {0}', u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/fr-MQ.ts b/packages/common/locales/fr-MQ.ts index 86edd16a94..573e908af7 100644 --- a/packages/common/locales/fr-MQ.ts +++ b/packages/common/locales/fr-MQ.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-MR.ts b/packages/common/locales/fr-MR.ts index c2ee8a3b75..0a0a234a2d 100644 --- a/packages/common/locales/fr-MR.ts +++ b/packages/common/locales/fr-MR.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MRU', 'UM', 'ouguiya mauritanien', { diff --git a/packages/common/locales/fr-MU.ts b/packages/common/locales/fr-MU.ts index 85ada09e5c..6231f6b0fb 100644 --- a/packages/common/locales/fr-MU.ts +++ b/packages/common/locales/fr-MU.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MUR', 'Rs', 'roupie mauricienne', { diff --git a/packages/common/locales/fr-NC.ts b/packages/common/locales/fr-NC.ts index 783ab96ac9..fc21fa7f74 100644 --- a/packages/common/locales/fr-NC.ts +++ b/packages/common/locales/fr-NC.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XPF', 'FCFP', 'franc CFP', { diff --git a/packages/common/locales/fr-NE.ts b/packages/common/locales/fr-NE.ts index 42906f023a..e35ccb6ca1 100644 --- a/packages/common/locales/fr-NE.ts +++ b/packages/common/locales/fr-NE.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/fr-PF.ts b/packages/common/locales/fr-PF.ts index acbea3c52f..c6e7c50fab 100644 --- a/packages/common/locales/fr-PF.ts +++ b/packages/common/locales/fr-PF.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XPF', 'FCFP', 'franc CFP', { diff --git a/packages/common/locales/fr-PM.ts b/packages/common/locales/fr-PM.ts index e62c93a447..816c031ecc 100644 --- a/packages/common/locales/fr-PM.ts +++ b/packages/common/locales/fr-PM.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-RE.ts b/packages/common/locales/fr-RE.ts index 0d67735f5b..f223efa6de 100644 --- a/packages/common/locales/fr-RE.ts +++ b/packages/common/locales/fr-RE.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr-RW.ts b/packages/common/locales/fr-RW.ts index 3f8b60cd02..0a60b2ef40 100644 --- a/packages/common/locales/fr-RW.ts +++ b/packages/common/locales/fr-RW.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RWF', 'RF', 'franc rwandais', { diff --git a/packages/common/locales/fr-SC.ts b/packages/common/locales/fr-SC.ts index 845719b811..53fd712780 100644 --- a/packages/common/locales/fr-SC.ts +++ b/packages/common/locales/fr-SC.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SCR', 'SR', 'roupie des Seychelles', { diff --git a/packages/common/locales/fr-SN.ts b/packages/common/locales/fr-SN.ts index 80615400e5..13ea9071c3 100644 --- a/packages/common/locales/fr-SN.ts +++ b/packages/common/locales/fr-SN.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/fr-SY.ts b/packages/common/locales/fr-SY.ts index 37ca12c777..e4413c917f 100644 --- a/packages/common/locales/fr-SY.ts +++ b/packages/common/locales/fr-SY.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SYP', 'LS', 'livre syrienne', { diff --git a/packages/common/locales/fr-TD.ts b/packages/common/locales/fr-TD.ts index 9b55b55e62..cafdc47212 100644 --- a/packages/common/locales/fr-TD.ts +++ b/packages/common/locales/fr-TD.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/fr-TG.ts b/packages/common/locales/fr-TG.ts index 2d3771b279..3b80af1eaa 100644 --- a/packages/common/locales/fr-TG.ts +++ b/packages/common/locales/fr-TG.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/fr-TN.ts b/packages/common/locales/fr-TN.ts index 029a9370ce..d82e554d6d 100644 --- a/packages/common/locales/fr-TN.ts +++ b/packages/common/locales/fr-TN.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'TND', 'DT', 'dinar tunisien', { diff --git a/packages/common/locales/fr-VU.ts b/packages/common/locales/fr-VU.ts index 568e8407e9..0095f8dd46 100644 --- a/packages/common/locales/fr-VU.ts +++ b/packages/common/locales/fr-VU.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'VUV', 'VT', 'vatu vanuatuan', { diff --git a/packages/common/locales/fr-WF.ts b/packages/common/locales/fr-WF.ts index 2705d26edd..f22c1d6037 100644 --- a/packages/common/locales/fr-WF.ts +++ b/packages/common/locales/fr-WF.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XPF', 'FCFP', 'franc CFP', { diff --git a/packages/common/locales/fr-YT.ts b/packages/common/locales/fr-YT.ts index d958ac7681..ba0516fc3c 100644 --- a/packages/common/locales/fr-YT.ts +++ b/packages/common/locales/fr-YT.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fr.ts b/packages/common/locales/fr.ts index aed47e433f..991e0ad0cc 100644 --- a/packages/common/locales/fr.ts +++ b/packages/common/locales/fr.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/fur.ts b/packages/common/locales/fur.ts index a1baa43a8c..773ba76ae4 100644 --- a/packages/common/locales/fur.ts +++ b/packages/common/locales/fur.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/fy.ts b/packages/common/locales/fy.ts index 88ae435bf7..e79ddb322f 100644 --- a/packages/common/locales/fy.ts +++ b/packages/common/locales/fy.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ #,##0.00-', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/ga-GB.ts b/packages/common/locales/ga-GB.ts index aab2161e25..8ec8ed2fa2 100644 --- a/packages/common/locales/ga-GB.ts +++ b/packages/common/locales/ga-GB.ts @@ -53,6 +53,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'Punt Steirling', {'THB': ['฿'], 'TWD': ['NT$'], 'XXX': []}, diff --git a/packages/common/locales/ga.ts b/packages/common/locales/ga.ts index 15e47f694e..24b9966dec 100644 --- a/packages/common/locales/ga.ts +++ b/packages/common/locales/ga.ts @@ -53,6 +53,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'THB': ['฿'], 'TWD': ['NT$'], 'XXX': []}, diff --git a/packages/common/locales/gd.ts b/packages/common/locales/gd.ts index 170a45c511..a89500f095 100644 --- a/packages/common/locales/gd.ts +++ b/packages/common/locales/gd.ts @@ -59,6 +59,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'Punnd Sasannach', {'JPY': ['JP¥', '¥'], 'RON': [u, 'leu'], 'THB': ['฿'], 'TWD': ['NT$'], 'XXX': []}, diff --git a/packages/common/locales/gl.ts b/packages/common/locales/gl.ts index e4e55ce687..c3a5e97ca9 100644 --- a/packages/common/locales/gl.ts +++ b/packages/common/locales/gl.ts @@ -62,6 +62,7 @@ export default [ ['{0}, {1}', u, '{0} \'do\' {1}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/af-NA.js b/packages/common/locales/global/af-NA.js index c3da09622b..471a48f7e9 100644 --- a/packages/common/locales/global/af-NA.js +++ b/packages/common/locales/global/af-NA.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'Suid-Afrikaanse rand', { diff --git a/packages/common/locales/global/af.js b/packages/common/locales/global/af.js index 60e46acbcf..ee0f963abb 100644 --- a/packages/common/locales/global/af.js +++ b/packages/common/locales/global/af.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'Suid-Afrikaanse rand', { diff --git a/packages/common/locales/global/agq.js b/packages/common/locales/global/agq.js index b3434399e6..bd7afe2bf6 100644 --- a/packages/common/locales/global/agq.js +++ b/packages/common/locales/global/agq.js @@ -47,6 +47,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XAF', 'FCFA', 'CFA Fàlâŋ BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ak.js b/packages/common/locales/global/ak.js index 09fe58421f..60e5be2218 100644 --- a/packages/common/locales/global/ak.js +++ b/packages/common/locales/global/ak.js @@ -47,6 +47,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GHS', 'GH₵', 'Ghana Sidi', {'GHS': ['GH₵'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/am.js b/packages/common/locales/global/am.js index 2f0e1eeb98..0f597a4f75 100644 --- a/packages/common/locales/global/am.js +++ b/packages/common/locales/global/am.js @@ -51,6 +51,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'ብር', 'የኢትዮጵያ ብር', { diff --git a/packages/common/locales/global/ar-AE.js b/packages/common/locales/global/ar-AE.js index b18d1affd9..37e655b587 100644 --- a/packages/common/locales/global/ar-AE.js +++ b/packages/common/locales/global/ar-AE.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'AED', 'د.إ.\u200f', 'درهم إماراتي', { diff --git a/packages/common/locales/global/ar-BH.js b/packages/common/locales/global/ar-BH.js index e2a26e1968..e190d93b54 100644 --- a/packages/common/locales/global/ar-BH.js +++ b/packages/common/locales/global/ar-BH.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'BHD', 'د.ب.\u200f', 'دينار بحريني', { diff --git a/packages/common/locales/global/ar-DJ.js b/packages/common/locales/global/ar-DJ.js index e309a8ed4a..e8d43396a2 100644 --- a/packages/common/locales/global/ar-DJ.js +++ b/packages/common/locales/global/ar-DJ.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'DJF', 'Fdj', 'فرنك جيبوتي', { diff --git a/packages/common/locales/global/ar-DZ.js b/packages/common/locales/global/ar-DZ.js index 5974f4bbff..0177a24685 100644 --- a/packages/common/locales/global/ar-DZ.js +++ b/packages/common/locales/global/ar-DZ.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'DZD', 'د.ج.\u200f', 'دينار جزائري', { diff --git a/packages/common/locales/global/ar-EG.js b/packages/common/locales/global/ar-EG.js index ea5697c7c7..974b5c95bc 100644 --- a/packages/common/locales/global/ar-EG.js +++ b/packages/common/locales/global/ar-EG.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EGP', 'ج.م.\u200f', 'جنيه مصري', { diff --git a/packages/common/locales/global/ar-EH.js b/packages/common/locales/global/ar-EH.js index 1ee162f2b1..fa2269483f 100644 --- a/packages/common/locales/global/ar-EH.js +++ b/packages/common/locales/global/ar-EH.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MAD', 'د.م.\u200f', 'درهم مغربي', { diff --git a/packages/common/locales/global/ar-ER.js b/packages/common/locales/global/ar-ER.js index e4bc1632d3..feacf13a10 100644 --- a/packages/common/locales/global/ar-ER.js +++ b/packages/common/locales/global/ar-ER.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'ERN', 'Nfk', 'ناكفا أريتري', { diff --git a/packages/common/locales/global/ar-IL.js b/packages/common/locales/global/ar-IL.js index 1e844d3e81..c8c839612e 100644 --- a/packages/common/locales/global/ar-IL.js +++ b/packages/common/locales/global/ar-IL.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'ILS', '₪', 'شيكل إسرائيلي جديد', { diff --git a/packages/common/locales/global/ar-IQ.js b/packages/common/locales/global/ar-IQ.js index e4fbbc673e..9e8ce9047f 100644 --- a/packages/common/locales/global/ar-IQ.js +++ b/packages/common/locales/global/ar-IQ.js @@ -23,7 +23,7 @@ if (n % 100 === Math.floor(n % 100) && n % 100 >= 11 && n % 100 <= 99) return 4; return 5; } - global.ng.common.locales['ar-iq'] = ['ar-IQ',[['ص','م'],u,u],[['ص','م'],u,['صباحًا','مساءً']],[['ح','ن','ث','ر','خ','ج','س'],['الأحد','الاثنين','الثلاثاء','الأربعاء','الخميس','الجمعة','السبت'],u,['أحد','إثنين','ثلاثاء','أربعاء','خميس','جمعة','سبت']],u,[['ك','ش','آ','ن','أ','ح','ت','آ','أ','ت','ت','ك'],['كانون الثاني','شباط','آذار','نيسان','أيار','حزيران','تموز','آب','أيلول','تشرين الأول','تشرين الثاني','كانون الأول'],['كانون الثاني','شباط','آذار','نيسان','أيار','حزيران','تموز','آب','أيلول','تشرين الأول','تشرين الثاني','كانون الأول']],[['ك','ش','آ','ن','أ','ح','ت','آ','أ','ت','ت','ك'],['كانون الثاني','شباط','آذار','نيسان','أيار','حزيران','تموز','آب','أيلول','تشرين الأول','تشرين الثاني','كانون الأول'],u],[['ق.م','م'],u,['قبل الميلاد','ميلادي']],6,[5,6],['d\u200f/M\u200f/y','dd\u200f/MM\u200f/y','d MMMM y','EEEE، d MMMM y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1} {0}',u,u,u],['.',',',';','\u200e%\u200e','\u200e+','\u200e-','E','×','‰','∞','ليس رقمًا',':'],['#,##0.###','#,##0%','¤ #,##0.00','#E0'],'د.ع.\u200f','دينار عراقي',{'AED':['د.إ.\u200f'],'ARS':[u,'AR$'],'AUD':['AU$'],'BBD':[u,'BB$'],'BHD':['د.ب.\u200f'],'BMD':[u,'BM$'],'BND':[u,'BN$'],'BSD':[u,'BS$'],'BZD':[u,'BZ$'],'CAD':['CA$'],'CLP':[u,'CL$'],'CNY':['CN¥'],'COP':[u,'CO$'],'CUP':[u,'CU$'],'DOP':[u,'DO$'],'DZD':['د.ج.\u200f'],'EGP':['ج.م.\u200f','E£'],'FJD':[u,'FJ$'],'GBP':['UK£'],'GYD':[u,'GY$'],'HKD':['HK$'],'IQD':['د.ع.\u200f'],'IRR':['ر.إ.'],'JMD':[u,'JM$'],'JOD':['د.أ.\u200f'],'JPY':['JP¥'],'KWD':['د.ك.\u200f'],'KYD':[u,'KY$'],'LBP':['ل.ل.\u200f','L£'],'LRD':[u,'$LR'],'LYD':['د.ل.\u200f'],'MAD':['د.م.\u200f'],'MRU':['أ.م.'],'MXN':['MX$'],'NZD':['NZ$'],'OMR':['ر.ع.\u200f'],'QAR':['ر.ق.\u200f'],'SAR':['ر.س.\u200f'],'SBD':[u,'SB$'],'SDD':['د.س.\u200f'],'SDG':['ج.س.'],'SRD':[u,'SR$'],'SYP':['ل.س.\u200f','£'],'THB':['฿'],'TND':['د.ت.\u200f'],'TTD':[u,'TT$'],'TWD':['NT$'],'USD':['US$'],'UYU':[u,'UY$'],'XXX':['***'],'YER':['ر.ي.\u200f']},'rtl', plural, [[['فجرًا','صباحًا','ظهرًا','بعد الظهر','مساءً','منتصف الليل','ليلاً'],['فجرًا','ص','ظهرًا','بعد الظهر','مساءً','منتصف الليل','ليلاً'],['فجرًا','صباحًا','ظهرًا','بعد الظهر','مساءً','منتصف الليل','ليلاً']],u,[['03:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','18:00'],['18:00','24:00'],['00:00','01:00'],['01:00','03:00']]]]; + global.ng.common.locales['ar-iq'] = ['ar-IQ',[['ص','م'],u,u],[['ص','م'],u,['صباحًا','مساءً']],[['ح','ن','ث','ر','خ','ج','س'],['الأحد','الاثنين','الثلاثاء','الأربعاء','الخميس','الجمعة','السبت'],u,['أحد','إثنين','ثلاثاء','أربعاء','خميس','جمعة','سبت']],u,[['ك','ش','آ','ن','أ','ح','ت','آ','أ','ت','ت','ك'],['كانون الثاني','شباط','آذار','نيسان','أيار','حزيران','تموز','آب','أيلول','تشرين الأول','تشرين الثاني','كانون الأول'],['كانون الثاني','شباط','آذار','نيسان','أيار','حزيران','تموز','آب','أيلول','تشرين الأول','تشرين الثاني','كانون الأول']],[['ك','ش','آ','ن','أ','ح','ت','آ','أ','ت','ت','ك'],['كانون الثاني','شباط','آذار','نيسان','أيار','حزيران','تموز','آب','أيلول','تشرين الأول','تشرين الثاني','كانون الأول'],u],[['ق.م','م'],u,['قبل الميلاد','ميلادي']],6,[5,6],['d\u200f/M\u200f/y','dd\u200f/MM\u200f/y','d MMMM y','EEEE، d MMMM y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1} {0}',u,u,u],['.',',',';','\u200e%\u200e','\u200e+','\u200e-','E','×','‰','∞','ليس رقمًا',':'],['#,##0.###','#,##0%','¤ #,##0.00','#E0'],'IQD','د.ع.\u200f','دينار عراقي',{'AED':['د.إ.\u200f'],'ARS':[u,'AR$'],'AUD':['AU$'],'BBD':[u,'BB$'],'BHD':['د.ب.\u200f'],'BMD':[u,'BM$'],'BND':[u,'BN$'],'BSD':[u,'BS$'],'BZD':[u,'BZ$'],'CAD':['CA$'],'CLP':[u,'CL$'],'CNY':['CN¥'],'COP':[u,'CO$'],'CUP':[u,'CU$'],'DOP':[u,'DO$'],'DZD':['د.ج.\u200f'],'EGP':['ج.م.\u200f','E£'],'FJD':[u,'FJ$'],'GBP':['UK£'],'GYD':[u,'GY$'],'HKD':['HK$'],'IQD':['د.ع.\u200f'],'IRR':['ر.إ.'],'JMD':[u,'JM$'],'JOD':['د.أ.\u200f'],'JPY':['JP¥'],'KWD':['د.ك.\u200f'],'KYD':[u,'KY$'],'LBP':['ل.ل.\u200f','L£'],'LRD':[u,'$LR'],'LYD':['د.ل.\u200f'],'MAD':['د.م.\u200f'],'MRU':['أ.م.'],'MXN':['MX$'],'NZD':['NZ$'],'OMR':['ر.ع.\u200f'],'QAR':['ر.ق.\u200f'],'SAR':['ر.س.\u200f'],'SBD':[u,'SB$'],'SDD':['د.س.\u200f'],'SDG':['ج.س.'],'SRD':[u,'SR$'],'SYP':['ل.س.\u200f','£'],'THB':['฿'],'TND':['د.ت.\u200f'],'TTD':[u,'TT$'],'TWD':['NT$'],'USD':['US$'],'UYU':[u,'UY$'],'XXX':['***'],'YER':['ر.ي.\u200f']},'rtl', plural, [[['فجرًا','صباحًا','ظهرًا','بعد الظهر','مساءً','منتصف الليل','ليلاً'],['فجرًا','ص','ظهرًا','بعد الظهر','مساءً','منتصف الليل','ليلاً'],['فجرًا','صباحًا','ظهرًا','بعد الظهر','مساءً','منتصف الليل','ليلاً']],u,[['03:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','18:00'],['18:00','24:00'],['00:00','01:00'],['01:00','03:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/ar-JO.js b/packages/common/locales/global/ar-JO.js index 012fadc2a7..df04d870be 100644 --- a/packages/common/locales/global/ar-JO.js +++ b/packages/common/locales/global/ar-JO.js @@ -57,6 +57,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'JOD', 'د.أ.\u200f', 'دينار أردني', { diff --git a/packages/common/locales/global/ar-KM.js b/packages/common/locales/global/ar-KM.js index 292d761e43..62150af6f4 100644 --- a/packages/common/locales/global/ar-KM.js +++ b/packages/common/locales/global/ar-KM.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'KMF', 'CF', 'فرنك جزر القمر', { diff --git a/packages/common/locales/global/ar-KW.js b/packages/common/locales/global/ar-KW.js index fae58acb55..b0f4919386 100644 --- a/packages/common/locales/global/ar-KW.js +++ b/packages/common/locales/global/ar-KW.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'KWD', 'د.ك.\u200f', 'دينار كويتي', { diff --git a/packages/common/locales/global/ar-LB.js b/packages/common/locales/global/ar-LB.js index 7e54cd1932..6d808580ff 100644 --- a/packages/common/locales/global/ar-LB.js +++ b/packages/common/locales/global/ar-LB.js @@ -57,6 +57,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'LBP', 'ل.ل.\u200f', 'جنيه لبناني', { diff --git a/packages/common/locales/global/ar-LY.js b/packages/common/locales/global/ar-LY.js index d9c45a7dfe..3493caa11b 100644 --- a/packages/common/locales/global/ar-LY.js +++ b/packages/common/locales/global/ar-LY.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'LYD', 'د.ل.\u200f', 'دينار ليبي', { diff --git a/packages/common/locales/global/ar-MA.js b/packages/common/locales/global/ar-MA.js index b85e0daf2f..1147e34b11 100644 --- a/packages/common/locales/global/ar-MA.js +++ b/packages/common/locales/global/ar-MA.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MAD', 'د.م.\u200f', 'درهم مغربي', { diff --git a/packages/common/locales/global/ar-MR.js b/packages/common/locales/global/ar-MR.js index d5c124b4a8..1aabaeb4a6 100644 --- a/packages/common/locales/global/ar-MR.js +++ b/packages/common/locales/global/ar-MR.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MRU', 'أ.م.', 'أوقية موريتانية', { diff --git a/packages/common/locales/global/ar-OM.js b/packages/common/locales/global/ar-OM.js index c42811cdfc..fae36199b8 100644 --- a/packages/common/locales/global/ar-OM.js +++ b/packages/common/locales/global/ar-OM.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'OMR', 'ر.ع.\u200f', 'ريال عماني', { diff --git a/packages/common/locales/global/ar-PS.js b/packages/common/locales/global/ar-PS.js index 16a6ed16e2..4d26adce61 100644 --- a/packages/common/locales/global/ar-PS.js +++ b/packages/common/locales/global/ar-PS.js @@ -57,6 +57,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'ILS', '₪', 'شيكل إسرائيلي جديد', { diff --git a/packages/common/locales/global/ar-QA.js b/packages/common/locales/global/ar-QA.js index bef480e50d..d2eab7bbea 100644 --- a/packages/common/locales/global/ar-QA.js +++ b/packages/common/locales/global/ar-QA.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'QAR', 'ر.ق.\u200f', 'ريال قطري', { diff --git a/packages/common/locales/global/ar-SA.js b/packages/common/locales/global/ar-SA.js index 864c120b64..c1b189ca85 100644 --- a/packages/common/locales/global/ar-SA.js +++ b/packages/common/locales/global/ar-SA.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '٪', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'ليس رقمًا', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SAR', 'ر.س.\u200f', 'ريال سعودي', { diff --git a/packages/common/locales/global/ar-SD.js b/packages/common/locales/global/ar-SD.js index a7b3e9f0ba..6b7060f6a7 100644 --- a/packages/common/locales/global/ar-SD.js +++ b/packages/common/locales/global/ar-SD.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SDG', 'ج.س.', 'جنيه سوداني', { diff --git a/packages/common/locales/global/ar-SO.js b/packages/common/locales/global/ar-SO.js index c901a618e5..489a94418f 100644 --- a/packages/common/locales/global/ar-SO.js +++ b/packages/common/locales/global/ar-SO.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '٪', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'ليس رقمًا', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SOS', 'S', 'شلن صومالي', { diff --git a/packages/common/locales/global/ar-SS.js b/packages/common/locales/global/ar-SS.js index 0acea4e8aa..007be5fddb 100644 --- a/packages/common/locales/global/ar-SS.js +++ b/packages/common/locales/global/ar-SS.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SSP', '£', 'جنيه جنوب السودان', { diff --git a/packages/common/locales/global/ar-SY.js b/packages/common/locales/global/ar-SY.js index d42e3545a4..d800ae1645 100644 --- a/packages/common/locales/global/ar-SY.js +++ b/packages/common/locales/global/ar-SY.js @@ -57,6 +57,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SYP', 'ل.س.\u200f', 'ليرة سورية', { diff --git a/packages/common/locales/global/ar-TD.js b/packages/common/locales/global/ar-TD.js index 2641da95a0..2ae8956f31 100644 --- a/packages/common/locales/global/ar-TD.js +++ b/packages/common/locales/global/ar-TD.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'فرنك وسط أفريقي', { diff --git a/packages/common/locales/global/ar-TN.js b/packages/common/locales/global/ar-TN.js index 1aea877369..a139f1aa48 100644 --- a/packages/common/locales/global/ar-TN.js +++ b/packages/common/locales/global/ar-TN.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TND', 'د.ت.\u200f', 'دينار تونسي', { diff --git a/packages/common/locales/global/ar-YE.js b/packages/common/locales/global/ar-YE.js index 7a563937d8..a424bfeec6 100644 --- a/packages/common/locales/global/ar-YE.js +++ b/packages/common/locales/global/ar-YE.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'YER', 'ر.ي.\u200f', 'ريال يمني', { diff --git a/packages/common/locales/global/ar.js b/packages/common/locales/global/ar.js index a41949bf1c..a3b36fc52c 100644 --- a/packages/common/locales/global/ar.js +++ b/packages/common/locales/global/ar.js @@ -56,6 +56,7 @@ 'ليس رقمًا', ':' ], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EGP', 'ج.م.\u200f', 'جنيه مصري', { diff --git a/packages/common/locales/global/as.js b/packages/common/locales/global/as.js index c49fec434e..9ee490fd81 100644 --- a/packages/common/locales/global/as.js +++ b/packages/common/locales/global/as.js @@ -66,6 +66,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'ভাৰতীয় ৰুপী', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/asa.js b/packages/common/locales/global/asa.js index 6454774522..fbb1bfeb4e 100644 --- a/packages/common/locales/global/asa.js +++ b/packages/common/locales/global/asa.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'TZS', 'TSh', 'shilingi ya Tandhania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ast.js b/packages/common/locales/global/ast.js index 4d50c37b19..0a9c664f00 100644 --- a/packages/common/locales/global/ast.js +++ b/packages/common/locales/global/ast.js @@ -53,6 +53,7 @@ ['{1} {0}', '{1}, {0}', '{1} \'a\' \'les\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'ND', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/az-Cyrl.js b/packages/common/locales/global/az-Cyrl.js index 826a8e8014..b89692d60f 100644 --- a/packages/common/locales/global/az-Cyrl.js +++ b/packages/common/locales/global/az-Cyrl.js @@ -59,6 +59,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AZN', '₼', 'AZN', {'AZN': ['₼'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/az-Latn.js b/packages/common/locales/global/az-Latn.js index 523f97c2be..c001130b9e 100644 --- a/packages/common/locales/global/az-Latn.js +++ b/packages/common/locales/global/az-Latn.js @@ -62,6 +62,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AZN', '₼', 'Azərbaycan Manatı', { diff --git a/packages/common/locales/global/az.js b/packages/common/locales/global/az.js index 625495b9d9..334cd9dd20 100644 --- a/packages/common/locales/global/az.js +++ b/packages/common/locales/global/az.js @@ -62,6 +62,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AZN', '₼', 'Azərbaycan Manatı', { diff --git a/packages/common/locales/global/bas.js b/packages/common/locales/global/bas.js index d03940a730..aceccdc63c 100644 --- a/packages/common/locales/global/bas.js +++ b/packages/common/locales/global/bas.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Frǎŋ CFA (BEAC)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/be.js b/packages/common/locales/global/be.js index 95124e748c..618da2dbff 100644 --- a/packages/common/locales/global/be.js +++ b/packages/common/locales/global/be.js @@ -73,6 +73,7 @@ ['{1}, {0}', u, '{1} \'у\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BYN', 'Br', 'беларускі рубель', { diff --git a/packages/common/locales/global/bem.js b/packages/common/locales/global/bem.js index 5984e9d52d..55d87dbeef 100644 --- a/packages/common/locales/global/bem.js +++ b/packages/common/locales/global/bem.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZMW', 'K', 'ZMW', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZMW': ['K', 'ZK']}, diff --git a/packages/common/locales/global/bez.js b/packages/common/locales/global/bez.js index 819f64f88a..10172145da 100644 --- a/packages/common/locales/global/bez.js +++ b/packages/common/locales/global/bez.js @@ -50,6 +50,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Hutanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/bg.js b/packages/common/locales/global/bg.js index 3767099211..e5bb8ce111 100644 --- a/packages/common/locales/global/bg.js +++ b/packages/common/locales/global/bg.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '0.00 ¤', '#E0'], + 'BGN', 'лв.', 'Български лев', { diff --git a/packages/common/locales/global/bm.js b/packages/common/locales/global/bm.js index 87f381a343..72375841f7 100644 --- a/packages/common/locales/global/bm.js +++ b/packages/common/locales/global/bm.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XOF', 'CFA', 'sefa Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/bn-IN.js b/packages/common/locales/global/bn-IN.js index 52dd685959..b0acd07684 100644 --- a/packages/common/locales/global/bn-IN.js +++ b/packages/common/locales/global/bn-IN.js @@ -78,6 +78,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'INR', '₹', 'ভারতীয় রুপি', {'BDT': ['৳'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/bn.js b/packages/common/locales/global/bn.js index 948a7c30cc..feecae0005 100644 --- a/packages/common/locales/global/bn.js +++ b/packages/common/locales/global/bn.js @@ -78,6 +78,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'BDT', '৳', 'বাংলাদেশী টাকা', {'BDT': ['৳'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/bo-IN.js b/packages/common/locales/global/bo-IN.js index b5a8d8b87b..e72f00df2a 100644 --- a/packages/common/locales/global/bo-IN.js +++ b/packages/common/locales/global/bo-IN.js @@ -82,6 +82,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'རྒྱ་གར་སྒོར་', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/bo.js b/packages/common/locales/global/bo.js index f5d45558be..9eef9ff0c3 100644 --- a/packages/common/locales/global/bo.js +++ b/packages/common/locales/global/bo.js @@ -82,6 +82,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'CNY', '¥', 'ཡུ་ཨན་', {'CNY': ['¥'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/br.js b/packages/common/locales/global/br.js index 450cb71b02..42bc652c2e 100644 --- a/packages/common/locales/global/br.js +++ b/packages/common/locales/global/br.js @@ -55,6 +55,7 @@ ['{1} {0}', '{1}, {0}', '{1} \'da\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/brx.js b/packages/common/locales/global/brx.js index 64e9259093..80445432a8 100644 --- a/packages/common/locales/global/brx.js +++ b/packages/common/locales/global/brx.js @@ -60,6 +60,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'रां', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/bs-Cyrl.js b/packages/common/locales/global/bs-Cyrl.js index 07399e2572..224c86112c 100644 --- a/packages/common/locales/global/bs-Cyrl.js +++ b/packages/common/locales/global/bs-Cyrl.js @@ -56,6 +56,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'BAM', 'КМ', 'Конвертибилна марка', { diff --git a/packages/common/locales/global/bs-Latn.js b/packages/common/locales/global/bs-Latn.js index 2cd5182faf..d53e41a4e5 100644 --- a/packages/common/locales/global/bs-Latn.js +++ b/packages/common/locales/global/bs-Latn.js @@ -27,7 +27,7 @@ return 3; return 5; } - global.ng.common.locales['bs-latn'] = ['bs-Latn',[['prijepodne','popodne'],['AM','PM'],['prijepodne','popodne']],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['n','p','u','s','č','p','s'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['j','f','m','a','m','j','j','a','s','o','n','d'],['jan','feb','mar','apr','maj','jun','jul','aug','sep','okt','nov','dec'],['januar','februar','mart','april','maj','juni','juli','august','septembar','oktobar','novembar','decembar']],u,[['p.n.e.','n.e.'],['p. n. e.','n. e.'],['prije nove ere','nove ere']],1,[6,0],['d. M. y.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'KM','Bosanskohercegovačka konvertibilna marka',{'AUD':[u,'$'],'BAM':['KM'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'HRK':['kn'],'ILS':[u,'₪'],'MXN':[u,'$'],'NZD':[u,'$'],'RSD':['din.'],'THB':['฿'],'TWD':['NT$'],'USD':[u,'$'],'XCD':[u,'$'],'XPF':[]},'ltr', plural, [[['ponoć','podne','ujutro','poslijepodne','navečer','po noći'],u,u],u,['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; + global.ng.common.locales['bs-latn'] = ['bs-Latn',[['prijepodne','popodne'],['AM','PM'],['prijepodne','popodne']],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['n','p','u','s','č','p','s'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['j','f','m','a','m','j','j','a','s','o','n','d'],['jan','feb','mar','apr','maj','jun','jul','aug','sep','okt','nov','dec'],['januar','februar','mart','april','maj','juni','juli','august','septembar','oktobar','novembar','decembar']],u,[['p.n.e.','n.e.'],['p. n. e.','n. e.'],['prije nove ere','nove ere']],1,[6,0],['d. M. y.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'BAM','KM','Bosanskohercegovačka konvertibilna marka',{'AUD':[u,'$'],'BAM':['KM'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'HRK':['kn'],'ILS':[u,'₪'],'MXN':[u,'$'],'NZD':[u,'$'],'RSD':['din.'],'THB':['฿'],'TWD':['NT$'],'USD':[u,'$'],'XCD':[u,'$'],'XPF':[]},'ltr', plural, [[['ponoć','podne','ujutro','poslijepodne','navečer','po noći'],u,u],u,['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/bs.js b/packages/common/locales/global/bs.js index 38177963d5..fac88cea2f 100644 --- a/packages/common/locales/global/bs.js +++ b/packages/common/locales/global/bs.js @@ -27,7 +27,7 @@ return 3; return 5; } - global.ng.common.locales['bs'] = ['bs',[['prijepodne','popodne'],['AM','PM'],['prijepodne','popodne']],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['n','p','u','s','č','p','s'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['j','f','m','a','m','j','j','a','s','o','n','d'],['jan','feb','mar','apr','maj','jun','jul','aug','sep','okt','nov','dec'],['januar','februar','mart','april','maj','juni','juli','august','septembar','oktobar','novembar','decembar']],u,[['p.n.e.','n.e.'],['p. n. e.','n. e.'],['prije nove ere','nove ere']],1,[6,0],['d. M. y.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'KM','Bosanskohercegovačka konvertibilna marka',{'AUD':[u,'$'],'BAM':['KM'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'HRK':['kn'],'ILS':[u,'₪'],'MXN':[u,'$'],'NZD':[u,'$'],'RSD':['din.'],'THB':['฿'],'TWD':['NT$'],'USD':[u,'$'],'XCD':[u,'$'],'XPF':[]},'ltr', plural, [[['ponoć','podne','ujutro','poslijepodne','navečer','po noći'],u,u],u,['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; + global.ng.common.locales['bs'] = ['bs',[['prijepodne','popodne'],['AM','PM'],['prijepodne','popodne']],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['n','p','u','s','č','p','s'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['j','f','m','a','m','j','j','a','s','o','n','d'],['jan','feb','mar','apr','maj','jun','jul','aug','sep','okt','nov','dec'],['januar','februar','mart','april','maj','juni','juli','august','septembar','oktobar','novembar','decembar']],u,[['p.n.e.','n.e.'],['p. n. e.','n. e.'],['prije nove ere','nove ere']],1,[6,0],['d. M. y.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'BAM','KM','Bosanskohercegovačka konvertibilna marka',{'AUD':[u,'$'],'BAM':['KM'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'HRK':['kn'],'ILS':[u,'₪'],'MXN':[u,'$'],'NZD':[u,'$'],'RSD':['din.'],'THB':['฿'],'TWD':['NT$'],'USD':[u,'$'],'XCD':[u,'$'],'XPF':[]},'ltr', plural, [[['ponoć','podne','ujutro','poslijepodne','navečer','po noći'],u,u],u,['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/ca-AD.js b/packages/common/locales/global/ca-AD.js index d2df9a192c..2ba18a2495 100644 --- a/packages/common/locales/global/ca-AD.js +++ b/packages/common/locales/global/ca-AD.js @@ -20,7 +20,7 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['ca-ad'] = ['ca-AD',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; + global.ng.common.locales['ca-ad'] = ['ca-AD',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'EUR','€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/ca-ES-VALENCIA.js b/packages/common/locales/global/ca-ES-VALENCIA.js index 8d9d3ea2e9..4a7def3856 100644 --- a/packages/common/locales/global/ca-ES-VALENCIA.js +++ b/packages/common/locales/global/ca-ES-VALENCIA.js @@ -20,7 +20,7 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['ca-es-valencia'] = ['ca-ES-VALENCIA',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; + global.ng.common.locales['ca-es-valencia'] = ['ca-ES-VALENCIA',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'EUR','€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/ca-FR.js b/packages/common/locales/global/ca-FR.js index e0078c8d01..c3a416eaec 100644 --- a/packages/common/locales/global/ca-FR.js +++ b/packages/common/locales/global/ca-FR.js @@ -20,7 +20,7 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['ca-fr'] = ['ca-FR',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'FRF':['F'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; + global.ng.common.locales['ca-fr'] = ['ca-FR',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'EUR','€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'FRF':['F'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/ca-IT.js b/packages/common/locales/global/ca-IT.js index 22b635f1c0..81c1a67557 100644 --- a/packages/common/locales/global/ca-IT.js +++ b/packages/common/locales/global/ca-IT.js @@ -20,7 +20,7 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['ca-it'] = ['ca-IT',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; + global.ng.common.locales['ca-it'] = ['ca-IT',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'EUR','€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/ca.js b/packages/common/locales/global/ca.js index 5542925146..47a968af35 100644 --- a/packages/common/locales/global/ca.js +++ b/packages/common/locales/global/ca.js @@ -20,7 +20,7 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['ca'] = ['ca',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; + global.ng.common.locales['ca'] = ['ca',[['a. m.','p. m.'],u,u],u,[['dg','dl','dt','dc','dj','dv','ds'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.'],['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'],['dg.','dl.','dt.','dc.','dj.','dv.','ds.']],u,[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['de gen.','de febr.','de març','d’abr.','de maig','de juny','de jul.','d’ag.','de set.','d’oct.','de nov.','de des.'],['de gener','de febrer','de març','d’abril','de maig','de juny','de juliol','d’agost','de setembre','d’octubre','de novembre','de desembre']],[['GN','FB','MÇ','AB','MG','JN','JL','AG','ST','OC','NV','DS'],['gen.','febr.','març','abr.','maig','juny','jul.','ag.','set.','oct.','nov.','des.'],['gener','febrer','març','abril','maig','juny','juliol','agost','setembre','octubre','novembre','desembre']],[['aC','dC'],u,['abans de Crist','després de Crist']],1,[6,0],['d/M/yy','d MMM y','d MMMM \'de\' y','EEEE, d MMMM \'de\' y'],['H:mm','H:mm:ss','H:mm:ss z','H:mm:ss zzzz'],['{1} {0}','{1}, {0}','{1} \'a\' \'les\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'EUR','€','euro',{'AUD':['AU$','$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'MXN':[u,'$'],'THB':['฿'],'USD':[u,'$'],'VEF':[u,'Bs F'],'XCD':[u,'$'],'XXX':[]},'ltr', plural, [[['mitjanit','mat.','matí','md','tarda','vespre','nit'],['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u],[['mitjanit','matinada','matí','migdia','tarda','vespre','nit'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','19:00'],['19:00','21:00'],['21:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/ccp-IN.js b/packages/common/locales/global/ccp-IN.js index 4074275b12..edc5814355 100644 --- a/packages/common/locales/global/ccp-IN.js +++ b/packages/common/locales/global/ccp-IN.js @@ -87,6 +87,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'INR', '₹', '𑄃𑄨𑄚𑄴𑄘𑄨𑄠𑄚𑄴 𑄢𑄪𑄛𑄨', { diff --git a/packages/common/locales/global/ccp.js b/packages/common/locales/global/ccp.js index c22d876eed..658bae826e 100644 --- a/packages/common/locales/global/ccp.js +++ b/packages/common/locales/global/ccp.js @@ -87,6 +87,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '#,##,##0.00¤', '#E0'], + 'BDT', '৳', '𑄝𑄁𑄣𑄘𑄬𑄥𑄨 𑄑𑄬𑄋', { diff --git a/packages/common/locales/global/ce.js b/packages/common/locales/global/ce.js index 52d05ddd63..cffb720673 100644 --- a/packages/common/locales/global/ce.js +++ b/packages/common/locales/global/ce.js @@ -66,6 +66,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'Терхьаш дац', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'Российн сом', {'JPY': ['JP¥', '¥'], 'RON': [u, 'лей'], 'RUB': ['₽'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ceb.js b/packages/common/locales/global/ceb.js index 6d603cf293..22a96dbfee 100644 --- a/packages/common/locales/global/ceb.js +++ b/packages/common/locales/global/ceb.js @@ -42,6 +42,7 @@ ['{1}, {0}', u, '{1} \'sa\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,#0%', '¤#,##0.00', '#E0'], + 'PHP', '₱', 'Philippine Piso', {'JPY': ['JP¥', '¥'], 'PHP': ['₱'], 'USD': ['US $', '$']}, diff --git a/packages/common/locales/global/cgg.js b/packages/common/locales/global/cgg.js index c1f05900e3..4eb7401e23 100644 --- a/packages/common/locales/global/cgg.js +++ b/packages/common/locales/global/cgg.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Eshiringi ya Uganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/chr.js b/packages/common/locales/global/chr.js index 55a1df0c5a..761f06bfc4 100644 --- a/packages/common/locales/global/chr.js +++ b/packages/common/locales/global/chr.js @@ -52,6 +52,7 @@ ['{1}, {0}', u, '{1} ᎤᎾᎢ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US ᎠᏕᎳ', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/global/ckb-IR.js b/packages/common/locales/global/ckb-IR.js index 4709f7786f..d565245c9f 100644 --- a/packages/common/locales/global/ckb-IR.js +++ b/packages/common/locales/global/ckb-IR.js @@ -51,6 +51,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'IRR', 'IRR', + 'IRR', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'rtl', plural, diff --git a/packages/common/locales/global/ckb.js b/packages/common/locales/global/ckb.js index 8f0baaf8bd..a185b9ecfa 100644 --- a/packages/common/locales/global/ckb.js +++ b/packages/common/locales/global/ckb.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'IQD', 'د.ع.\u200f', 'IQD', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/cs.js b/packages/common/locales/global/cs.js index 11e06aabf0..aa9946508c 100644 --- a/packages/common/locales/global/cs.js +++ b/packages/common/locales/global/cs.js @@ -58,6 +58,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CZK', 'Kč', 'česká koruna', { diff --git a/packages/common/locales/global/cu.js b/packages/common/locales/global/cu.js index 295756700f..0e413ac445 100644 --- a/packages/common/locales/global/cu.js +++ b/packages/common/locales/global/cu.js @@ -34,6 +34,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'RUB', '₽', 'RUB', {'JPY': ['JP¥', '¥'], 'RUB': ['₽'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/cy.js b/packages/common/locales/global/cy.js index 906b84dbe9..0f502e5b9b 100644 --- a/packages/common/locales/global/cy.js +++ b/packages/common/locales/global/cy.js @@ -66,6 +66,7 @@ ['{1} {0}', u, '{1} \'am\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'Punt Prydain', { diff --git a/packages/common/locales/global/da-GL.js b/packages/common/locales/global/da-GL.js index 664955c55e..cdf3c8d273 100644 --- a/packages/common/locales/global/da-GL.js +++ b/packages/common/locales/global/da-GL.js @@ -55,6 +55,7 @@ ['{1} {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'dansk krone', { diff --git a/packages/common/locales/global/da.js b/packages/common/locales/global/da.js index de3028642b..0046ebb767 100644 --- a/packages/common/locales/global/da.js +++ b/packages/common/locales/global/da.js @@ -55,6 +55,7 @@ ['{1} {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'dansk krone', { diff --git a/packages/common/locales/global/dav.js b/packages/common/locales/global/dav.js index ecdc69089f..8be697e5bd 100644 --- a/packages/common/locales/global/dav.js +++ b/packages/common/locales/global/dav.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/de-AT.js b/packages/common/locales/global/de-AT.js index 3ccdf21119..bf064c7b5c 100644 --- a/packages/common/locales/global/de-AT.js +++ b/packages/common/locales/global/de-AT.js @@ -60,6 +60,7 @@ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':', u, '.'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/de-BE.js b/packages/common/locales/global/de-BE.js index 2b5863ef36..b6b6cde58a 100644 --- a/packages/common/locales/global/de-BE.js +++ b/packages/common/locales/global/de-BE.js @@ -60,6 +60,7 @@ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/de-CH.js b/packages/common/locales/global/de-CH.js index 5bfd67058c..7d73241a07 100644 --- a/packages/common/locales/global/de-CH.js +++ b/packages/common/locales/global/de-CH.js @@ -61,6 +61,7 @@ ['.', '’', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤-#,##0.00', '#E0'], 'CHF', + 'CHF', 'Schweizer Franken', { 'ATS': ['öS'], diff --git a/packages/common/locales/global/de-IT.js b/packages/common/locales/global/de-IT.js index ceea3440eb..b90769e392 100644 --- a/packages/common/locales/global/de-IT.js +++ b/packages/common/locales/global/de-IT.js @@ -60,6 +60,7 @@ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/de-LI.js b/packages/common/locales/global/de-LI.js index 3b329e4125..7d82d5a35d 100644 --- a/packages/common/locales/global/de-LI.js +++ b/packages/common/locales/global/de-LI.js @@ -61,6 +61,7 @@ ['.', '’', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'CHF', + 'CHF', 'Schweizer Franken', { 'ATS': ['öS'], diff --git a/packages/common/locales/global/de-LU.js b/packages/common/locales/global/de-LU.js index bdde550185..a9e844a010 100644 --- a/packages/common/locales/global/de-LU.js +++ b/packages/common/locales/global/de-LU.js @@ -60,6 +60,7 @@ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/de.js b/packages/common/locales/global/de.js index fc6cf108df..1379bbaacf 100644 --- a/packages/common/locales/global/de.js +++ b/packages/common/locales/global/de.js @@ -60,6 +60,7 @@ ['{1}, {0}', u, '{1} \'um\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/dje.js b/packages/common/locales/global/dje.js index 665f0ae33a..82a7c7ff40 100644 --- a/packages/common/locales/global/dje.js +++ b/packages/common/locales/global/dje.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/dsb.js b/packages/common/locales/global/dsb.js index 11bb66735a..736887461d 100644 --- a/packages/common/locales/global/dsb.js +++ b/packages/common/locales/global/dsb.js @@ -64,6 +64,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'AUD': [u, '$'], 'PLN': ['zł'], 'THB': ['฿']}, diff --git a/packages/common/locales/global/dua.js b/packages/common/locales/global/dua.js index 046c9aa3ed..b145567ede 100644 --- a/packages/common/locales/global/dua.js +++ b/packages/common/locales/global/dua.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'XAF', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/dyo.js b/packages/common/locales/global/dyo.js index 42248bc981..80c4e69119 100644 --- a/packages/common/locales/global/dyo.js +++ b/packages/common/locales/global/dyo.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'seefa yati BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/dz.js b/packages/common/locales/global/dz.js index 3e7c4079cb..a7383c10aa 100644 --- a/packages/common/locales/global/dz.js +++ b/packages/common/locales/global/dz.js @@ -82,6 +82,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0 %', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'རྒྱ་གར་གྱི་དངུལ་ རུ་པི', { diff --git a/packages/common/locales/global/ebu.js b/packages/common/locales/global/ebu.js index d2f35dc199..3b93c21ef8 100644 --- a/packages/common/locales/global/ebu.js +++ b/packages/common/locales/global/ebu.js @@ -44,6 +44,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ee-TG.js b/packages/common/locales/global/ee-TG.js index cfae06452a..29176223bf 100644 --- a/packages/common/locales/global/ee-TG.js +++ b/packages/common/locales/global/ee-TG.js @@ -45,6 +45,7 @@ ['{0} {1}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'mnn', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XOF', 'CFA', 'ɣetoɖofe afrikaga CFA franc BCEAO', { diff --git a/packages/common/locales/global/ee.js b/packages/common/locales/global/ee.js index 8129046226..57c5d0a879 100644 --- a/packages/common/locales/global/ee.js +++ b/packages/common/locales/global/ee.js @@ -45,6 +45,7 @@ ['{0} {1}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'mnn', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GHS', 'GH₵', 'ghana siɖi', { diff --git a/packages/common/locales/global/el-CY.js b/packages/common/locales/global/el-CY.js index f84db31280..37f97c384d 100644 --- a/packages/common/locales/global/el-CY.js +++ b/packages/common/locales/global/el-CY.js @@ -64,6 +64,7 @@ ['{1}, {0}', u, '{1} - {0}', u], [',', '.', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Ευρώ', {'GRD': ['Δρχ'], 'JPY': ['JP¥', '¥'], 'THB': ['฿']}, diff --git a/packages/common/locales/global/el.js b/packages/common/locales/global/el.js index 9b523c6fb0..1ab2d32cdb 100644 --- a/packages/common/locales/global/el.js +++ b/packages/common/locales/global/el.js @@ -64,6 +64,7 @@ ['{1}, {0}', u, '{1} - {0}', u], [',', '.', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Ευρώ', {'GRD': ['Δρχ'], 'JPY': ['JP¥', '¥'], 'THB': ['฿']}, diff --git a/packages/common/locales/global/en-001.js b/packages/common/locales/global/en-001.js index 9eb96bf631..5b6c65bb38 100644 --- a/packages/common/locales/global/en-001.js +++ b/packages/common/locales/global/en-001.js @@ -48,6 +48,7 @@ ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural, diff --git a/packages/common/locales/global/en-150.js b/packages/common/locales/global/en-150.js index 4ac4a72f76..3e9dc483fa 100644 --- a/packages/common/locales/global/en-150.js +++ b/packages/common/locales/global/en-150.js @@ -48,6 +48,7 @@ ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural, diff --git a/packages/common/locales/global/en-AE.js b/packages/common/locales/global/en-AE.js index b040826dd8..e6c14527c8 100644 --- a/packages/common/locales/global/en-AE.js +++ b/packages/common/locales/global/en-AE.js @@ -47,6 +47,7 @@ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'AED', + 'AED', 'United Arab Emirates Dirham', {}, 'ltr', diff --git a/packages/common/locales/global/en-AG.js b/packages/common/locales/global/en-AG.js index 6c2beb3200..078f168fe5 100644 --- a/packages/common/locales/global/en-AG.js +++ b/packages/common/locales/global/en-AG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-AI.js b/packages/common/locales/global/en-AI.js index 9903abfce6..8e1057e1bd 100644 --- a/packages/common/locales/global/en-AI.js +++ b/packages/common/locales/global/en-AI.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-AS.js b/packages/common/locales/global/en-AS.js index 4392e5bbb5..6b288707dd 100644 --- a/packages/common/locales/global/en-AS.js +++ b/packages/common/locales/global/en-AS.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-AT.js b/packages/common/locales/global/en-AT.js index a7efcbc1cb..765b638621 100644 --- a/packages/common/locales/global/en-AT.js +++ b/packages/common/locales/global/en-AT.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-AU.js b/packages/common/locales/global/en-AU.js index e62b057a87..5cc7523db9 100644 --- a/packages/common/locales/global/en-AU.js +++ b/packages/common/locales/global/en-AU.js @@ -20,7 +20,7 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['en-au'] = ['en-AU',[['am','pm'],u,u],u,[['Su.','M.','Tu.','W.','Th.','F.','Sa.'],['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],['Su','Mon','Tu','Wed','Th','Fri','Sat']],u,[['J','F','M','A','M','J','J','A','S','O','N','D'],['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],['January','February','March','April','May','June','July','August','September','October','November','December']],u,[['B','A'],['BC','AD'],['Before Christ','Anno Domini']],0,[6,0],['d/M/yy','d MMM y','d MMMM y','EEEE, d MMMM y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1}, {0}',u,'{1} \'at\' {0}',u],['.',',',';','%','+','-','e','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','¤#,##0.00','#E0'],'$','Australian Dollar',{'AUD':['$'],'BDT':[u,'Tk'],'BOB':[u,'$b'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'CUP':[u,'₱'],'EGP':[u,'£'],'EUR':[u,'€'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'ISK':[u,'Kr'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PYG':[u,'Gs'],'SCR':['Rs'],'SEK':[u,'Kr'],'TWD':[u,'$'],'USD':[u,'$'],'UYU':[u,'$U'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[],'XPF':['CFP']},'ltr', plural, [[['midnight','midday','morning','afternoon','evening','night'],u,['midnight','midday','in the morning','in the afternoon','in the evening','at night']],[['midnight','midday','morning','afternoon','evening','night'],u,u],['00:00','12:00',['06:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','06:00']]]]; + global.ng.common.locales['en-au'] = ['en-AU',[['am','pm'],u,u],u,[['Su.','M.','Tu.','W.','Th.','F.','Sa.'],['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],['Su','Mon','Tu','Wed','Th','Fri','Sat']],u,[['J','F','M','A','M','J','J','A','S','O','N','D'],['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],['January','February','March','April','May','June','July','August','September','October','November','December']],u,[['B','A'],['BC','AD'],['Before Christ','Anno Domini']],0,[6,0],['d/M/yy','d MMM y','d MMMM y','EEEE, d MMMM y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1}, {0}',u,'{1} \'at\' {0}',u],['.',',',';','%','+','-','e','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','¤#,##0.00','#E0'],'AUD','$','Australian Dollar',{'AUD':['$'],'BDT':[u,'Tk'],'BOB':[u,'$b'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'CUP':[u,'₱'],'EGP':[u,'£'],'EUR':[u,'€'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'ISK':[u,'Kr'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PYG':[u,'Gs'],'SCR':['Rs'],'SEK':[u,'Kr'],'TWD':[u,'$'],'USD':[u,'$'],'UYU':[u,'$U'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[],'XPF':['CFP']},'ltr', plural, [[['midnight','midday','morning','afternoon','evening','night'],u,['midnight','midday','in the morning','in the afternoon','in the evening','at night']],[['midnight','midday','morning','afternoon','evening','night'],u,u],['00:00','12:00',['06:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','06:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/en-BB.js b/packages/common/locales/global/en-BB.js index c1739d92f1..3476054b26 100644 --- a/packages/common/locales/global/en-BB.js +++ b/packages/common/locales/global/en-BB.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BBD', '$', 'Barbadian Dollar', {'BBD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-BE.js b/packages/common/locales/global/en-BE.js index 87f8c2084d..0e5e65193d 100644 --- a/packages/common/locales/global/en-BE.js +++ b/packages/common/locales/global/en-BE.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-BI.js b/packages/common/locales/global/en-BI.js index efcc06e0dc..8de64318bb 100644 --- a/packages/common/locales/global/en-BI.js +++ b/packages/common/locales/global/en-BI.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BIF', 'FBu', 'Burundian Franc', {'BIF': ['FBu']}, diff --git a/packages/common/locales/global/en-BM.js b/packages/common/locales/global/en-BM.js index 0c22e2f33e..5b322c8867 100644 --- a/packages/common/locales/global/en-BM.js +++ b/packages/common/locales/global/en-BM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BMD', '$', 'Bermudan Dollar', {'BMD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-BS.js b/packages/common/locales/global/en-BS.js index 57610bef06..60618313a3 100644 --- a/packages/common/locales/global/en-BS.js +++ b/packages/common/locales/global/en-BS.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BSD', '$', 'Bahamian Dollar', {'BSD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-BW.js b/packages/common/locales/global/en-BW.js index bc67d68f15..4f4c5a99ab 100644 --- a/packages/common/locales/global/en-BW.js +++ b/packages/common/locales/global/en-BW.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BWP', 'P', 'Botswanan Pula', {'BWP': ['P'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-BZ.js b/packages/common/locales/global/en-BZ.js index 20a2cbe236..64e8e8f066 100644 --- a/packages/common/locales/global/en-BZ.js +++ b/packages/common/locales/global/en-BZ.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'BZD', '$', 'Belize Dollar', {'BZD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-CA.js b/packages/common/locales/global/en-CA.js index 7d839715e7..3c31c19e20 100644 --- a/packages/common/locales/global/en-CA.js +++ b/packages/common/locales/global/en-CA.js @@ -49,6 +49,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CAD', '$', 'Canadian Dollar', {'CAD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-CC.js b/packages/common/locales/global/en-CC.js index c0a4e697f8..17ee2e3fd8 100644 --- a/packages/common/locales/global/en-CC.js +++ b/packages/common/locales/global/en-CC.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-CH.js b/packages/common/locales/global/en-CH.js index 7237b428f7..d04abb05fd 100644 --- a/packages/common/locales/global/en-CH.js +++ b/packages/common/locales/global/en-CH.js @@ -47,6 +47,7 @@ ['.', '’', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤-#,##0.00', '#E0'], 'CHF', + 'CHF', 'Swiss Franc', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/en-CK.js b/packages/common/locales/global/en-CK.js index 091015294f..9d93825802 100644 --- a/packages/common/locales/global/en-CK.js +++ b/packages/common/locales/global/en-CK.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-CM.js b/packages/common/locales/global/en-CM.js index 02a959d2ed..efcafac9f1 100644 --- a/packages/common/locales/global/en-CM.js +++ b/packages/common/locales/global/en-CM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XAF', 'FCFA', 'Central African CFA Franc', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-CX.js b/packages/common/locales/global/en-CX.js index aacc80e1e3..f62312d48c 100644 --- a/packages/common/locales/global/en-CX.js +++ b/packages/common/locales/global/en-CX.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-CY.js b/packages/common/locales/global/en-CY.js index ff0664990d..f2bc8bef4c 100644 --- a/packages/common/locales/global/en-CY.js +++ b/packages/common/locales/global/en-CY.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-DE.js b/packages/common/locales/global/en-DE.js index 20c2a253ca..f80a3d7347 100644 --- a/packages/common/locales/global/en-DE.js +++ b/packages/common/locales/global/en-DE.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-DG.js b/packages/common/locales/global/en-DG.js index 380326b8f6..34256c3fe0 100644 --- a/packages/common/locales/global/en-DG.js +++ b/packages/common/locales/global/en-DG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-DK.js b/packages/common/locales/global/en-DK.js index 5b3786ef2e..78fa0c6146 100644 --- a/packages/common/locales/global/en-DK.js +++ b/packages/common/locales/global/en-DK.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'Danish Krone', {'DKK': ['kr.', 'kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-DM.js b/packages/common/locales/global/en-DM.js index 021f15dd1b..c850ef2dc4 100644 --- a/packages/common/locales/global/en-DM.js +++ b/packages/common/locales/global/en-DM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-ER.js b/packages/common/locales/global/en-ER.js index 4d5442b6b3..993c85bc39 100644 --- a/packages/common/locales/global/en-ER.js +++ b/packages/common/locales/global/en-ER.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ERN', 'Nfk', 'Eritrean Nakfa', {'ERN': ['Nfk'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-FI.js b/packages/common/locales/global/en-FI.js index a74bd29b55..ff6c12041b 100644 --- a/packages/common/locales/global/en-FI.js +++ b/packages/common/locales/global/en-FI.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-FJ.js b/packages/common/locales/global/en-FJ.js index 8dff78e848..a7c0b92fd3 100644 --- a/packages/common/locales/global/en-FJ.js +++ b/packages/common/locales/global/en-FJ.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'FJD', '$', 'Fijian Dollar', {'FJD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-FK.js b/packages/common/locales/global/en-FK.js index 40377e16ef..4af4727e15 100644 --- a/packages/common/locales/global/en-FK.js +++ b/packages/common/locales/global/en-FK.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'FKP', '£', 'Falkland Islands Pound', {'FKP': ['£'], 'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-FM.js b/packages/common/locales/global/en-FM.js index 3c6e6a8a26..97c0f85e60 100644 --- a/packages/common/locales/global/en-FM.js +++ b/packages/common/locales/global/en-FM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-GB.js b/packages/common/locales/global/en-GB.js index d7f98009e8..c174fd35d4 100644 --- a/packages/common/locales/global/en-GB.js +++ b/packages/common/locales/global/en-GB.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'British Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-GD.js b/packages/common/locales/global/en-GD.js index 256bef92e8..4eb58a1b49 100644 --- a/packages/common/locales/global/en-GD.js +++ b/packages/common/locales/global/en-GD.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-GG.js b/packages/common/locales/global/en-GG.js index b9f0a75a24..4ad6f137f5 100644 --- a/packages/common/locales/global/en-GG.js +++ b/packages/common/locales/global/en-GG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'UK Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-GH.js b/packages/common/locales/global/en-GH.js index b20710efc1..e7e30f5ad7 100644 --- a/packages/common/locales/global/en-GH.js +++ b/packages/common/locales/global/en-GH.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GHS', 'GH₵', 'Ghanaian Cedi', {'GHS': ['GH₵'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-GI.js b/packages/common/locales/global/en-GI.js index 04622d090d..f37963fb4c 100644 --- a/packages/common/locales/global/en-GI.js +++ b/packages/common/locales/global/en-GI.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GIP', '£', 'Gibraltar Pound', {'GBP': ['GB£', '£'], 'GIP': ['£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-GM.js b/packages/common/locales/global/en-GM.js index 11cc43fe9c..eb6316c2d5 100644 --- a/packages/common/locales/global/en-GM.js +++ b/packages/common/locales/global/en-GM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GMD', 'D', 'Gambian Dalasi', {'GMD': ['D'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-GU.js b/packages/common/locales/global/en-GU.js index 7792bab1b8..6a58f2de19 100644 --- a/packages/common/locales/global/en-GU.js +++ b/packages/common/locales/global/en-GU.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-GY.js b/packages/common/locales/global/en-GY.js index bf5b3dc560..9293f01435 100644 --- a/packages/common/locales/global/en-GY.js +++ b/packages/common/locales/global/en-GY.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GYD', '$', 'Guyanaese Dollar', {'GYD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-HK.js b/packages/common/locales/global/en-HK.js index 6b191f444f..bb3c267a7f 100644 --- a/packages/common/locales/global/en-HK.js +++ b/packages/common/locales/global/en-HK.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', 'Hong Kong Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-IE.js b/packages/common/locales/global/en-IE.js index ef8a5e3801..ebbfdbabbb 100644 --- a/packages/common/locales/global/en-IE.js +++ b/packages/common/locales/global/en-IE.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-IL.js b/packages/common/locales/global/en-IL.js index e9c64c9c4f..08f452f6d2 100644 --- a/packages/common/locales/global/en-IL.js +++ b/packages/common/locales/global/en-IL.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ILS', '₪', 'Israeli New Shekel', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-IM.js b/packages/common/locales/global/en-IM.js index 3232fbe385..f7eb391040 100644 --- a/packages/common/locales/global/en-IM.js +++ b/packages/common/locales/global/en-IM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'UK Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-IN.js b/packages/common/locales/global/en-IN.js index 434e06177d..931d986449 100644 --- a/packages/common/locales/global/en-IN.js +++ b/packages/common/locales/global/en-IN.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'Indian Rupee', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-IO.js b/packages/common/locales/global/en-IO.js index fa72a621b0..7be7cb49c5 100644 --- a/packages/common/locales/global/en-IO.js +++ b/packages/common/locales/global/en-IO.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-JE.js b/packages/common/locales/global/en-JE.js index 363ecb2bd2..93c24c5dea 100644 --- a/packages/common/locales/global/en-JE.js +++ b/packages/common/locales/global/en-JE.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'UK Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-JM.js b/packages/common/locales/global/en-JM.js index 87dc925fef..408a1dd842 100644 --- a/packages/common/locales/global/en-JM.js +++ b/packages/common/locales/global/en-JM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'JMD', '$', 'Jamaican Dollar', {'JMD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-KE.js b/packages/common/locales/global/en-KE.js index d007114b73..b050ba9242 100644 --- a/packages/common/locales/global/en-KE.js +++ b/packages/common/locales/global/en-KE.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Kenyan Shilling', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-KI.js b/packages/common/locales/global/en-KI.js index e03559a4fc..c0033bddba 100644 --- a/packages/common/locales/global/en-KI.js +++ b/packages/common/locales/global/en-KI.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-KN.js b/packages/common/locales/global/en-KN.js index cbfffe2c23..39da662be4 100644 --- a/packages/common/locales/global/en-KN.js +++ b/packages/common/locales/global/en-KN.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-KY.js b/packages/common/locales/global/en-KY.js index f91e3e8d24..74499ae280 100644 --- a/packages/common/locales/global/en-KY.js +++ b/packages/common/locales/global/en-KY.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KYD', '$', 'Cayman Islands Dollar', {'JPY': ['JP¥', '¥'], 'KYD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-LC.js b/packages/common/locales/global/en-LC.js index ae00525d83..fe549aff2c 100644 --- a/packages/common/locales/global/en-LC.js +++ b/packages/common/locales/global/en-LC.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-LR.js b/packages/common/locales/global/en-LR.js index 36772da658..3890a885ca 100644 --- a/packages/common/locales/global/en-LR.js +++ b/packages/common/locales/global/en-LR.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'Liberian Dollar', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-LS.js b/packages/common/locales/global/en-LS.js index 5ba74133dd..4e28db09a9 100644 --- a/packages/common/locales/global/en-LS.js +++ b/packages/common/locales/global/en-LS.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'South African Rand', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZAR': ['R']}, diff --git a/packages/common/locales/global/en-MG.js b/packages/common/locales/global/en-MG.js index f2eab672e9..ca6ce4e4d6 100644 --- a/packages/common/locales/global/en-MG.js +++ b/packages/common/locales/global/en-MG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MGA', 'Ar', 'Malagasy Ariary', {'JPY': ['JP¥', '¥'], 'MGA': ['Ar'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-MH.js b/packages/common/locales/global/en-MH.js index bd49a2571b..499e8a6bd5 100644 --- a/packages/common/locales/global/en-MH.js +++ b/packages/common/locales/global/en-MH.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-MO.js b/packages/common/locales/global/en-MO.js index a1e87956ea..4a7457d478 100644 --- a/packages/common/locales/global/en-MO.js +++ b/packages/common/locales/global/en-MO.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MOP', 'MOP$', 'Macanese Pataca', {'JPY': ['JP¥', '¥'], 'MOP': ['MOP$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-MP.js b/packages/common/locales/global/en-MP.js index dd74ec612c..8afe11c18e 100644 --- a/packages/common/locales/global/en-MP.js +++ b/packages/common/locales/global/en-MP.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-MS.js b/packages/common/locales/global/en-MS.js index 59f51082b3..eefe032f5a 100644 --- a/packages/common/locales/global/en-MS.js +++ b/packages/common/locales/global/en-MS.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-MT.js b/packages/common/locales/global/en-MT.js index 1ac83c7dfd..4e88841ac2 100644 --- a/packages/common/locales/global/en-MT.js +++ b/packages/common/locales/global/en-MT.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-MU.js b/packages/common/locales/global/en-MU.js index fd4dac2f47..0c5f51a0a0 100644 --- a/packages/common/locales/global/en-MU.js +++ b/packages/common/locales/global/en-MU.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MUR', 'Rs', 'Mauritian Rupee', {'JPY': ['JP¥', '¥'], 'MUR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-MW.js b/packages/common/locales/global/en-MW.js index db0c147924..d936b75bf6 100644 --- a/packages/common/locales/global/en-MW.js +++ b/packages/common/locales/global/en-MW.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MWK', 'MK', 'Malawian Kwacha', {'JPY': ['JP¥', '¥'], 'MWK': ['MK'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-MY.js b/packages/common/locales/global/en-MY.js index 4da6f1d543..3102a86043 100644 --- a/packages/common/locales/global/en-MY.js +++ b/packages/common/locales/global/en-MY.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MYR', 'RM', 'Malaysian Ringgit', {'JPY': ['JP¥', '¥'], 'MYR': ['RM'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-NA.js b/packages/common/locales/global/en-NA.js index 4f5a4d1d9d..dee551b0c8 100644 --- a/packages/common/locales/global/en-NA.js +++ b/packages/common/locales/global/en-NA.js @@ -47,6 +47,7 @@ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'ZAR', + 'ZAR', 'South African Rand', {'JPY': ['JP¥', '¥'], 'NAD': ['$'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/en-NF.js b/packages/common/locales/global/en-NF.js index f810104642..1cce502afa 100644 --- a/packages/common/locales/global/en-NF.js +++ b/packages/common/locales/global/en-NF.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-NG.js b/packages/common/locales/global/en-NG.js index 82c7b723e7..2d339ef24b 100644 --- a/packages/common/locales/global/en-NG.js +++ b/packages/common/locales/global/en-NG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NGN', '₦', 'Nigerian Naira', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-NL.js b/packages/common/locales/global/en-NL.js index 31efc4f3bd..fcde4a243c 100644 --- a/packages/common/locales/global/en-NL.js +++ b/packages/common/locales/global/en-NL.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-NR.js b/packages/common/locales/global/en-NR.js index 39e0573ebe..b6f9732968 100644 --- a/packages/common/locales/global/en-NR.js +++ b/packages/common/locales/global/en-NR.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-NU.js b/packages/common/locales/global/en-NU.js index 67497cafce..466ef028a7 100644 --- a/packages/common/locales/global/en-NU.js +++ b/packages/common/locales/global/en-NU.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-NZ.js b/packages/common/locales/global/en-NZ.js index 0b552327a0..15229a37a5 100644 --- a/packages/common/locales/global/en-NZ.js +++ b/packages/common/locales/global/en-NZ.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-PG.js b/packages/common/locales/global/en-PG.js index 6b3958bbde..ff6edcad39 100644 --- a/packages/common/locales/global/en-PG.js +++ b/packages/common/locales/global/en-PG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PGK', 'K', 'Papua New Guinean Kina', {'JPY': ['JP¥', '¥'], 'PGK': ['K'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-PH.js b/packages/common/locales/global/en-PH.js index a4f1b6cc8c..38c481b481 100644 --- a/packages/common/locales/global/en-PH.js +++ b/packages/common/locales/global/en-PH.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PHP', '₱', 'Philippine Piso', {'JPY': ['JP¥', '¥'], 'PHP': ['₱'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-PK.js b/packages/common/locales/global/en-PK.js index 7fa5970781..a1526e78b5 100644 --- a/packages/common/locales/global/en-PK.js +++ b/packages/common/locales/global/en-PK.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PKR', 'Rs', 'Pakistani Rupee', {'JPY': ['JP¥', '¥'], 'PKR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-PN.js b/packages/common/locales/global/en-PN.js index ef382e974d..c8fa0348dd 100644 --- a/packages/common/locales/global/en-PN.js +++ b/packages/common/locales/global/en-PN.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-PR.js b/packages/common/locales/global/en-PR.js index 2693c19c43..ca573c7075 100644 --- a/packages/common/locales/global/en-PR.js +++ b/packages/common/locales/global/en-PR.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-PW.js b/packages/common/locales/global/en-PW.js index b170a95b0e..0de86f3573 100644 --- a/packages/common/locales/global/en-PW.js +++ b/packages/common/locales/global/en-PW.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-RW.js b/packages/common/locales/global/en-RW.js index d6809f3034..12a60eb6cc 100644 --- a/packages/common/locales/global/en-RW.js +++ b/packages/common/locales/global/en-RW.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'RWF', 'RF', 'Rwandan Franc', {'JPY': ['JP¥', '¥'], 'RWF': ['RF'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SB.js b/packages/common/locales/global/en-SB.js index 475409b59d..d4a5f27874 100644 --- a/packages/common/locales/global/en-SB.js +++ b/packages/common/locales/global/en-SB.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SBD', '$', 'Solomon Islands Dollar', {'JPY': ['JP¥', '¥'], 'SBD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SC.js b/packages/common/locales/global/en-SC.js index 1fa086431b..6b25fd1bbd 100644 --- a/packages/common/locales/global/en-SC.js +++ b/packages/common/locales/global/en-SC.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SCR', 'SR', 'Seychellois Rupee', {'JPY': ['JP¥', '¥'], 'SCR': ['SR'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SD.js b/packages/common/locales/global/en-SD.js index 4b66999300..ae72a66cec 100644 --- a/packages/common/locales/global/en-SD.js +++ b/packages/common/locales/global/en-SD.js @@ -47,6 +47,7 @@ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'SDG', + 'SDG', 'Sudanese Pound', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/en-SE.js b/packages/common/locales/global/en-SE.js index d2f65c329e..eddb4e1578 100644 --- a/packages/common/locales/global/en-SE.js +++ b/packages/common/locales/global/en-SE.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', ' ', ';', '%', '+', '-', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SEK', 'kr', 'Swedish Krona', {'JPY': ['JP¥', '¥'], 'SEK': ['kr'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SG.js b/packages/common/locales/global/en-SG.js index 14937753fb..8e9de3572b 100644 --- a/packages/common/locales/global/en-SG.js +++ b/packages/common/locales/global/en-SG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SGD', '$', 'Singapore Dollar', {'JPY': ['JP¥', '¥'], 'SGD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SH.js b/packages/common/locales/global/en-SH.js index d39396c2e7..c66dbb29a9 100644 --- a/packages/common/locales/global/en-SH.js +++ b/packages/common/locales/global/en-SH.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SHP', '£', 'St Helena Pound', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'SHP': ['£'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SI.js b/packages/common/locales/global/en-SI.js index e4cd151467..4aad71c3f9 100644 --- a/packages/common/locales/global/en-SI.js +++ b/packages/common/locales/global/en-SI.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', '.', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SL.js b/packages/common/locales/global/en-SL.js index f01994b3d2..2ee48417ad 100644 --- a/packages/common/locales/global/en-SL.js +++ b/packages/common/locales/global/en-SL.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SLL', 'Le', 'Sierra Leonean Leone', {'JPY': ['JP¥', '¥'], 'SLL': ['Le'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SS.js b/packages/common/locales/global/en-SS.js index 6c775fb21e..12202ac75a 100644 --- a/packages/common/locales/global/en-SS.js +++ b/packages/common/locales/global/en-SS.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SSP', '£', 'South Sudanese Pound', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'SSP': ['£'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SX.js b/packages/common/locales/global/en-SX.js index 4e3b5f6faa..25b0237a2f 100644 --- a/packages/common/locales/global/en-SX.js +++ b/packages/common/locales/global/en-SX.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ANG', 'NAf.', 'Netherlands Antillean Guilder', {'ANG': ['NAf.'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-SZ.js b/packages/common/locales/global/en-SZ.js index a5a0f42d3c..755d49edad 100644 --- a/packages/common/locales/global/en-SZ.js +++ b/packages/common/locales/global/en-SZ.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SZL', 'E', 'Swazi Lilangeni', {'JPY': ['JP¥', '¥'], 'SZL': ['E'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-TC.js b/packages/common/locales/global/en-TC.js index 808edca218..4615c0ee70 100644 --- a/packages/common/locales/global/en-TC.js +++ b/packages/common/locales/global/en-TC.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-TK.js b/packages/common/locales/global/en-TK.js index 0046b354c0..4e02f43a3d 100644 --- a/packages/common/locales/global/en-TK.js +++ b/packages/common/locales/global/en-TK.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NZD', '$', 'New Zealand Dollar', {'JPY': ['JP¥', '¥'], 'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-TO.js b/packages/common/locales/global/en-TO.js index 13e90b9731..4bc3f20af9 100644 --- a/packages/common/locales/global/en-TO.js +++ b/packages/common/locales/global/en-TO.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TOP', 'T$', 'Tongan Paʻanga', {'JPY': ['JP¥', '¥'], 'TOP': ['T$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-TT.js b/packages/common/locales/global/en-TT.js index 8e904bdab9..7197069cd3 100644 --- a/packages/common/locales/global/en-TT.js +++ b/packages/common/locales/global/en-TT.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TTD', '$', 'Trinidad & Tobago Dollar', {'JPY': ['JP¥', '¥'], 'TTD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-TV.js b/packages/common/locales/global/en-TV.js index e310028fa7..cb6ce847ec 100644 --- a/packages/common/locales/global/en-TV.js +++ b/packages/common/locales/global/en-TV.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'AUD', '$', 'Australian Dollar', {'AUD': ['$'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-TZ.js b/packages/common/locales/global/en-TZ.js index 59852cb6a6..67094aecbe 100644 --- a/packages/common/locales/global/en-TZ.js +++ b/packages/common/locales/global/en-TZ.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Tanzanian Shilling', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-UG.js b/packages/common/locales/global/en-UG.js index add3df8dba..ca7f59b1c0 100644 --- a/packages/common/locales/global/en-UG.js +++ b/packages/common/locales/global/en-UG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Ugandan Shilling', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-UM.js b/packages/common/locales/global/en-UM.js index bda7a06a17..382278a166 100644 --- a/packages/common/locales/global/en-UM.js +++ b/packages/common/locales/global/en-UM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-US-POSIX.js b/packages/common/locales/global/en-US-POSIX.js index 66d35de220..228879be92 100644 --- a/packages/common/locales/global/en-US-POSIX.js +++ b/packages/common/locales/global/en-US-POSIX.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '0/00', 'INF', 'NaN', ':'], ['0.######', '0%', '¤ 0.00', '0.000000E+000'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-VC.js b/packages/common/locales/global/en-VC.js index 3b08139196..a436135deb 100644 --- a/packages/common/locales/global/en-VC.js +++ b/packages/common/locales/global/en-VC.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XCD', '$', 'East Caribbean Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'XCD': ['$']}, diff --git a/packages/common/locales/global/en-VG.js b/packages/common/locales/global/en-VG.js index 6943f17338..3b3ddb8d2b 100644 --- a/packages/common/locales/global/en-VG.js +++ b/packages/common/locales/global/en-VG.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en-VI.js b/packages/common/locales/global/en-VI.js index a9d18ce62a..84f9c115e1 100644 --- a/packages/common/locales/global/en-VI.js +++ b/packages/common/locales/global/en-VI.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/en-VU.js b/packages/common/locales/global/en-VU.js index 2f04b8c47a..65232c1f5b 100644 --- a/packages/common/locales/global/en-VU.js +++ b/packages/common/locales/global/en-VU.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'VUV', 'VT', 'Vanuatu Vatu', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'VUV': ['VT']}, diff --git a/packages/common/locales/global/en-WS.js b/packages/common/locales/global/en-WS.js index fafc976e27..3b0d4be8d2 100644 --- a/packages/common/locales/global/en-WS.js +++ b/packages/common/locales/global/en-WS.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'WST', 'WS$', 'Samoan Tala', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'WST': ['WS$']}, diff --git a/packages/common/locales/global/en-ZA.js b/packages/common/locales/global/en-ZA.js index 9192e65e23..f9e330d69a 100644 --- a/packages/common/locales/global/en-ZA.js +++ b/packages/common/locales/global/en-ZA.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'South African Rand', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZAR': ['R']}, diff --git a/packages/common/locales/global/en-ZM.js b/packages/common/locales/global/en-ZM.js index ef01127b09..75ecaa50ed 100644 --- a/packages/common/locales/global/en-ZM.js +++ b/packages/common/locales/global/en-ZM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZMW', 'K', 'Zambian Kwacha', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZMW': ['K', 'ZK']}, diff --git a/packages/common/locales/global/en-ZW.js b/packages/common/locales/global/en-ZW.js index 35afbd01e7..f408a96404 100644 --- a/packages/common/locales/global/en-ZW.js +++ b/packages/common/locales/global/en-ZW.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'US Dollar', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/en.js b/packages/common/locales/global/en.js index 1c05557f01..e4f3e8830a 100644 --- a/packages/common/locales/global/en.js +++ b/packages/common/locales/global/en.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/eo.js b/packages/common/locales/global/eo.js index ce417b37cb..62e1a1d1ea 100644 --- a/packages/common/locales/global/eo.js +++ b/packages/common/locales/global/eo.js @@ -47,6 +47,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural, diff --git a/packages/common/locales/global/es-419.js b/packages/common/locales/global/es-419.js index 46d34879f5..89716bbf05 100644 --- a/packages/common/locales/global/es-419.js +++ b/packages/common/locales/global/es-419.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-419'] = ['es-419',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'EUR','euro',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-419'] = ['es-419',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'EUR','EUR','euro',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-AR.js b/packages/common/locales/global/es-AR.js index 6852f86d8b..ba96bc05d2 100644 --- a/packages/common/locales/global/es-AR.js +++ b/packages/common/locales/global/es-AR.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'ARS', '$', 'peso argentino', { diff --git a/packages/common/locales/global/es-BO.js b/packages/common/locales/global/es-BO.js index 96b77600b8..86a30a2c68 100644 --- a/packages/common/locales/global/es-BO.js +++ b/packages/common/locales/global/es-BO.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-bo'] = ['es-BO',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM \'de\' y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'Bs','boliviano',{'AUD':[u,'$'],'BOB':['Bs'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-bo'] = ['es-BO',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM \'de\' y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'BOB','Bs','boliviano',{'AUD':[u,'$'],'BOB':['Bs'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-BR.js b/packages/common/locales/global/es-BR.js index e45c5cc9a1..65dc00aba8 100644 --- a/packages/common/locales/global/es-BR.js +++ b/packages/common/locales/global/es-BR.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-br'] = ['es-BR',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'R$','real brasileño',{'AUD':[u,'$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-br'] = ['es-BR',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'BRL','R$','real brasileño',{'AUD':[u,'$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-BZ.js b/packages/common/locales/global/es-BZ.js index c26dc1b1b7..ff53cc45c4 100644 --- a/packages/common/locales/global/es-BZ.js +++ b/packages/common/locales/global/es-BZ.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-bz'] = ['es-BZ',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'$','dólar beliceño',{'AUD':[u,'$'],'BRL':[u,'R$'],'BZD':['$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-bz'] = ['es-BZ',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'BZD','$','dólar beliceño',{'AUD':[u,'$'],'BRL':[u,'R$'],'BZD':['$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-CL.js b/packages/common/locales/global/es-CL.js index 123127e8be..7ddf2309d3 100644 --- a/packages/common/locales/global/es-CL.js +++ b/packages/common/locales/global/es-CL.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-cl'] = ['es-CL',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['do','lu','ma','mi','ju','vi','sá']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sept.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['dd-MM-yy','dd-MM-y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00;¤-#,##0.00','#E0'],'$','Peso chileno',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CLP':['$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':['US$','$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-cl'] = ['es-CL',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['do','lu','ma','mi','ju','vi','sá']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sept.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['dd-MM-yy','dd-MM-y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00;¤-#,##0.00','#E0'],'CLP','$','Peso chileno',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CLP':['$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':['US$','$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-CO.js b/packages/common/locales/global/es-CO.js index 395e847b34..c4cc34c392 100644 --- a/packages/common/locales/global/es-CO.js +++ b/packages/common/locales/global/es-CO.js @@ -64,6 +64,7 @@ ['{1}, {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'COP', '$', 'peso colombiano', { diff --git a/packages/common/locales/global/es-CR.js b/packages/common/locales/global/es-CR.js index 0a008c440d..d16216b8fb 100644 --- a/packages/common/locales/global/es-CR.js +++ b/packages/common/locales/global/es-CR.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-cr'] = ['es-CR',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',',' ',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'₡','colón costarricense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'CRC':['₡'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-cr'] = ['es-CR',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',',' ',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'CRC','₡','colón costarricense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'CRC':['₡'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-CU.js b/packages/common/locales/global/es-CU.js index 62fc61b4b8..c4c4d1dbb9 100644 --- a/packages/common/locales/global/es-CU.js +++ b/packages/common/locales/global/es-CU.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-cu'] = ['es-CU',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'$','peso cubano',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'CUP':['$'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':['US$','$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-cu'] = ['es-CU',[['a. m.','p. m.'],['a.m.','p.m.'],u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'CUP','$','peso cubano',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'CUP':['$'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':['US$','$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-DO.js b/packages/common/locales/global/es-DO.js index 87e7f78575..88dbf09caf 100644 --- a/packages/common/locales/global/es-DO.js +++ b/packages/common/locales/global/es-DO.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'DOP', 'RD$', 'peso dominicano', { diff --git a/packages/common/locales/global/es-EA.js b/packages/common/locales/global/es-EA.js index 3dc074c5d7..ad22653f6d 100644 --- a/packages/common/locales/global/es-EA.js +++ b/packages/common/locales/global/es-EA.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/es-EC.js b/packages/common/locales/global/es-EC.js index 978963f39b..5f9f691db3 100644 --- a/packages/common/locales/global/es-EC.js +++ b/packages/common/locales/global/es-EC.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-ec'] = ['es-EC',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00;¤-#,##0.00','#E0'],'$','dólar estadounidense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-ec'] = ['es-EC',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00;¤-#,##0.00','#E0'],'USD','$','dólar estadounidense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-GQ.js b/packages/common/locales/global/es-GQ.js index 330643bad9..65d5cfdbfe 100644 --- a/packages/common/locales/global/es-GQ.js +++ b/packages/common/locales/global/es-GQ.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'XAF', 'FCFA', 'franco CFA de África Central', { diff --git a/packages/common/locales/global/es-GT.js b/packages/common/locales/global/es-GT.js index ddf4e2ebef..7e3d07e20f 100644 --- a/packages/common/locales/global/es-GT.js +++ b/packages/common/locales/global/es-GT.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-gt'] = ['es-GT',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/MM/yy','d/MM/y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'Q','quetzal',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'GTQ':['Q'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-gt'] = ['es-GT',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/MM/yy','d/MM/y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'GTQ','Q','quetzal',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'GTQ':['Q'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-HN.js b/packages/common/locales/global/es-HN.js index f78d405117..4ad92812ef 100644 --- a/packages/common/locales/global/es-HN.js +++ b/packages/common/locales/global/es-HN.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-hn'] = ['es-HN',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','dd \'de\' MMMM \'de\' y','EEEE dd \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'L','lempira hondureño',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'HNL':['L'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-hn'] = ['es-HN',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','dd \'de\' MMMM \'de\' y','EEEE dd \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'HNL','L','lempira hondureño',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'HNL':['L'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-IC.js b/packages/common/locales/global/es-IC.js index d34dd2f1d7..b8c513415f 100644 --- a/packages/common/locales/global/es-IC.js +++ b/packages/common/locales/global/es-IC.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/es-MX.js b/packages/common/locales/global/es-MX.js index 514565d7f6..7f17449cba 100644 --- a/packages/common/locales/global/es-MX.js +++ b/packages/common/locales/global/es-MX.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'MXN', '$', 'peso mexicano', { diff --git a/packages/common/locales/global/es-NI.js b/packages/common/locales/global/es-NI.js index b4fb9862b4..3927165457 100644 --- a/packages/common/locales/global/es-NI.js +++ b/packages/common/locales/global/es-NI.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-ni'] = ['es-NI',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'C$','córdoba nicaragüense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NIO':['C$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-ni'] = ['es-NI',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'NIO','C$','córdoba nicaragüense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NIO':['C$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-PA.js b/packages/common/locales/global/es-PA.js index 48f4a933ef..15b395b39a 100644 --- a/packages/common/locales/global/es-PA.js +++ b/packages/common/locales/global/es-PA.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-pa'] = ['es-PA',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['MM/dd/yy','MM/dd/y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'B/.','balboa panameño',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PAB':['B/.'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],['mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-pa'] = ['es-PA',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['MM/dd/yy','MM/dd/y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'PAB','B/.','balboa panameño',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PAB':['B/.'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],['mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-PE.js b/packages/common/locales/global/es-PE.js index 23ca4ec2de..1370da8869 100644 --- a/packages/common/locales/global/es-PE.js +++ b/packages/common/locales/global/es-PE.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-pe'] = ['es-PE',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','set.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','setiembre','octubre','noviembre','diciembre']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['Ene.','Feb.','Mar.','Abr.','May.','Jun.','Jul.','Ago.','Set.','Oct.','Nov.','Dic.'],['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Setiembre','Octubre','Noviembre','Diciembre']],[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/MM/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤ #,##0.00','#E0'],'S/','sol peruano',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PEN':['S/'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-pe'] = ['es-PE',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','set.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','setiembre','octubre','noviembre','diciembre']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['Ene.','Feb.','Mar.','Abr.','May.','Jun.','Jul.','Ago.','Set.','Oct.','Nov.','Dic.'],['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Setiembre','Octubre','Noviembre','Diciembre']],[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/MM/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤ #,##0.00','#E0'],'PEN','S/','sol peruano',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PEN':['S/'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':[u,'$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-PH.js b/packages/common/locales/global/es-PH.js index 804b91d834..2565a82b13 100644 --- a/packages/common/locales/global/es-PH.js +++ b/packages/common/locales/global/es-PH.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'PHP', '₱', 'peso filipino', { diff --git a/packages/common/locales/global/es-PR.js b/packages/common/locales/global/es-PR.js index 10e1228751..50bd9b60e3 100644 --- a/packages/common/locales/global/es-PR.js +++ b/packages/common/locales/global/es-PR.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-pr'] = ['es-PR',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['MM/dd/yy','MM/dd/y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'$','dólar estadounidense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-pr'] = ['es-PR',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['MM/dd/yy','MM/dd/y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['h:mm a','h:mm:ss a','h:mm:ss a z','h:mm:ss a zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'USD','$','dólar estadounidense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-PY.js b/packages/common/locales/global/es-PY.js index 6811383d6b..1f035aacf1 100644 --- a/packages/common/locales/global/es-PY.js +++ b/packages/common/locales/global/es-PY.js @@ -54,6 +54,7 @@ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'PYG', 'Gs.', 'guaraní paraguayo', { diff --git a/packages/common/locales/global/es-SV.js b/packages/common/locales/global/es-SV.js index bae65eae23..8cfda5a099 100644 --- a/packages/common/locales/global/es-SV.js +++ b/packages/common/locales/global/es-SV.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-sv'] = ['es-SV',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'$','dólar estadounidense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-sv'] = ['es-SV',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','sep.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre']],u,[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],0,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤#,##0.00','#E0'],'USD','$','dólar estadounidense',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-US.js b/packages/common/locales/global/es-US.js index 352cebf9bc..62048686b5 100644 --- a/packages/common/locales/global/es-US.js +++ b/packages/common/locales/global/es-US.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00', '#E0'], + 'USD', '$', 'dólar estadounidense', { diff --git a/packages/common/locales/global/es-UY.js b/packages/common/locales/global/es-UY.js index 20eccf8091..82e44cfd0d 100644 --- a/packages/common/locales/global/es-UY.js +++ b/packages/common/locales/global/es-UY.js @@ -19,7 +19,7 @@ if (n === 1) return 1; return 5; } - global.ng.common.locales['es-uy'] = ['es-UY',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','set.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','setiembre','octubre','noviembre','diciembre']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['Ene.','Feb.','Mar.','Abr.','May.','Jun.','Jul.','Ago.','Set.','Oct.','Nov.','Dic.'],['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Setiembre','Octubre','Noviembre','Diciembre']],[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤ #,##0.00','#E0'],'$','peso uruguayo',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':['US$','$'],'UYU':['$'],'UYW':['UP'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; + global.ng.common.locales['es-uy'] = ['es-UY',[['a. m.','p. m.'],u,u],u,[['d','l','m','m','j','v','s'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['D','L','M','M','J','V','S'],['dom.','lun.','mar.','mié.','jue.','vie.','sáb.'],['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],['DO','LU','MA','MI','JU','VI','SA']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['ene.','feb.','mar.','abr.','may.','jun.','jul.','ago.','set.','oct.','nov.','dic.'],['enero','febrero','marzo','abril','mayo','junio','julio','agosto','setiembre','octubre','noviembre','diciembre']],[['E','F','M','A','M','J','J','A','S','O','N','D'],['Ene.','Feb.','Mar.','Abr.','May.','Jun.','Jul.','Ago.','Set.','Oct.','Nov.','Dic.'],['Enero','Febrero','Marzo','Abril','Mayo','Junio','Julio','Agosto','Setiembre','Octubre','Noviembre','Diciembre']],[['a. C.','d. C.'],u,['antes de Cristo','después de Cristo']],1,[6,0],['d/M/yy','d MMM y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,'{1} \'a\' \'las\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','¤ #,##0.00','#E0'],'UYU','$','peso uruguayo',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'ESP':['₧'],'EUR':[u,'€'],'FKP':[u,'FK£'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'RON':[u,'L'],'SSP':[u,'SD£'],'SYP':[u,'S£'],'TWD':[u,'NT$'],'USD':['US$','$'],'UYU':['$'],'UYW':['UP'],'VEF':[u,'BsF'],'VND':[u,'₫'],'XAF':[],'XCD':[u,'$'],'XOF':[]},'ltr', plural, [[['del mediodía','de la madrugada','de la mañana','de la tarde','de la noche'],u,u],[['mediodía','madrugada','mañana','tarde','noche'],u,u],['12:00',['00:00','06:00'],['06:00','12:00'],['12:00','20:00'],['20:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/es-VE.js b/packages/common/locales/global/es-VE.js index af13388b79..4e247a1ec5 100644 --- a/packages/common/locales/global/es-VE.js +++ b/packages/common/locales/global/es-VE.js @@ -54,6 +54,7 @@ ['{1} {0}', u, '{1} \'a\' \'las\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'VES', 'Bs.S', 'bolívar soberano', { diff --git a/packages/common/locales/global/es.js b/packages/common/locales/global/es.js index c99410b574..403be2819b 100644 --- a/packages/common/locales/global/es.js +++ b/packages/common/locales/global/es.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1}, {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/et.js b/packages/common/locales/global/et.js index 5945d1a547..df789d76d2 100644 --- a/packages/common/locales/global/et.js +++ b/packages/common/locales/global/et.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'AUD': ['AU$', '$'], 'EEK': ['kr'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/eu.js b/packages/common/locales/global/eu.js index 5b198161d8..9605e1e58f 100644 --- a/packages/common/locales/global/eu.js +++ b/packages/common/locales/global/eu.js @@ -51,6 +51,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '% #,##0', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euroa', {'ESP': ['₧'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ewo.js b/packages/common/locales/global/ewo.js index 3433c9face..e7d6ce2be8 100644 --- a/packages/common/locales/global/ewo.js +++ b/packages/common/locales/global/ewo.js @@ -47,6 +47,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Fəláŋ CFA (BEAC)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/fa-AF.js b/packages/common/locales/global/fa-AF.js index d52acd9e6f..d39cdecac6 100644 --- a/packages/common/locales/global/fa-AF.js +++ b/packages/common/locales/global/fa-AF.js @@ -59,6 +59,7 @@ ['{1}،\u200f {0}', u, '{1}، ساعت {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'ناعدد', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'AFN', '؋', 'افغانی افغانستان', { diff --git a/packages/common/locales/global/fa.js b/packages/common/locales/global/fa.js index d02398cfac..da637bf952 100644 --- a/packages/common/locales/global/fa.js +++ b/packages/common/locales/global/fa.js @@ -56,6 +56,7 @@ ['{1}،\u200f {0}', u, '{1}، ساعت {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'ناعدد', ':'], ['#,##0.###', '#,##0%', '\u200e¤ #,##0.00', '#E0'], + 'IRR', 'ریال', 'ریال ایران', { diff --git a/packages/common/locales/global/ff-Latn-BF.js b/packages/common/locales/global/ff-Latn-BF.js index 8f3cd6652d..b2450efe23 100644 --- a/packages/common/locales/global/ff-Latn-BF.js +++ b/packages/common/locales/global/ff-Latn-BF.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-CM.js b/packages/common/locales/global/ff-Latn-CM.js index 62360b3908..cde16b99e0 100644 --- a/packages/common/locales/global/ff-Latn-CM.js +++ b/packages/common/locales/global/ff-Latn-CM.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Mbuuɗi Seefaa BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-GH.js b/packages/common/locales/global/ff-Latn-GH.js index d75b9ac750..040449270f 100644 --- a/packages/common/locales/global/ff-Latn-GH.js +++ b/packages/common/locales/global/ff-Latn-GH.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GHS', 'GH₵', 'GHS', {'GHS': ['GH₵'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-GM.js b/packages/common/locales/global/ff-Latn-GM.js index 9f055e6c84..7a7c14b48c 100644 --- a/packages/common/locales/global/ff-Latn-GM.js +++ b/packages/common/locales/global/ff-Latn-GM.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GMD', 'D', 'Dalasi Gammbi', {'GMD': ['D'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-GN.js b/packages/common/locales/global/ff-Latn-GN.js index 77d274dd06..e79d8f8fce 100644 --- a/packages/common/locales/global/ff-Latn-GN.js +++ b/packages/common/locales/global/ff-Latn-GN.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GNF', 'FG', 'GNF', {'GNF': ['FG'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-GW.js b/packages/common/locales/global/ff-Latn-GW.js index d6b93a2497..143eb1e0eb 100644 --- a/packages/common/locales/global/ff-Latn-GW.js +++ b/packages/common/locales/global/ff-Latn-GW.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-LR.js b/packages/common/locales/global/ff-Latn-LR.js index 5b0e6366d7..2f7a9abe55 100644 --- a/packages/common/locales/global/ff-Latn-LR.js +++ b/packages/common/locales/global/ff-Latn-LR.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'LRD', '$', 'Dolaar Liberiyaa', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-MR.js b/packages/common/locales/global/ff-Latn-MR.js index 5e30f5a56b..0eeddd3ca7 100644 --- a/packages/common/locales/global/ff-Latn-MR.js +++ b/packages/common/locales/global/ff-Latn-MR.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MRU', 'UM', 'Ugiyya Muritani', {'JPY': ['JP¥', '¥'], 'MRU': ['UM'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-NE.js b/packages/common/locales/global/ff-Latn-NE.js index 57672db332..fdd3598325 100644 --- a/packages/common/locales/global/ff-Latn-NE.js +++ b/packages/common/locales/global/ff-Latn-NE.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-NG.js b/packages/common/locales/global/ff-Latn-NG.js index fd3f8d52fb..b3379cd49f 100644 --- a/packages/common/locales/global/ff-Latn-NG.js +++ b/packages/common/locales/global/ff-Latn-NG.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'NGN', '₦', 'Nayraa Nijeriyaa', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn-SL.js b/packages/common/locales/global/ff-Latn-SL.js index 0da81bcc93..09635ebc38 100644 --- a/packages/common/locales/global/ff-Latn-SL.js +++ b/packages/common/locales/global/ff-Latn-SL.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'SLL', 'Le', 'Lewoon Seraa Liyon', {'JPY': ['JP¥', '¥'], 'SLL': ['Le'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff-Latn.js b/packages/common/locales/global/ff-Latn.js index 5594221b6e..47a9da1709 100644 --- a/packages/common/locales/global/ff-Latn.js +++ b/packages/common/locales/global/ff-Latn.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ff.js b/packages/common/locales/global/ff.js index 0c040c660a..8255730de3 100644 --- a/packages/common/locales/global/ff.js +++ b/packages/common/locales/global/ff.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'Mbuuɗu Seefaa BCEAO', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/fi.js b/packages/common/locales/global/fi.js index 095c030f61..e6296457d2 100644 --- a/packages/common/locales/global/fi.js +++ b/packages/common/locales/global/fi.js @@ -19,6 +19,6 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['fi'] = ['fi',[['ap.','ip.'],u,u],u,[['S','M','T','K','T','P','L'],['su','ma','ti','ke','to','pe','la'],['sunnuntaina','maanantaina','tiistaina','keskiviikkona','torstaina','perjantaina','lauantaina'],['su','ma','ti','ke','to','pe','la']],[['S','M','T','K','T','P','L'],['su','ma','ti','ke','to','pe','la'],['sunnuntai','maanantai','tiistai','keskiviikko','torstai','perjantai','lauantai'],['su','ma','ti','ke','to','pe','la']],[['T','H','M','H','T','K','H','E','S','L','M','J'],['tammik.','helmik.','maalisk.','huhtik.','toukok.','kesäk.','heinäk.','elok.','syysk.','lokak.','marrask.','jouluk.'],['tammikuuta','helmikuuta','maaliskuuta','huhtikuuta','toukokuuta','kesäkuuta','heinäkuuta','elokuuta','syyskuuta','lokakuuta','marraskuuta','joulukuuta']],[['T','H','M','H','T','K','H','E','S','L','M','J'],['tammi','helmi','maalis','huhti','touko','kesä','heinä','elo','syys','loka','marras','joulu'],['tammikuu','helmikuu','maaliskuu','huhtikuu','toukokuu','kesäkuu','heinäkuu','elokuu','syyskuu','lokakuu','marraskuu','joulukuu']],[['eKr','jKr'],['eKr.','jKr.'],['ennen Kristuksen syntymää','jälkeen Kristuksen syntymän']],1,[6,0],['d.M.y',u,'d. MMMM y','cccc d. MMMM y'],['H.mm','H.mm.ss','H.mm.ss z','H.mm.ss zzzz'],['{1} {0}','{1} \'klo\' {0}',u,u],[',',' ',';','%','+','−','E','×','‰','∞','epäluku','.'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'€','euro',{'AOA':[],'ARS':[],'AUD':[],'BAM':[],'BBD':[],'BDT':[],'BMD':[],'BND':[],'BOB':[],'BRL':[],'BSD':[],'BWP':[],'BYN':[],'BZD':[],'CAD':[],'CLP':[],'CNY':[],'COP':[],'CRC':[],'CUC':[],'CUP':[],'CZK':[],'DKK':[],'DOP':[],'EGP':[],'ESP':[],'FIM':['mk'],'FJD':[],'FKP':[],'GEL':[],'GIP':[],'GNF':[],'GTQ':[],'GYD':[],'HKD':[],'HNL':[],'HRK':[],'HUF':[],'IDR':[],'ILS':[],'INR':[],'ISK':[],'JMD':[],'KHR':[],'KMF':[],'KPW':[],'KRW':[],'KYD':[],'KZT':[],'LAK':[],'LBP':[],'LKR':[],'LRD':[],'LTL':[],'LVL':[],'MGA':[],'MMK':[],'MNT':[],'MUR':[],'MXN':[],'MYR':[],'NAD':[],'NGN':[],'NIO':[],'NOK':[],'NPR':[],'NZD':[],'PHP':[],'PKR':[],'PLN':[],'PYG':[],'RON':[],'RUR':[],'RWF':[],'SBD':[],'SEK':[],'SGD':[],'SHP':[],'SRD':[],'SSP':[],'STN':[u,'STD'],'SYP':[],'THB':[],'TOP':[],'TRY':[],'TTD':[],'TWD':[],'UAH':[],'UYU':[],'VEF':[],'VND':[],'XCD':[],'XPF':[],'XXX':[],'ZAR':[],'ZMW':[]},'ltr', plural, [[['ky.','kp.','aamulla','ap.','ip.','illalla','yöllä'],['keskiyöllä','keskip.','aamulla','aamup.','iltap.','illalla','yöllä'],['keskiyöllä','keskipäivällä','aamulla','aamupäivällä','iltapäivällä','illalla','yöllä']],[['ky.','kp.','aamu','ap.','ip.','ilta','yö'],['keskiyö','keskip.','aamu','aamup.','iltap.','ilta','yö'],['keskiyö','keskipäivä','aamu','aamupäivä','iltapäivä','ilta','yö']],['00:00','12:00',['05:00','10:00'],['10:00','12:00'],['12:00','18:00'],['18:00','23:00'],['23:00','05:00']]]]; + global.ng.common.locales['fi'] = ['fi',[['ap.','ip.'],u,u],u,[['S','M','T','K','T','P','L'],['su','ma','ti','ke','to','pe','la'],['sunnuntaina','maanantaina','tiistaina','keskiviikkona','torstaina','perjantaina','lauantaina'],['su','ma','ti','ke','to','pe','la']],[['S','M','T','K','T','P','L'],['su','ma','ti','ke','to','pe','la'],['sunnuntai','maanantai','tiistai','keskiviikko','torstai','perjantai','lauantai'],['su','ma','ti','ke','to','pe','la']],[['T','H','M','H','T','K','H','E','S','L','M','J'],['tammik.','helmik.','maalisk.','huhtik.','toukok.','kesäk.','heinäk.','elok.','syysk.','lokak.','marrask.','jouluk.'],['tammikuuta','helmikuuta','maaliskuuta','huhtikuuta','toukokuuta','kesäkuuta','heinäkuuta','elokuuta','syyskuuta','lokakuuta','marraskuuta','joulukuuta']],[['T','H','M','H','T','K','H','E','S','L','M','J'],['tammi','helmi','maalis','huhti','touko','kesä','heinä','elo','syys','loka','marras','joulu'],['tammikuu','helmikuu','maaliskuu','huhtikuu','toukokuu','kesäkuu','heinäkuu','elokuu','syyskuu','lokakuu','marraskuu','joulukuu']],[['eKr','jKr'],['eKr.','jKr.'],['ennen Kristuksen syntymää','jälkeen Kristuksen syntymän']],1,[6,0],['d.M.y',u,'d. MMMM y','cccc d. MMMM y'],['H.mm','H.mm.ss','H.mm.ss z','H.mm.ss zzzz'],['{1} {0}','{1} \'klo\' {0}',u,u],[',',' ',';','%','+','−','E','×','‰','∞','epäluku','.'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'EUR','€','euro',{'AOA':[],'ARS':[],'AUD':[],'BAM':[],'BBD':[],'BDT':[],'BMD':[],'BND':[],'BOB':[],'BRL':[],'BSD':[],'BWP':[],'BYN':[],'BZD':[],'CAD':[],'CLP':[],'CNY':[],'COP':[],'CRC':[],'CUC':[],'CUP':[],'CZK':[],'DKK':[],'DOP':[],'EGP':[],'ESP':[],'FIM':['mk'],'FJD':[],'FKP':[],'GEL':[],'GIP':[],'GNF':[],'GTQ':[],'GYD':[],'HKD':[],'HNL':[],'HRK':[],'HUF':[],'IDR':[],'ILS':[],'INR':[],'ISK':[],'JMD':[],'KHR':[],'KMF':[],'KPW':[],'KRW':[],'KYD':[],'KZT':[],'LAK':[],'LBP':[],'LKR':[],'LRD':[],'LTL':[],'LVL':[],'MGA':[],'MMK':[],'MNT':[],'MUR':[],'MXN':[],'MYR':[],'NAD':[],'NGN':[],'NIO':[],'NOK':[],'NPR':[],'NZD':[],'PHP':[],'PKR':[],'PLN':[],'PYG':[],'RON':[],'RUR':[],'RWF':[],'SBD':[],'SEK':[],'SGD':[],'SHP':[],'SRD':[],'SSP':[],'STN':[u,'STD'],'SYP':[],'THB':[],'TOP':[],'TRY':[],'TTD':[],'TWD':[],'UAH':[],'UYU':[],'VEF':[],'VND':[],'XCD':[],'XPF':[],'XXX':[],'ZAR':[],'ZMW':[]},'ltr', plural, [[['ky.','kp.','aamulla','ap.','ip.','illalla','yöllä'],['keskiyöllä','keskip.','aamulla','aamup.','iltap.','illalla','yöllä'],['keskiyöllä','keskipäivällä','aamulla','aamupäivällä','iltapäivällä','illalla','yöllä']],[['ky.','kp.','aamu','ap.','ip.','ilta','yö'],['keskiyö','keskip.','aamu','aamup.','iltap.','ilta','yö'],['keskiyö','keskipäivä','aamu','aamupäivä','iltapäivä','ilta','yö']],['00:00','12:00',['05:00','10:00'],['10:00','12:00'],['12:00','18:00'],['18:00','23:00'],['23:00','05:00']]]]; })(typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/fil.js b/packages/common/locales/global/fil.js index 8f7b09e299..cb59ad85c3 100644 --- a/packages/common/locales/global/fil.js +++ b/packages/common/locales/global/fil.js @@ -56,6 +56,7 @@ ['{1}, {0}', u, '{1} \'nang\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'PHP', '₱', 'Piso ng Pilipinas', {'PHP': ['₱'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/fo-DK.js b/packages/common/locales/global/fo-DK.js index 006650b8df..c0f93453f9 100644 --- a/packages/common/locales/global/fo-DK.js +++ b/packages/common/locales/global/fo-DK.js @@ -66,6 +66,7 @@ ['{1}, {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr.', 'donsk króna', {'DKK': ['kr.', 'kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/fo.js b/packages/common/locales/global/fo.js index 471fcad6b9..809712a01c 100644 --- a/packages/common/locales/global/fo.js +++ b/packages/common/locales/global/fo.js @@ -66,6 +66,7 @@ ['{1}, {0}', u, '{1} \'kl\'. {0}', u], [',', '.', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DKK', 'kr', 'donsk króna', {'DKK': ['kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/fr-BE.js b/packages/common/locales/global/fr-BE.js index ae35527ec3..391249f601 100644 --- a/packages/common/locales/global/fr-BE.js +++ b/packages/common/locales/global/fr-BE.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-BF.js b/packages/common/locales/global/fr-BF.js index e4e98fe209..103371a94a 100644 --- a/packages/common/locales/global/fr-BF.js +++ b/packages/common/locales/global/fr-BF.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/global/fr-BI.js b/packages/common/locales/global/fr-BI.js index ec80a8084a..f4311189e2 100644 --- a/packages/common/locales/global/fr-BI.js +++ b/packages/common/locales/global/fr-BI.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BIF', 'FBu', 'franc burundais', { diff --git a/packages/common/locales/global/fr-BJ.js b/packages/common/locales/global/fr-BJ.js index 26bc488ed9..114f6d3bd7 100644 --- a/packages/common/locales/global/fr-BJ.js +++ b/packages/common/locales/global/fr-BJ.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/global/fr-BL.js b/packages/common/locales/global/fr-BL.js index f3de91aecc..a95b8a8190 100644 --- a/packages/common/locales/global/fr-BL.js +++ b/packages/common/locales/global/fr-BL.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-CA.js b/packages/common/locales/global/fr-CA.js index ff2e4c32eb..4f1b1e8950 100644 --- a/packages/common/locales/global/fr-CA.js +++ b/packages/common/locales/global/fr-CA.js @@ -52,6 +52,7 @@ ['{1} {0}', u, '{1} \'à\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CAD', '$', 'dollar canadien', { diff --git a/packages/common/locales/global/fr-CD.js b/packages/common/locales/global/fr-CD.js index ccbd4d2885..3c40538fd6 100644 --- a/packages/common/locales/global/fr-CD.js +++ b/packages/common/locales/global/fr-CD.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'CDF', 'FC', 'franc congolais', { diff --git a/packages/common/locales/global/fr-CF.js b/packages/common/locales/global/fr-CF.js index e92b04db8b..e71ad66237 100644 --- a/packages/common/locales/global/fr-CF.js +++ b/packages/common/locales/global/fr-CF.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/global/fr-CG.js b/packages/common/locales/global/fr-CG.js index 3ed7093dc4..f3711b2bde 100644 --- a/packages/common/locales/global/fr-CG.js +++ b/packages/common/locales/global/fr-CG.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/global/fr-CH.js b/packages/common/locales/global/fr-CH.js index e860d243a2..36728bb5a6 100644 --- a/packages/common/locales/global/fr-CH.js +++ b/packages/common/locales/global/fr-CH.js @@ -50,6 +50,7 @@ [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':', '.'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'franc suisse', { 'ARS': ['$AR', '$'], diff --git a/packages/common/locales/global/fr-CI.js b/packages/common/locales/global/fr-CI.js index 2a7f233211..ac0362af1d 100644 --- a/packages/common/locales/global/fr-CI.js +++ b/packages/common/locales/global/fr-CI.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/global/fr-CM.js b/packages/common/locales/global/fr-CM.js index 785c46f7f8..8b8372f2ca 100644 --- a/packages/common/locales/global/fr-CM.js +++ b/packages/common/locales/global/fr-CM.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/global/fr-DJ.js b/packages/common/locales/global/fr-DJ.js index ce43c99c47..09098da1db 100644 --- a/packages/common/locales/global/fr-DJ.js +++ b/packages/common/locales/global/fr-DJ.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DJF', 'Fdj', 'franc djiboutien', { diff --git a/packages/common/locales/global/fr-DZ.js b/packages/common/locales/global/fr-DZ.js index 6d4e2cb7f3..2fdf877eaa 100644 --- a/packages/common/locales/global/fr-DZ.js +++ b/packages/common/locales/global/fr-DZ.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'DZD', 'DA', 'dinar algérien', { diff --git a/packages/common/locales/global/fr-GA.js b/packages/common/locales/global/fr-GA.js index 948e9e00d6..3b3fcd8c28 100644 --- a/packages/common/locales/global/fr-GA.js +++ b/packages/common/locales/global/fr-GA.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/global/fr-GF.js b/packages/common/locales/global/fr-GF.js index 1d7be212d1..89284fc2c1 100644 --- a/packages/common/locales/global/fr-GF.js +++ b/packages/common/locales/global/fr-GF.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-GN.js b/packages/common/locales/global/fr-GN.js index 81e4e2bd63..75a480d7a7 100644 --- a/packages/common/locales/global/fr-GN.js +++ b/packages/common/locales/global/fr-GN.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'GNF', 'FG', 'franc guinéen', { diff --git a/packages/common/locales/global/fr-GP.js b/packages/common/locales/global/fr-GP.js index c7dd3024fe..e75c673580 100644 --- a/packages/common/locales/global/fr-GP.js +++ b/packages/common/locales/global/fr-GP.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-GQ.js b/packages/common/locales/global/fr-GQ.js index 8060e24f15..11deee8d51 100644 --- a/packages/common/locales/global/fr-GQ.js +++ b/packages/common/locales/global/fr-GQ.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/global/fr-HT.js b/packages/common/locales/global/fr-HT.js index 6a3ccac325..1b436b12bd 100644 --- a/packages/common/locales/global/fr-HT.js +++ b/packages/common/locales/global/fr-HT.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'HTG', 'G', 'gourde haïtienne', { diff --git a/packages/common/locales/global/fr-KM.js b/packages/common/locales/global/fr-KM.js index 72614a3549..4954b27880 100644 --- a/packages/common/locales/global/fr-KM.js +++ b/packages/common/locales/global/fr-KM.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'KMF', 'CF', 'franc comorien', { diff --git a/packages/common/locales/global/fr-LU.js b/packages/common/locales/global/fr-LU.js index 40ba6dc295..4edd776e05 100644 --- a/packages/common/locales/global/fr-LU.js +++ b/packages/common/locales/global/fr-LU.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-MA.js b/packages/common/locales/global/fr-MA.js index b3f6c51615..a93d9821fb 100644 --- a/packages/common/locales/global/fr-MA.js +++ b/packages/common/locales/global/fr-MA.js @@ -50,6 +50,7 @@ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'MAD', + 'MAD', 'dirham marocain', { 'ARS': ['$AR', '$'], diff --git a/packages/common/locales/global/fr-MC.js b/packages/common/locales/global/fr-MC.js index a56045708b..ae9bde399d 100644 --- a/packages/common/locales/global/fr-MC.js +++ b/packages/common/locales/global/fr-MC.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-MF.js b/packages/common/locales/global/fr-MF.js index cf4c74518f..df342fd9a6 100644 --- a/packages/common/locales/global/fr-MF.js +++ b/packages/common/locales/global/fr-MF.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-MG.js b/packages/common/locales/global/fr-MG.js index 69808ccd8f..72891a999b 100644 --- a/packages/common/locales/global/fr-MG.js +++ b/packages/common/locales/global/fr-MG.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MGA', 'Ar', 'ariary malgache', { diff --git a/packages/common/locales/global/fr-ML.js b/packages/common/locales/global/fr-ML.js index 2cad649e70..3eff899b9d 100644 --- a/packages/common/locales/global/fr-ML.js +++ b/packages/common/locales/global/fr-ML.js @@ -49,6 +49,7 @@ ['{1}, {0}', u, '{1} \'à\' {0}', u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/global/fr-MQ.js b/packages/common/locales/global/fr-MQ.js index 7eb86f503a..256902f232 100644 --- a/packages/common/locales/global/fr-MQ.js +++ b/packages/common/locales/global/fr-MQ.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-MR.js b/packages/common/locales/global/fr-MR.js index 5d83e3b3fb..c90be32699 100644 --- a/packages/common/locales/global/fr-MR.js +++ b/packages/common/locales/global/fr-MR.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MRU', 'UM', 'ouguiya mauritanien', { diff --git a/packages/common/locales/global/fr-MU.js b/packages/common/locales/global/fr-MU.js index b0d727273f..437271ae51 100644 --- a/packages/common/locales/global/fr-MU.js +++ b/packages/common/locales/global/fr-MU.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MUR', 'Rs', 'roupie mauricienne', { diff --git a/packages/common/locales/global/fr-NC.js b/packages/common/locales/global/fr-NC.js index 15a0bfc92d..622525f99a 100644 --- a/packages/common/locales/global/fr-NC.js +++ b/packages/common/locales/global/fr-NC.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XPF', 'FCFP', 'franc CFP', { diff --git a/packages/common/locales/global/fr-NE.js b/packages/common/locales/global/fr-NE.js index 3de955c595..d97c8c510c 100644 --- a/packages/common/locales/global/fr-NE.js +++ b/packages/common/locales/global/fr-NE.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/global/fr-PF.js b/packages/common/locales/global/fr-PF.js index 576d156f4c..8e18925250 100644 --- a/packages/common/locales/global/fr-PF.js +++ b/packages/common/locales/global/fr-PF.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XPF', 'FCFP', 'franc CFP', { diff --git a/packages/common/locales/global/fr-PM.js b/packages/common/locales/global/fr-PM.js index 6eb0078ced..200be437d5 100644 --- a/packages/common/locales/global/fr-PM.js +++ b/packages/common/locales/global/fr-PM.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-RE.js b/packages/common/locales/global/fr-RE.js index d04b743c11..aac33e3a0d 100644 --- a/packages/common/locales/global/fr-RE.js +++ b/packages/common/locales/global/fr-RE.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr-RW.js b/packages/common/locales/global/fr-RW.js index 69533862f3..be31eef96f 100644 --- a/packages/common/locales/global/fr-RW.js +++ b/packages/common/locales/global/fr-RW.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RWF', 'RF', 'franc rwandais', { diff --git a/packages/common/locales/global/fr-SC.js b/packages/common/locales/global/fr-SC.js index 44303d17d8..66d1b20a6c 100644 --- a/packages/common/locales/global/fr-SC.js +++ b/packages/common/locales/global/fr-SC.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SCR', 'SR', 'roupie des Seychelles', { diff --git a/packages/common/locales/global/fr-SN.js b/packages/common/locales/global/fr-SN.js index 5cfe86edea..7f84ea9704 100644 --- a/packages/common/locales/global/fr-SN.js +++ b/packages/common/locales/global/fr-SN.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/global/fr-SY.js b/packages/common/locales/global/fr-SY.js index 6e715662ef..5404df5ce0 100644 --- a/packages/common/locales/global/fr-SY.js +++ b/packages/common/locales/global/fr-SY.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SYP', 'LS', 'livre syrienne', { diff --git a/packages/common/locales/global/fr-TD.js b/packages/common/locales/global/fr-TD.js index 97ed681d7a..4c379d8741 100644 --- a/packages/common/locales/global/fr-TD.js +++ b/packages/common/locales/global/fr-TD.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franc CFA (BEAC)', { diff --git a/packages/common/locales/global/fr-TG.js b/packages/common/locales/global/fr-TG.js index 000fad9cfb..cb3a8a9658 100644 --- a/packages/common/locales/global/fr-TG.js +++ b/packages/common/locales/global/fr-TG.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franc CFA (BCEAO)', { diff --git a/packages/common/locales/global/fr-TN.js b/packages/common/locales/global/fr-TN.js index b6fcd36e6c..8e58e32880 100644 --- a/packages/common/locales/global/fr-TN.js +++ b/packages/common/locales/global/fr-TN.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'TND', 'DT', 'dinar tunisien', { diff --git a/packages/common/locales/global/fr-VU.js b/packages/common/locales/global/fr-VU.js index 735ba4f098..c5a6e715b0 100644 --- a/packages/common/locales/global/fr-VU.js +++ b/packages/common/locales/global/fr-VU.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'VUV', 'VT', 'vatu vanuatuan', { diff --git a/packages/common/locales/global/fr-WF.js b/packages/common/locales/global/fr-WF.js index c36a903dcb..effd70cb60 100644 --- a/packages/common/locales/global/fr-WF.js +++ b/packages/common/locales/global/fr-WF.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'XPF', 'FCFP', 'franc CFP', { diff --git a/packages/common/locales/global/fr-YT.js b/packages/common/locales/global/fr-YT.js index aff4286bf2..4842c78851 100644 --- a/packages/common/locales/global/fr-YT.js +++ b/packages/common/locales/global/fr-YT.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fr.js b/packages/common/locales/global/fr.js index 764b5a84eb..41852a1be6 100644 --- a/packages/common/locales/global/fr.js +++ b/packages/common/locales/global/fr.js @@ -49,6 +49,7 @@ ['{1} {0}', '{1} \'à\' {0}', u, u], [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/fur.js b/packages/common/locales/global/fur.js index bc35bf7223..2d2590bb1a 100644 --- a/packages/common/locales/global/fur.js +++ b/packages/common/locales/global/fur.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/fy.js b/packages/common/locales/global/fy.js index def72362d0..0ba917deef 100644 --- a/packages/common/locales/global/fy.js +++ b/packages/common/locales/global/fy.js @@ -46,6 +46,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ #,##0.00-', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/ga-GB.js b/packages/common/locales/global/ga-GB.js index 15f772c464..0deb956941 100644 --- a/packages/common/locales/global/ga-GB.js +++ b/packages/common/locales/global/ga-GB.js @@ -55,6 +55,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'Punt Steirling', {'THB': ['฿'], 'TWD': ['NT$'], 'XXX': []}, diff --git a/packages/common/locales/global/ga.js b/packages/common/locales/global/ga.js index fed04b8dde..222542f3d7 100644 --- a/packages/common/locales/global/ga.js +++ b/packages/common/locales/global/ga.js @@ -55,6 +55,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'THB': ['฿'], 'TWD': ['NT$'], 'XXX': []}, diff --git a/packages/common/locales/global/gd.js b/packages/common/locales/global/gd.js index 3c6f3320c0..c809a0e86b 100644 --- a/packages/common/locales/global/gd.js +++ b/packages/common/locales/global/gd.js @@ -62,6 +62,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'Punnd Sasannach', {'JPY': ['JP¥', '¥'], 'RON': [u, 'leu'], 'THB': ['฿'], 'TWD': ['NT$'], 'XXX': []}, diff --git a/packages/common/locales/global/gl.js b/packages/common/locales/global/gl.js index bf928dcd46..befcf63be6 100644 --- a/packages/common/locales/global/gl.js +++ b/packages/common/locales/global/gl.js @@ -20,7 +20,7 @@ if (i === 1 && v === 0) return 1; return 5; } - global.ng.common.locales['gl'] = ['gl',[['a.m.','p.m.'],u,u],u,[['d.','l.','m.','m.','x.','v.','s.'],['dom.','luns','mar.','mér.','xov.','ven.','sáb.'],['domingo','luns','martes','mércores','xoves','venres','sábado'],['do.','lu.','ma.','mé.','xo.','ve.','sá.']],[['D','L','M','M','X','V','S'],['Dom.','Luns','Mar.','Mér.','Xov.','Ven.','Sáb.'],['Domingo','Luns','Martes','Mércores','Xoves','Venres','Sábado'],['Do','Lu','Ma','Mé','Xo','Ve','Sá']],[['x.','f.','m.','a.','m.','x.','x.','a.','s.','o.','n.','d.'],['xan.','feb.','mar.','abr.','maio','xuño','xul.','ago.','set.','out.','nov.','dec.'],['xaneiro','febreiro','marzo','abril','maio','xuño','xullo','agosto','setembro','outubro','novembro','decembro']],[['X','F','M','A','M','X','X','A','S','O','N','D'],['Xan.','Feb.','Mar.','Abr.','Maio','Xuño','Xul.','Ago.','Set.','Out.','Nov.','Dec.'],['Xaneiro','Febreiro','Marzo','Abril','Maio','Xuño','Xullo','Agosto','Setembro','Outubro','Novembro','Decembro']],[['a.C.','d.C.'],u,['antes de Cristo','despois de Cristo']],1,[6,0],['dd/MM/yy','d \'de\' MMM \'de\' y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{0}, {1}',u,'{0} \'do\' {1}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'€','euro',{'BYN':[u,'Br'],'ESP':['₧'],'JPY':['JP¥','¥'],'KMF':[u,'FC'],'MXN':['$MX','$'],'RUB':[u,'руб'],'THB':['฿'],'TWD':['NT$'],'XCD':[u,'$']},'ltr', plural, [[['da noite','da madrugada','da mañá','do mediodía','da tarde','da noite'],u,u],[['medianoite','madrugada','mañá','mediodía','tarde','noite'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','21:00'],['21:00','24:00']]]]; + global.ng.common.locales['gl'] = ['gl',[['a.m.','p.m.'],u,u],u,[['d.','l.','m.','m.','x.','v.','s.'],['dom.','luns','mar.','mér.','xov.','ven.','sáb.'],['domingo','luns','martes','mércores','xoves','venres','sábado'],['do.','lu.','ma.','mé.','xo.','ve.','sá.']],[['D','L','M','M','X','V','S'],['Dom.','Luns','Mar.','Mér.','Xov.','Ven.','Sáb.'],['Domingo','Luns','Martes','Mércores','Xoves','Venres','Sábado'],['Do','Lu','Ma','Mé','Xo','Ve','Sá']],[['x.','f.','m.','a.','m.','x.','x.','a.','s.','o.','n.','d.'],['xan.','feb.','mar.','abr.','maio','xuño','xul.','ago.','set.','out.','nov.','dec.'],['xaneiro','febreiro','marzo','abril','maio','xuño','xullo','agosto','setembro','outubro','novembro','decembro']],[['X','F','M','A','M','X','X','A','S','O','N','D'],['Xan.','Feb.','Mar.','Abr.','Maio','Xuño','Xul.','Ago.','Set.','Out.','Nov.','Dec.'],['Xaneiro','Febreiro','Marzo','Abril','Maio','Xuño','Xullo','Agosto','Setembro','Outubro','Novembro','Decembro']],[['a.C.','d.C.'],u,['antes de Cristo','despois de Cristo']],1,[6,0],['dd/MM/yy','d \'de\' MMM \'de\' y','d \'de\' MMMM \'de\' y','EEEE, d \'de\' MMMM \'de\' y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{0}, {1}',u,'{0} \'do\' {1}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'EUR','€','euro',{'BYN':[u,'Br'],'ESP':['₧'],'JPY':['JP¥','¥'],'KMF':[u,'FC'],'MXN':['$MX','$'],'RUB':[u,'руб'],'THB':['฿'],'TWD':['NT$'],'XCD':[u,'$']},'ltr', plural, [[['da noite','da madrugada','da mañá','do mediodía','da tarde','da noite'],u,u],[['medianoite','madrugada','mañá','mediodía','tarde','noite'],u,u],['00:00',['00:00','06:00'],['06:00','12:00'],['12:00','13:00'],['13:00','21:00'],['21:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/gsw-FR.js b/packages/common/locales/global/gsw-FR.js index 6b228d1e2a..51288964b1 100644 --- a/packages/common/locales/global/gsw-FR.js +++ b/packages/common/locales/global/gsw-FR.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'ATS': ['öS']}, diff --git a/packages/common/locales/global/gsw-LI.js b/packages/common/locales/global/gsw-LI.js index 4fd92223f7..3a1f56fae1 100644 --- a/packages/common/locales/global/gsw-LI.js +++ b/packages/common/locales/global/gsw-LI.js @@ -46,6 +46,7 @@ ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'Schwiizer Franke', {'ATS': ['öS']}, 'ltr', diff --git a/packages/common/locales/global/gsw.js b/packages/common/locales/global/gsw.js index 34206b05b5..35616f29c0 100644 --- a/packages/common/locales/global/gsw.js +++ b/packages/common/locales/global/gsw.js @@ -46,6 +46,7 @@ ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'Schwiizer Franke', {'ATS': ['öS']}, 'ltr', diff --git a/packages/common/locales/global/gu.js b/packages/common/locales/global/gu.js index c5646d152d..df4d1bacf1 100644 --- a/packages/common/locales/global/gu.js +++ b/packages/common/locales/global/gu.js @@ -65,6 +65,7 @@ ['{1} {0}', u, '{1} એ {0} વાગ્યે', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '[#E0]'], + 'INR', '₹', 'ભારતીય રૂપિયા', { diff --git a/packages/common/locales/global/guz.js b/packages/common/locales/global/guz.js index 1786d6da5f..514c3a6ab6 100644 --- a/packages/common/locales/global/guz.js +++ b/packages/common/locales/global/guz.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/gv.js b/packages/common/locales/global/gv.js index 811d376af8..ef367547bb 100644 --- a/packages/common/locales/global/gv.js +++ b/packages/common/locales/global/gv.js @@ -54,6 +54,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'GBP', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ha-GH.js b/packages/common/locales/global/ha-GH.js index f7b76c299b..a6a745d9b2 100644 --- a/packages/common/locales/global/ha-GH.js +++ b/packages/common/locales/global/ha-GH.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'GHS', 'GH₵', 'GHS', {'GHS': ['GH₵'], 'NGN': ['₦']}, diff --git a/packages/common/locales/global/ha-NE.js b/packages/common/locales/global/ha-NE.js index afa50f610f..4c9fb10ae4 100644 --- a/packages/common/locales/global/ha-NE.js +++ b/packages/common/locales/global/ha-NE.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XOF', 'CFA', 'Kuɗin Sefa na Afirka Ta Yamma', {'NGN': ['₦']}, diff --git a/packages/common/locales/global/ha.js b/packages/common/locales/global/ha.js index 7f2aa57990..4200a66969 100644 --- a/packages/common/locales/global/ha.js +++ b/packages/common/locales/global/ha.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'NGN', '₦', 'Nairar Najeriya', {'NGN': ['₦']}, diff --git a/packages/common/locales/global/haw.js b/packages/common/locales/global/haw.js index 4533b55e95..22f10d6bd5 100644 --- a/packages/common/locales/global/haw.js +++ b/packages/common/locales/global/haw.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'USD', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/global/he.js b/packages/common/locales/global/he.js index 86902b0473..d6eee2ce34 100644 --- a/packages/common/locales/global/he.js +++ b/packages/common/locales/global/he.js @@ -58,6 +58,7 @@ ['{1}, {0}', u, '{1} בשעה {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '\u200f#,##0.00 ¤;\u200f-#,##0.00 ¤', '#E0'], + 'ILS', '₪', 'שקל חדש', { diff --git a/packages/common/locales/global/hi.js b/packages/common/locales/global/hi.js index 7629af42b0..ef335a399a 100644 --- a/packages/common/locales/global/hi.js +++ b/packages/common/locales/global/hi.js @@ -64,6 +64,7 @@ ['{1}, {0}', u, '{1} को {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '[#E0]'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'RON': [u, 'लेई'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/hr-BA.js b/packages/common/locales/global/hr-BA.js index 293ffd25ba..9777b0fe95 100644 --- a/packages/common/locales/global/hr-BA.js +++ b/packages/common/locales/global/hr-BA.js @@ -25,6 +25,6 @@ return 3; return 5; } - global.ng.common.locales['hr-ba'] = ['hr-BA',[['AM','PM'],u,u],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],u,[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječnja','veljače','ožujka','travnja','svibnja','lipnja','srpnja','kolovoza','rujna','listopada','studenoga','prosinca']],[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječanj','veljača','ožujak','travanj','svibanj','lipanj','srpanj','kolovoz','rujan','listopad','studeni','prosinac']],[['pr.n.e.','AD'],['pr. Kr.','po. Kr.'],['prije Krista','poslije Krista']],1,[6,0],['d. M. yy.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss (zzzz)'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'KM','konvertibilna marka',{'AUD':[u,'$'],'BAM':['KM'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'EUR':[u,'€'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'TWD':[u,'NT$'],'USD':[u,'$'],'VND':[u,'₫'],'XCD':[u,'$'],'XPF':[],'XXX':[]},'ltr', plural, [[['ponoć','podne','ujutro','popodne','navečer','noću'],u,['ponoć','podne','ujutro','poslije podne','navečer','noću']],[['ponoć','podne','ujutro','popodne','navečer','noću'],u,u],['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; + global.ng.common.locales['hr-ba'] = ['hr-BA',[['AM','PM'],u,u],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],u,[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječnja','veljače','ožujka','travnja','svibnja','lipnja','srpnja','kolovoza','rujna','listopada','studenoga','prosinca']],[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječanj','veljača','ožujak','travanj','svibanj','lipanj','srpanj','kolovoz','rujan','listopad','studeni','prosinac']],[['pr.n.e.','AD'],['pr. Kr.','po. Kr.'],['prije Krista','poslije Krista']],1,[6,0],['d. M. yy.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss (zzzz)'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'BAM','KM','konvertibilna marka',{'AUD':[u,'$'],'BAM':['KM'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'EUR':[u,'€'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'TWD':[u,'NT$'],'USD':[u,'$'],'VND':[u,'₫'],'XCD':[u,'$'],'XPF':[],'XXX':[]},'ltr', plural, [[['ponoć','podne','ujutro','popodne','navečer','noću'],u,['ponoć','podne','ujutro','poslije podne','navečer','noću']],[['ponoć','podne','ujutro','popodne','navečer','noću'],u,u],['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; })(typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/hr.js b/packages/common/locales/global/hr.js index 2fad4f6e1e..51ca643469 100644 --- a/packages/common/locales/global/hr.js +++ b/packages/common/locales/global/hr.js @@ -25,6 +25,6 @@ return 3; return 5; } - global.ng.common.locales['hr'] = ['hr',[['AM','PM'],u,u],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['n','p','u','s','č','p','s'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječnja','veljače','ožujka','travnja','svibnja','lipnja','srpnja','kolovoza','rujna','listopada','studenoga','prosinca']],[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječanj','veljača','ožujak','travanj','svibanj','lipanj','srpanj','kolovoz','rujan','listopad','studeni','prosinac']],[['pr.n.e.','AD'],['pr. Kr.','po. Kr.'],['prije Krista','poslije Krista']],1,[6,0],['dd. MM. y.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss (zzzz)'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'HRK','hrvatska kuna',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'EUR':[u,'€'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'TWD':[u,'NT$'],'USD':[u,'$'],'VND':[u,'₫'],'XCD':[u,'$'],'XPF':[],'XXX':[]},'ltr', plural, [[['ponoć','podne','ujutro','popodne','navečer','noću'],u,['ponoć','podne','ujutro','poslije podne','navečer','noću']],[['ponoć','podne','ujutro','popodne','navečer','noću'],u,u],['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; + global.ng.common.locales['hr'] = ['hr',[['AM','PM'],u,u],u,[['N','P','U','S','Č','P','S'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['n','p','u','s','č','p','s'],['ned','pon','uto','sri','čet','pet','sub'],['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'],['ned','pon','uto','sri','čet','pet','sub']],[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječnja','veljače','ožujka','travnja','svibnja','lipnja','srpnja','kolovoza','rujna','listopada','studenoga','prosinca']],[['1.','2.','3.','4.','5.','6.','7.','8.','9.','10.','11.','12.'],['sij','velj','ožu','tra','svi','lip','srp','kol','ruj','lis','stu','pro'],['siječanj','veljača','ožujak','travanj','svibanj','lipanj','srpanj','kolovoz','rujan','listopad','studeni','prosinac']],[['pr.n.e.','AD'],['pr. Kr.','po. Kr.'],['prije Krista','poslije Krista']],1,[6,0],['dd. MM. y.','d. MMM y.','d. MMMM y.','EEEE, d. MMMM y.'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss (zzzz)'],['{1} {0}',u,'{1} \'u\' {0}',u],[',','.',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'HRK','HRK','hrvatska kuna',{'AUD':[u,'$'],'BRL':[u,'R$'],'CAD':[u,'$'],'CNY':[u,'¥'],'EUR':[u,'€'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'TWD':[u,'NT$'],'USD':[u,'$'],'VND':[u,'₫'],'XCD':[u,'$'],'XPF':[],'XXX':[]},'ltr', plural, [[['ponoć','podne','ujutro','popodne','navečer','noću'],u,['ponoć','podne','ujutro','poslije podne','navečer','noću']],[['ponoć','podne','ujutro','popodne','navečer','noću'],u,u],['00:00','12:00',['04:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','04:00']]]]; })(typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/hsb.js b/packages/common/locales/global/hsb.js index cda24d825b..90c97a1ee7 100644 --- a/packages/common/locales/global/hsb.js +++ b/packages/common/locales/global/hsb.js @@ -64,6 +64,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'AUD': [u, '$'], 'PLN': ['zł'], 'THB': ['฿']}, diff --git a/packages/common/locales/global/hu.js b/packages/common/locales/global/hu.js index 6d77a53e90..15df0a9c18 100644 --- a/packages/common/locales/global/hu.js +++ b/packages/common/locales/global/hu.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'HUF', 'Ft', 'magyar forint', { diff --git a/packages/common/locales/global/hy.js b/packages/common/locales/global/hy.js index 14b347aa08..fac06183ab 100644 --- a/packages/common/locales/global/hy.js +++ b/packages/common/locales/global/hy.js @@ -65,6 +65,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'ՈչԹ', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AMD', '֏', 'հայկական դրամ', {'AMD': ['֏'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/ia.js b/packages/common/locales/global/ia.js index 1e4d887c0a..101aef6dd2 100644 --- a/packages/common/locales/global/ia.js +++ b/packages/common/locales/global/ia.js @@ -51,6 +51,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'NLG': ['ƒ'], 'RUB': ['₽'], 'USD': ['US$', '$']}, 'ltr', plural, diff --git a/packages/common/locales/global/id.js b/packages/common/locales/global/id.js index 488a81b201..6e380a6de5 100644 --- a/packages/common/locales/global/id.js +++ b/packages/common/locales/global/id.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'IDR', 'Rp', 'Rupiah Indonesia', { diff --git a/packages/common/locales/global/ig.js b/packages/common/locales/global/ig.js index 5dd6a25131..572c257013 100644 --- a/packages/common/locales/global/ig.js +++ b/packages/common/locales/global/ig.js @@ -43,6 +43,7 @@ ['{1}, {0}', u, '{1} \'na\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NGN', '₦', 'Naịra', {'NGN': ['₦']}, diff --git a/packages/common/locales/global/ii.js b/packages/common/locales/global/ii.js index 0b0b235a3b..d20f704886 100644 --- a/packages/common/locales/global/ii.js +++ b/packages/common/locales/global/ii.js @@ -43,6 +43,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'CNY', '¥', 'CNY', {'CNY': ['¥'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/is.js b/packages/common/locales/global/is.js index 7dc782ef9e..10b8f3f605 100644 --- a/packages/common/locales/global/is.js +++ b/packages/common/locales/global/is.js @@ -55,6 +55,7 @@ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'ISK', + 'ISK', 'íslensk króna', { 'AUD': [u, '$'], diff --git a/packages/common/locales/global/it-CH.js b/packages/common/locales/global/it-CH.js index cc38600c39..52d74c13df 100644 --- a/packages/common/locales/global/it-CH.js +++ b/packages/common/locales/global/it-CH.js @@ -47,6 +47,7 @@ ['.', '’', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤-#,##0.00', '#E0'], 'CHF', + 'CHF', 'franco svizzero', { 'BRL': [u, 'R$'], diff --git a/packages/common/locales/global/it-SM.js b/packages/common/locales/global/it-SM.js index 0e31d7a96a..0e462cce36 100644 --- a/packages/common/locales/global/it-SM.js +++ b/packages/common/locales/global/it-SM.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/it-VA.js b/packages/common/locales/global/it-VA.js index 0260c8319f..76d23d169f 100644 --- a/packages/common/locales/global/it-VA.js +++ b/packages/common/locales/global/it-VA.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/it.js b/packages/common/locales/global/it.js index 0daf6d6b9f..4f0bdb4521 100644 --- a/packages/common/locales/global/it.js +++ b/packages/common/locales/global/it.js @@ -46,6 +46,7 @@ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/ja.js b/packages/common/locales/global/ja.js index 0056e13f9d..94d6f90814 100644 --- a/packages/common/locales/global/ja.js +++ b/packages/common/locales/global/ja.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'JPY', '¥', '日本円', {'CNY': ['元', '¥'], 'JPY': ['¥'], 'RON': [u, 'レイ'], 'XXX': []}, diff --git a/packages/common/locales/global/jgo.js b/packages/common/locales/global/jgo.js index 984dfabf8f..c742e0cb5d 100644 --- a/packages/common/locales/global/jgo.js +++ b/packages/common/locales/global/jgo.js @@ -56,6 +56,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'Fɛlâŋ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/jmc.js b/packages/common/locales/global/jmc.js index 1b1c9cf94f..504f88a41b 100644 --- a/packages/common/locales/global/jmc.js +++ b/packages/common/locales/global/jmc.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/jv.js b/packages/common/locales/global/jv.js index 1c77b9bb24..dd1c37fa1a 100644 --- a/packages/common/locales/global/jv.js +++ b/packages/common/locales/global/jv.js @@ -42,6 +42,7 @@ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'IDR', 'Rp', 'Rupiah Indonesia', {'IDR': ['Rp'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ka.js b/packages/common/locales/global/ka.js index 2fad225ec1..d3e1892a25 100644 --- a/packages/common/locales/global/ka.js +++ b/packages/common/locales/global/ka.js @@ -64,6 +64,7 @@ 'არ არის რიცხვი', ':' ], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GEL', '₾', 'ქართული ლარი', { diff --git a/packages/common/locales/global/kab.js b/packages/common/locales/global/kab.js index 688c2ec9fb..787cb64ea4 100644 --- a/packages/common/locales/global/kab.js +++ b/packages/common/locales/global/kab.js @@ -47,6 +47,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'DZD', 'DA', 'Adinar Azzayri', {'DZD': ['DA'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/kam.js b/packages/common/locales/global/kam.js index 94b72976e5..010a0cad91 100644 --- a/packages/common/locales/global/kam.js +++ b/packages/common/locales/global/kam.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Silingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/kde.js b/packages/common/locales/global/kde.js index d0bba79b45..6bea04324b 100644 --- a/packages/common/locales/global/kde.js +++ b/packages/common/locales/global/kde.js @@ -47,6 +47,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/kea.js b/packages/common/locales/global/kea.js index 2661082e54..47e7efa898 100644 --- a/packages/common/locales/global/kea.js +++ b/packages/common/locales/global/kea.js @@ -51,6 +51,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'CVE', '​', 'Skudu Kabuverdianu', { diff --git a/packages/common/locales/global/khq.js b/packages/common/locales/global/khq.js index 75af03159e..f4507dce5b 100644 --- a/packages/common/locales/global/khq.js +++ b/packages/common/locales/global/khq.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ki.js b/packages/common/locales/global/ki.js index 70bddd05d0..dae343a766 100644 --- a/packages/common/locales/global/ki.js +++ b/packages/common/locales/global/ki.js @@ -43,6 +43,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Ciringi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/kk.js b/packages/common/locales/global/kk.js index a71e22504a..ecdb24f2d6 100644 --- a/packages/common/locales/global/kk.js +++ b/packages/common/locales/global/kk.js @@ -67,6 +67,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'сан емес', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'KZT', '₸', 'Қазақстан теңгесі', {'JPY': ['JP¥', '¥'], 'KZT': ['₸'], 'RUB': ['₽'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/kkj.js b/packages/common/locales/global/kkj.js index dc855122a9..a7e22d62d5 100644 --- a/packages/common/locales/global/kkj.js +++ b/packages/common/locales/global/kkj.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'Franc CFA', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/kl.js b/packages/common/locales/global/kl.js index 6ee9eb1103..c0df8b1c78 100644 --- a/packages/common/locales/global/kl.js +++ b/packages/common/locales/global/kl.js @@ -55,6 +55,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'DKK', 'kr.', 'DKK', {'DKK': ['kr.', 'kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/kln.js b/packages/common/locales/global/kln.js index 2e2fd49153..7a6580d8a2 100644 --- a/packages/common/locales/global/kln.js +++ b/packages/common/locales/global/kln.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Silingitab ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/km.js b/packages/common/locales/global/km.js index 0a2018e30d..a5242dd4e2 100644 --- a/packages/common/locales/global/km.js +++ b/packages/common/locales/global/km.js @@ -64,6 +64,7 @@ ['{1}, {0}', u, '{1} នៅ​ម៉ោង {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'KHR', '៛', 'រៀល​កម្ពុជា', {'JPY': ['JP¥', '¥'], 'KHR': ['៛'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/kn.js b/packages/common/locales/global/kn.js index bbc9cd5d0d..aed3529b37 100644 --- a/packages/common/locales/global/kn.js +++ b/packages/common/locales/global/kn.js @@ -85,6 +85,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ಭಾರತೀಯ ರೂಪಾಯಿ', {'JPY': ['JP¥', '¥'], 'RON': [u, 'ಲೀ'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/ko-KP.js b/packages/common/locales/global/ko-KP.js index a483322759..3dffa782bb 100644 --- a/packages/common/locales/global/ko-KP.js +++ b/packages/common/locales/global/ko-KP.js @@ -42,6 +42,7 @@ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'KPW', + 'KPW', '조선 민주주의 인민 공화국 원', { 'AUD': ['AU$', '$'], diff --git a/packages/common/locales/global/ko.js b/packages/common/locales/global/ko.js index 1d4e141f2e..1283b78118 100644 --- a/packages/common/locales/global/ko.js +++ b/packages/common/locales/global/ko.js @@ -41,6 +41,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KRW', '₩', '대한민국 원', { diff --git a/packages/common/locales/global/kok.js b/packages/common/locales/global/kok.js index fbfc2b0dda..1a9f317ebf 100644 --- a/packages/common/locales/global/kok.js +++ b/packages/common/locales/global/kok.js @@ -51,6 +51,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'RON': ['रॉन', 'लेई'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ks.js b/packages/common/locales/global/ks.js index 1f5aea90c2..b92b49fc94 100644 --- a/packages/common/locales/global/ks.js +++ b/packages/common/locales/global/ks.js @@ -55,6 +55,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'ہِندُستٲنۍ رۄپَے', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ksb.js b/packages/common/locales/global/ksb.js index bb4640f1aa..dfaaa3b3a5 100644 --- a/packages/common/locales/global/ksb.js +++ b/packages/common/locales/global/ksb.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ksf.js b/packages/common/locales/global/ksf.js index bce3d8a5f8..2248835c00 100644 --- a/packages/common/locales/global/ksf.js +++ b/packages/common/locales/global/ksf.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'fráŋ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ksh.js b/packages/common/locales/global/ksh.js index 1e1524cae7..755939b7a9 100644 --- a/packages/common/locales/global/ksh.js +++ b/packages/common/locales/global/ksh.js @@ -56,6 +56,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ku.js b/packages/common/locales/global/ku.js index 1e69ef89c7..2fc30a4848 100644 --- a/packages/common/locales/global/ku.js +++ b/packages/common/locales/global/ku.js @@ -52,6 +52,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '%#,##0', '#,##0.00 ¤', '#E0'], + 'TRY', '₺', 'TRY', {'JPY': ['JP¥', '¥'], 'TRY': ['₺'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/kw.js b/packages/common/locales/global/kw.js index 2a916fe6ae..b55445a906 100644 --- a/packages/common/locales/global/kw.js +++ b/packages/common/locales/global/kw.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'GBP', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ky.js b/packages/common/locales/global/ky.js index bb8095272a..fa62c3f68a 100644 --- a/packages/common/locales/global/ky.js +++ b/packages/common/locales/global/ky.js @@ -67,6 +67,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'сан эмес', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'KGS', 'сом', 'Кыргызстан сому', { diff --git a/packages/common/locales/global/lag.js b/packages/common/locales/global/lag.js index 5c23d7ac28..f81cdf7edd 100644 --- a/packages/common/locales/global/lag.js +++ b/packages/common/locales/global/lag.js @@ -51,6 +51,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilíingi ya Taansanía', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/lb.js b/packages/common/locales/global/lb.js index a611608e93..59fdf08fae 100644 --- a/packages/common/locales/global/lb.js +++ b/packages/common/locales/global/lb.js @@ -60,6 +60,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'ATS': ['öS'], 'AUD': ['AU$', '$'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/lg.js b/packages/common/locales/global/lg.js index 8e75756bd4..e7ac188d99 100644 --- a/packages/common/locales/global/lg.js +++ b/packages/common/locales/global/lg.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'UGX', 'USh', 'Silingi eya Yuganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/lkt.js b/packages/common/locales/global/lkt.js index 99b16b9da9..52163af6db 100644 --- a/packages/common/locales/global/lkt.js +++ b/packages/common/locales/global/lkt.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'USD', '$', 'USD', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/global/ln-AO.js b/packages/common/locales/global/ln-AO.js index f2a9617d8c..09732287e5 100644 --- a/packages/common/locales/global/ln-AO.js +++ b/packages/common/locales/global/ln-AO.js @@ -50,6 +50,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AOA', 'Kz', 'Kwanza ya Angóla', {'AOA': ['Kz'], 'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ln-CF.js b/packages/common/locales/global/ln-CF.js index 5b79232d1f..bcead109e5 100644 --- a/packages/common/locales/global/ln-CF.js +++ b/packages/common/locales/global/ln-CF.js @@ -50,6 +50,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Falánga CFA BEAC', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ln-CG.js b/packages/common/locales/global/ln-CG.js index 0da242f6e0..4b8b33eb55 100644 --- a/packages/common/locales/global/ln-CG.js +++ b/packages/common/locales/global/ln-CG.js @@ -50,6 +50,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Falánga CFA BEAC', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ln.js b/packages/common/locales/global/ln.js index 7dcc71fce2..9fc4e74df0 100644 --- a/packages/common/locales/global/ln.js +++ b/packages/common/locales/global/ln.js @@ -50,6 +50,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'CDF', 'FC', 'Falánga ya Kongó', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/lo.js b/packages/common/locales/global/lo.js index b67edf2b66..ed97e65fe8 100644 --- a/packages/common/locales/global/lo.js +++ b/packages/common/locales/global/lo.js @@ -63,6 +63,7 @@ 'ບໍ່​ແມ່ນ​ໂຕ​ເລກ', ':' ], ['#,##0.###', '#,##0%', '¤#,##0.00;¤-#,##0.00', '#'], + 'LAK', '₭', 'ລາວ ກີບ', {'JPY': ['JP¥', '¥'], 'LAK': ['₭'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/lrc-IQ.js b/packages/common/locales/global/lrc-IQ.js index f0731fed6f..359477d9e0 100644 --- a/packages/common/locales/global/lrc-IQ.js +++ b/packages/common/locales/global/lrc-IQ.js @@ -39,6 +39,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'IQD', 'د.ع.\u200f', 'IQD', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/lrc.js b/packages/common/locales/global/lrc.js index 280f98b86b..091746c2ea 100644 --- a/packages/common/locales/global/lrc.js +++ b/packages/common/locales/global/lrc.js @@ -41,6 +41,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'IRR', 'IRR', + 'IRR', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'rtl', plural, diff --git a/packages/common/locales/global/lt.js b/packages/common/locales/global/lt.js index 41f56481dc..ac683f5183 100644 --- a/packages/common/locales/global/lt.js +++ b/packages/common/locales/global/lt.js @@ -24,7 +24,7 @@ if (!(f === 0)) return 4; return 5; } - global.ng.common.locales['lt'] = ['lt',[['pr. p.','pop.'],['priešpiet','popiet'],u],u,[['S','P','A','T','K','P','Š'],['sk','pr','an','tr','kt','pn','št'],['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'],['Sk','Pr','An','Tr','Kt','Pn','Št']],u,[['S','V','K','B','G','B','L','R','R','S','L','G'],['saus.','vas.','kov.','bal.','geg.','birž.','liep.','rugp.','rugs.','spal.','lapkr.','gruod.'],['sausio','vasario','kovo','balandžio','gegužės','birželio','liepos','rugpjūčio','rugsėjo','spalio','lapkričio','gruodžio']],[['S','V','K','B','G','B','L','R','R','S','L','G'],['saus.','vas.','kov.','bal.','geg.','birž.','liep.','rugp.','rugs.','spal.','lapkr.','gruod.'],['sausis','vasaris','kovas','balandis','gegužė','birželis','liepa','rugpjūtis','rugsėjis','spalis','lapkritis','gruodis']],[['pr. Kr.','po Kr.'],u,['prieš Kristų','po Kristaus']],1,[6,0],['y-MM-dd',u,'y \'m\'. MMMM d \'d\'.','y \'m\'. MMMM d \'d\'., EEEE'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,u,u],[',',' ',';','%','+','−','×10^','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'€','Euras',{'AUD':[u,'$'],'BDT':[],'BRL':[u,'R$'],'BYN':[u,'Br'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[],'INR':[],'JPY':[u,'¥'],'KHR':[],'KRW':[u,'₩'],'LAK':[],'MNT':[],'MXN':[u,'$'],'NZD':[u,'$'],'PLN':[u,'zl'],'PYG':[u,'Gs'],'RUB':[u,'rb'],'TWD':[u,'$'],'USD':[u,'$'],'VND':[],'XAF':[],'XCD':[u,'$'],'XOF':[],'XPF':[]},'ltr', plural, [[['vidurnaktis','perpiet','rytas','popietė','vakaras','naktis'],u,u],[['vidurnaktis','vidurdienis','rytas','diena','vakaras','naktis'],u,u],['00:00','12:00',['06:00','12:00'],['12:00','18:00'],['18:00','24:00'],['00:00','06:00']]]]; + global.ng.common.locales['lt'] = ['lt',[['pr. p.','pop.'],['priešpiet','popiet'],u],u,[['S','P','A','T','K','P','Š'],['sk','pr','an','tr','kt','pn','št'],['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'],['Sk','Pr','An','Tr','Kt','Pn','Št']],u,[['S','V','K','B','G','B','L','R','R','S','L','G'],['saus.','vas.','kov.','bal.','geg.','birž.','liep.','rugp.','rugs.','spal.','lapkr.','gruod.'],['sausio','vasario','kovo','balandžio','gegužės','birželio','liepos','rugpjūčio','rugsėjo','spalio','lapkričio','gruodžio']],[['S','V','K','B','G','B','L','R','R','S','L','G'],['saus.','vas.','kov.','bal.','geg.','birž.','liep.','rugp.','rugs.','spal.','lapkr.','gruod.'],['sausis','vasaris','kovas','balandis','gegužė','birželis','liepa','rugpjūtis','rugsėjis','spalis','lapkritis','gruodis']],[['pr. Kr.','po Kr.'],u,['prieš Kristų','po Kristaus']],1,[6,0],['y-MM-dd',u,'y \'m\'. MMMM d \'d\'.','y \'m\'. MMMM d \'d\'., EEEE'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,u,u],[',',' ',';','%','+','−','×10^','×','‰','∞','NaN',':'],['#,##0.###','#,##0 %','#,##0.00 ¤','#E0'],'EUR','€','Euras',{'AUD':[u,'$'],'BDT':[],'BRL':[u,'R$'],'BYN':[u,'Br'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[],'INR':[],'JPY':[u,'¥'],'KHR':[],'KRW':[u,'₩'],'LAK':[],'MNT':[],'MXN':[u,'$'],'NZD':[u,'$'],'PLN':[u,'zl'],'PYG':[u,'Gs'],'RUB':[u,'rb'],'TWD':[u,'$'],'USD':[u,'$'],'VND':[],'XAF':[],'XCD':[u,'$'],'XOF':[],'XPF':[]},'ltr', plural, [[['vidurnaktis','perpiet','rytas','popietė','vakaras','naktis'],u,u],[['vidurnaktis','vidurdienis','rytas','diena','vakaras','naktis'],u,u],['00:00','12:00',['06:00','12:00'],['12:00','18:00'],['18:00','24:00'],['00:00','06:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/lu.js b/packages/common/locales/global/lu.js index e71d4bd6a0..cb390fc2f6 100644 --- a/packages/common/locales/global/lu.js +++ b/packages/common/locales/global/lu.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'CDF', 'FC', 'Nfalanga wa Kongu', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/luo.js b/packages/common/locales/global/luo.js index 0c4292caac..920718cede 100644 --- a/packages/common/locales/global/luo.js +++ b/packages/common/locales/global/luo.js @@ -43,6 +43,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'KES', 'Ksh', 'Siling mar Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/luy.js b/packages/common/locales/global/luy.js index dff2c7aa12..2b0eabb48d 100644 --- a/packages/common/locales/global/luy.js +++ b/packages/common/locales/global/luy.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00;¤- #,##0.00', '#E0'], + 'KES', 'Ksh', 'Sirinji ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/lv.js b/packages/common/locales/global/lv.js index 832606e20a..d7828a1705 100644 --- a/packages/common/locales/global/lv.js +++ b/packages/common/locales/global/lv.js @@ -67,6 +67,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NS', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'eiro', {'AUD': ['AU$', '$'], 'LVL': ['Ls'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/mas-TZ.js b/packages/common/locales/global/mas-TZ.js index 2a9a3c6490..7b75972a5f 100644 --- a/packages/common/locales/global/mas-TZ.js +++ b/packages/common/locales/global/mas-TZ.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Iropiyianí e Tanzania', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mas.js b/packages/common/locales/global/mas.js index 4c94947b2b..ae15b235c5 100644 --- a/packages/common/locales/global/mas.js +++ b/packages/common/locales/global/mas.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Iropiyianí e Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mer.js b/packages/common/locales/global/mer.js index 946c8e3a25..315db7e742 100644 --- a/packages/common/locales/global/mer.js +++ b/packages/common/locales/global/mer.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mfe.js b/packages/common/locales/global/mfe.js index 3cf9d4320b..7e4d5d267c 100644 --- a/packages/common/locales/global/mfe.js +++ b/packages/common/locales/global/mfe.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MUR', 'Rs', 'roupi morisien', {'JPY': ['JP¥', '¥'], 'MUR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mg.js b/packages/common/locales/global/mg.js index 438715eede..97a35f3152 100644 --- a/packages/common/locales/global/mg.js +++ b/packages/common/locales/global/mg.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MGA', 'Ar', 'Ariary', {'JPY': ['JP¥', '¥'], 'MGA': ['Ar'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mgh.js b/packages/common/locales/global/mgh.js index ed20382c09..305c349589 100644 --- a/packages/common/locales/global/mgh.js +++ b/packages/common/locales/global/mgh.js @@ -43,6 +43,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MZN', 'MTn', 'MZN', {'JPY': ['JP¥', '¥'], 'MZN': ['MTn'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mgo.js b/packages/common/locales/global/mgo.js index 2892b8a250..01d1a6b6ed 100644 --- a/packages/common/locales/global/mgo.js +++ b/packages/common/locales/global/mgo.js @@ -50,6 +50,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'shirè', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mi.js b/packages/common/locales/global/mi.js index deb09375d5..429dfc3e17 100644 --- a/packages/common/locales/global/mi.js +++ b/packages/common/locales/global/mi.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'NZD', '$', 'Tāra o Aotearoa', {'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mk.js b/packages/common/locales/global/mk.js index 0a1966bfb1..4c2a48b1d6 100644 --- a/packages/common/locales/global/mk.js +++ b/packages/common/locales/global/mk.js @@ -63,6 +63,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MKD', 'ден.', 'Македонски денар', { diff --git a/packages/common/locales/global/ml.js b/packages/common/locales/global/ml.js index a08afaf8dd..a8062bf890 100644 --- a/packages/common/locales/global/ml.js +++ b/packages/common/locales/global/ml.js @@ -82,6 +82,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ഇന്ത്യൻ രൂപ', {'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/mn.js b/packages/common/locales/global/mn.js index 2be9f46d47..392d0ff90d 100644 --- a/packages/common/locales/global/mn.js +++ b/packages/common/locales/global/mn.js @@ -77,6 +77,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MNT', '₮', 'Монгол төгрөг', {'JPY': ['JP¥', '¥'], 'MNT': ['₮'], 'SEK': [u, 'кр'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/mr.js b/packages/common/locales/global/mr.js index 4527afd617..918bc65de8 100644 --- a/packages/common/locales/global/mr.js +++ b/packages/common/locales/global/mr.js @@ -65,6 +65,7 @@ ['{1}, {0}', u, '{1} रोजी {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '[#E0]'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/ms-BN.js b/packages/common/locales/global/ms-BN.js index 38a0312927..eda717c9d5 100644 --- a/packages/common/locales/global/ms-BN.js +++ b/packages/common/locales/global/ms-BN.js @@ -42,6 +42,7 @@ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'BND', '$', 'Dolar Brunei', { diff --git a/packages/common/locales/global/ms-SG.js b/packages/common/locales/global/ms-SG.js index ca11744dd4..6e47535da4 100644 --- a/packages/common/locales/global/ms-SG.js +++ b/packages/common/locales/global/ms-SG.js @@ -42,6 +42,7 @@ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SGD', '$', 'Dolar Singapura', { diff --git a/packages/common/locales/global/ms.js b/packages/common/locales/global/ms.js index 97c08105af..9a22871e8d 100644 --- a/packages/common/locales/global/ms.js +++ b/packages/common/locales/global/ms.js @@ -42,6 +42,7 @@ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MYR', 'RM', 'Ringgit Malaysia', { diff --git a/packages/common/locales/global/mt.js b/packages/common/locales/global/mt.js index 4f9293c7b6..de28fb3c60 100644 --- a/packages/common/locales/global/mt.js +++ b/packages/common/locales/global/mt.js @@ -60,6 +60,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'ewro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/mua.js b/packages/common/locales/global/mua.js index 91a898df47..afa6520a69 100644 --- a/packages/common/locales/global/mua.js +++ b/packages/common/locales/global/mua.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XAF', 'FCFA', 'solai BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/my.js b/packages/common/locales/global/my.js index f0602064df..357fe87ae7 100644 --- a/packages/common/locales/global/my.js +++ b/packages/common/locales/global/my.js @@ -56,6 +56,7 @@ 'ဂဏန်းမဟုတ်သော', ':' ], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MMK', 'K', 'မြန်မာ ကျပ်', { diff --git a/packages/common/locales/global/mzn.js b/packages/common/locales/global/mzn.js index 9d2adc27a0..bb09a4e8af 100644 --- a/packages/common/locales/global/mzn.js +++ b/packages/common/locales/global/mzn.js @@ -39,6 +39,7 @@ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'IRR', + 'IRR', 'ایران ریال', {'JPY': ['JP¥', '¥']}, 'rtl', diff --git a/packages/common/locales/global/naq.js b/packages/common/locales/global/naq.js index 10b429756c..75aed02896 100644 --- a/packages/common/locales/global/naq.js +++ b/packages/common/locales/global/naq.js @@ -51,6 +51,7 @@ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'ZAR', + 'ZAR', 'South African Randi', {'JPY': ['JP¥', '¥'], 'NAD': ['$'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/nb-SJ.js b/packages/common/locales/global/nb-SJ.js index e67886888d..8318ae5a42 100644 --- a/packages/common/locales/global/nb-SJ.js +++ b/packages/common/locales/global/nb-SJ.js @@ -56,6 +56,7 @@ ['{1}, {0}', u, '{1} \'kl\'. {0}', '{1} {0}'], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'NOK', 'kr', 'norske kroner', { diff --git a/packages/common/locales/global/nb.js b/packages/common/locales/global/nb.js index d6e6ae102d..0acc2d7b06 100644 --- a/packages/common/locales/global/nb.js +++ b/packages/common/locales/global/nb.js @@ -56,6 +56,7 @@ ['{1}, {0}', u, '{1} \'kl\'. {0}', '{1} {0}'], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'NOK', 'kr', 'norske kroner', { diff --git a/packages/common/locales/global/nd.js b/packages/common/locales/global/nd.js index ff7eb061cc..29506c7e6a 100644 --- a/packages/common/locales/global/nd.js +++ b/packages/common/locales/global/nd.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'Dola yase Amelika', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/nds-NL.js b/packages/common/locales/global/nds-NL.js index bcb35ffc12..90cb3d38fb 100644 --- a/packages/common/locales/global/nds-NL.js +++ b/packages/common/locales/global/nds-NL.js @@ -34,6 +34,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'EUR', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/nds.js b/packages/common/locales/global/nds.js index a45fb025bc..79c4b1f134 100644 --- a/packages/common/locales/global/nds.js +++ b/packages/common/locales/global/nds.js @@ -34,6 +34,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'EUR', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ne-IN.js b/packages/common/locales/global/ne-IN.js index ea3bb7865a..505bdd3360 100644 --- a/packages/common/locales/global/ne-IN.js +++ b/packages/common/locales/global/ne-IN.js @@ -73,6 +73,7 @@ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'भारतीय रूपिँया', {'JPY': ['JP¥', '¥'], 'NPR': ['नेरू', 'रू'], 'THB': ['฿'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ne.js b/packages/common/locales/global/ne.js index 5cc2891fff..59ea879fd0 100644 --- a/packages/common/locales/global/ne.js +++ b/packages/common/locales/global/ne.js @@ -73,6 +73,7 @@ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'NPR', 'नेरू', 'नेपाली रूपैयाँ', {'JPY': ['JP¥', '¥'], 'NPR': ['नेरू', 'रू'], 'THB': ['฿'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/nl-AW.js b/packages/common/locales/global/nl-AW.js index a0055402e6..16097d539b 100644 --- a/packages/common/locales/global/nl-AW.js +++ b/packages/common/locales/global/nl-AW.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'AWG', 'Afl.', 'Arubaanse gulden', { diff --git a/packages/common/locales/global/nl-BE.js b/packages/common/locales/global/nl-BE.js index 100302351e..20588592b3 100644 --- a/packages/common/locales/global/nl-BE.js +++ b/packages/common/locales/global/nl-BE.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/nl-BQ.js b/packages/common/locales/global/nl-BQ.js index a135bd0863..241e1e53d8 100644 --- a/packages/common/locales/global/nl-BQ.js +++ b/packages/common/locales/global/nl-BQ.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'USD', '$', 'Amerikaanse dollar', { diff --git a/packages/common/locales/global/nl-CW.js b/packages/common/locales/global/nl-CW.js index a0ba6911b1..d11ae5dc3a 100644 --- a/packages/common/locales/global/nl-CW.js +++ b/packages/common/locales/global/nl-CW.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'ANG', 'NAf.', 'Nederlands-Antilliaanse gulden', { diff --git a/packages/common/locales/global/nl-SR.js b/packages/common/locales/global/nl-SR.js index e578227834..8d5b154012 100644 --- a/packages/common/locales/global/nl-SR.js +++ b/packages/common/locales/global/nl-SR.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'SRD', '$', 'Surinaamse dollar', { diff --git a/packages/common/locales/global/nl-SX.js b/packages/common/locales/global/nl-SX.js index fd624fe6a8..e8c4c77e83 100644 --- a/packages/common/locales/global/nl-SX.js +++ b/packages/common/locales/global/nl-SX.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'ANG', 'NAf.', 'Nederlands-Antilliaanse gulden', { diff --git a/packages/common/locales/global/nl.js b/packages/common/locales/global/nl.js index 4d40ccdc2d..c4556ce50c 100644 --- a/packages/common/locales/global/nl.js +++ b/packages/common/locales/global/nl.js @@ -49,6 +49,7 @@ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/global/nmg.js b/packages/common/locales/global/nmg.js index aad6d21dff..c0144eb2b8 100644 --- a/packages/common/locales/global/nmg.js +++ b/packages/common/locales/global/nmg.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Fraŋ CFA BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/nn.js b/packages/common/locales/global/nn.js index 0a9d7bdb69..8e8c3b8846 100644 --- a/packages/common/locales/global/nn.js +++ b/packages/common/locales/global/nn.js @@ -59,6 +59,7 @@ ['{1}, {0}', u, '{1} \'kl\'. {0}', '{1} {0}'], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'NOK', 'kr', 'norske kroner', { diff --git a/packages/common/locales/global/nnh.js b/packages/common/locales/global/nnh.js index 27f6d08e79..3c160fb899 100644 --- a/packages/common/locales/global/nnh.js +++ b/packages/common/locales/global/nnh.js @@ -53,6 +53,7 @@ ['{1} {0}', u, '{1}, {0}', '{1},{0}'], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'feláŋ CFA', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/nus.js b/packages/common/locales/global/nus.js index 556c9d7b57..4efa858c3a 100644 --- a/packages/common/locales/global/nus.js +++ b/packages/common/locales/global/nus.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SSP', '£', 'SSP', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'SSP': ['£'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/nyn.js b/packages/common/locales/global/nyn.js index 511ac582f3..1d216526a4 100644 --- a/packages/common/locales/global/nyn.js +++ b/packages/common/locales/global/nyn.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Eshiringi ya Uganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/om-KE.js b/packages/common/locales/global/om-KE.js index 0c06c8e1c6..ab9ca6dba3 100644 --- a/packages/common/locales/global/om-KE.js +++ b/packages/common/locales/global/om-KE.js @@ -52,6 +52,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'KES', {'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/om.js b/packages/common/locales/global/om.js index 7eaf6ebef2..3e86164662 100644 --- a/packages/common/locales/global/om.js +++ b/packages/common/locales/global/om.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'Br', 'Itoophiyaa Birrii', {'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/or.js b/packages/common/locales/global/or.js index e5065cff5d..5c4bda9b8f 100644 --- a/packages/common/locales/global/or.js +++ b/packages/common/locales/global/or.js @@ -64,6 +64,7 @@ ['{1}, {0}', u, '{0} ଠାରେ {1}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ଭାରତୀୟ ଟଙ୍କା', {}, diff --git a/packages/common/locales/global/os-RU.js b/packages/common/locales/global/os-RU.js index 39d510b2a1..fdcf71000e 100644 --- a/packages/common/locales/global/os-RU.js +++ b/packages/common/locales/global/os-RU.js @@ -72,6 +72,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'НН', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'RUB', '₽', 'Сом', {'JPY': ['JP¥', '¥'], 'RUB': ['₽']}, diff --git a/packages/common/locales/global/os.js b/packages/common/locales/global/os.js index 11aa9981bb..33e4b2a616 100644 --- a/packages/common/locales/global/os.js +++ b/packages/common/locales/global/os.js @@ -72,6 +72,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'НН', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'GEL', '₾', 'Лар', {'GEL': ['₾'], 'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/global/pa-Arab.js b/packages/common/locales/global/pa-Arab.js index 82fde110a6..b8c51f6ede 100644 --- a/packages/common/locales/global/pa-Arab.js +++ b/packages/common/locales/global/pa-Arab.js @@ -41,6 +41,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'PKR', 'ر', 'روپئیہ', {'JPY': ['JP¥', '¥'], 'PKR': ['ر', 'Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/pa-Guru.js b/packages/common/locales/global/pa-Guru.js index 158479b80a..134b60e954 100644 --- a/packages/common/locales/global/pa-Guru.js +++ b/packages/common/locales/global/pa-Guru.js @@ -65,6 +65,7 @@ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '[#E0]'], + 'INR', '₹', 'ਭਾਰਤੀ ਰੁਪਇਆ', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/global/pa.js b/packages/common/locales/global/pa.js index 20fcb294da..c4ef9eb6b3 100644 --- a/packages/common/locales/global/pa.js +++ b/packages/common/locales/global/pa.js @@ -65,6 +65,7 @@ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '[#E0]'], + 'INR', '₹', 'ਭਾਰਤੀ ਰੁਪਇਆ', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/global/pl.js b/packages/common/locales/global/pl.js index 2bb3121bb3..1d8172ceb3 100644 --- a/packages/common/locales/global/pl.js +++ b/packages/common/locales/global/pl.js @@ -26,6 +26,6 @@ return 4; return 5; } - global.ng.common.locales['pl'] = ['pl',[['a','p'],['AM','PM'],u],u,[['n','p','w','ś','c','p','s'],['niedz.','pon.','wt.','śr.','czw.','pt.','sob.'],['niedziela','poniedziałek','wtorek','środa','czwartek','piątek','sobota'],['nie','pon','wto','śro','czw','pią','sob']],[['N','P','W','Ś','C','P','S'],['niedz.','pon.','wt.','śr.','czw.','pt.','sob.'],['niedziela','poniedziałek','wtorek','środa','czwartek','piątek','sobota'],['nie','pon','wto','śro','czw','pią','sob']],[['s','l','m','k','m','c','l','s','w','p','l','g'],['sty','lut','mar','kwi','maj','cze','lip','sie','wrz','paź','lis','gru'],['stycznia','lutego','marca','kwietnia','maja','czerwca','lipca','sierpnia','września','października','listopada','grudnia']],[['S','L','M','K','M','C','L','S','W','P','L','G'],['sty','lut','mar','kwi','maj','cze','lip','sie','wrz','paź','lis','gru'],['styczeń','luty','marzec','kwiecień','maj','czerwiec','lipiec','sierpień','wrzesień','październik','listopad','grudzień']],[['p.n.e.','n.e.'],u,['przed naszą erą','naszej ery']],1,[6,0],['dd.MM.y','d MMM y','d MMMM y','EEEE, d MMMM y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1}, {0}',u,'{1} {0}',u],[',',' ',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'zł','złoty polski',{'AUD':[u,'$'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PLN':['zł'],'RON':[u,'lej'],'TWD':[u,'NT$'],'USD':[u,'$'],'VND':[u,'₫']},'ltr', plural, [[['o półn.','w poł.','rano','przed poł.','po poł.','wiecz.','w nocy'],['o północy','w południe','rano','przed południem','po południu','wieczorem','w nocy'],u],[['półn.','poł.','rano','przedpoł.','popoł.','wiecz.','noc'],['północ','południe','rano','przedpołudnie','popołudnie','wieczór','noc'],u],['00:00','12:00',['06:00','10:00'],['10:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','06:00']]]]; + global.ng.common.locales['pl'] = ['pl',[['a','p'],['AM','PM'],u],u,[['n','p','w','ś','c','p','s'],['niedz.','pon.','wt.','śr.','czw.','pt.','sob.'],['niedziela','poniedziałek','wtorek','środa','czwartek','piątek','sobota'],['nie','pon','wto','śro','czw','pią','sob']],[['N','P','W','Ś','C','P','S'],['niedz.','pon.','wt.','śr.','czw.','pt.','sob.'],['niedziela','poniedziałek','wtorek','środa','czwartek','piątek','sobota'],['nie','pon','wto','śro','czw','pią','sob']],[['s','l','m','k','m','c','l','s','w','p','l','g'],['sty','lut','mar','kwi','maj','cze','lip','sie','wrz','paź','lis','gru'],['stycznia','lutego','marca','kwietnia','maja','czerwca','lipca','sierpnia','września','października','listopada','grudnia']],[['S','L','M','K','M','C','L','S','W','P','L','G'],['sty','lut','mar','kwi','maj','cze','lip','sie','wrz','paź','lis','gru'],['styczeń','luty','marzec','kwiecień','maj','czerwiec','lipiec','sierpień','wrzesień','październik','listopad','grudzień']],[['p.n.e.','n.e.'],u,['przed naszą erą','naszej ery']],1,[6,0],['dd.MM.y','d MMM y','d MMMM y','EEEE, d MMMM y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1}, {0}',u,'{1} {0}',u],[',',' ',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','#,##0.00 ¤','#E0'],'PLN','zł','złoty polski',{'AUD':[u,'$'],'CAD':[u,'$'],'CNY':[u,'¥'],'GBP':[u,'£'],'HKD':[u,'$'],'ILS':[u,'₪'],'INR':[u,'₹'],'JPY':[u,'¥'],'KRW':[u,'₩'],'MXN':[u,'$'],'NZD':[u,'$'],'PLN':['zł'],'RON':[u,'lej'],'TWD':[u,'NT$'],'USD':[u,'$'],'VND':[u,'₫']},'ltr', plural, [[['o półn.','w poł.','rano','przed poł.','po poł.','wiecz.','w nocy'],['o północy','w południe','rano','przed południem','po południu','wieczorem','w nocy'],u],[['półn.','poł.','rano','przedpoł.','popoł.','wiecz.','noc'],['północ','południe','rano','przedpołudnie','popołudnie','wieczór','noc'],u],['00:00','12:00',['06:00','10:00'],['10:00','12:00'],['12:00','18:00'],['18:00','21:00'],['21:00','06:00']]]]; })(typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/global/prg.js b/packages/common/locales/global/prg.js index 77a9f17ad0..484561bb4c 100644 --- a/packages/common/locales/global/prg.js +++ b/packages/common/locales/global/prg.js @@ -46,6 +46,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural, diff --git a/packages/common/locales/global/ps-PK.js b/packages/common/locales/global/ps-PK.js index 3a5bad546e..a3761cb53f 100644 --- a/packages/common/locales/global/ps-PK.js +++ b/packages/common/locales/global/ps-PK.js @@ -58,6 +58,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'PKR', 'Rs', 'پاکستانۍ کلداره', {'AFN': ['؋'], 'JPY': ['JP¥', '¥'], 'PKR': ['Rs']}, diff --git a/packages/common/locales/global/ps.js b/packages/common/locales/global/ps.js index 90182b56e9..7d39173443 100644 --- a/packages/common/locales/global/ps.js +++ b/packages/common/locales/global/ps.js @@ -58,6 +58,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AFN', '؋', 'افغانۍ', {'AFN': ['؋'], 'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/global/pt-AO.js b/packages/common/locales/global/pt-AO.js index 97a6d45382..6ee0d7c8f5 100644 --- a/packages/common/locales/global/pt-AO.js +++ b/packages/common/locales/global/pt-AO.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AOA', 'Kz', 'kwanza angolano', { diff --git a/packages/common/locales/global/pt-CH.js b/packages/common/locales/global/pt-CH.js index a101581252..67b22c5970 100644 --- a/packages/common/locales/global/pt-CH.js +++ b/packages/common/locales/global/pt-CH.js @@ -54,6 +54,7 @@ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'franco suíço', { 'AUD': ['AU$', '$'], diff --git a/packages/common/locales/global/pt-CV.js b/packages/common/locales/global/pt-CV.js index 793c2fbc01..798bf70016 100644 --- a/packages/common/locales/global/pt-CV.js +++ b/packages/common/locales/global/pt-CV.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'CVE', '​', 'escudo cabo-verdiano', { diff --git a/packages/common/locales/global/pt-GQ.js b/packages/common/locales/global/pt-GQ.js index bafd30bdd2..f17a8fbae7 100644 --- a/packages/common/locales/global/pt-GQ.js +++ b/packages/common/locales/global/pt-GQ.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franco CFA (BEAC)', { diff --git a/packages/common/locales/global/pt-GW.js b/packages/common/locales/global/pt-GW.js index 271428d5dd..e9d90527d5 100644 --- a/packages/common/locales/global/pt-GW.js +++ b/packages/common/locales/global/pt-GW.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franco CFA (BCEAO)', { diff --git a/packages/common/locales/global/pt-LU.js b/packages/common/locales/global/pt-LU.js index f529afff7f..49163460cb 100644 --- a/packages/common/locales/global/pt-LU.js +++ b/packages/common/locales/global/pt-LU.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/pt-MO.js b/packages/common/locales/global/pt-MO.js index 4c98356f1c..c9a83a9e2d 100644 --- a/packages/common/locales/global/pt-MO.js +++ b/packages/common/locales/global/pt-MO.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MOP', 'MOP$', 'pataca macaense', { diff --git a/packages/common/locales/global/pt-MZ.js b/packages/common/locales/global/pt-MZ.js index 603a0c518c..a4c6e3d253 100644 --- a/packages/common/locales/global/pt-MZ.js +++ b/packages/common/locales/global/pt-MZ.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MZN', 'MTn', 'metical moçambicano', { diff --git a/packages/common/locales/global/pt-PT.js b/packages/common/locales/global/pt-PT.js index d26a6727e8..554a67d39d 100644 --- a/packages/common/locales/global/pt-PT.js +++ b/packages/common/locales/global/pt-PT.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/pt-ST.js b/packages/common/locales/global/pt-ST.js index 6ca8756660..f8ede4438c 100644 --- a/packages/common/locales/global/pt-ST.js +++ b/packages/common/locales/global/pt-ST.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'STN', 'Db', 'dobra de São Tomé e Príncipe', { diff --git a/packages/common/locales/global/pt-TL.js b/packages/common/locales/global/pt-TL.js index d89f4dbdb1..039e8e1ba4 100644 --- a/packages/common/locales/global/pt-TL.js +++ b/packages/common/locales/global/pt-TL.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'USD', 'US$', 'dólar dos Estados Unidos', { diff --git a/packages/common/locales/global/pt.js b/packages/common/locales/global/pt.js index 6a5d451af6..97e269601a 100644 --- a/packages/common/locales/global/pt.js +++ b/packages/common/locales/global/pt.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'BRL', 'R$', 'Real brasileiro', { diff --git a/packages/common/locales/global/qu-BO.js b/packages/common/locales/global/qu-BO.js index 310dd58d55..27f69478c1 100644 --- a/packages/common/locales/global/qu-BO.js +++ b/packages/common/locales/global/qu-BO.js @@ -42,6 +42,7 @@ ['{1} {0}', u, '{0} {1}', '{1} {0}'], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'BOB', 'Bs', 'Boliviano', { diff --git a/packages/common/locales/global/qu-EC.js b/packages/common/locales/global/qu-EC.js index 39ce6db4d9..b1de706c62 100644 --- a/packages/common/locales/global/qu-EC.js +++ b/packages/common/locales/global/qu-EC.js @@ -42,6 +42,7 @@ ['{1} {0}', u, '{0} {1}', '{1} {0}'], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'USD', '$', 'Dólar Americano', { diff --git a/packages/common/locales/global/qu.js b/packages/common/locales/global/qu.js index ac71c4dc00..ac4f263fd2 100644 --- a/packages/common/locales/global/qu.js +++ b/packages/common/locales/global/qu.js @@ -42,6 +42,7 @@ ['{1} {0}', u, '{0} {1}', '{1} {0}'], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'PEN', 'S/', 'Sol Peruano', { diff --git a/packages/common/locales/global/rm.js b/packages/common/locales/global/rm.js index 4e4975635c..d51cf6f8ee 100644 --- a/packages/common/locales/global/rm.js +++ b/packages/common/locales/global/rm.js @@ -59,6 +59,7 @@ ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'franc svizzer', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/rn.js b/packages/common/locales/global/rn.js index 2c3c1d37e2..52ff5e0075 100644 --- a/packages/common/locales/global/rn.js +++ b/packages/common/locales/global/rn.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00¤', '#E0'], + 'BIF', 'FBu', 'Ifaranga ry’Uburundi', {'BIF': ['FBu'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ro-MD.js b/packages/common/locales/global/ro-MD.js index 127e2c9a04..69d5f85fdd 100644 --- a/packages/common/locales/global/ro-MD.js +++ b/packages/common/locales/global/ro-MD.js @@ -52,6 +52,7 @@ ['{1}, {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MDL', 'L', 'leu moldovenesc', { diff --git a/packages/common/locales/global/ro.js b/packages/common/locales/global/ro.js index ff596e0952..e23796db5a 100644 --- a/packages/common/locales/global/ro.js +++ b/packages/common/locales/global/ro.js @@ -53,6 +53,7 @@ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'RON', + 'RON', 'leu românesc', { 'AUD': [u, '$'], diff --git a/packages/common/locales/global/rof.js b/packages/common/locales/global/rof.js index d4812375ec..f37a0d1b79 100644 --- a/packages/common/locales/global/rof.js +++ b/packages/common/locales/global/rof.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'heleri sa Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/root.js b/packages/common/locales/global/root.js index 6555ec4971..64788dbc0e 100644 --- a/packages/common/locales/global/root.js +++ b/packages/common/locales/global/root.js @@ -42,6 +42,7 @@ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/global/ru-BY.js b/packages/common/locales/global/ru-BY.js index 026b2f0b54..9b5adef61a 100644 --- a/packages/common/locales/global/ru-BY.js +++ b/packages/common/locales/global/ru-BY.js @@ -82,6 +82,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BYN', 'Br', 'белорусский рубль', { diff --git a/packages/common/locales/global/ru-KG.js b/packages/common/locales/global/ru-KG.js index 5fd6cbbbdc..241ad8734e 100644 --- a/packages/common/locales/global/ru-KG.js +++ b/packages/common/locales/global/ru-KG.js @@ -82,6 +82,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'KGS', 'сом', 'киргизский сом', { diff --git a/packages/common/locales/global/ru-KZ.js b/packages/common/locales/global/ru-KZ.js index 6110f78ef8..0660885b26 100644 --- a/packages/common/locales/global/ru-KZ.js +++ b/packages/common/locales/global/ru-KZ.js @@ -82,6 +82,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'KZT', '₸', 'казахский тенге', { diff --git a/packages/common/locales/global/ru-MD.js b/packages/common/locales/global/ru-MD.js index ffb126ea08..e90b2b770d 100644 --- a/packages/common/locales/global/ru-MD.js +++ b/packages/common/locales/global/ru-MD.js @@ -82,6 +82,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MDL', 'L', 'молдавский лей', { diff --git a/packages/common/locales/global/ru-UA.js b/packages/common/locales/global/ru-UA.js index d46d02a7b6..b761fa6269 100644 --- a/packages/common/locales/global/ru-UA.js +++ b/packages/common/locales/global/ru-UA.js @@ -82,6 +82,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'UAH', '₴', 'украинская гривна', { diff --git a/packages/common/locales/global/ru.js b/packages/common/locales/global/ru.js index c5f044f001..63c9a13c7f 100644 --- a/packages/common/locales/global/ru.js +++ b/packages/common/locales/global/ru.js @@ -82,6 +82,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'российский рубль', { diff --git a/packages/common/locales/global/rw.js b/packages/common/locales/global/rw.js index 40e0c4a980..bd63081879 100644 --- a/packages/common/locales/global/rw.js +++ b/packages/common/locales/global/rw.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'RWF', 'RF', 'RWF', {'JPY': ['JP¥', '¥'], 'RWF': ['RF'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/rwk.js b/packages/common/locales/global/rwk.js index ad89abd47d..57800d3ab3 100644 --- a/packages/common/locales/global/rwk.js +++ b/packages/common/locales/global/rwk.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/sah.js b/packages/common/locales/global/sah.js index 6807e7cfc2..edb48091a4 100644 --- a/packages/common/locales/global/sah.js +++ b/packages/common/locales/global/sah.js @@ -61,6 +61,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'чыыһыла буотах', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'Арассыыйа солкуобайа', {'JPY': ['JP¥', '¥'], 'RUB': ['₽'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/saq.js b/packages/common/locales/global/saq.js index a565aad35d..8a597173b2 100644 --- a/packages/common/locales/global/saq.js +++ b/packages/common/locales/global/saq.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Njilingi eel Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/sbp.js b/packages/common/locales/global/sbp.js index 01e07fa920..e7ad1f645b 100644 --- a/packages/common/locales/global/sbp.js +++ b/packages/common/locales/global/sbp.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'Ihela ya Tansaniya', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/sd.js b/packages/common/locales/global/sd.js index 6267b6b36c..dce74785b5 100644 --- a/packages/common/locales/global/sd.js +++ b/packages/common/locales/global/sd.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'PKR', 'Rs', 'پاڪستاني رپي', {'JPY': ['JP¥', '¥'], 'PKR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/se-FI.js b/packages/common/locales/global/se-FI.js index 2bca4c37eb..7da2b23c99 100644 --- a/packages/common/locales/global/se-FI.js +++ b/packages/common/locales/global/se-FI.js @@ -50,6 +50,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '·10^', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/se-SE.js b/packages/common/locales/global/se-SE.js index de0f3ee53b..5b76de3007 100644 --- a/packages/common/locales/global/se-SE.js +++ b/packages/common/locales/global/se-SE.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '·10^', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SEK', 'kr', 'ruoŧŧa kruvdno', { diff --git a/packages/common/locales/global/se.js b/packages/common/locales/global/se.js index 74d70be2e5..27203c21ea 100644 --- a/packages/common/locales/global/se.js +++ b/packages/common/locales/global/se.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '·10^', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'NOK', 'kr', 'norgga kruvdno', { diff --git a/packages/common/locales/global/seh.js b/packages/common/locales/global/seh.js index 6447bd8bf8..8bf3bcf335 100644 --- a/packages/common/locales/global/seh.js +++ b/packages/common/locales/global/seh.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'MZN', 'MTn', 'Metical de Moçambique', {'JPY': ['JP¥', '¥'], 'MZN': ['MTn'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ses.js b/packages/common/locales/global/ses.js index 17fb816e32..cec8a6d8ff 100644 --- a/packages/common/locales/global/ses.js +++ b/packages/common/locales/global/ses.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/sg.js b/packages/common/locales/global/sg.js index d5624453d0..9282f7ab9d 100644 --- a/packages/common/locales/global/sg.js +++ b/packages/common/locales/global/sg.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'XAF', 'FCFA', 'farânga CFA (BEAC)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/shi-Latn.js b/packages/common/locales/global/shi-Latn.js index bf52be3e6c..791eab3e0b 100644 --- a/packages/common/locales/global/shi-Latn.js +++ b/packages/common/locales/global/shi-Latn.js @@ -43,6 +43,7 @@ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'adrim n lmɣrib', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/shi-Tfng.js b/packages/common/locales/global/shi-Tfng.js index c01676b14d..b4fd43257e 100644 --- a/packages/common/locales/global/shi-Tfng.js +++ b/packages/common/locales/global/shi-Tfng.js @@ -66,6 +66,7 @@ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'ⴰⴷⵔⵉⵎ ⵏ ⵍⵎⵖⵔⵉⴱ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/shi.js b/packages/common/locales/global/shi.js index ccede0d32c..747ce4fb84 100644 --- a/packages/common/locales/global/shi.js +++ b/packages/common/locales/global/shi.js @@ -66,6 +66,7 @@ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'ⴰⴷⵔⵉⵎ ⵏ ⵍⵎⵖⵔⵉⴱ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/si.js b/packages/common/locales/global/si.js index f404679bcf..98a0c668c1 100644 --- a/packages/common/locales/global/si.js +++ b/packages/common/locales/global/si.js @@ -88,6 +88,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#'], + 'LKR', 'රු.', 'ශ්\u200dරී ලංකා රුපියල', { diff --git a/packages/common/locales/global/sk.js b/packages/common/locales/global/sk.js index ccae793fa6..d23f3f853d 100644 --- a/packages/common/locales/global/sk.js +++ b/packages/common/locales/global/sk.js @@ -55,6 +55,7 @@ ['{1} {0}', '{1}, {0}', u, u], [',', ' ', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/sl.js b/packages/common/locales/global/sl.js index f010cd16ec..5316a375d5 100644 --- a/packages/common/locales/global/sl.js +++ b/packages/common/locales/global/sl.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '−', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'evro', { diff --git a/packages/common/locales/global/smn.js b/packages/common/locales/global/smn.js index 89f6eea218..4f3ea04500 100644 --- a/packages/common/locales/global/smn.js +++ b/packages/common/locales/global/smn.js @@ -60,6 +60,7 @@ ['{1} {0}', '{1} \'tme\' {0}', u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'epiloho', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/sn.js b/packages/common/locales/global/sn.js index 03d6169a47..ad23df4910 100644 --- a/packages/common/locales/global/sn.js +++ b/packages/common/locales/global/sn.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'Dora re Amerika', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/so-DJ.js b/packages/common/locales/global/so-DJ.js index 4e0e7d9879..c09ddff2d9 100644 --- a/packages/common/locales/global/so-DJ.js +++ b/packages/common/locales/global/so-DJ.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'DJF', 'Fdj', 'Faran Jabuuti', {'BBD': ['DBB', '$'], 'DJF': ['Fdj'], 'JPY': ['JP¥', '¥'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/so-ET.js b/packages/common/locales/global/so-ET.js index df12915f5e..be8180f81b 100644 --- a/packages/common/locales/global/so-ET.js +++ b/packages/common/locales/global/so-ET.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'Br', 'Birta Itoobbiya', {'BBD': ['DBB', '$'], 'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/so-KE.js b/packages/common/locales/global/so-KE.js index 4adf3f4b07..a8f48871ce 100644 --- a/packages/common/locales/global/so-KE.js +++ b/packages/common/locales/global/so-KE.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingka Kenya', {'BBD': ['DBB', '$'], 'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/so.js b/packages/common/locales/global/so.js index dd61aa66cb..e5bfebc21e 100644 --- a/packages/common/locales/global/so.js +++ b/packages/common/locales/global/so.js @@ -53,6 +53,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SOS', 'S', 'Shilingka Soomaaliya', {'BBD': ['DBB', '$'], 'JPY': ['JP¥', '¥'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/sq-MK.js b/packages/common/locales/global/sq-MK.js index b0c07e857c..34277d3cbd 100644 --- a/packages/common/locales/global/sq-MK.js +++ b/packages/common/locales/global/sq-MK.js @@ -50,6 +50,7 @@ ['{1}, {0}', u, '{1} \'në\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MKD', 'den', 'Denari maqedonas', { diff --git a/packages/common/locales/global/sq-XK.js b/packages/common/locales/global/sq-XK.js index 3a670a803a..9fce09b66c 100644 --- a/packages/common/locales/global/sq-XK.js +++ b/packages/common/locales/global/sq-XK.js @@ -50,6 +50,7 @@ ['{1}, {0}', u, '{1} \'në\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euroja', { diff --git a/packages/common/locales/global/sq.js b/packages/common/locales/global/sq.js index 698b6ac307..d441c6ded5 100644 --- a/packages/common/locales/global/sq.js +++ b/packages/common/locales/global/sq.js @@ -50,6 +50,7 @@ ['{1}, {0}', u, '{1} \'në\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'ALL', 'Lekë', 'Leku shqiptar', { diff --git a/packages/common/locales/global/sr-Cyrl-BA.js b/packages/common/locales/global/sr-Cyrl-BA.js index 9f6bbb06bf..ac28a2cb34 100644 --- a/packages/common/locales/global/sr-Cyrl-BA.js +++ b/packages/common/locales/global/sr-Cyrl-BA.js @@ -63,6 +63,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'BAM', 'КМ', 'Босанско-херцеговачка конвертибилна марка', { diff --git a/packages/common/locales/global/sr-Cyrl-ME.js b/packages/common/locales/global/sr-Cyrl-ME.js index 656bc4f018..815d2f72ad 100644 --- a/packages/common/locales/global/sr-Cyrl-ME.js +++ b/packages/common/locales/global/sr-Cyrl-ME.js @@ -63,6 +63,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Евро', { diff --git a/packages/common/locales/global/sr-Cyrl-XK.js b/packages/common/locales/global/sr-Cyrl-XK.js index 84de9ab2da..c2ab9caf3c 100644 --- a/packages/common/locales/global/sr-Cyrl-XK.js +++ b/packages/common/locales/global/sr-Cyrl-XK.js @@ -63,6 +63,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Евро', { diff --git a/packages/common/locales/global/sr-Cyrl.js b/packages/common/locales/global/sr-Cyrl.js index 90fa7cfa72..e13f483b90 100644 --- a/packages/common/locales/global/sr-Cyrl.js +++ b/packages/common/locales/global/sr-Cyrl.js @@ -64,6 +64,7 @@ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Српски динар', { 'AUD': [u, '$'], diff --git a/packages/common/locales/global/sr-Latn-BA.js b/packages/common/locales/global/sr-Latn-BA.js index 229406eb8a..4ecdab6a88 100644 --- a/packages/common/locales/global/sr-Latn-BA.js +++ b/packages/common/locales/global/sr-Latn-BA.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'BAM', 'KM', 'Bosansko-hercegovačka konvertibilna marka', { diff --git a/packages/common/locales/global/sr-Latn-ME.js b/packages/common/locales/global/sr-Latn-ME.js index e9d01923e4..9a01bc4fb5 100644 --- a/packages/common/locales/global/sr-Latn-ME.js +++ b/packages/common/locales/global/sr-Latn-ME.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Evro', { diff --git a/packages/common/locales/global/sr-Latn-XK.js b/packages/common/locales/global/sr-Latn-XK.js index 7d60b68538..bf2acb6b68 100644 --- a/packages/common/locales/global/sr-Latn-XK.js +++ b/packages/common/locales/global/sr-Latn-XK.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Evro', { diff --git a/packages/common/locales/global/sr-Latn.js b/packages/common/locales/global/sr-Latn.js index 3869944fa4..2130a6a1f6 100644 --- a/packages/common/locales/global/sr-Latn.js +++ b/packages/common/locales/global/sr-Latn.js @@ -43,6 +43,7 @@ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Srpski dinar', { 'AUD': [u, '$'], diff --git a/packages/common/locales/global/sr.js b/packages/common/locales/global/sr.js index 9630622f79..cd8085f52f 100644 --- a/packages/common/locales/global/sr.js +++ b/packages/common/locales/global/sr.js @@ -64,6 +64,7 @@ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Српски динар', { 'AUD': [u, '$'], diff --git a/packages/common/locales/global/sv-AX.js b/packages/common/locales/global/sv-AX.js index 5eaaaac2f6..0fa55b18cc 100644 --- a/packages/common/locales/global/sv-AX.js +++ b/packages/common/locales/global/sv-AX.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/sv-FI.js b/packages/common/locales/global/sv-FI.js index c976aed2cf..5d417d6e00 100644 --- a/packages/common/locales/global/sv-FI.js +++ b/packages/common/locales/global/sv-FI.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/global/sv.js b/packages/common/locales/global/sv.js index 29c62ade62..b40fbf2770 100644 --- a/packages/common/locales/global/sv.js +++ b/packages/common/locales/global/sv.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SEK', 'kr', 'svensk krona', { diff --git a/packages/common/locales/global/sw-CD.js b/packages/common/locales/global/sw-CD.js index 69fb9fa581..1c97c85d30 100644 --- a/packages/common/locales/global/sw-CD.js +++ b/packages/common/locales/global/sw-CD.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'CDF', 'FC', 'Faranga ya Kongo', { diff --git a/packages/common/locales/global/sw-KE.js b/packages/common/locales/global/sw-KE.js index e1eb236082..ff6930a26e 100644 --- a/packages/common/locales/global/sw-KE.js +++ b/packages/common/locales/global/sw-KE.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'THB': ['฿'], 'TWD': ['NT$'], 'TZS': ['TSh']}, diff --git a/packages/common/locales/global/sw-UG.js b/packages/common/locales/global/sw-UG.js index 8fc094621b..36e2497025 100644 --- a/packages/common/locales/global/sw-UG.js +++ b/packages/common/locales/global/sw-UG.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'UGX', 'USh', 'Shilingi ya Uganda', { diff --git a/packages/common/locales/global/sw.js b/packages/common/locales/global/sw.js index 335cdc668f..293c306a44 100644 --- a/packages/common/locales/global/sw.js +++ b/packages/common/locales/global/sw.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', { diff --git a/packages/common/locales/global/ta-LK.js b/packages/common/locales/global/ta-LK.js index 63a0939089..07f32a2f06 100644 --- a/packages/common/locales/global/ta-LK.js +++ b/packages/common/locales/global/ta-LK.js @@ -66,6 +66,7 @@ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'LKR', 'Rs.', 'இலங்கை ரூபாய்', {'LKR': ['Rs.', 'Rs'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/ta-MY.js b/packages/common/locales/global/ta-MY.js index 3829aeea2e..42b8c2fc5f 100644 --- a/packages/common/locales/global/ta-MY.js +++ b/packages/common/locales/global/ta-MY.js @@ -66,6 +66,7 @@ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MYR', 'RM', 'மலேஷியன் ரிங்கிட்', {'MYR': ['RM'], 'SGD': ['S$', '$'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/ta-SG.js b/packages/common/locales/global/ta-SG.js index 0d42991a67..4a90c2565e 100644 --- a/packages/common/locales/global/ta-SG.js +++ b/packages/common/locales/global/ta-SG.js @@ -66,6 +66,7 @@ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SGD', '$', 'சிங்கப்பூர் டாலர்', {'MYR': ['RM'], 'SGD': ['$'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ta.js b/packages/common/locales/global/ta.js index 3f1030881b..7049c828d7 100644 --- a/packages/common/locales/global/ta.js +++ b/packages/common/locales/global/ta.js @@ -66,6 +66,7 @@ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'இந்திய ரூபாய்', {'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/te.js b/packages/common/locales/global/te.js index 8c810de2b3..b0265c5338 100644 --- a/packages/common/locales/global/te.js +++ b/packages/common/locales/global/te.js @@ -68,6 +68,7 @@ ['{1} {0}', u, '{1} {0}కి', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'రూపాయి', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/teo-KE.js b/packages/common/locales/global/teo-KE.js index 3e5de2ed0f..b423928838 100644 --- a/packages/common/locales/global/teo-KE.js +++ b/packages/common/locales/global/teo-KE.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Ango’otol lok’ Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/teo.js b/packages/common/locales/global/teo.js index 96c30da673..7c439f141e 100644 --- a/packages/common/locales/global/teo.js +++ b/packages/common/locales/global/teo.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Ango’otol lok’ Uganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/tg.js b/packages/common/locales/global/tg.js index 9251144390..652481b69a 100644 --- a/packages/common/locales/global/tg.js +++ b/packages/common/locales/global/tg.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'TJS', 'сом.', 'Сомонӣ', {'JPY': ['JP¥', '¥'], 'TJS': ['сом.']}, diff --git a/packages/common/locales/global/th.js b/packages/common/locales/global/th.js index c1596b77bf..199d0b01b5 100644 --- a/packages/common/locales/global/th.js +++ b/packages/common/locales/global/th.js @@ -58,6 +58,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'THB', '฿', 'บาท', {'AUD': ['AU$', '$'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/global/ti-ER.js b/packages/common/locales/global/ti-ER.js index c8456c9b93..a0e2b874a4 100644 --- a/packages/common/locales/global/ti-ER.js +++ b/packages/common/locales/global/ti-ER.js @@ -51,6 +51,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ERN', 'Nfk', 'ERN', {'ERN': ['Nfk'], 'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/ti.js b/packages/common/locales/global/ti.js index b4b4c53c18..d9645991dc 100644 --- a/packages/common/locales/global/ti.js +++ b/packages/common/locales/global/ti.js @@ -58,6 +58,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'Br', 'የኢትዮጵያ ብር', {'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/tk.js b/packages/common/locales/global/tk.js index 7cf01e1434..673fbe5d72 100644 --- a/packages/common/locales/global/tk.js +++ b/packages/common/locales/global/tk.js @@ -59,6 +59,7 @@ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'san däl', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'TMT', + 'TMT', 'Türkmen manady', {'EUR': [u, '€'], 'GBP': [u, '£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/to.js b/packages/common/locales/global/to.js index 49c655325b..d3218d4b20 100644 --- a/packages/common/locales/global/to.js +++ b/packages/common/locales/global/to.js @@ -45,6 +45,7 @@ ['{1} {0}', '{1}, {0}', u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'TF', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TOP', 'T$', 'Paʻanga fakatonga', { diff --git a/packages/common/locales/global/tr-CY.js b/packages/common/locales/global/tr-CY.js index 060c61b9d5..eb0799e4a0 100644 --- a/packages/common/locales/global/tr-CY.js +++ b/packages/common/locales/global/tr-CY.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '%#,##0', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'THB': ['฿'], 'TRY': ['₺'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/tr.js b/packages/common/locales/global/tr.js index 5808ca2f8b..55de148b02 100644 --- a/packages/common/locales/global/tr.js +++ b/packages/common/locales/global/tr.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '%#,##0', '¤#,##0.00', '#E0'], + 'TRY', '₺', 'Türk Lirası', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'THB': ['฿'], 'TRY': ['₺'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/tt.js b/packages/common/locales/global/tt.js index 51ec68eb97..8187af7484 100644 --- a/packages/common/locales/global/tt.js +++ b/packages/common/locales/global/tt.js @@ -53,6 +53,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'Россия сумы', {'JPY': ['JP¥', '¥'], 'RUB': ['₽']}, diff --git a/packages/common/locales/global/twq.js b/packages/common/locales/global/twq.js index 9ccc7658f8..4f1358379c 100644 --- a/packages/common/locales/global/twq.js +++ b/packages/common/locales/global/twq.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/tzm.js b/packages/common/locales/global/tzm.js index 9cf70ef718..a5144d97f9 100644 --- a/packages/common/locales/global/tzm.js +++ b/packages/common/locales/global/tzm.js @@ -47,6 +47,7 @@ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'MAD', + 'MAD', 'Derhem Umeṛṛuki', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/ug.js b/packages/common/locales/global/ug.js index bbead1c9e6..502d59e565 100644 --- a/packages/common/locales/global/ug.js +++ b/packages/common/locales/global/ug.js @@ -50,6 +50,7 @@ ['{1}، {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', 'جۇڭگو يۈەنى', {'CNY': ['¥', '¥'], 'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/global/uk.js b/packages/common/locales/global/uk.js index ece1f253c6..58087a9c37 100644 --- a/packages/common/locales/global/uk.js +++ b/packages/common/locales/global/uk.js @@ -75,6 +75,7 @@ ['{1}, {0}', u, '{1} \'о\' {0}', u], [',', ' ', ';', '%', '+', '-', 'Е', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UAH', '₴', 'українська гривня', { diff --git a/packages/common/locales/global/ur-IN.js b/packages/common/locales/global/ur-IN.js index e8cb2d68e7..d6ad633597 100644 --- a/packages/common/locales/global/ur-IN.js +++ b/packages/common/locales/global/ur-IN.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'بھارتی روپیہ', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/ur.js b/packages/common/locales/global/ur.js index b8c7e77f96..2e05ce7dcc 100644 --- a/packages/common/locales/global/ur.js +++ b/packages/common/locales/global/ur.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'PKR', 'Rs', 'پاکستانی روپیہ', {'JPY': ['JP¥', '¥'], 'PKR': ['Rs'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/global/uz-Arab.js b/packages/common/locales/global/uz-Arab.js index b38b95ac70..c091a19a73 100644 --- a/packages/common/locales/global/uz-Arab.js +++ b/packages/common/locales/global/uz-Arab.js @@ -48,6 +48,7 @@ ['{1} {0}', u, u, u], [',', '.', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'AFN', '؋', 'افغانی', {'AFN': ['؋'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/uz-Cyrl.js b/packages/common/locales/global/uz-Cyrl.js index 1a44aee982..57cf0689dd 100644 --- a/packages/common/locales/global/uz-Cyrl.js +++ b/packages/common/locales/global/uz-Cyrl.js @@ -52,6 +52,7 @@ ':' ], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UZS', 'сўм', 'Ўзбекистон сўм', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'USD': ['US$', '$'], 'UZS': ['сўм']}, diff --git a/packages/common/locales/global/uz-Latn.js b/packages/common/locales/global/uz-Latn.js index f4abefe047..3d66b9cd30 100644 --- a/packages/common/locales/global/uz-Latn.js +++ b/packages/common/locales/global/uz-Latn.js @@ -52,6 +52,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'son emas', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UZS', 'soʻm', 'O‘zbekiston so‘mi', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'UZS': ['soʻm']}, diff --git a/packages/common/locales/global/uz.js b/packages/common/locales/global/uz.js index 97d2500364..275707d604 100644 --- a/packages/common/locales/global/uz.js +++ b/packages/common/locales/global/uz.js @@ -52,6 +52,7 @@ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'son emas', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UZS', 'soʻm', 'O‘zbekiston so‘mi', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'UZS': ['soʻm']}, diff --git a/packages/common/locales/global/vai-Latn.js b/packages/common/locales/global/vai-Latn.js index c51b053570..c6eb75aa35 100644 --- a/packages/common/locales/global/vai-Latn.js +++ b/packages/common/locales/global/vai-Latn.js @@ -41,6 +41,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'Laibhiya Dala', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/vai-Vaii.js b/packages/common/locales/global/vai-Vaii.js index 7fdb901ada..ae4fd662ea 100644 --- a/packages/common/locales/global/vai-Vaii.js +++ b/packages/common/locales/global/vai-Vaii.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'ꕞꔤꔫꕩ ꕜꕞꕌ', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/vai.js b/packages/common/locales/global/vai.js index 05a6fcee1a..e6f3dc9b17 100644 --- a/packages/common/locales/global/vai.js +++ b/packages/common/locales/global/vai.js @@ -49,6 +49,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'ꕞꔤꔫꕩ ꕜꕞꕌ', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/vi.js b/packages/common/locales/global/vi.js index 5d2ce88bf2..5a4642ba31 100644 --- a/packages/common/locales/global/vi.js +++ b/packages/common/locales/global/vi.js @@ -59,6 +59,7 @@ ['{0}, {1}', u, '{0} {1}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'VND', '₫', 'Đồng Việt Nam', { diff --git a/packages/common/locales/global/vo.js b/packages/common/locales/global/vo.js index f8a27762fa..67d04b9a87 100644 --- a/packages/common/locales/global/vo.js +++ b/packages/common/locales/global/vo.js @@ -39,6 +39,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural, diff --git a/packages/common/locales/global/vun.js b/packages/common/locales/global/vun.js index e978956911..c33a46a54b 100644 --- a/packages/common/locales/global/vun.js +++ b/packages/common/locales/global/vun.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/wae.js b/packages/common/locales/global/wae.js index 815f845997..62f9c53005 100644 --- a/packages/common/locales/global/wae.js +++ b/packages/common/locales/global/wae.js @@ -47,6 +47,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'CHF', 'CHF', + 'CHF', {}, 'ltr', plural, diff --git a/packages/common/locales/global/wo.js b/packages/common/locales/global/wo.js index ba5e2739d5..8cec261b21 100644 --- a/packages/common/locales/global/wo.js +++ b/packages/common/locales/global/wo.js @@ -42,6 +42,7 @@ ['{1} - {0}', u, '{1} \'ci\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XOF', 'CFA', 'Franc CFA bu Afrik Sowwu-jant', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/global/xh.js b/packages/common/locales/global/xh.js index fdfc59c345..b33c08d7a3 100644 --- a/packages/common/locales/global/xh.js +++ b/packages/common/locales/global/xh.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'iRandi yaseMzanzi Afrika', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZAR': ['R']}, diff --git a/packages/common/locales/global/xog.js b/packages/common/locales/global/xog.js index e3def72665..e883cca213 100644 --- a/packages/common/locales/global/xog.js +++ b/packages/common/locales/global/xog.js @@ -45,6 +45,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UGX', 'USh', 'Silingi eya Yuganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/yav.js b/packages/common/locales/global/yav.js index 2015523d70..ce0534be67 100644 --- a/packages/common/locales/global/yav.js +++ b/packages/common/locales/global/yav.js @@ -47,6 +47,7 @@ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'XAF', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/global/yi.js b/packages/common/locales/global/yi.js index 8e19dc5eb5..f0b7880b2e 100644 --- a/packages/common/locales/global/yi.js +++ b/packages/common/locales/global/yi.js @@ -63,6 +63,7 @@ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'rtl', plural, diff --git a/packages/common/locales/global/yo-BJ.js b/packages/common/locales/global/yo-BJ.js index ff632812c9..09cb6be215 100644 --- a/packages/common/locales/global/yo-BJ.js +++ b/packages/common/locales/global/yo-BJ.js @@ -61,6 +61,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XOF', 'CFA', 'Faransi ti Orílɛ́ède BIKEAO', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'RUB': ['₽']}, diff --git a/packages/common/locales/global/yo.js b/packages/common/locales/global/yo.js index b4314ff97c..bf10dbdb0b 100644 --- a/packages/common/locales/global/yo.js +++ b/packages/common/locales/global/yo.js @@ -69,6 +69,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NGN', '₦', 'Náìrà ti Orílẹ̀-èdè Nàìjíríà', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'RUB': ['₽']}, diff --git a/packages/common/locales/global/yue-Hans.js b/packages/common/locales/global/yue-Hans.js index bc9adee053..d92a63b3e4 100644 --- a/packages/common/locales/global/yue-Hans.js +++ b/packages/common/locales/global/yue-Hans.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非数值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { diff --git a/packages/common/locales/global/yue-Hant.js b/packages/common/locales/global/yue-Hant.js index 24b83396a2..ada7a41c13 100644 --- a/packages/common/locales/global/yue-Hant.js +++ b/packages/common/locales/global/yue-Hant.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港幣', {'AUD': ['AU$', '$'], 'KRW': ['₩', '₩'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/global/yue.js b/packages/common/locales/global/yue.js index 98ab618520..99a450fe4f 100644 --- a/packages/common/locales/global/yue.js +++ b/packages/common/locales/global/yue.js @@ -42,6 +42,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港幣', {'AUD': ['AU$', '$'], 'KRW': ['₩', '₩'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/global/zgh.js b/packages/common/locales/global/zgh.js index c33cd188ce..d431e438cf 100644 --- a/packages/common/locales/global/zgh.js +++ b/packages/common/locales/global/zgh.js @@ -61,6 +61,7 @@ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'ⴰⴷⵔⵉⵎ ⵏ ⵍⵎⵖⵔⵉⴱ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/global/zh-Hans-HK.js b/packages/common/locales/global/zh-Hans-HK.js index 3cfdafa49b..5ac2fe792b 100644 --- a/packages/common/locales/global/zh-Hans-HK.js +++ b/packages/common/locales/global/zh-Hans-HK.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港元', { diff --git a/packages/common/locales/global/zh-Hans-MO.js b/packages/common/locales/global/zh-Hans-MO.js index 9fce9fd380..7252f091ad 100644 --- a/packages/common/locales/global/zh-Hans-MO.js +++ b/packages/common/locales/global/zh-Hans-MO.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MOP', 'MOP$', '澳门币', { diff --git a/packages/common/locales/global/zh-Hans-SG.js b/packages/common/locales/global/zh-Hans-SG.js index 89530c95da..fdeecc45eb 100644 --- a/packages/common/locales/global/zh-Hans-SG.js +++ b/packages/common/locales/global/zh-Hans-SG.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SGD', '$', '新加坡元', { diff --git a/packages/common/locales/global/zh-Hans.js b/packages/common/locales/global/zh-Hans.js index f26e80dc33..8d8f46ac99 100644 --- a/packages/common/locales/global/zh-Hans.js +++ b/packages/common/locales/global/zh-Hans.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { diff --git a/packages/common/locales/global/zh-Hant-HK.js b/packages/common/locales/global/zh-Hant-HK.js index caef059214..728e970fc2 100644 --- a/packages/common/locales/global/zh-Hant-HK.js +++ b/packages/common/locales/global/zh-Hant-HK.js @@ -43,6 +43,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港元', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/global/zh-Hant-MO.js b/packages/common/locales/global/zh-Hant-MO.js index 3d7c33cbee..b020eecc2b 100644 --- a/packages/common/locales/global/zh-Hant-MO.js +++ b/packages/common/locales/global/zh-Hant-MO.js @@ -43,6 +43,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MOP', 'MOP$', '澳門元', {'AUD': ['AU$', '$'], 'MOP': ['MOP$'], 'RON': [u, 'L'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/global/zh-Hant.js b/packages/common/locales/global/zh-Hant.js index 7d8c28d861..922ed5cdfd 100644 --- a/packages/common/locales/global/zh-Hant.js +++ b/packages/common/locales/global/zh-Hant.js @@ -43,6 +43,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TWD', '$', '新台幣', { diff --git a/packages/common/locales/global/zh.js b/packages/common/locales/global/zh.js index 1cf0b42a62..d5e867ce76 100644 --- a/packages/common/locales/global/zh.js +++ b/packages/common/locales/global/zh.js @@ -46,6 +46,7 @@ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { diff --git a/packages/common/locales/global/zu.js b/packages/common/locales/global/zu.js index 6dea137749..99afd55abf 100644 --- a/packages/common/locales/global/zu.js +++ b/packages/common/locales/global/zu.js @@ -20,7 +20,7 @@ if (i === 0 || n === 1) return 1; return 5; } - global.ng.common.locales['zu'] = ['zu',[['a','p'],['AM','PM'],u],[['AM','PM'],u,u],[['S','M','B','T','S','H','M'],['Son','Mso','Bil','Tha','Sin','Hla','Mgq'],['ISonto','UMsombuluko','ULwesibili','ULwesithathu','ULwesine','ULwesihlanu','UMgqibelo'],['Son','Mso','Bil','Tha','Sin','Hla','Mgq']],u,[['J','F','M','E','M','J','J','A','S','O','N','D'],['Jan','Feb','Mas','Eph','Mey','Jun','Jul','Aga','Sep','Okt','Nov','Dis'],['Januwari','Februwari','Mashi','Ephreli','Meyi','Juni','Julayi','Agasti','Septhemba','Okthoba','Novemba','Disemba']],[['J','F','M','A','M','J','J','A','S','O','N','D'],['Jan','Feb','Mas','Eph','Mey','Jun','Jul','Aga','Sep','Okt','Nov','Dis'],['Januwari','Februwari','Mashi','Ephreli','Meyi','Juni','Julayi','Agasti','Septhemba','Okthoba','Novemba','Disemba']],[['BC','AD'],u,u],0,[6,0],['M/d/yy','MMM d, y','MMMM d, y','EEEE, MMMM d, y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,u,u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','¤#,##0.00','#E0'],'R','i-South African Rand',{'BYN':[u,'P.'],'DKK':[u,'Kr'],'HRK':[u,'Kn'],'ISK':[u,'Kr'],'JPY':['JP¥','¥'],'NOK':[u,'Kr'],'PLN':[u,'Zł'],'SEK':[u,'Kr'],'THB':['฿'],'TWD':['NT$'],'ZAR':['R']},'ltr', plural, [[['entathakusa','ekuseni','emini','ntambama','ebusuku'],u,u],u,[['00:00','06:00'],['06:00','10:00'],['10:00','13:00'],['13:00','19:00'],['19:00','24:00']]]]; + global.ng.common.locales['zu'] = ['zu',[['a','p'],['AM','PM'],u],[['AM','PM'],u,u],[['S','M','B','T','S','H','M'],['Son','Mso','Bil','Tha','Sin','Hla','Mgq'],['ISonto','UMsombuluko','ULwesibili','ULwesithathu','ULwesine','ULwesihlanu','UMgqibelo'],['Son','Mso','Bil','Tha','Sin','Hla','Mgq']],u,[['J','F','M','E','M','J','J','A','S','O','N','D'],['Jan','Feb','Mas','Eph','Mey','Jun','Jul','Aga','Sep','Okt','Nov','Dis'],['Januwari','Februwari','Mashi','Ephreli','Meyi','Juni','Julayi','Agasti','Septhemba','Okthoba','Novemba','Disemba']],[['J','F','M','A','M','J','J','A','S','O','N','D'],['Jan','Feb','Mas','Eph','Mey','Jun','Jul','Aga','Sep','Okt','Nov','Dis'],['Januwari','Februwari','Mashi','Ephreli','Meyi','Juni','Julayi','Agasti','Septhemba','Okthoba','Novemba','Disemba']],[['BC','AD'],u,u],0,[6,0],['M/d/yy','MMM d, y','MMMM d, y','EEEE, MMMM d, y'],['HH:mm','HH:mm:ss','HH:mm:ss z','HH:mm:ss zzzz'],['{1} {0}',u,u,u],['.',',',';','%','+','-','E','×','‰','∞','NaN',':'],['#,##0.###','#,##0%','¤#,##0.00','#E0'],'ZAR','R','i-South African Rand',{'BYN':[u,'P.'],'DKK':[u,'Kr'],'HRK':[u,'Kn'],'ISK':[u,'Kr'],'JPY':['JP¥','¥'],'NOK':[u,'Kr'],'PLN':[u,'Zł'],'SEK':[u,'Kr'],'THB':['฿'],'TWD':['NT$'],'ZAR':['R']},'ltr', plural, [[['entathakusa','ekuseni','emini','ntambama','ebusuku'],u,u],u,[['00:00','06:00'],['06:00','10:00'],['10:00','13:00'],['13:00','19:00'],['19:00','24:00']]]]; })( typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); diff --git a/packages/common/locales/gsw-FR.ts b/packages/common/locales/gsw-FR.ts index 5407e0bb2b..073bf70b20 100644 --- a/packages/common/locales/gsw-FR.ts +++ b/packages/common/locales/gsw-FR.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'ATS': ['öS']}, diff --git a/packages/common/locales/gsw-LI.ts b/packages/common/locales/gsw-LI.ts index 9f3a212038..c4b8394808 100644 --- a/packages/common/locales/gsw-LI.ts +++ b/packages/common/locales/gsw-LI.ts @@ -44,6 +44,7 @@ export default [ ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'Schwiizer Franke', {'ATS': ['öS']}, 'ltr', diff --git a/packages/common/locales/gsw.ts b/packages/common/locales/gsw.ts index 2220fd4e07..f512bd6e22 100644 --- a/packages/common/locales/gsw.ts +++ b/packages/common/locales/gsw.ts @@ -44,6 +44,7 @@ export default [ ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'Schwiizer Franke', {'ATS': ['öS']}, 'ltr', diff --git a/packages/common/locales/gu.ts b/packages/common/locales/gu.ts index 601fb9280f..ef0bb793bc 100644 --- a/packages/common/locales/gu.ts +++ b/packages/common/locales/gu.ts @@ -63,6 +63,7 @@ export default [ ['{1} {0}', u, '{1} એ {0} વાગ્યે', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '[#E0]'], + 'INR', '₹', 'ભારતીય રૂપિયા', { diff --git a/packages/common/locales/guz.ts b/packages/common/locales/guz.ts index 74e1f16d1b..183276f28c 100644 --- a/packages/common/locales/guz.ts +++ b/packages/common/locales/guz.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/gv.ts b/packages/common/locales/gv.ts index 6024debecf..9de833c01a 100644 --- a/packages/common/locales/gv.ts +++ b/packages/common/locales/gv.ts @@ -52,6 +52,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'GBP', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ha-GH.ts b/packages/common/locales/ha-GH.ts index 1a4f46ed6b..45e062c9d1 100644 --- a/packages/common/locales/ha-GH.ts +++ b/packages/common/locales/ha-GH.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'GHS', 'GH₵', 'GHS', {'GHS': ['GH₵'], 'NGN': ['₦']}, diff --git a/packages/common/locales/ha-NE.ts b/packages/common/locales/ha-NE.ts index 063f91dd9b..599731a83b 100644 --- a/packages/common/locales/ha-NE.ts +++ b/packages/common/locales/ha-NE.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XOF', 'CFA', 'Kuɗin Sefa na Afirka Ta Yamma', {'NGN': ['₦']}, diff --git a/packages/common/locales/ha.ts b/packages/common/locales/ha.ts index 1a7f9031c6..32816bd477 100644 --- a/packages/common/locales/ha.ts +++ b/packages/common/locales/ha.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'NGN', '₦', 'Nairar Najeriya', {'NGN': ['₦']}, diff --git a/packages/common/locales/haw.ts b/packages/common/locales/haw.ts index 3a32be069b..08c68bbe6e 100644 --- a/packages/common/locales/haw.ts +++ b/packages/common/locales/haw.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'USD', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/he.ts b/packages/common/locales/he.ts index f11d289baa..60521a76dd 100644 --- a/packages/common/locales/he.ts +++ b/packages/common/locales/he.ts @@ -56,6 +56,7 @@ export default [ ['{1}, {0}', u, '{1} בשעה {0}', u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '\u200f#,##0.00 ¤;\u200f-#,##0.00 ¤', '#E0'], + 'ILS', '₪', 'שקל חדש', { diff --git a/packages/common/locales/hi.ts b/packages/common/locales/hi.ts index 49ab263bd0..13df15aa16 100644 --- a/packages/common/locales/hi.ts +++ b/packages/common/locales/hi.ts @@ -61,6 +61,7 @@ export default [ ['{1}, {0}', u, '{1} को {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤#,##,##0.00', '[#E0]'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'RON': [u, 'लेई'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/hr-BA.ts b/packages/common/locales/hr-BA.ts index 4a1958b232..b414384d2f 100644 --- a/packages/common/locales/hr-BA.ts +++ b/packages/common/locales/hr-BA.ts @@ -57,6 +57,7 @@ export default [ ['{1} {0}', u, '{1} \'u\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BAM', 'KM', 'konvertibilna marka', { diff --git a/packages/common/locales/hr.ts b/packages/common/locales/hr.ts index 73fa889b2b..edbbd45f6f 100644 --- a/packages/common/locales/hr.ts +++ b/packages/common/locales/hr.ts @@ -62,6 +62,7 @@ export default [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'HRK', + 'HRK', 'hrvatska kuna', { 'AUD': [u, '$'], diff --git a/packages/common/locales/hsb.ts b/packages/common/locales/hsb.ts index 4e5c03d653..2aa6513715 100644 --- a/packages/common/locales/hsb.ts +++ b/packages/common/locales/hsb.ts @@ -59,6 +59,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'AUD': [u, '$'], 'PLN': ['zł'], 'THB': ['฿']}, diff --git a/packages/common/locales/hu.ts b/packages/common/locales/hu.ts index 18c75df3cf..d3729257f6 100644 --- a/packages/common/locales/hu.ts +++ b/packages/common/locales/hu.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'HUF', 'Ft', 'magyar forint', { diff --git a/packages/common/locales/hy.ts b/packages/common/locales/hy.ts index 9da49e8b03..09493b839a 100644 --- a/packages/common/locales/hy.ts +++ b/packages/common/locales/hy.ts @@ -63,6 +63,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'ՈչԹ', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AMD', '֏', 'հայկական դրամ', {'AMD': ['֏'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/ia.ts b/packages/common/locales/ia.ts index a0f8ccccdb..d174f24f08 100644 --- a/packages/common/locales/ia.ts +++ b/packages/common/locales/ia.ts @@ -51,6 +51,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'NLG': ['ƒ'], 'RUB': ['₽'], 'USD': ['US$', '$']}, 'ltr', plural diff --git a/packages/common/locales/id.ts b/packages/common/locales/id.ts index fbc9ead7a3..2145005331 100644 --- a/packages/common/locales/id.ts +++ b/packages/common/locales/id.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'IDR', 'Rp', 'Rupiah Indonesia', { diff --git a/packages/common/locales/ig.ts b/packages/common/locales/ig.ts index b30cbf350b..00e160dcdd 100644 --- a/packages/common/locales/ig.ts +++ b/packages/common/locales/ig.ts @@ -43,6 +43,7 @@ export default [ ['{1}, {0}', u, '{1} \'na\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NGN', '₦', 'Naịra', {'NGN': ['₦']}, diff --git a/packages/common/locales/ii.ts b/packages/common/locales/ii.ts index 7cf9bb82c1..eb276bbcc7 100644 --- a/packages/common/locales/ii.ts +++ b/packages/common/locales/ii.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'CNY', '¥', 'CNY', {'CNY': ['¥'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/is.ts b/packages/common/locales/is.ts index 597e9cbc75..d77dca53bb 100644 --- a/packages/common/locales/is.ts +++ b/packages/common/locales/is.ts @@ -53,6 +53,7 @@ export default [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'ISK', + 'ISK', 'íslensk króna', { 'AUD': [u, '$'], diff --git a/packages/common/locales/it-CH.ts b/packages/common/locales/it-CH.ts index 4eff29c409..b29e4d86c2 100644 --- a/packages/common/locales/it-CH.ts +++ b/packages/common/locales/it-CH.ts @@ -45,6 +45,7 @@ export default [ ['.', '’', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤-#,##0.00', '#E0'], 'CHF', + 'CHF', 'franco svizzero', { 'BRL': [u, 'R$'], diff --git a/packages/common/locales/it-SM.ts b/packages/common/locales/it-SM.ts index 99642d2d51..0b7fd1e569 100644 --- a/packages/common/locales/it-SM.ts +++ b/packages/common/locales/it-SM.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/it-VA.ts b/packages/common/locales/it-VA.ts index 15c6de9271..a65630c993 100644 --- a/packages/common/locales/it-VA.ts +++ b/packages/common/locales/it-VA.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/it.ts b/packages/common/locales/it.ts index b694fa7121..8be39e9b1f 100644 --- a/packages/common/locales/it.ts +++ b/packages/common/locales/it.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/ja.ts b/packages/common/locales/ja.ts index 5115c1cff5..aa10662ce5 100644 --- a/packages/common/locales/ja.ts +++ b/packages/common/locales/ja.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'JPY', '¥', '日本円', {'CNY': ['元', '¥'], 'JPY': ['¥'], 'RON': [u, 'レイ'], 'XXX': []}, diff --git a/packages/common/locales/jgo.ts b/packages/common/locales/jgo.ts index 0fdddd29d3..7a42f32f3d 100644 --- a/packages/common/locales/jgo.ts +++ b/packages/common/locales/jgo.ts @@ -54,6 +54,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'Fɛlâŋ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/jmc.ts b/packages/common/locales/jmc.ts index 8c29e7ef68..285485f644 100644 --- a/packages/common/locales/jmc.ts +++ b/packages/common/locales/jmc.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/jv.ts b/packages/common/locales/jv.ts index 1e1dc237bc..32176e1320 100644 --- a/packages/common/locales/jv.ts +++ b/packages/common/locales/jv.ts @@ -42,6 +42,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'IDR', 'Rp', 'Rupiah Indonesia', {'IDR': ['Rp'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ka.ts b/packages/common/locales/ka.ts index 99cc75fcfc..1bd34b8e0c 100644 --- a/packages/common/locales/ka.ts +++ b/packages/common/locales/ka.ts @@ -62,6 +62,7 @@ export default [ 'არ არის რიცხვი', ':' ], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'GEL', '₾', 'ქართული ლარი', { diff --git a/packages/common/locales/kab.ts b/packages/common/locales/kab.ts index b0704a6945..354112d09a 100644 --- a/packages/common/locales/kab.ts +++ b/packages/common/locales/kab.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'DZD', 'DA', 'Adinar Azzayri', {'DZD': ['DA'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/kam.ts b/packages/common/locales/kam.ts index f68b90f88c..fdedd6cb50 100644 --- a/packages/common/locales/kam.ts +++ b/packages/common/locales/kam.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Silingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/kde.ts b/packages/common/locales/kde.ts index 43bbd1ade7..57dd2026a6 100644 --- a/packages/common/locales/kde.ts +++ b/packages/common/locales/kde.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/kea.ts b/packages/common/locales/kea.ts index 4b1e1e7033..141064b907 100644 --- a/packages/common/locales/kea.ts +++ b/packages/common/locales/kea.ts @@ -46,6 +46,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'CVE', '​', 'Skudu Kabuverdianu', {'AUD': ['AU$', '$'], 'CVE': ['​'], 'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/khq.ts b/packages/common/locales/khq.ts index 0388f52fe5..01f67a9fbf 100644 --- a/packages/common/locales/khq.ts +++ b/packages/common/locales/khq.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ki.ts b/packages/common/locales/ki.ts index 2249318f12..a8802db514 100644 --- a/packages/common/locales/ki.ts +++ b/packages/common/locales/ki.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Ciringi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/kk.ts b/packages/common/locales/kk.ts index 05248076ad..04a999279b 100644 --- a/packages/common/locales/kk.ts +++ b/packages/common/locales/kk.ts @@ -65,6 +65,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'сан емес', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'KZT', '₸', 'Қазақстан теңгесі', {'JPY': ['JP¥', '¥'], 'KZT': ['₸'], 'RUB': ['₽'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/kkj.ts b/packages/common/locales/kkj.ts index 11eb687293..3f7a01992e 100644 --- a/packages/common/locales/kkj.ts +++ b/packages/common/locales/kkj.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'Franc CFA', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/kl.ts b/packages/common/locales/kl.ts index ae8fd84c39..44d6a2529b 100644 --- a/packages/common/locales/kl.ts +++ b/packages/common/locales/kl.ts @@ -53,6 +53,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'DKK', 'kr.', 'DKK', {'DKK': ['kr.', 'kr'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/kln.ts b/packages/common/locales/kln.ts index c13505cad3..4f43e5044b 100644 --- a/packages/common/locales/kln.ts +++ b/packages/common/locales/kln.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Silingitab ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/km.ts b/packages/common/locales/km.ts index 6664c7be32..580b59db47 100644 --- a/packages/common/locales/km.ts +++ b/packages/common/locales/km.ts @@ -64,6 +64,7 @@ export default [ ['{1}, {0}', u, '{1} នៅ​ម៉ោង {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'KHR', '៛', 'រៀល​កម្ពុជា', {'JPY': ['JP¥', '¥'], 'KHR': ['៛'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/kn.ts b/packages/common/locales/kn.ts index 975da663ef..6d4e137ce6 100644 --- a/packages/common/locales/kn.ts +++ b/packages/common/locales/kn.ts @@ -82,6 +82,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ಭಾರತೀಯ ರೂಪಾಯಿ', {'JPY': ['JP¥', '¥'], 'RON': [u, 'ಲೀ'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/ko-KP.ts b/packages/common/locales/ko-KP.ts index fc6b0936d9..a1a8dafe41 100644 --- a/packages/common/locales/ko-KP.ts +++ b/packages/common/locales/ko-KP.ts @@ -42,6 +42,7 @@ export default [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'KPW', + 'KPW', '조선 민주주의 인민 공화국 원', { 'AUD': ['AU$', '$'], diff --git a/packages/common/locales/ko.ts b/packages/common/locales/ko.ts index a45324d5be..c357bff853 100644 --- a/packages/common/locales/ko.ts +++ b/packages/common/locales/ko.ts @@ -41,6 +41,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KRW', '₩', '대한민국 원', { diff --git a/packages/common/locales/kok.ts b/packages/common/locales/kok.ts index 1476387ab1..2208f33385 100644 --- a/packages/common/locales/kok.ts +++ b/packages/common/locales/kok.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'RON': ['रॉन', 'लेई'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ks.ts b/packages/common/locales/ks.ts index e45c3b46b9..467da984eb 100644 --- a/packages/common/locales/ks.ts +++ b/packages/common/locales/ks.ts @@ -53,6 +53,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'ہِندُستٲنۍ رۄپَے', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ksb.ts b/packages/common/locales/ksb.ts index 85a6cc161c..e141ac45e6 100644 --- a/packages/common/locales/ksb.ts +++ b/packages/common/locales/ksb.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ksf.ts b/packages/common/locales/ksf.ts index be227589ef..9ab774fa40 100644 --- a/packages/common/locales/ksf.ts +++ b/packages/common/locales/ksf.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'fráŋ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ksh.ts b/packages/common/locales/ksh.ts index 424cbaf1e1..b55eccbe0f 100644 --- a/packages/common/locales/ksh.ts +++ b/packages/common/locales/ksh.ts @@ -54,6 +54,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ku.ts b/packages/common/locales/ku.ts index bcf8a87b87..5fe17560a0 100644 --- a/packages/common/locales/ku.ts +++ b/packages/common/locales/ku.ts @@ -50,6 +50,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '%#,##0', '#,##0.00 ¤', '#E0'], + 'TRY', '₺', 'TRY', {'JPY': ['JP¥', '¥'], 'TRY': ['₺'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/kw.ts b/packages/common/locales/kw.ts index 74accb5806..3fb0df8b60 100644 --- a/packages/common/locales/kw.ts +++ b/packages/common/locales/kw.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'GBP', '£', 'GBP', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ky.ts b/packages/common/locales/ky.ts index d22d0d30ec..fffc310100 100644 --- a/packages/common/locales/ky.ts +++ b/packages/common/locales/ky.ts @@ -65,6 +65,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'сан эмес', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'KGS', 'сом', 'Кыргызстан сому', { diff --git a/packages/common/locales/lag.ts b/packages/common/locales/lag.ts index ab28e5f571..571c781d0c 100644 --- a/packages/common/locales/lag.ts +++ b/packages/common/locales/lag.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilíingi ya Taansanía', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/lb.ts b/packages/common/locales/lb.ts index 60ba0383c8..7048c9a10a 100644 --- a/packages/common/locales/lb.ts +++ b/packages/common/locales/lb.ts @@ -57,6 +57,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euro', {'ATS': ['öS'], 'AUD': ['AU$', '$'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/lg.ts b/packages/common/locales/lg.ts index d72ad92215..ecaac910cc 100644 --- a/packages/common/locales/lg.ts +++ b/packages/common/locales/lg.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'UGX', 'USh', 'Silingi eya Yuganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/lkt.ts b/packages/common/locales/lkt.ts index fa42260b96..1689506841 100644 --- a/packages/common/locales/lkt.ts +++ b/packages/common/locales/lkt.ts @@ -53,6 +53,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'USD', '$', 'USD', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/ln-AO.ts b/packages/common/locales/ln-AO.ts index 65123c96ce..2d3def6b08 100644 --- a/packages/common/locales/ln-AO.ts +++ b/packages/common/locales/ln-AO.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AOA', 'Kz', 'Kwanza ya Angóla', {'AOA': ['Kz'], 'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ln-CF.ts b/packages/common/locales/ln-CF.ts index f365c48c8a..56e5c8f305 100644 --- a/packages/common/locales/ln-CF.ts +++ b/packages/common/locales/ln-CF.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Falánga CFA BEAC', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ln-CG.ts b/packages/common/locales/ln-CG.ts index c4f8b8ef84..8d03b6a61b 100644 --- a/packages/common/locales/ln-CG.ts +++ b/packages/common/locales/ln-CG.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Falánga CFA BEAC', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ln.ts b/packages/common/locales/ln.ts index aaf16dd8ba..5ccf6aabc4 100644 --- a/packages/common/locales/ln.ts +++ b/packages/common/locales/ln.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'CDF', 'FC', 'Falánga ya Kongó', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/lo.ts b/packages/common/locales/lo.ts index 8195d2ccac..40c0011d8f 100644 --- a/packages/common/locales/lo.ts +++ b/packages/common/locales/lo.ts @@ -63,6 +63,7 @@ export default [ 'ບໍ່​ແມ່ນ​ໂຕ​ເລກ', ':' ], ['#,##0.###', '#,##0%', '¤#,##0.00;¤-#,##0.00', '#'], + 'LAK', '₭', 'ລາວ ກີບ', {'JPY': ['JP¥', '¥'], 'LAK': ['₭'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/lrc-IQ.ts b/packages/common/locales/lrc-IQ.ts index afccbf6d01..55a7c69026 100644 --- a/packages/common/locales/lrc-IQ.ts +++ b/packages/common/locales/lrc-IQ.ts @@ -38,6 +38,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'IQD', 'د.ع.\u200f', 'IQD', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/lrc.ts b/packages/common/locales/lrc.ts index 8af99156c6..d861eb270a 100644 --- a/packages/common/locales/lrc.ts +++ b/packages/common/locales/lrc.ts @@ -40,6 +40,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'IRR', 'IRR', + 'IRR', {'IQD': ['د.ع.\u200f'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'rtl', plural diff --git a/packages/common/locales/lt.ts b/packages/common/locales/lt.ts index 3152318cd3..c613c30381 100644 --- a/packages/common/locales/lt.ts +++ b/packages/common/locales/lt.ts @@ -64,6 +64,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euras', { diff --git a/packages/common/locales/lu.ts b/packages/common/locales/lu.ts index 50e3de3335..85a4fe2a6f 100644 --- a/packages/common/locales/lu.ts +++ b/packages/common/locales/lu.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'CDF', 'FC', 'Nfalanga wa Kongu', {'CDF': ['FC'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/luo.ts b/packages/common/locales/luo.ts index f5d117a4b5..2299b4863d 100644 --- a/packages/common/locales/luo.ts +++ b/packages/common/locales/luo.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'KES', 'Ksh', 'Siling mar Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/luy.ts b/packages/common/locales/luy.ts index ba7383f1a8..e1924558a6 100644 --- a/packages/common/locales/luy.ts +++ b/packages/common/locales/luy.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00;¤- #,##0.00', '#E0'], + 'KES', 'Ksh', 'Sirinji ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/lv.ts b/packages/common/locales/lv.ts index 20e980b2d0..08acb91635 100644 --- a/packages/common/locales/lv.ts +++ b/packages/common/locales/lv.ts @@ -59,6 +59,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NS', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'eiro', {'AUD': ['AU$', '$'], 'LVL': ['Ls'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/mas-TZ.ts b/packages/common/locales/mas-TZ.ts index ecd70fdb05..ebe2f15a14 100644 --- a/packages/common/locales/mas-TZ.ts +++ b/packages/common/locales/mas-TZ.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Iropiyianí e Tanzania', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mas.ts b/packages/common/locales/mas.ts index 1cdc0f6bd7..0bdbd998d0 100644 --- a/packages/common/locales/mas.ts +++ b/packages/common/locales/mas.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Iropiyianí e Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mer.ts b/packages/common/locales/mer.ts index 0ac000efe9..73616127da 100644 --- a/packages/common/locales/mer.ts +++ b/packages/common/locales/mer.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mfe.ts b/packages/common/locales/mfe.ts index f04d4c2be0..b013808994 100644 --- a/packages/common/locales/mfe.ts +++ b/packages/common/locales/mfe.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MUR', 'Rs', 'roupi morisien', {'JPY': ['JP¥', '¥'], 'MUR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mg.ts b/packages/common/locales/mg.ts index ac6d8dcee0..e2e593f0cc 100644 --- a/packages/common/locales/mg.ts +++ b/packages/common/locales/mg.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MGA', 'Ar', 'Ariary', {'JPY': ['JP¥', '¥'], 'MGA': ['Ar'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mgh.ts b/packages/common/locales/mgh.ts index c40688ee00..43d50463da 100644 --- a/packages/common/locales/mgh.ts +++ b/packages/common/locales/mgh.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MZN', 'MTn', 'MZN', {'JPY': ['JP¥', '¥'], 'MZN': ['MTn'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mgo.ts b/packages/common/locales/mgo.ts index 80d0d841b9..994b7f6c19 100644 --- a/packages/common/locales/mgo.ts +++ b/packages/common/locales/mgo.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'shirè', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mi.ts b/packages/common/locales/mi.ts index b11ae2ee92..3e479422ac 100644 --- a/packages/common/locales/mi.ts +++ b/packages/common/locales/mi.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'NZD', '$', 'Tāra o Aotearoa', {'NZD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mk.ts b/packages/common/locales/mk.ts index 5f7059d383..8e5ca96dd4 100644 --- a/packages/common/locales/mk.ts +++ b/packages/common/locales/mk.ts @@ -61,6 +61,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MKD', 'ден.', 'Македонски денар', { diff --git a/packages/common/locales/ml.ts b/packages/common/locales/ml.ts index f66f105f70..c4c853b7e0 100644 --- a/packages/common/locales/ml.ts +++ b/packages/common/locales/ml.ts @@ -80,6 +80,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ഇന്ത്യൻ രൂപ', {'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/mn.ts b/packages/common/locales/mn.ts index 6641e2daa2..2f3d1006bb 100644 --- a/packages/common/locales/mn.ts +++ b/packages/common/locales/mn.ts @@ -75,6 +75,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MNT', '₮', 'Монгол төгрөг', {'JPY': ['JP¥', '¥'], 'MNT': ['₮'], 'SEK': [u, 'кр'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/mr.ts b/packages/common/locales/mr.ts index 23c6f9320b..b5dd26d6db 100644 --- a/packages/common/locales/mr.ts +++ b/packages/common/locales/mr.ts @@ -63,6 +63,7 @@ export default [ ['{1}, {0}', u, '{1} रोजी {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '[#E0]'], + 'INR', '₹', 'भारतीय रुपया', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/ms-BN.ts b/packages/common/locales/ms-BN.ts index 96cd26bd4e..600658e620 100644 --- a/packages/common/locales/ms-BN.ts +++ b/packages/common/locales/ms-BN.ts @@ -42,6 +42,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'BND', '$', 'Dolar Brunei', { diff --git a/packages/common/locales/ms-SG.ts b/packages/common/locales/ms-SG.ts index 8783943fda..22f17c92f0 100644 --- a/packages/common/locales/ms-SG.ts +++ b/packages/common/locales/ms-SG.ts @@ -42,6 +42,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SGD', '$', 'Dolar Singapura', { diff --git a/packages/common/locales/ms.ts b/packages/common/locales/ms.ts index 5f59b33252..1fce851592 100644 --- a/packages/common/locales/ms.ts +++ b/packages/common/locales/ms.ts @@ -42,6 +42,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MYR', 'RM', 'Ringgit Malaysia', { diff --git a/packages/common/locales/mt.ts b/packages/common/locales/mt.ts index a8624920c2..10dd133788 100644 --- a/packages/common/locales/mt.ts +++ b/packages/common/locales/mt.ts @@ -58,6 +58,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'EUR', '€', 'ewro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/mua.ts b/packages/common/locales/mua.ts index 8c21dc3fc9..b3c6f6ce67 100644 --- a/packages/common/locales/mua.ts +++ b/packages/common/locales/mua.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XAF', 'FCFA', 'solai BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/my.ts b/packages/common/locales/my.ts index 1153df748c..4bd6e2498b 100644 --- a/packages/common/locales/my.ts +++ b/packages/common/locales/my.ts @@ -56,6 +56,7 @@ export default [ 'ဂဏန်းမဟုတ်သော', ':' ], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MMK', 'K', 'မြန်မာ ကျပ်', { diff --git a/packages/common/locales/mzn.ts b/packages/common/locales/mzn.ts index 1edd3d1bfc..f6d8006b78 100644 --- a/packages/common/locales/mzn.ts +++ b/packages/common/locales/mzn.ts @@ -39,6 +39,7 @@ export default [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'IRR', + 'IRR', 'ایران ریال', {'JPY': ['JP¥', '¥']}, 'rtl', diff --git a/packages/common/locales/naq.ts b/packages/common/locales/naq.ts index 0058e57ff8..b2db7cbf65 100644 --- a/packages/common/locales/naq.ts +++ b/packages/common/locales/naq.ts @@ -49,6 +49,7 @@ export default [ ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], 'ZAR', + 'ZAR', 'South African Randi', {'JPY': ['JP¥', '¥'], 'NAD': ['$'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/nb-SJ.ts b/packages/common/locales/nb-SJ.ts index c2bb971a29..6a35f2089f 100644 --- a/packages/common/locales/nb-SJ.ts +++ b/packages/common/locales/nb-SJ.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'kl\'. {0}', '{1} {0}'], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'NOK', 'kr', 'norske kroner', { diff --git a/packages/common/locales/nb.ts b/packages/common/locales/nb.ts index f4b1b4dd37..6e1237fb5b 100644 --- a/packages/common/locales/nb.ts +++ b/packages/common/locales/nb.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'kl\'. {0}', '{1} {0}'], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'NOK', 'kr', 'norske kroner', { diff --git a/packages/common/locales/nd.ts b/packages/common/locales/nd.ts index 25ae0d4d15..aa78ce2fe0 100644 --- a/packages/common/locales/nd.ts +++ b/packages/common/locales/nd.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'Dola yase Amelika', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/nds-NL.ts b/packages/common/locales/nds-NL.ts index 33384b8137..225b17739f 100644 --- a/packages/common/locales/nds-NL.ts +++ b/packages/common/locales/nds-NL.ts @@ -34,6 +34,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'EUR', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/nds.ts b/packages/common/locales/nds.ts index d0b426f8c7..86d0ee666e 100644 --- a/packages/common/locales/nds.ts +++ b/packages/common/locales/nds.ts @@ -34,6 +34,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'EUR', '€', 'EUR', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ne-IN.ts b/packages/common/locales/ne-IN.ts index 66a5212723..2ccbe30e7d 100644 --- a/packages/common/locales/ne-IN.ts +++ b/packages/common/locales/ne-IN.ts @@ -68,6 +68,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'भारतीय रूपिँया', {'JPY': ['JP¥', '¥'], 'NPR': ['नेरू', 'रू'], 'THB': ['฿'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ne.ts b/packages/common/locales/ne.ts index 56c5b832e6..f93c004f9f 100644 --- a/packages/common/locales/ne.ts +++ b/packages/common/locales/ne.ts @@ -68,6 +68,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'NPR', 'नेरू', 'नेपाली रूपैयाँ', {'JPY': ['JP¥', '¥'], 'NPR': ['नेरू', 'रू'], 'THB': ['฿'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/nl-AW.ts b/packages/common/locales/nl-AW.ts index 7ccc561b88..ab27f400e8 100644 --- a/packages/common/locales/nl-AW.ts +++ b/packages/common/locales/nl-AW.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'AWG', 'Afl.', 'Arubaanse gulden', { diff --git a/packages/common/locales/nl-BE.ts b/packages/common/locales/nl-BE.ts index b892238369..d509f8602f 100644 --- a/packages/common/locales/nl-BE.ts +++ b/packages/common/locales/nl-BE.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/nl-BQ.ts b/packages/common/locales/nl-BQ.ts index 30765c513e..f4509dc83c 100644 --- a/packages/common/locales/nl-BQ.ts +++ b/packages/common/locales/nl-BQ.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'USD', '$', 'Amerikaanse dollar', { diff --git a/packages/common/locales/nl-CW.ts b/packages/common/locales/nl-CW.ts index 6d161b6c9a..06af3561ab 100644 --- a/packages/common/locales/nl-CW.ts +++ b/packages/common/locales/nl-CW.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'ANG', 'NAf.', 'Nederlands-Antilliaanse gulden', { diff --git a/packages/common/locales/nl-SR.ts b/packages/common/locales/nl-SR.ts index 26a79fab0d..d74025de4a 100644 --- a/packages/common/locales/nl-SR.ts +++ b/packages/common/locales/nl-SR.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'SRD', '$', 'Surinaamse dollar', { diff --git a/packages/common/locales/nl-SX.ts b/packages/common/locales/nl-SX.ts index 7425211889..2de6a329fc 100644 --- a/packages/common/locales/nl-SX.ts +++ b/packages/common/locales/nl-SX.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'ANG', 'NAf.', 'Nederlands-Antilliaanse gulden', { diff --git a/packages/common/locales/nl.ts b/packages/common/locales/nl.ts index 73c596b086..fffd4257be 100644 --- a/packages/common/locales/nl.ts +++ b/packages/common/locales/nl.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, '{1} \'om\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00;¤ -#,##0.00', '#E0'], + 'EUR', '€', 'Euro', { diff --git a/packages/common/locales/nmg.ts b/packages/common/locales/nmg.ts index d41650a9c2..71d73a0060 100644 --- a/packages/common/locales/nmg.ts +++ b/packages/common/locales/nmg.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'Fraŋ CFA BEAC', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/nn.ts b/packages/common/locales/nn.ts index ab58d3a1b7..4553907452 100644 --- a/packages/common/locales/nn.ts +++ b/packages/common/locales/nn.ts @@ -54,6 +54,7 @@ export default [ ['{1}, {0}', u, '{1} \'kl\'. {0}', '{1} {0}'], [',', ' ', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'NOK', 'kr', 'norske kroner', { diff --git a/packages/common/locales/nnh.ts b/packages/common/locales/nnh.ts index 1d991173a7..4822e0687c 100644 --- a/packages/common/locales/nnh.ts +++ b/packages/common/locales/nnh.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, '{1}, {0}', '{1},{0}'], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XAF', 'FCFA', 'feláŋ CFA', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/nus.ts b/packages/common/locales/nus.ts index d4e04fd3c5..b0d598e571 100644 --- a/packages/common/locales/nus.ts +++ b/packages/common/locales/nus.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SSP', '£', 'SSP', {'GBP': ['GB£', '£'], 'JPY': ['JP¥', '¥'], 'SSP': ['£'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/nyn.ts b/packages/common/locales/nyn.ts index 6d0619f45f..4d1834e857 100644 --- a/packages/common/locales/nyn.ts +++ b/packages/common/locales/nyn.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Eshiringi ya Uganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/om-KE.ts b/packages/common/locales/om-KE.ts index fd7726cd1f..7cd066bc9e 100644 --- a/packages/common/locales/om-KE.ts +++ b/packages/common/locales/om-KE.ts @@ -50,6 +50,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'KES', {'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/om.ts b/packages/common/locales/om.ts index a5b031a9ce..36152b71b3 100644 --- a/packages/common/locales/om.ts +++ b/packages/common/locales/om.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'Br', 'Itoophiyaa Birrii', {'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/or.ts b/packages/common/locales/or.ts index f74bc11696..6e477c548b 100644 --- a/packages/common/locales/or.ts +++ b/packages/common/locales/or.ts @@ -58,6 +58,7 @@ export default [ ['{1}, {0}', u, '{0} ଠାରେ {1}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'INR', '₹', 'ଭାରତୀୟ ଟଙ୍କା', {}, diff --git a/packages/common/locales/os-RU.ts b/packages/common/locales/os-RU.ts index 329cd8fc7a..6015835504 100644 --- a/packages/common/locales/os-RU.ts +++ b/packages/common/locales/os-RU.ts @@ -70,6 +70,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'НН', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'RUB', '₽', 'Сом', {'JPY': ['JP¥', '¥'], 'RUB': ['₽']}, diff --git a/packages/common/locales/os.ts b/packages/common/locales/os.ts index 9173006ad6..2752d2f575 100644 --- a/packages/common/locales/os.ts +++ b/packages/common/locales/os.ts @@ -70,6 +70,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'НН', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'GEL', '₾', 'Лар', {'GEL': ['₾'], 'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/pa-Arab.ts b/packages/common/locales/pa-Arab.ts index d43751c9fc..3598bf1c3d 100644 --- a/packages/common/locales/pa-Arab.ts +++ b/packages/common/locales/pa-Arab.ts @@ -41,6 +41,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'PKR', 'ر', 'روپئیہ', {'JPY': ['JP¥', '¥'], 'PKR': ['ر', 'Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/pa-Guru.ts b/packages/common/locales/pa-Guru.ts index 8ffe8ae6f7..eb15441946 100644 --- a/packages/common/locales/pa-Guru.ts +++ b/packages/common/locales/pa-Guru.ts @@ -62,6 +62,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '[#E0]'], + 'INR', '₹', 'ਭਾਰਤੀ ਰੁਪਇਆ', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/pa.ts b/packages/common/locales/pa.ts index 2b06190f2a..fa7a27c4d7 100644 --- a/packages/common/locales/pa.ts +++ b/packages/common/locales/pa.ts @@ -62,6 +62,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '[#E0]'], + 'INR', '₹', 'ਭਾਰਤੀ ਰੁਪਇਆ', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/pl.ts b/packages/common/locales/pl.ts index 68ab253f72..16cb8f6d72 100644 --- a/packages/common/locales/pl.ts +++ b/packages/common/locales/pl.ts @@ -62,6 +62,7 @@ export default [ ['{1}, {0}', u, '{1} {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'PLN', 'zł', 'złoty polski', { diff --git a/packages/common/locales/prg.ts b/packages/common/locales/prg.ts index b675129622..7988b951ac 100644 --- a/packages/common/locales/prg.ts +++ b/packages/common/locales/prg.ts @@ -44,6 +44,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural diff --git a/packages/common/locales/ps-PK.ts b/packages/common/locales/ps-PK.ts index 5c339ed4dd..10ba850f2f 100644 --- a/packages/common/locales/ps-PK.ts +++ b/packages/common/locales/ps-PK.ts @@ -56,6 +56,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'PKR', 'Rs', 'پاکستانۍ کلداره', {'AFN': ['؋'], 'JPY': ['JP¥', '¥'], 'PKR': ['Rs']}, diff --git a/packages/common/locales/ps.ts b/packages/common/locales/ps.ts index 08f1590069..b4d933b688 100644 --- a/packages/common/locales/ps.ts +++ b/packages/common/locales/ps.ts @@ -56,6 +56,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AFN', '؋', 'افغانۍ', {'AFN': ['؋'], 'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/pt-AO.ts b/packages/common/locales/pt-AO.ts index 9594aa72d3..d7dbb71840 100644 --- a/packages/common/locales/pt-AO.ts +++ b/packages/common/locales/pt-AO.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'AOA', 'Kz', 'kwanza angolano', { diff --git a/packages/common/locales/pt-CH.ts b/packages/common/locales/pt-CH.ts index 82b7aa197f..b65373e657 100644 --- a/packages/common/locales/pt-CH.ts +++ b/packages/common/locales/pt-CH.ts @@ -51,6 +51,7 @@ export default [ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'franco suíço', { 'AUD': ['AU$', '$'], diff --git a/packages/common/locales/pt-CV.ts b/packages/common/locales/pt-CV.ts index b5c8a86bbc..53a1238674 100644 --- a/packages/common/locales/pt-CV.ts +++ b/packages/common/locales/pt-CV.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'CVE', '​', 'escudo cabo-verdiano', { diff --git a/packages/common/locales/pt-GQ.ts b/packages/common/locales/pt-GQ.ts index 6019e24a19..b0080fb505 100644 --- a/packages/common/locales/pt-GQ.ts +++ b/packages/common/locales/pt-GQ.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'franco CFA (BEAC)', { diff --git a/packages/common/locales/pt-GW.ts b/packages/common/locales/pt-GW.ts index 6601b9d9fe..b22be1d296 100644 --- a/packages/common/locales/pt-GW.ts +++ b/packages/common/locales/pt-GW.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XOF', 'CFA', 'franco CFA (BCEAO)', { diff --git a/packages/common/locales/pt-LU.ts b/packages/common/locales/pt-LU.ts index ada189e129..79a5914dc2 100644 --- a/packages/common/locales/pt-LU.ts +++ b/packages/common/locales/pt-LU.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/pt-MO.ts b/packages/common/locales/pt-MO.ts index 34bff1242f..abf36cdf46 100644 --- a/packages/common/locales/pt-MO.ts +++ b/packages/common/locales/pt-MO.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MOP', 'MOP$', 'pataca macaense', { diff --git a/packages/common/locales/pt-MZ.ts b/packages/common/locales/pt-MZ.ts index 52b39e0401..29a6ab6dc2 100644 --- a/packages/common/locales/pt-MZ.ts +++ b/packages/common/locales/pt-MZ.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MZN', 'MTn', 'metical moçambicano', { diff --git a/packages/common/locales/pt-PT.ts b/packages/common/locales/pt-PT.ts index 964f527aee..d9d13b2c63 100644 --- a/packages/common/locales/pt-PT.ts +++ b/packages/common/locales/pt-PT.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/pt-ST.ts b/packages/common/locales/pt-ST.ts index 06571f4fb0..21d9bd1f46 100644 --- a/packages/common/locales/pt-ST.ts +++ b/packages/common/locales/pt-ST.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'STN', 'Db', 'dobra de São Tomé e Príncipe', { diff --git a/packages/common/locales/pt-TL.ts b/packages/common/locales/pt-TL.ts index e8e30f2ec4..ef0724791a 100644 --- a/packages/common/locales/pt-TL.ts +++ b/packages/common/locales/pt-TL.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, '{1} \'às\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'USD', 'US$', 'dólar dos Estados Unidos', { diff --git a/packages/common/locales/pt.ts b/packages/common/locales/pt.ts index be958512d0..e72bcda684 100644 --- a/packages/common/locales/pt.ts +++ b/packages/common/locales/pt.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'BRL', 'R$', 'Real brasileiro', { diff --git a/packages/common/locales/qu-BO.ts b/packages/common/locales/qu-BO.ts index 2a9c3378d0..c7d409c712 100644 --- a/packages/common/locales/qu-BO.ts +++ b/packages/common/locales/qu-BO.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, '{0} {1}', '{1} {0}'], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'BOB', 'Bs', 'Boliviano', { diff --git a/packages/common/locales/qu-EC.ts b/packages/common/locales/qu-EC.ts index efa5b23aa3..d5a7b21637 100644 --- a/packages/common/locales/qu-EC.ts +++ b/packages/common/locales/qu-EC.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, '{0} {1}', '{1} {0}'], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'USD', '$', 'Dólar Americano', { diff --git a/packages/common/locales/qu.ts b/packages/common/locales/qu.ts index f2797b9eb4..73a7c4ef3d 100644 --- a/packages/common/locales/qu.ts +++ b/packages/common/locales/qu.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, '{0} {1}', '{1} {0}'], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '¤ #,##0.00', '#E0'], + 'PEN', 'S/', 'Sol Peruano', { diff --git a/packages/common/locales/rm.ts b/packages/common/locales/rm.ts index b490bf5253..1f693b2682 100644 --- a/packages/common/locales/rm.ts +++ b/packages/common/locales/rm.ts @@ -57,6 +57,7 @@ export default [ ['.', '’', ';', '%', '+', '−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'CHF', + 'CHF', 'franc svizzer', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/rn.ts b/packages/common/locales/rn.ts index 532837c4a0..0667067a61 100644 --- a/packages/common/locales/rn.ts +++ b/packages/common/locales/rn.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00¤', '#E0'], + 'BIF', 'FBu', 'Ifaranga ry’Uburundi', {'BIF': ['FBu'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ro-MD.ts b/packages/common/locales/ro-MD.ts index 4ff129c58c..903ea77d04 100644 --- a/packages/common/locales/ro-MD.ts +++ b/packages/common/locales/ro-MD.ts @@ -49,6 +49,7 @@ export default [ ['{1}, {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MDL', 'L', 'leu moldovenesc', { diff --git a/packages/common/locales/ro.ts b/packages/common/locales/ro.ts index eb15737873..9e0df521ee 100644 --- a/packages/common/locales/ro.ts +++ b/packages/common/locales/ro.ts @@ -50,6 +50,7 @@ export default [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'RON', + 'RON', 'leu românesc', { 'AUD': [u, '$'], diff --git a/packages/common/locales/rof.ts b/packages/common/locales/rof.ts index fa85342788..480ecd3e84 100644 --- a/packages/common/locales/rof.ts +++ b/packages/common/locales/rof.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'heleri sa Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/root.ts b/packages/common/locales/root.ts index 9e180d3b6b..f0e269bb9c 100644 --- a/packages/common/locales/root.ts +++ b/packages/common/locales/root.ts @@ -42,6 +42,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/common/locales/ru-BY.ts b/packages/common/locales/ru-BY.ts index d2eac3dd70..97e5f12b89 100644 --- a/packages/common/locales/ru-BY.ts +++ b/packages/common/locales/ru-BY.ts @@ -80,6 +80,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'BYN', 'Br', 'белорусский рубль', { diff --git a/packages/common/locales/ru-KG.ts b/packages/common/locales/ru-KG.ts index 3a6af258c8..d6675e51b5 100644 --- a/packages/common/locales/ru-KG.ts +++ b/packages/common/locales/ru-KG.ts @@ -80,6 +80,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'KGS', 'сом', 'киргизский сом', { diff --git a/packages/common/locales/ru-KZ.ts b/packages/common/locales/ru-KZ.ts index 69fdf16a96..e88b22074b 100644 --- a/packages/common/locales/ru-KZ.ts +++ b/packages/common/locales/ru-KZ.ts @@ -80,6 +80,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'KZT', '₸', 'казахский тенге', { diff --git a/packages/common/locales/ru-MD.ts b/packages/common/locales/ru-MD.ts index aef9f94998..866927406d 100644 --- a/packages/common/locales/ru-MD.ts +++ b/packages/common/locales/ru-MD.ts @@ -80,6 +80,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'MDL', 'L', 'молдавский лей', { diff --git a/packages/common/locales/ru-UA.ts b/packages/common/locales/ru-UA.ts index af04c1a36b..8664570e9a 100644 --- a/packages/common/locales/ru-UA.ts +++ b/packages/common/locales/ru-UA.ts @@ -80,6 +80,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'UAH', '₴', 'украинская гривна', { diff --git a/packages/common/locales/ru.ts b/packages/common/locales/ru.ts index 9ec9584da4..290fd9ff20 100644 --- a/packages/common/locales/ru.ts +++ b/packages/common/locales/ru.ts @@ -80,6 +80,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'не число', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'российский рубль', { diff --git a/packages/common/locales/rw.ts b/packages/common/locales/rw.ts index fe71fdaec3..4b5670fb5e 100644 --- a/packages/common/locales/rw.ts +++ b/packages/common/locales/rw.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'RWF', 'RF', 'RWF', {'JPY': ['JP¥', '¥'], 'RWF': ['RF'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/rwk.ts b/packages/common/locales/rwk.ts index 4ada6f3ae9..95214989ca 100644 --- a/packages/common/locales/rwk.ts +++ b/packages/common/locales/rwk.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/sah.ts b/packages/common/locales/sah.ts index 9155f1095f..3717cba847 100644 --- a/packages/common/locales/sah.ts +++ b/packages/common/locales/sah.ts @@ -61,6 +61,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'чыыһыла буотах', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'Арассыыйа солкуобайа', {'JPY': ['JP¥', '¥'], 'RUB': ['₽'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/saq.ts b/packages/common/locales/saq.ts index 28976939c7..2724aea288 100644 --- a/packages/common/locales/saq.ts +++ b/packages/common/locales/saq.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Njilingi eel Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/sbp.ts b/packages/common/locales/sbp.ts index 2b9a5dbf16..4eda7f88dd 100644 --- a/packages/common/locales/sbp.ts +++ b/packages/common/locales/sbp.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'TZS', 'TSh', 'Ihela ya Tansaniya', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/sd.ts b/packages/common/locales/sd.ts index 58e847bfeb..55568acc9d 100644 --- a/packages/common/locales/sd.ts +++ b/packages/common/locales/sd.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'PKR', 'Rs', 'پاڪستاني رپي', {'JPY': ['JP¥', '¥'], 'PKR': ['Rs'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/se-FI.ts b/packages/common/locales/se-FI.ts index 7ea9c392d0..6150ff45ae 100644 --- a/packages/common/locales/se-FI.ts +++ b/packages/common/locales/se-FI.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '·10^', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/se-SE.ts b/packages/common/locales/se-SE.ts index 52a0276b6e..1cdd8f3571 100644 --- a/packages/common/locales/se-SE.ts +++ b/packages/common/locales/se-SE.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '·10^', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SEK', 'kr', 'ruoŧŧa kruvdno', { diff --git a/packages/common/locales/se.ts b/packages/common/locales/se.ts index d0122a8f70..a26aa40072 100644 --- a/packages/common/locales/se.ts +++ b/packages/common/locales/se.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '·10^', '·', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'NOK', 'kr', 'norgga kruvdno', { diff --git a/packages/common/locales/seh.ts b/packages/common/locales/seh.ts index b1fdbdb12b..7729cbcaba 100644 --- a/packages/common/locales/seh.ts +++ b/packages/common/locales/seh.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'MZN', 'MTn', 'Metical de Moçambique', {'JPY': ['JP¥', '¥'], 'MZN': ['MTn'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ses.ts b/packages/common/locales/ses.ts index 1f6e20be17..00c404beac 100644 --- a/packages/common/locales/ses.ts +++ b/packages/common/locales/ses.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/sg.ts b/packages/common/locales/sg.ts index 8d385fae89..a1abd9af51 100644 --- a/packages/common/locales/sg.ts +++ b/packages/common/locales/sg.ts @@ -45,6 +45,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00;¤-#,##0.00', '#E0'], + 'XAF', 'FCFA', 'farânga CFA (BEAC)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/shi-Latn.ts b/packages/common/locales/shi-Latn.ts index 9236dfcd05..620c94eb4b 100644 --- a/packages/common/locales/shi-Latn.ts +++ b/packages/common/locales/shi-Latn.ts @@ -43,6 +43,7 @@ export default [ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'adrim n lmɣrib', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/shi-Tfng.ts b/packages/common/locales/shi-Tfng.ts index 878df01cba..423ccdf7bc 100644 --- a/packages/common/locales/shi-Tfng.ts +++ b/packages/common/locales/shi-Tfng.ts @@ -63,6 +63,7 @@ export default [ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'ⴰⴷⵔⵉⵎ ⵏ ⵍⵎⵖⵔⵉⴱ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/shi.ts b/packages/common/locales/shi.ts index 8f88395323..7ff6475174 100644 --- a/packages/common/locales/shi.ts +++ b/packages/common/locales/shi.ts @@ -63,6 +63,7 @@ export default [ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'ⴰⴷⵔⵉⵎ ⵏ ⵍⵎⵖⵔⵉⴱ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/si.ts b/packages/common/locales/si.ts index 6a88e5c8a9..ad1fade104 100644 --- a/packages/common/locales/si.ts +++ b/packages/common/locales/si.ts @@ -86,6 +86,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#'], + 'LKR', 'රු.', 'ශ්\u200dරී ලංකා රුපියල', { diff --git a/packages/common/locales/sk.ts b/packages/common/locales/sk.ts index 01dbe23e57..38eb7546fa 100644 --- a/packages/common/locales/sk.ts +++ b/packages/common/locales/sk.ts @@ -53,6 +53,7 @@ export default [ ['{1} {0}', '{1}, {0}', u, u], [',', ' ', ';', '%', '+', '-', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/sl.ts b/packages/common/locales/sl.ts index 8accafe08e..4031d933cd 100644 --- a/packages/common/locales/sl.ts +++ b/packages/common/locales/sl.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '−', 'e', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'evro', { diff --git a/packages/common/locales/smn.ts b/packages/common/locales/smn.ts index a956ac166a..45291c99ba 100644 --- a/packages/common/locales/smn.ts +++ b/packages/common/locales/smn.ts @@ -58,6 +58,7 @@ export default [ ['{1} {0}', '{1} \'tme\' {0}', u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'epiloho', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/sn.ts b/packages/common/locales/sn.ts index 15e45bf8d3..e4c97575ff 100644 --- a/packages/common/locales/sn.ts +++ b/packages/common/locales/sn.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', 'US$', 'Dora re Amerika', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/so-DJ.ts b/packages/common/locales/so-DJ.ts index a0951eef48..fffa374ce8 100644 --- a/packages/common/locales/so-DJ.ts +++ b/packages/common/locales/so-DJ.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'DJF', 'Fdj', 'Faran Jabuuti', {'BBD': ['DBB', '$'], 'DJF': ['Fdj'], 'JPY': ['JP¥', '¥'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/so-ET.ts b/packages/common/locales/so-ET.ts index 2d693f286c..6d23f0018c 100644 --- a/packages/common/locales/so-ET.ts +++ b/packages/common/locales/so-ET.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'Br', 'Birta Itoobbiya', {'BBD': ['DBB', '$'], 'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/so-KE.ts b/packages/common/locales/so-KE.ts index 0905592cf0..0266a9e1b6 100644 --- a/packages/common/locales/so-KE.ts +++ b/packages/common/locales/so-KE.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingka Kenya', {'BBD': ['DBB', '$'], 'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/so.ts b/packages/common/locales/so.ts index 9b49567cf1..642a7c7d1c 100644 --- a/packages/common/locales/so.ts +++ b/packages/common/locales/so.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'MaL', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SOS', 'S', 'Shilingka Soomaaliya', {'BBD': ['DBB', '$'], 'JPY': ['JP¥', '¥'], 'SOS': ['S'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/sq-MK.ts b/packages/common/locales/sq-MK.ts index 2e92d61740..e2029735a4 100644 --- a/packages/common/locales/sq-MK.ts +++ b/packages/common/locales/sq-MK.ts @@ -47,6 +47,7 @@ export default [ ['{1}, {0}', u, '{1} \'në\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'MKD', 'den', 'Denari maqedonas', { diff --git a/packages/common/locales/sq-XK.ts b/packages/common/locales/sq-XK.ts index 03bb0a8081..5e6bbf9c85 100644 --- a/packages/common/locales/sq-XK.ts +++ b/packages/common/locales/sq-XK.ts @@ -47,6 +47,7 @@ export default [ ['{1}, {0}', u, '{1} \'në\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Euroja', { diff --git a/packages/common/locales/sq.ts b/packages/common/locales/sq.ts index 8ff7ff02e1..05dda19fb2 100644 --- a/packages/common/locales/sq.ts +++ b/packages/common/locales/sq.ts @@ -47,6 +47,7 @@ export default [ ['{1}, {0}', u, '{1} \'në\' {0}', u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'ALL', 'Lekë', 'Leku shqiptar', { diff --git a/packages/common/locales/sr-Cyrl-BA.ts b/packages/common/locales/sr-Cyrl-BA.ts index 577b86d732..02e9f198f2 100644 --- a/packages/common/locales/sr-Cyrl-BA.ts +++ b/packages/common/locales/sr-Cyrl-BA.ts @@ -60,6 +60,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'BAM', 'КМ', 'Босанско-херцеговачка конвертибилна марка', { diff --git a/packages/common/locales/sr-Cyrl-ME.ts b/packages/common/locales/sr-Cyrl-ME.ts index 1b2fede3d8..e7bba8bd2b 100644 --- a/packages/common/locales/sr-Cyrl-ME.ts +++ b/packages/common/locales/sr-Cyrl-ME.ts @@ -60,6 +60,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Евро', { diff --git a/packages/common/locales/sr-Cyrl-XK.ts b/packages/common/locales/sr-Cyrl-XK.ts index bc6d7783b2..35e51c4744 100644 --- a/packages/common/locales/sr-Cyrl-XK.ts +++ b/packages/common/locales/sr-Cyrl-XK.ts @@ -60,6 +60,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Евро', { diff --git a/packages/common/locales/sr-Cyrl.ts b/packages/common/locales/sr-Cyrl.ts index f6d17e5340..3c70504443 100644 --- a/packages/common/locales/sr-Cyrl.ts +++ b/packages/common/locales/sr-Cyrl.ts @@ -61,6 +61,7 @@ export default [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Српски динар', { 'AUD': [u, '$'], diff --git a/packages/common/locales/sr-Latn-BA.ts b/packages/common/locales/sr-Latn-BA.ts index 4b457579e4..8cccf22868 100644 --- a/packages/common/locales/sr-Latn-BA.ts +++ b/packages/common/locales/sr-Latn-BA.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'BAM', 'KM', 'Bosansko-hercegovačka konvertibilna marka', { diff --git a/packages/common/locales/sr-Latn-ME.ts b/packages/common/locales/sr-Latn-ME.ts index 84489ceabd..239e9bfded 100644 --- a/packages/common/locales/sr-Latn-ME.ts +++ b/packages/common/locales/sr-Latn-ME.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Evro', { diff --git a/packages/common/locales/sr-Latn-XK.ts b/packages/common/locales/sr-Latn-XK.ts index 94ded3cecf..8ff241de13 100644 --- a/packages/common/locales/sr-Latn-XK.ts +++ b/packages/common/locales/sr-Latn-XK.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'Evro', { diff --git a/packages/common/locales/sr-Latn.ts b/packages/common/locales/sr-Latn.ts index 98852e876e..5dc7b6605e 100644 --- a/packages/common/locales/sr-Latn.ts +++ b/packages/common/locales/sr-Latn.ts @@ -43,6 +43,7 @@ export default [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Srpski dinar', { 'AUD': [u, '$'], diff --git a/packages/common/locales/sr.ts b/packages/common/locales/sr.ts index 12907accdb..c0dfb289c1 100644 --- a/packages/common/locales/sr.ts +++ b/packages/common/locales/sr.ts @@ -61,6 +61,7 @@ export default [ [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'RSD', + 'RSD', 'Српски динар', { 'AUD': [u, '$'], diff --git a/packages/common/locales/sv-AX.ts b/packages/common/locales/sv-AX.ts index 41d8806d57..83992c1894 100644 --- a/packages/common/locales/sv-AX.ts +++ b/packages/common/locales/sv-AX.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/sv-FI.ts b/packages/common/locales/sv-FI.ts index 82e90fa56f..f383727eca 100644 --- a/packages/common/locales/sv-FI.ts +++ b/packages/common/locales/sv-FI.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', '.'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', '€', 'euro', { diff --git a/packages/common/locales/sv.ts b/packages/common/locales/sv.ts index 2c45793039..859e0d1944 100644 --- a/packages/common/locales/sv.ts +++ b/packages/common/locales/sv.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '−', '×10^', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'SEK', 'kr', 'svensk krona', { diff --git a/packages/common/locales/sw-CD.ts b/packages/common/locales/sw-CD.ts index f100309f4c..0d49637eaf 100644 --- a/packages/common/locales/sw-CD.ts +++ b/packages/common/locales/sw-CD.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'CDF', 'FC', 'Faranga ya Kongo', { diff --git a/packages/common/locales/sw-KE.ts b/packages/common/locales/sw-KE.ts index ebe3557f7b..d4748e4874 100644 --- a/packages/common/locales/sw-KE.ts +++ b/packages/common/locales/sw-KE.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'KES', 'Ksh', 'Shilingi ya Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'THB': ['฿'], 'TWD': ['NT$'], 'TZS': ['TSh']}, diff --git a/packages/common/locales/sw-UG.ts b/packages/common/locales/sw-UG.ts index 711b6e1ff1..347e66386e 100644 --- a/packages/common/locales/sw-UG.ts +++ b/packages/common/locales/sw-UG.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'UGX', 'USh', 'Shilingi ya Uganda', { diff --git a/packages/common/locales/sw.ts b/packages/common/locales/sw.ts index 9cac57d9f0..ec192a0a97 100644 --- a/packages/common/locales/sw.ts +++ b/packages/common/locales/sw.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', { diff --git a/packages/common/locales/ta-LK.ts b/packages/common/locales/ta-LK.ts index 41df40fc92..455efe9adb 100644 --- a/packages/common/locales/ta-LK.ts +++ b/packages/common/locales/ta-LK.ts @@ -64,6 +64,7 @@ export default [ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'LKR', 'Rs.', 'இலங்கை ரூபாய்', {'LKR': ['Rs.', 'Rs'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/ta-MY.ts b/packages/common/locales/ta-MY.ts index c4349ff4eb..5bec786a60 100644 --- a/packages/common/locales/ta-MY.ts +++ b/packages/common/locales/ta-MY.ts @@ -64,6 +64,7 @@ export default [ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'MYR', 'RM', 'மலேஷியன் ரிங்கிட்', {'MYR': ['RM'], 'SGD': ['S$', '$'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/ta-SG.ts b/packages/common/locales/ta-SG.ts index 38e34f36b4..9cc0df4799 100644 --- a/packages/common/locales/ta-SG.ts +++ b/packages/common/locales/ta-SG.ts @@ -64,6 +64,7 @@ export default [ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'SGD', '$', 'சிங்கப்பூர் டாலர்', {'MYR': ['RM'], 'SGD': ['$'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ta.ts b/packages/common/locales/ta.ts index cd587303ec..8c7c71cb2b 100644 --- a/packages/common/locales/ta.ts +++ b/packages/common/locales/ta.ts @@ -64,6 +64,7 @@ export default [ ['{1}, {0}', u, '{1} ’அன்று’ {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##,##0%', '¤ #,##,##0.00', '#E0'], + 'INR', '₹', 'இந்திய ரூபாய்', {'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/te.ts b/packages/common/locales/te.ts index 1ef055176e..cd27a00580 100644 --- a/packages/common/locales/te.ts +++ b/packages/common/locales/te.ts @@ -66,6 +66,7 @@ export default [ ['{1} {0}', u, '{1} {0}కి', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##,##0.###', '#,##0%', '¤#,##,##0.00', '#E0'], + 'INR', '₹', 'రూపాయి', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/teo-KE.ts b/packages/common/locales/teo-KE.ts index d418b79158..fdd51c1977 100644 --- a/packages/common/locales/teo-KE.ts +++ b/packages/common/locales/teo-KE.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'KES', 'Ksh', 'Ango’otol lok’ Kenya', {'JPY': ['JP¥', '¥'], 'KES': ['Ksh'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/teo.ts b/packages/common/locales/teo.ts index 7373123ff2..da57698819 100644 --- a/packages/common/locales/teo.ts +++ b/packages/common/locales/teo.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'UGX', 'USh', 'Ango’otol lok’ Uganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/tg.ts b/packages/common/locales/tg.ts index f5e95fb9e2..a851765ca9 100644 --- a/packages/common/locales/tg.ts +++ b/packages/common/locales/tg.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'TJS', 'сом.', 'Сомонӣ', {'JPY': ['JP¥', '¥'], 'TJS': ['сом.']}, diff --git a/packages/common/locales/th.ts b/packages/common/locales/th.ts index 8225a21954..3e4b59318a 100644 --- a/packages/common/locales/th.ts +++ b/packages/common/locales/th.ts @@ -58,6 +58,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'THB', '฿', 'บาท', {'AUD': ['AU$', '$'], 'THB': ['฿'], 'TWD': ['NT$'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/ti-ER.ts b/packages/common/locales/ti-ER.ts index fd4e23321e..350fbb7d05 100644 --- a/packages/common/locales/ti-ER.ts +++ b/packages/common/locales/ti-ER.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ERN', 'Nfk', 'ERN', {'ERN': ['Nfk'], 'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/ti.ts b/packages/common/locales/ti.ts index fe7ce8f086..04e423edfd 100644 --- a/packages/common/locales/ti.ts +++ b/packages/common/locales/ti.ts @@ -52,6 +52,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ETB', 'Br', 'የኢትዮጵያ ብር', {'ETB': ['Br'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/tk.ts b/packages/common/locales/tk.ts index 08e05076c4..9142c44911 100644 --- a/packages/common/locales/tk.ts +++ b/packages/common/locales/tk.ts @@ -55,6 +55,7 @@ export default [ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'san däl', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], 'TMT', + 'TMT', 'Türkmen manady', {'EUR': [u, '€'], 'GBP': [u, '£'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/to.ts b/packages/common/locales/to.ts index 1ef094bd09..2c020a0238 100644 --- a/packages/common/locales/to.ts +++ b/packages/common/locales/to.ts @@ -44,6 +44,7 @@ export default [ ['{1} {0}', '{1}, {0}', u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'TF', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'TOP', 'T$', 'Paʻanga fakatonga', { diff --git a/packages/common/locales/tr-CY.ts b/packages/common/locales/tr-CY.ts index bc99d2bfb9..0989f5ca68 100644 --- a/packages/common/locales/tr-CY.ts +++ b/packages/common/locales/tr-CY.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '%#,##0', '¤#,##0.00', '#E0'], + 'EUR', '€', 'Euro', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'THB': ['฿'], 'TRY': ['₺'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/tr.ts b/packages/common/locales/tr.ts index 6718eb13dd..889a3fb972 100644 --- a/packages/common/locales/tr.ts +++ b/packages/common/locales/tr.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '%#,##0', '¤#,##0.00', '#E0'], + 'TRY', '₺', 'Türk Lirası', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'THB': ['฿'], 'TRY': ['₺'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/tt.ts b/packages/common/locales/tt.ts index c5a522efde..7936ac3e2c 100644 --- a/packages/common/locales/tt.ts +++ b/packages/common/locales/tt.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'RUB', '₽', 'Россия сумы', {'JPY': ['JP¥', '¥'], 'RUB': ['₽']}, diff --git a/packages/common/locales/twq.ts b/packages/common/locales/twq.ts index b72a0cc790..c17442b537 100644 --- a/packages/common/locales/twq.ts +++ b/packages/common/locales/twq.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00¤', '#E0'], + 'XOF', 'CFA', 'CFA Fraŋ (BCEAO)', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/tzm.ts b/packages/common/locales/tzm.ts index 186eb6ab10..5d482ce275 100644 --- a/packages/common/locales/tzm.ts +++ b/packages/common/locales/tzm.ts @@ -45,6 +45,7 @@ export default [ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], 'MAD', + 'MAD', 'Derhem Umeṛṛuki', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/ug.ts b/packages/common/locales/ug.ts index 4db3d9e200..be7328a798 100644 --- a/packages/common/locales/ug.ts +++ b/packages/common/locales/ug.ts @@ -48,6 +48,7 @@ export default [ ['{1}، {0}', u, '{1} {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', 'جۇڭگو يۈەنى', {'CNY': ['¥', '¥'], 'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/uk.ts b/packages/common/locales/uk.ts index 4b3a41c266..d157003dbe 100644 --- a/packages/common/locales/uk.ts +++ b/packages/common/locales/uk.ts @@ -73,6 +73,7 @@ export default [ ['{1}, {0}', u, '{1} \'о\' {0}', u], [',', ' ', ';', '%', '+', '-', 'Е', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UAH', '₴', 'українська гривня', { diff --git a/packages/common/locales/ur-IN.ts b/packages/common/locales/ur-IN.ts index 32734a2106..b0d7d366c9 100644 --- a/packages/common/locales/ur-IN.ts +++ b/packages/common/locales/ur-IN.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'INR', '₹', 'بھارتی روپیہ', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/ur.ts b/packages/common/locales/ur.ts index 898d179479..aefc098d5a 100644 --- a/packages/common/locales/ur.ts +++ b/packages/common/locales/ur.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '\u200e+', '\u200e-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'PKR', 'Rs', 'پاکستانی روپیہ', {'JPY': ['JP¥', '¥'], 'PKR': ['Rs'], 'THB': ['฿'], 'TWD': ['NT$']}, diff --git a/packages/common/locales/uz-Arab.ts b/packages/common/locales/uz-Arab.ts index c523a902d6..2a6d7f16df 100644 --- a/packages/common/locales/uz-Arab.ts +++ b/packages/common/locales/uz-Arab.ts @@ -48,6 +48,7 @@ export default [ ['{1} {0}', u, u, u], [',', '.', ';', '%', '\u200e+', '\u200e−', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'AFN', '؋', 'افغانی', {'AFN': ['؋'], 'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/uz-Cyrl.ts b/packages/common/locales/uz-Cyrl.ts index 3a527cdbb8..38b34e53af 100644 --- a/packages/common/locales/uz-Cyrl.ts +++ b/packages/common/locales/uz-Cyrl.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'ҳақиқий сон эмас', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UZS', 'сўм', 'Ўзбекистон сўм', {'JPY': ['JP¥', '¥'], 'THB': ['฿'], 'USD': ['US$', '$'], 'UZS': ['сўм']}, diff --git a/packages/common/locales/uz-Latn.ts b/packages/common/locales/uz-Latn.ts index f95327e939..48b3952024 100644 --- a/packages/common/locales/uz-Latn.ts +++ b/packages/common/locales/uz-Latn.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'son emas', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UZS', 'soʻm', 'O‘zbekiston so‘mi', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'UZS': ['soʻm']}, diff --git a/packages/common/locales/uz.ts b/packages/common/locales/uz.ts index b6aa7d0845..b291a24272 100644 --- a/packages/common/locales/uz.ts +++ b/packages/common/locales/uz.ts @@ -50,6 +50,7 @@ export default [ ['{1}, {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'son emas', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UZS', 'soʻm', 'O‘zbekiston so‘mi', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'UZS': ['soʻm']}, diff --git a/packages/common/locales/vai-Latn.ts b/packages/common/locales/vai-Latn.ts index 8aff1548b4..0f1d7aea98 100644 --- a/packages/common/locales/vai-Latn.ts +++ b/packages/common/locales/vai-Latn.ts @@ -41,6 +41,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'Laibhiya Dala', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/vai-Vaii.ts b/packages/common/locales/vai-Vaii.ts index 8dd1148cc6..5ed1b1a78d 100644 --- a/packages/common/locales/vai-Vaii.ts +++ b/packages/common/locales/vai-Vaii.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'ꕞꔤꔫꕩ ꕜꕞꕌ', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/vai.ts b/packages/common/locales/vai.ts index 808ddbde9f..69ce4967c0 100644 --- a/packages/common/locales/vai.ts +++ b/packages/common/locales/vai.ts @@ -49,6 +49,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'LRD', '$', 'ꕞꔤꔫꕩ ꕜꕞꕌ', {'JPY': ['JP¥', '¥'], 'LRD': ['$'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/vi.ts b/packages/common/locales/vi.ts index ee3629ee60..caca8af16d 100644 --- a/packages/common/locales/vi.ts +++ b/packages/common/locales/vi.ts @@ -59,6 +59,7 @@ export default [ ['{0}, {1}', u, '{0} {1}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'VND', '₫', 'Đồng Việt Nam', { diff --git a/packages/common/locales/vo.ts b/packages/common/locales/vo.ts index 1357be8e0d..018d198ea7 100644 --- a/packages/common/locales/vo.ts +++ b/packages/common/locales/vo.ts @@ -37,6 +37,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', plural diff --git a/packages/common/locales/vun.ts b/packages/common/locales/vun.ts index 735ab077e1..96874c5147 100644 --- a/packages/common/locales/vun.ts +++ b/packages/common/locales/vun.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TZS', 'TSh', 'Shilingi ya Tanzania', {'JPY': ['JP¥', '¥'], 'TZS': ['TSh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/wae.ts b/packages/common/locales/wae.ts index 74505c7d15..34e97e1d07 100644 --- a/packages/common/locales/wae.ts +++ b/packages/common/locales/wae.ts @@ -45,6 +45,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], 'CHF', 'CHF', + 'CHF', {}, 'ltr', plural diff --git a/packages/common/locales/wo.ts b/packages/common/locales/wo.ts index 1363d4677c..0458cceb68 100644 --- a/packages/common/locales/wo.ts +++ b/packages/common/locales/wo.ts @@ -42,6 +42,7 @@ export default [ ['{1} - {0}', u, '{1} \'ci\' {0}', u], [',', '.', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], + 'XOF', 'CFA', 'Franc CFA bu Afrik Sowwu-jant', {'JPY': ['JP¥', '¥']}, diff --git a/packages/common/locales/xh.ts b/packages/common/locales/xh.ts index cdf2c2968a..c252edc997 100644 --- a/packages/common/locales/xh.ts +++ b/packages/common/locales/xh.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'iRandi yaseMzanzi Afrika', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$'], 'ZAR': ['R']}, diff --git a/packages/common/locales/xog.ts b/packages/common/locales/xog.ts index a3b0373053..f37edfe92c 100644 --- a/packages/common/locales/xog.ts +++ b/packages/common/locales/xog.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'UGX', 'USh', 'Silingi eya Yuganda', {'JPY': ['JP¥', '¥'], 'UGX': ['USh'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/yav.ts b/packages/common/locales/yav.ts index 572a06349e..50c4fd78eb 100644 --- a/packages/common/locales/yav.ts +++ b/packages/common/locales/yav.ts @@ -47,6 +47,7 @@ export default [ ['{1} {0}', u, u, u], [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '#,##0.00 ¤', '#E0'], + 'XAF', 'FCFA', 'XAF', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, diff --git a/packages/common/locales/yi.ts b/packages/common/locales/yi.ts index 319e2b6682..fc9172a88f 100644 --- a/packages/common/locales/yi.ts +++ b/packages/common/locales/yi.ts @@ -61,6 +61,7 @@ export default [ ['#,##0.###', '#,##0%', '¤ #,##0.00', '#E0'], u, u, + u, {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'rtl', plural diff --git a/packages/common/locales/yo-BJ.ts b/packages/common/locales/yo-BJ.ts index c826af729d..638e56e01f 100644 --- a/packages/common/locales/yo-BJ.ts +++ b/packages/common/locales/yo-BJ.ts @@ -61,6 +61,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'XOF', 'CFA', 'Faransi ti Orílɛ́ède BIKEAO', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'RUB': ['₽']}, diff --git a/packages/common/locales/yo.ts b/packages/common/locales/yo.ts index 6cdd503027..c69310c89d 100644 --- a/packages/common/locales/yo.ts +++ b/packages/common/locales/yo.ts @@ -65,6 +65,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'NGN', '₦', 'Náìrà ti Orílẹ̀-èdè Nàìjíríà', {'JPY': ['JP¥', '¥'], 'NGN': ['₦'], 'RUB': ['₽']}, diff --git a/packages/common/locales/yue-Hans.ts b/packages/common/locales/yue-Hans.ts index 6c0ad0c46f..56e26f03b1 100644 --- a/packages/common/locales/yue-Hans.ts +++ b/packages/common/locales/yue-Hans.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非数值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { diff --git a/packages/common/locales/yue-Hant.ts b/packages/common/locales/yue-Hant.ts index 3f48bffe45..ac867b32d9 100644 --- a/packages/common/locales/yue-Hant.ts +++ b/packages/common/locales/yue-Hant.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港幣', {'AUD': ['AU$', '$'], 'KRW': ['₩', '₩'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/yue.ts b/packages/common/locales/yue.ts index 51a34fdfcb..08f326a867 100644 --- a/packages/common/locales/yue.ts +++ b/packages/common/locales/yue.ts @@ -42,6 +42,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港幣', {'AUD': ['AU$', '$'], 'KRW': ['₩', '₩'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/zgh.ts b/packages/common/locales/zgh.ts index 7128b301d9..3317707160 100644 --- a/packages/common/locales/zgh.ts +++ b/packages/common/locales/zgh.ts @@ -60,6 +60,7 @@ export default [ [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0 %', '#,##0.00¤', '#E0'], 'MAD', + 'MAD', 'ⴰⴷⵔⵉⵎ ⵏ ⵍⵎⵖⵔⵉⴱ', {'JPY': ['JP¥', '¥'], 'USD': ['US$', '$']}, 'ltr', diff --git a/packages/common/locales/zh-Hans-HK.ts b/packages/common/locales/zh-Hans-HK.ts index 203ec30e6a..28a1957cb0 100644 --- a/packages/common/locales/zh-Hans-HK.ts +++ b/packages/common/locales/zh-Hans-HK.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港元', { diff --git a/packages/common/locales/zh-Hans-MO.ts b/packages/common/locales/zh-Hans-MO.ts index 649431a401..2b4fc24d1b 100644 --- a/packages/common/locales/zh-Hans-MO.ts +++ b/packages/common/locales/zh-Hans-MO.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MOP', 'MOP$', '澳门币', { diff --git a/packages/common/locales/zh-Hans-SG.ts b/packages/common/locales/zh-Hans-SG.ts index 18df7c88a0..3b33f60030 100644 --- a/packages/common/locales/zh-Hans-SG.ts +++ b/packages/common/locales/zh-Hans-SG.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'SGD', '$', '新加坡元', { diff --git a/packages/common/locales/zh-Hans.ts b/packages/common/locales/zh-Hans.ts index c7c86751d5..4644e69b79 100644 --- a/packages/common/locales/zh-Hans.ts +++ b/packages/common/locales/zh-Hans.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { diff --git a/packages/common/locales/zh-Hant-HK.ts b/packages/common/locales/zh-Hant-HK.ts index c203048fbf..643cfa6e9d 100644 --- a/packages/common/locales/zh-Hant-HK.ts +++ b/packages/common/locales/zh-Hant-HK.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'HKD', 'HK$', '港元', {'AUD': ['AU$', '$'], 'RON': [u, 'L'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/zh-Hant-MO.ts b/packages/common/locales/zh-Hant-MO.ts index 6735b252b9..c614f4cd08 100644 --- a/packages/common/locales/zh-Hant-MO.ts +++ b/packages/common/locales/zh-Hant-MO.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'MOP', 'MOP$', '澳門元', {'AUD': ['AU$', '$'], 'MOP': ['MOP$'], 'RON': [u, 'L'], 'USD': ['US$', '$'], 'XXX': []}, diff --git a/packages/common/locales/zh-Hant.ts b/packages/common/locales/zh-Hant.ts index 879c0adf04..50aabcd43b 100644 --- a/packages/common/locales/zh-Hant.ts +++ b/packages/common/locales/zh-Hant.ts @@ -43,6 +43,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', '非數值', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'TWD', '$', '新台幣', { diff --git a/packages/common/locales/zh.ts b/packages/common/locales/zh.ts index dc49281ce8..8d904a31b1 100644 --- a/packages/common/locales/zh.ts +++ b/packages/common/locales/zh.ts @@ -46,6 +46,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'CNY', '¥', '人民币', { diff --git a/packages/common/locales/zu.ts b/packages/common/locales/zu.ts index 9391debc2c..d435cf36b6 100644 --- a/packages/common/locales/zu.ts +++ b/packages/common/locales/zu.ts @@ -51,6 +51,7 @@ export default [ ['{1} {0}', u, u, u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'ZAR', 'R', 'i-South African Rand', { diff --git a/packages/common/src/common.ts b/packages/common/src/common.ts index 9e0763cd87..e9be42668a 100644 --- a/packages/common/src/common.ts +++ b/packages/common/src/common.ts @@ -17,10 +17,10 @@ export {formatDate} from './i18n/format_date'; export {formatCurrency, formatNumber, formatPercent} from './i18n/format_number'; export {NgLocaleLocalization, NgLocalization} from './i18n/localization'; export {registerLocaleData} from './i18n/locale_data'; -export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getNumberOfCurrencyDigits, getCurrencySymbol, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyName, getLocaleCurrencySymbol, getLocaleDirection} from './i18n/locale_data_api'; +export {Plural, NumberFormatStyle, FormStyle, Time, TranslationWidth, FormatWidth, NumberSymbol, WeekDay, getNumberOfCurrencyDigits, getCurrencySymbol, getLocaleDayPeriods, getLocaleDayNames, getLocaleMonthNames, getLocaleId, getLocaleEraNames, getLocaleWeekEndRange, getLocaleFirstDayOfWeek, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocalePluralCase, getLocaleTimeFormat, getLocaleNumberSymbol, getLocaleNumberFormat, getLocaleCurrencyCode, getLocaleCurrencyName, getLocaleCurrencySymbol, getLocaleDirection} from './i18n/locale_data_api'; export {parseCookieValue as ɵparseCookieValue} from './cookie'; export {CommonModule} from './common_module'; -export {NgClass, NgClassBase, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgStyleBase, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index'; +export {NgClass, NgForOf, NgForOfContext, NgIf, NgIfContext, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NgComponentOutlet} from './directives/index'; export {DOCUMENT} from './dom_tokens'; export {AsyncPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, LowerCasePipe, CurrencyPipe, DecimalPipe, PercentPipe, SlicePipe, UpperCasePipe, TitleCasePipe, KeyValuePipe, KeyValue} from './pipes/index'; export {PLATFORM_BROWSER_ID as ɵPLATFORM_BROWSER_ID, PLATFORM_SERVER_ID as ɵPLATFORM_SERVER_ID, PLATFORM_WORKER_APP_ID as ɵPLATFORM_WORKER_APP_ID, PLATFORM_WORKER_UI_ID as ɵPLATFORM_WORKER_UI_ID, isPlatformBrowser, isPlatformServer, isPlatformWorkerApp, isPlatformWorkerUi} from './platform_id'; diff --git a/packages/common/src/directives/index.ts b/packages/common/src/directives/index.ts index 214e2f9aa5..c776cb8ee2 100644 --- a/packages/common/src/directives/index.ts +++ b/packages/common/src/directives/index.ts @@ -7,18 +7,17 @@ */ import {Provider} from '@angular/core'; -import {NgClass, NgClassBase} from './ng_class'; +import {NgClass} from './ng_class'; import {NgComponentOutlet} from './ng_component_outlet'; import {NgForOf, NgForOfContext} from './ng_for_of'; import {NgIf, NgIfContext} from './ng_if'; import {NgPlural, NgPluralCase} from './ng_plural'; -import {NgStyle, NgStyleBase} from './ng_style'; +import {NgStyle} from './ng_style'; import {NgSwitch, NgSwitchCase, NgSwitchDefault} from './ng_switch'; import {NgTemplateOutlet} from './ng_template_outlet'; export { NgClass, - NgClassBase, NgComponentOutlet, NgForOf, NgForOfContext, @@ -27,7 +26,6 @@ export { NgPlural, NgPluralCase, NgStyle, - NgStyleBase, NgSwitch, NgSwitchCase, NgSwitchDefault, diff --git a/packages/common/src/directives/ng_class.ts b/packages/common/src/directives/ng_class.ts index 84588a9b07..5cea65d224 100644 --- a/packages/common/src/directives/ng_class.ts +++ b/packages/common/src/directives/ng_class.ts @@ -5,71 +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 {Directive, DoCheck, Input, ɵRenderFlags, ɵɵallocHostVars, ɵɵclassMap, ɵɵdefineDirective} from '@angular/core'; +import {Directive, DoCheck, ElementRef, Input, IterableChanges, IterableDiffer, IterableDiffers, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer2, ɵisListLikeIterable as isListLikeIterable, ɵstringify as stringify} from '@angular/core'; -import {NgClassImpl, NgClassImplProvider} from './ng_class_impl'; - - - -/* - * NgClass (as well as NgStyle) behaves differently when loaded in the VE and when not. - * - * If the VE is present (which is for older versions of Angular) then NgClass will inject - * the legacy diffing algorithm as a service and delegate all styling changes to that. - * - * If the VE is not present then NgStyle will normalize (through the injected service) and - * then write all styling changes to the `[style]` binding directly (through a host binding). - * Then Angular will notice the host binding change and treat the changes as styling - * changes and apply them via the core styling instructions that exist within Angular. - */ - -// used when the VE is present -export const ngClassDirectiveDef__PRE_R3__ = undefined; - -// used when the VE is not present (note the directive will -// never be instantiated normally because it is apart of a -// base class) -export const ngClassDirectiveDef__POST_R3__ = ɵɵdefineDirective({ - type: function() {} as any, - selectors: null as any, - hostBindings: function(rf: ɵRenderFlags, ctx: any, elIndex: number) { - if (rf & ɵRenderFlags.Create) { - ɵɵallocHostVars(2); - } - if (rf & ɵRenderFlags.Update) { - ɵɵclassMap(ctx.getValue()); - } - } -}); - -export const ngClassDirectiveDef = ngClassDirectiveDef__PRE_R3__; - -export const ngClassFactoryDef__PRE_R3__ = undefined; -export const ngClassFactoryDef__POST_R3__ = function() {}; -export const ngClassFactoryDef = ngClassFactoryDef__PRE_R3__; - -/** - * Serves as the base non-VE container for NgClass. - * - * While this is a base class that NgClass extends from, the - * class itself acts as a container for non-VE code to setup - * a link to the `[class]` host binding (via the static - * `ɵdir` property on the class). - * - * Note that the `ɵdir` property's code is switched - * depending if VE is present or not (this allows for the - * binding code to be set only for newer versions of Angular). - * - * @publicApi - */ -export class NgClassBase { - static ɵdir: any = ngClassDirectiveDef; - static ɵfac: any = ngClassFactoryDef; - - constructor(protected _delegate: NgClassImpl) {} - - getValue() { return this._delegate.getValue(); } -} +type NgClassSupportedTypes = string[] | Set| {[klass: string]: any} | null | undefined; /** * @ngModule CommonModule @@ -112,17 +50,124 @@ export class NgClassBase { * * @publicApi */ -@Directive({selector: '[ngClass]', providers: [NgClassImplProvider]}) -export class NgClass extends NgClassBase implements DoCheck { - constructor(delegate: NgClassImpl) { super(delegate); } +@Directive({selector: '[ngClass]'}) +export class NgClass implements DoCheck { + private _iterableDiffer: IterableDiffer|null = null; + private _keyValueDiffer: KeyValueDiffer|null = null; + private _initialClasses: string[] = []; + private _rawClass: NgClassSupportedTypes = null; + + constructor( + private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers, + private _ngEl: ElementRef, private _renderer: Renderer2) {} + @Input('class') - set klass(value: string) { this._delegate.setClass(value); } + set klass(value: string) { + this._removeClasses(this._initialClasses); + this._initialClasses = typeof value === 'string' ? value.split(/\s+/) : []; + this._applyClasses(this._initialClasses); + this._applyClasses(this._rawClass); + } @Input('ngClass') set ngClass(value: string|string[]|Set|{[klass: string]: any}) { - this._delegate.setNgClass(value); + this._removeClasses(this._rawClass); + this._applyClasses(this._initialClasses); + + this._iterableDiffer = null; + this._keyValueDiffer = null; + + this._rawClass = typeof value === 'string' ? value.split(/\s+/) : value; + + if (this._rawClass) { + if (isListLikeIterable(this._rawClass)) { + this._iterableDiffer = this._iterableDiffers.find(this._rawClass).create(); + } else { + this._keyValueDiffer = this._keyValueDiffers.find(this._rawClass).create(); + } + } } - ngDoCheck() { this._delegate.applyChanges(); } + ngDoCheck() { + if (this._iterableDiffer) { + const iterableChanges = this._iterableDiffer.diff(this._rawClass as string[]); + if (iterableChanges) { + this._applyIterableChanges(iterableChanges); + } + } else if (this._keyValueDiffer) { + const keyValueChanges = this._keyValueDiffer.diff(this._rawClass as{[k: string]: any}); + if (keyValueChanges) { + this._applyKeyValueChanges(keyValueChanges); + } + } + } + + private _applyKeyValueChanges(changes: KeyValueChanges): void { + changes.forEachAddedItem((record) => this._toggleClass(record.key, record.currentValue)); + changes.forEachChangedItem((record) => this._toggleClass(record.key, record.currentValue)); + changes.forEachRemovedItem((record) => { + if (record.previousValue) { + this._toggleClass(record.key, false); + } + }); + } + + private _applyIterableChanges(changes: IterableChanges): void { + changes.forEachAddedItem((record) => { + if (typeof record.item === 'string') { + this._toggleClass(record.item, true); + } else { + throw new Error( + `NgClass can only toggle CSS classes expressed as strings, got ${stringify(record.item)}`); + } + }); + + changes.forEachRemovedItem((record) => this._toggleClass(record.item, false)); + } + + /** + * Applies a collection of CSS classes to the DOM element. + * + * For argument of type Set and Array CSS class names contained in those collections are always + * added. + * For argument of type Map CSS class name in the map's key is toggled based on the value (added + * for truthy and removed for falsy). + */ + private _applyClasses(rawClassVal: NgClassSupportedTypes) { + if (rawClassVal) { + if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) { + (rawClassVal).forEach((klass: string) => this._toggleClass(klass, true)); + } else { + Object.keys(rawClassVal).forEach(klass => this._toggleClass(klass, !!rawClassVal[klass])); + } + } + } + + /** + * Removes a collection of CSS classes from the DOM element. This is mostly useful for cleanup + * purposes. + */ + private _removeClasses(rawClassVal: NgClassSupportedTypes) { + if (rawClassVal) { + if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) { + (rawClassVal).forEach((klass: string) => this._toggleClass(klass, false)); + } else { + Object.keys(rawClassVal).forEach(klass => this._toggleClass(klass, false)); + } + } + } + + private _toggleClass(klass: string, enabled: boolean): void { + klass = klass.trim(); + if (klass) { + klass.split(/\s+/g).forEach(klass => { + if (enabled) { + this._renderer.addClass(this._ngEl.nativeElement, klass); + } else { + this._renderer.removeClass(this._ngEl.nativeElement, klass); + } + }); + } + } } diff --git a/packages/common/src/directives/ng_class_impl.ts b/packages/common/src/directives/ng_class_impl.ts deleted file mode 100644 index ef48b17292..0000000000 --- a/packages/common/src/directives/ng_class_impl.ts +++ /dev/null @@ -1,208 +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 {ElementRef, Injectable, IterableChanges, IterableDiffer, IterableDiffers, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer2, ɵisListLikeIterable as isListLikeIterable, ɵstringify as stringify} from '@angular/core'; - -import {StylingDiffer, StylingDifferOptions} from './styling_differ'; - -/** - * Used as a token for an injected service within the NgClass directive. - * - * NgClass behaves differenly whether or not VE is being used or not. If - * present then the legacy ngClass diffing algorithm will be used as an - * injected service. Otherwise the new diffing algorithm (which delegates - * to the `[class]` binding) will be used. This toggle behavior is done so - * via the ivy_switch mechanism. - */ -export abstract class NgClassImpl { - abstract setClass(value: string): void; - abstract setNgClass(value: string|string[]|Set|{[klass: string]: any}): void; - abstract applyChanges(): void; - abstract getValue(): {[key: string]: any}|null; -} - -@Injectable() -export class NgClassR2Impl implements NgClassImpl { - // TODO(issue/24571): remove '!'. - private _iterableDiffer !: IterableDiffer| null; - // TODO(issue/24571): remove '!'. - private _keyValueDiffer !: KeyValueDiffer| null; - private _initialClasses: string[] = []; - // TODO(issue/24571): remove '!'. - private _rawClass !: string[] | Set| {[klass: string]: any}; - - constructor( - private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers, - private _ngEl: ElementRef, private _renderer: Renderer2) {} - - getValue() { return null; } - - setClass(value: string) { - this._removeClasses(this._initialClasses); - this._initialClasses = typeof value === 'string' ? value.split(/\s+/) : []; - this._applyClasses(this._initialClasses); - this._applyClasses(this._rawClass); - } - - setNgClass(value: string) { - this._removeClasses(this._rawClass); - this._applyClasses(this._initialClasses); - - this._iterableDiffer = null; - this._keyValueDiffer = null; - - this._rawClass = typeof value === 'string' ? value.split(/\s+/) : value; - - if (this._rawClass) { - if (isListLikeIterable(this._rawClass)) { - this._iterableDiffer = this._iterableDiffers.find(this._rawClass).create(); - } else { - this._keyValueDiffer = this._keyValueDiffers.find(this._rawClass).create(); - } - } - } - - applyChanges() { - if (this._iterableDiffer) { - const iterableChanges = this._iterableDiffer.diff(this._rawClass as string[]); - if (iterableChanges) { - this._applyIterableChanges(iterableChanges); - } - } else if (this._keyValueDiffer) { - const keyValueChanges = this._keyValueDiffer.diff(this._rawClass as{[k: string]: any}); - if (keyValueChanges) { - this._applyKeyValueChanges(keyValueChanges); - } - } - } - - private _applyKeyValueChanges(changes: KeyValueChanges): void { - changes.forEachAddedItem((record) => this._toggleClass(record.key, record.currentValue)); - changes.forEachChangedItem((record) => this._toggleClass(record.key, record.currentValue)); - changes.forEachRemovedItem((record) => { - if (record.previousValue) { - this._toggleClass(record.key, false); - } - }); - } - - private _applyIterableChanges(changes: IterableChanges): void { - changes.forEachAddedItem((record) => { - if (typeof record.item === 'string') { - this._toggleClass(record.item, true); - } else { - throw new Error( - `NgClass can only toggle CSS classes expressed as strings, got ${stringify(record.item)}`); - } - }); - - changes.forEachRemovedItem((record) => this._toggleClass(record.item, false)); - } - - /** - * Applies a collection of CSS classes to the DOM element. - * - * For argument of type Set and Array CSS class names contained in those collections are always - * added. - * For argument of type Map CSS class name in the map's key is toggled based on the value (added - * for truthy and removed for falsy). - */ - private _applyClasses(rawClassVal: string[]|Set|{[klass: string]: any}) { - if (rawClassVal) { - if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) { - (rawClassVal).forEach((klass: string) => this._toggleClass(klass, true)); - } else { - Object.keys(rawClassVal).forEach(klass => this._toggleClass(klass, !!rawClassVal[klass])); - } - } - } - - /** - * Removes a collection of CSS classes from the DOM element. This is mostly useful for cleanup - * purposes. - */ - private _removeClasses(rawClassVal: string[]|Set|{[klass: string]: any}) { - if (rawClassVal) { - if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) { - (rawClassVal).forEach((klass: string) => this._toggleClass(klass, false)); - } else { - Object.keys(rawClassVal).forEach(klass => this._toggleClass(klass, false)); - } - } - } - - private _toggleClass(klass: string, enabled: boolean): void { - klass = klass.trim(); - if (klass) { - klass.split(/\s+/g).forEach(klass => { - if (enabled) { - this._renderer.addClass(this._ngEl.nativeElement, klass); - } else { - this._renderer.removeClass(this._ngEl.nativeElement, klass); - } - }); - } - } -} - -@Injectable() -export class NgClassR3Impl implements NgClassImpl { - private _value: {[key: string]: boolean}|null = null; - private _ngClassDiffer = new StylingDiffer<{[key: string]: boolean}|null>( - 'NgClass', StylingDifferOptions.TrimProperties| - StylingDifferOptions.AllowSubKeys| - StylingDifferOptions.AllowStringValue|StylingDifferOptions.ForceAsMap); - private _classStringDiffer: StylingDiffer<{[key: string]: boolean}>|null = null; - - getValue() { return this._value; } - - setClass(value: string) { - // early exit incase the binding gets emitted as an empty value which - // means there is no reason to instantiate and diff the values... - if (!value && !this._classStringDiffer) return; - - this._classStringDiffer = this._classStringDiffer || - new StylingDiffer('class', - StylingDifferOptions.AllowStringValue | StylingDifferOptions.ForceAsMap); - this._classStringDiffer.setValue(value); - } - - setNgClass(value: string|string[]|Set|{[klass: string]: any}) { - this._ngClassDiffer.setValue(value); - } - - applyChanges() { - const classChanged = - this._classStringDiffer ? this._classStringDiffer.hasValueChanged() : false; - const ngClassChanged = this._ngClassDiffer.hasValueChanged(); - if (classChanged || ngClassChanged) { - let value = this._ngClassDiffer.value; - if (this._classStringDiffer) { - let classValue = this._classStringDiffer.value; - if (classValue) { - value = value ? {...classValue, ...value} : classValue; - } - } - this._value = value; - } - } -} - -// the implementation for both NgStyleR2Impl and NgStyleR3Impl are -// not ivy_switch'd away, instead they are only hooked up into the -// DI via NgStyle's directive's provider property. -export const NgClassImplProvider__PRE_R3__ = { - provide: NgClassImpl, - useClass: NgClassR2Impl -}; - -export const NgClassImplProvider__POST_R3__ = { - provide: NgClassImpl, - useClass: NgClassR3Impl -}; - -export const NgClassImplProvider = NgClassImplProvider__PRE_R3__; diff --git a/packages/common/src/directives/ng_style.ts b/packages/common/src/directives/ng_style.ts index 137f13a0cb..899ece0087 100644 --- a/packages/common/src/directives/ng_style.ts +++ b/packages/common/src/directives/ng_style.ts @@ -5,71 +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 {Directive, DoCheck, Input, ɵRenderFlags, ɵɵallocHostVars, ɵɵdefineDirective, ɵɵstyleMap} from '@angular/core'; +import {Directive, DoCheck, ElementRef, Input, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer2} from '@angular/core'; -import {NgStyleImpl, NgStyleImplProvider} from './ng_style_impl'; - - - -/* - * NgStyle (as well as NgClass) behaves differently when loaded in the VE and when not. - * - * If the VE is present (which is for older versions of Angular) then NgStyle will inject - * the legacy diffing algorithm as a service and delegate all styling changes to that. - * - * If the VE is not present then NgStyle will normalize (through the injected service) and - * then write all styling changes to the `[style]` binding directly (through a host binding). - * Then Angular will notice the host binding change and treat the changes as styling - * changes and apply them via the core styling instructions that exist within Angular. - */ - -// used when the VE is present -export const ngStyleDirectiveDef__PRE_R3__ = undefined; -export const ngStyleFactoryDef__PRE_R3__ = undefined; - -// used when the VE is not present (note the directive will -// never be instantiated normally because it is apart of a -// base class) -export const ngStyleDirectiveDef__POST_R3__ = ɵɵdefineDirective({ - type: function() {} as any, - selectors: null as any, - hostBindings: function(rf: ɵRenderFlags, ctx: any, elIndex: number) { - if (rf & ɵRenderFlags.Create) { - ɵɵallocHostVars(2); - } - if (rf & ɵRenderFlags.Update) { - ɵɵstyleMap(ctx.getValue()); - } - } -}); - -export const ngStyleFactoryDef__POST_R3__ = function() {}; - -export const ngStyleDirectiveDef = ngStyleDirectiveDef__PRE_R3__; -export const ngStyleFactoryDef = ngStyleDirectiveDef__PRE_R3__; - -/** - * Serves as the base non-VE container for NgStyle. - * - * While this is a base class that NgStyle extends from, the - * class itself acts as a container for non-VE code to setup - * a link to the `[style]` host binding (via the static - * `ɵdir` property on the class). - * - * Note that the `ɵdir` property's code is switched - * depending if VE is present or not (this allows for the - * binding code to be set only for newer versions of Angular). - * - * @publicApi - */ -export class NgStyleBase { - static ɵdir: any = ngStyleDirectiveDef; - static ɵfac: any = ngStyleFactoryDef; - - constructor(protected _delegate: NgStyleImpl) {} - - getValue() { return this._delegate.getValue(); } -} /** * @ngModule CommonModule @@ -109,12 +46,45 @@ export class NgStyleBase { * * @publicApi */ -@Directive({selector: '[ngStyle]', providers: [NgStyleImplProvider]}) -export class NgStyle extends NgStyleBase implements DoCheck { - constructor(delegate: NgStyleImpl) { super(delegate); } +@Directive({selector: '[ngStyle]'}) +export class NgStyle implements DoCheck { + private _ngStyle: {[key: string]: string}|null = null; + private _differ: KeyValueDiffer|null = null; + + constructor( + private _ngEl: ElementRef, private _differs: KeyValueDiffers, private _renderer: Renderer2) {} @Input('ngStyle') - set ngStyle(value: {[klass: string]: any}|null) { this._delegate.setNgStyle(value); } + set ngStyle(values: {[klass: string]: any}|null) { + this._ngStyle = values; + if (!this._differ && values) { + this._differ = this._differs.find(values).create(); + } + } - ngDoCheck() { this._delegate.applyChanges(); } + ngDoCheck() { + if (this._differ) { + const changes = this._differ.diff(this._ngStyle !); + if (changes) { + this._applyChanges(changes); + } + } + } + + private _setStyle(nameAndUnit: string, value: string|number|null|undefined): void { + const [name, unit] = nameAndUnit.split('.'); + value = value != null && unit ? `${value}${unit}` : value; + + if (value != null) { + this._renderer.setStyle(this._ngEl.nativeElement, name, value as string); + } else { + this._renderer.removeStyle(this._ngEl.nativeElement, name); + } + } + + private _applyChanges(changes: KeyValueChanges): void { + changes.forEachRemovedItem((record) => this._setStyle(record.key, null)); + changes.forEachAddedItem((record) => this._setStyle(record.key, record.currentValue)); + changes.forEachChangedItem((record) => this._setStyle(record.key, record.currentValue)); + } } diff --git a/packages/common/src/directives/ng_style_impl.ts b/packages/common/src/directives/ng_style_impl.ts deleted file mode 100644 index 5c0e87566d..0000000000 --- a/packages/common/src/directives/ng_style_impl.ts +++ /dev/null @@ -1,114 +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 {ElementRef, Injectable, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer2} from '@angular/core'; - -import {StylingDiffer, StylingDifferOptions} from './styling_differ'; - -/** - * Used as a token for an injected service within the NgStyle directive. - * - * NgStyle behaves differenly whether or not VE is being used or not. If - * present then the legacy ngClass diffing algorithm will be used as an - * injected service. Otherwise the new diffing algorithm (which delegates - * to the `[style]` binding) will be used. This toggle behavior is done so - * via the ivy_switch mechanism. - */ -export abstract class NgStyleImpl { - abstract getValue(): {[key: string]: any}|null; - abstract setNgStyle(value: {[key: string]: any}|null): void; - abstract applyChanges(): void; -} - -@Injectable() -export class NgStyleR2Impl implements NgStyleImpl { - // TODO(issue/24571): remove '!'. - private _ngStyle !: {[key: string]: string}; - // TODO(issue/24571): remove '!'. - private _differ !: KeyValueDiffer; - - constructor( - private _ngEl: ElementRef, private _differs: KeyValueDiffers, private _renderer: Renderer2) {} - - getValue() { return null; } - - /** - * 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. - */ - setNgStyle(values: {[key: string]: string}) { - this._ngStyle = values; - if (!this._differ && values) { - this._differ = this._differs.find(values).create(); - } - } - - /** - * Applies the new styles if needed. - */ - applyChanges() { - if (this._differ) { - const changes = this._differ.diff(this._ngStyle); - if (changes) { - this._applyChanges(changes); - } - } - } - - private _applyChanges(changes: KeyValueChanges): void { - changes.forEachRemovedItem((record) => this._setStyle(record.key, null)); - changes.forEachAddedItem((record) => this._setStyle(record.key, record.currentValue)); - changes.forEachChangedItem((record) => this._setStyle(record.key, record.currentValue)); - } - - private _setStyle(nameAndUnit: string, value: string|number|null|undefined): void { - const [name, unit] = nameAndUnit.split('.'); - value = value != null && unit ? `${value}${unit}` : value; - - if (value != null) { - this._renderer.setStyle(this._ngEl.nativeElement, name, value as string); - } else { - this._renderer.removeStyle(this._ngEl.nativeElement, name); - } - } -} - -@Injectable() -export class NgStyleR3Impl implements NgStyleImpl { - private _differ = - new StylingDiffer<{[key: string]: any}|null>('NgStyle', StylingDifferOptions.AllowUnits); - - private _value: {[key: string]: any}|null = null; - - getValue() { return this._value; } - - setNgStyle(value: {[key: string]: any}|null) { this._differ.setValue(value); } - - applyChanges() { - if (this._differ.hasValueChanged()) { - this._value = this._differ.value; - } - } -} - -// the implementation for both NgClassR2Impl and NgClassR3Impl are -// not ivy_switch'd away, instead they are only hooked up into the -// DI via NgStyle's directive's provider property. -export const NgStyleImplProvider__PRE_R3__ = { - provide: NgStyleImpl, - useClass: NgStyleR2Impl -}; - -export const NgStyleImplProvider__POST_R3__ = { - provide: NgStyleImpl, - useClass: NgStyleR3Impl -}; - -export const NgStyleImplProvider = NgStyleImplProvider__PRE_R3__; diff --git a/packages/common/src/directives/styling_differ.ts b/packages/common/src/directives/styling_differ.ts deleted file mode 100644 index 972c15337d..0000000000 --- a/packages/common/src/directives/styling_differ.ts +++ /dev/null @@ -1,305 +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 - */ - -/** - * Used to diff and convert ngStyle/ngClass instructions into [style] and [class] bindings. - * - * ngStyle and ngClass both accept various forms of input and behave differently than that - * of how [style] and [class] behave in Angular. - * - * The differences are: - * - ngStyle and ngClass both **watch** their binding values for changes each time CD runs - * while [style] and [class] bindings do not (they check for identity changes) - * - ngStyle allows for unit-based keys (e.g. `{'max-width.px':value}`) and [style] does not - * - ngClass supports arrays of class values and [class] only accepts map and string values - * - ngClass allows for multiple className keys (space-separated) within an array or map - * (as the * key) while [class] only accepts a simple key/value map object - * - * Having Angular understand and adapt to all the different forms of behavior is complicated - * and unnecessary. Instead, ngClass and ngStyle should have their input values be converted - * into something that the core-level [style] and [class] bindings understand. - * - * This [StylingDiffer] class handles this conversion by creating a new input value each time - * the inner representation of the binding value have changed. - * - * ## Why do we care about ngStyle/ngClass? - * The styling algorithm code (documented inside of `render3/interfaces/styling.ts`) needs to - * respect and understand the styling values emitted through ngStyle and ngClass (when they - * are present and used in a template). - * - * Instead of having these directives manage styling on their own, they should be included - * into the Angular styling algorithm that exists for [style] and [class] bindings. - * - * Here's why: - * - * - If ngStyle/ngClass is used in combination with [style]/[class] bindings then the - * styles and classes would fall out of sync and be applied and updated at - * inconsistent times - * - Both ngClass/ngStyle do not respect [class.name] and [style.prop] bindings - * (they will write over them given the right combination of events) - * - * ``` - * - *
...
- * - * - *
...
- * ``` - * - ngClass/ngStyle were written as a directives and made use of maps, closures and other - * expensive data structures which were evaluated each time CD runs - */ -export class StylingDiffer { - public readonly value: T|null = null; - - private _lastSetValue: {[key: string]: any}|string|string[]|null = null; - private _lastSetValueType: StylingDifferValueTypes = StylingDifferValueTypes.Null; - private _lastSetValueIdentityChange = false; - - constructor(private _name: string, private _options: StylingDifferOptions) {} - - /** - * Sets (updates) the styling value within the differ. - * - * Only when `hasValueChanged` is called then this new value will be evaluted - * and checked against the previous value. - * - * @param value the new styling value provided from the ngClass/ngStyle binding - */ - setValue(value: {[key: string]: any}|string[]|string|null) { - if (Array.isArray(value)) { - this._lastSetValueType = StylingDifferValueTypes.Array; - } else if (value instanceof Set) { - this._lastSetValueType = StylingDifferValueTypes.Set; - } else if (value && typeof value === 'string') { - if (!(this._options & StylingDifferOptions.AllowStringValue)) { - throw new Error(this._name + ' string values are not allowed'); - } - this._lastSetValueType = StylingDifferValueTypes.String; - } else { - this._lastSetValueType = value ? StylingDifferValueTypes.Map : StylingDifferValueTypes.Null; - } - - this._lastSetValueIdentityChange = true; - this._lastSetValue = value || null; - } - - /** - * Determines whether or not the value has changed. - * - * This function can be called right after `setValue()` is called, but it can also be - * called incase the existing value (if it's a collection) changes internally. If the - * value is indeed a collection it will do the necessary diffing work and produce a - * new object value as assign that to `value`. - * - * @returns whether or not the value has changed in some way. - */ - hasValueChanged(): boolean { - let valueHasChanged = this._lastSetValueIdentityChange; - if (!valueHasChanged && !(this._lastSetValueType & StylingDifferValueTypes.Collection)) - return false; - - let finalValue: {[key: string]: any}|string|null = null; - const trimValues = (this._options & StylingDifferOptions.TrimProperties) ? true : false; - const parseOutUnits = (this._options & StylingDifferOptions.AllowUnits) ? true : false; - const allowSubKeys = (this._options & StylingDifferOptions.AllowSubKeys) ? true : false; - - switch (this._lastSetValueType) { - // case 1: [input]="string" - case StylingDifferValueTypes.String: - const tokens = (this._lastSetValue as string).split(/\s+/g); - if (this._options & StylingDifferOptions.ForceAsMap) { - finalValue = {}; - tokens.forEach((token, i) => (finalValue as{[key: string]: any})[token] = true); - } else { - finalValue = tokens.reduce((str, token, i) => str + (i ? ' ' : '') + token); - } - break; - - // case 2: [input]="{key:value}" - case StylingDifferValueTypes.Map: - const map: {[key: string]: any} = this._lastSetValue as{[key: string]: any}; - const keys = Object.keys(map); - if (!valueHasChanged) { - if (this.value) { - // we know that the classExp value exists and that it is - // a map (otherwise an identity change would have occurred) - valueHasChanged = mapHasChanged(keys, this.value as{[key: string]: any}, map); - } else { - valueHasChanged = true; - } - } - - if (valueHasChanged) { - finalValue = - bulidMapFromValues(this._name, trimValues, parseOutUnits, allowSubKeys, map, keys); - } - break; - - // case 3a: [input]="[str1, str2, ...]" - // case 3b: [input]="Set" - case StylingDifferValueTypes.Array: - case StylingDifferValueTypes.Set: - const values = Array.from(this._lastSetValue as string[] | Set); - if (!valueHasChanged) { - const keys = Object.keys(this.value !); - valueHasChanged = !arrayEqualsArray(keys, values); - } - if (valueHasChanged) { - finalValue = - bulidMapFromValues(this._name, trimValues, parseOutUnits, allowSubKeys, values); - } - break; - - // case 4: [input]="null|undefined" - default: - finalValue = null; - break; - } - - if (valueHasChanged) { - (this as any).value = finalValue !; - } - - return valueHasChanged; - } -} - -/** - * Various options that are consumed by the [StylingDiffer] class. - */ -export const enum StylingDifferOptions { - None = 0b00000, - TrimProperties = 0b00001, - AllowSubKeys = 0b00010, - AllowStringValue = 0b00100, - AllowUnits = 0b01000, - ForceAsMap = 0b10000, -} - -/** - * The different types of inputs that the [StylingDiffer] can deal with - */ -const enum StylingDifferValueTypes { - Null = 0b0000, - String = 0b0001, - Map = 0b0010, - Array = 0b0100, - Set = 0b1000, - Collection = 0b1110, -} - - -/** - * builds and returns a map based on the values input value - * - * If the `keys` param is provided then the `values` param is treated as a - * string map. Otherwise `values` is treated as a string array. - */ -function bulidMapFromValues( - errorPrefix: string, trim: boolean, parseOutUnits: boolean, allowSubKeys: boolean, - values: {[key: string]: any} | string[], keys?: string[]) { - const map: {[key: string]: any} = {}; - if (keys) { - // case 1: map - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - const value = (values as{[key: string]: any})[key]; - - if (value !== undefined) { - // Map uses untrimmed keys, so don't trim until passing to `setMapValues` - setMapValues(map, trim ? key.trim() : key, value, parseOutUnits, allowSubKeys); - } - } - } else { - // case 2: array - for (let i = 0; i < values.length; i++) { - let value = (values as string[])[i]; - assertValidValue(errorPrefix, value); - value = trim ? value.trim() : value; - setMapValues(map, value, true, false, allowSubKeys); - } - } - - return map; -} - -function assertValidValue(errorPrefix: string, value: any) { - if (typeof value !== 'string') { - throw new Error( - `${errorPrefix} can only toggle CSS classes expressed as strings, got ${value}`); - } -} - -function setMapValues( - map: {[key: string]: any}, key: string, value: any, parseOutUnits: boolean, - allowSubKeys: boolean) { - if (allowSubKeys && key.indexOf(' ') > 0) { - const innerKeys = key.split(/\s+/g); - for (let j = 0; j < innerKeys.length; j++) { - setIndividualMapValue(map, innerKeys[j], value, parseOutUnits); - } - } else { - setIndividualMapValue(map, key, value, parseOutUnits); - } -} - -function setIndividualMapValue( - map: {[key: string]: any}, key: string, value: any, parseOutUnits: boolean) { - if (parseOutUnits) { - const values = normalizeStyleKeyAndValue(key, value); - value = values.value; - key = values.key; - } - map[key] = value; -} - -function normalizeStyleKeyAndValue(key: string, value: string | null) { - const index = key.indexOf('.'); - if (index > 0) { - const unit = key.substr(index + 1); // ignore the . ([width.px]="'40'" => "40px") - key = key.substring(0, index); - if (value != null) { // we should not convert null values to string - value += unit; - } - } - return {key, value}; -} - -function mapHasChanged(keys: string[], a: {[key: string]: any}, b: {[key: string]: any}) { - const oldKeys = Object.keys(a); - const newKeys = keys; - - // the keys are different which means the map changed - if (!arrayEqualsArray(oldKeys, newKeys)) { - return true; - } - - for (let i = 0; i < newKeys.length; i++) { - const key = newKeys[i]; - if (a[key] !== b[key]) { - return true; - } - } - - return false; -} - -function arrayEqualsArray(a: any[] | null, b: any[] | null) { - if (a && b) { - if (a.length !== b.length) return false; - for (let i = 0; i < a.length; i++) { - if (b.indexOf(a[i]) === -1) return false; - } - return true; - } - return false; -} diff --git a/packages/common/src/i18n/locale_data_api.ts b/packages/common/src/i18n/locale_data_api.ts index 66e14703d5..2354580d43 100644 --- a/packages/common/src/i18n/locale_data_api.ts +++ b/packages/common/src/i18n/locale_data_api.ts @@ -6,9 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {ɵCurrencyIndex, ɵExtraLocaleDataIndex, ɵLocaleDataIndex, ɵfindLocaleData, ɵgetLocalePluralCase} from '@angular/core'; +import {ɵCurrencyIndex, ɵExtraLocaleDataIndex, ɵLocaleDataIndex, ɵfindLocaleData, ɵgetLocaleCurrencyCode, ɵgetLocalePluralCase} from '@angular/core'; + import {CURRENCIES_EN, CurrenciesSymbols} from './currencies'; + /** * Format styles that can be used to represent numbers. * @see `getLocaleNumberFormat()`. @@ -473,6 +475,20 @@ export function getLocaleCurrencyName(locale: string): string|null { return data[ɵLocaleDataIndex.CurrencyName] || null; } +/** + * Retrieves the default currency code for the given locale. + * + * The default is defined as the first currency which is still in use. + * + * @param locale The code of the locale whose currency code we want. + * @returns The code of the default currency for the given locale. + * + * @publicApi + */ +export function getLocaleCurrencyCode(locale: string): string|null { + return ɵgetLocaleCurrencyCode(locale); +} + /** * Retrieves the currency values for a given locale. * @param locale A locale code for the locale format rules to use. diff --git a/packages/common/src/pipes/number_pipe.ts b/packages/common/src/pipes/number_pipe.ts index 34bff323fa..22ed7e81fe 100644 --- a/packages/common/src/pipes/number_pipe.ts +++ b/packages/common/src/pipes/number_pipe.ts @@ -6,11 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core'; +import {DEFAULT_CURRENCY_CODE, Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core'; import {formatCurrency, formatNumber, formatPercent} from '../i18n/format_number'; import {getCurrencySymbol} from '../i18n/locale_data_api'; + import {invalidPipeArgumentError} from './invalid_pipe_argument_error'; + /** * @ngModule CommonModule * @description @@ -179,9 +181,7 @@ export class PercentPipe implements PipeTransform { */ transform(value: any, digitsInfo?: string, locale?: string): string|null { if (isEmpty(value)) return null; - locale = locale || this._locale; - try { const num = strToNumber(value); return formatPercent(num, locale, digitsInfo); @@ -202,6 +202,26 @@ export class PercentPipe implements PipeTransform { * 把数字转换成金额字符串, * 根据本地化规则进行格式化,这些规则会决定分组大小和分组分隔符、小数点字符以及其它与本地化环境有关的配置项。 * + * {@a currency-code-deprecation} + *
+ * + * **Deprecation notice:** + * + * The default currency code is currently always `USD` but this is deprecated from v9. + * + * **In v11 the default currency code will be taken from the current locale identified by + * the `LOCAL_ID` token. See the [i18n guide](guide/i18n#setting-up-the-locale-of-your-app) for + * more information.** + * + * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in + * your application `NgModule`: + * + * ```ts + * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'} + * ``` + * + *
+ * * @see `getCurrencySymbol()` * @see `formatCurrency()` * @@ -219,7 +239,9 @@ export class PercentPipe implements PipeTransform { */ @Pipe({name: 'currency'}) export class CurrencyPipe implements PipeTransform { - constructor(@Inject(LOCALE_ID) private _locale: string) {} + constructor( + @Inject(LOCALE_ID) private _locale: string, + @Inject(DEFAULT_CURRENCY_CODE) private _defaultCurrencyCode: string = 'USD') {} /** * @@ -228,9 +250,10 @@ export class CurrencyPipe implements PipeTransform { * 要格式化为货币的数字。 * * @param currencyCode The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code, - * such as `USD` for the US dollar and `EUR` for the euro. + * such as `USD` for the US dollar and `EUR` for the euro. The default currency code can be + * configured using the `DEFAULT_CURRENCY_CODE` injection token. * - * [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) 中的货币代码,比如 `USD` 表示美元,`EUR` 表示欧元。 + * [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) 中的货币代码,比如 `USD` 表示美元,`EUR` 表示欧元。可以用 `DEFAULT_CURRENCY_CODE` 这个注入令牌来配置默认货币代码。 * * @param display The format for the currency indicator. One of the following: * @@ -314,7 +337,7 @@ export class CurrencyPipe implements PipeTransform { display = display ? 'symbol' : 'code'; } - let currency: string = currencyCode || 'USD'; + let currency: string = currencyCode || this._defaultCurrencyCode; if (display !== 'code') { if (display === 'symbol' || display === 'symbol-narrow') { currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow', locale); diff --git a/packages/common/src/private_export.ts b/packages/common/src/private_export.ts index 7801e395d0..a18c76694d 100644 --- a/packages/common/src/private_export.ts +++ b/packages/common/src/private_export.ts @@ -6,9 +6,5 @@ * found in the LICENSE file at https://angular.io/license */ -export {ngClassDirectiveDef__POST_R3__ as ɵngClassDirectiveDef__POST_R3__, ngClassFactoryDef__POST_R3__ as ɵngClassFactoryDef__POST_R3__} from './directives/ng_class'; -export {NgClassImpl as ɵNgClassImpl, NgClassImplProvider__POST_R3__ as ɵNgClassImplProvider__POST_R3__, NgClassR2Impl as ɵNgClassR2Impl} from './directives/ng_class_impl'; -export {ngStyleDirectiveDef__POST_R3__ as ɵngStyleDirectiveDef__POST_R3__, ngStyleFactoryDef__POST_R3__ as ɵngStyleFactoryDef__POST_R3__} from './directives/ng_style'; -export {NgStyleImpl as ɵNgStyleImpl, NgStyleImplProvider__POST_R3__ as ɵNgStyleImplProvider__POST_R3__, NgStyleR2Impl as ɵNgStyleR2Impl} from './directives/ng_style_impl'; export {DomAdapter as ɵDomAdapter, getDOM as ɵgetDOM, setRootDomAdapter as ɵsetRootDomAdapter} from './dom_adapter'; -export {BrowserPlatformLocation as ɵBrowserPlatformLocation} from './location/platform_location'; \ No newline at end of file +export {BrowserPlatformLocation as ɵBrowserPlatformLocation} from './location/platform_location'; diff --git a/packages/common/test/BUILD.bazel b/packages/common/test/BUILD.bazel index 87e8552355..4a0bd15c85 100644 --- a/packages/common/test/BUILD.bazel +++ b/packages/common/test/BUILD.bazel @@ -1,4 +1,17 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/common/index.js", + deps = ["//packages/common"], +) + +circular_dependency_test( + name = "testing_circular_deps_test", + entry_point = "angular/packages/common/testing/index.js", + deps = ["//packages/common/testing"], +) ts_library( name = "test_lib", @@ -24,10 +37,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/common/test/directives/ng_class_spec.ts b/packages/common/test/directives/ng_class_spec.ts index 36706aa884..d31771932d 100644 --- a/packages/common/test/directives/ng_class_spec.ts +++ b/packages/common/test/directives/ng_class_spec.ts @@ -352,14 +352,55 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; detectChangesAndExpectClassName('init baz'); })); }); + + describe('prevent regressions', () => { + + // https://github.com/angular/angular/issues/34336 + it('should not write to the native node unless the bound expression has changed', () => { + fixture = createTestComponent(`
`); + detectChangesAndExpectClassName('color-red'); + + // Overwrite CSS classes so that we can check if ngClass performed DOM manipulation to + // update it + fixture.debugElement.children[0].nativeElement.className = ''; + // Assert that the DOM node still has the same value after change detection + detectChangesAndExpectClassName(''); + + fixture.componentInstance.condition = false; + fixture.detectChanges(); + fixture.componentInstance.condition = true; + detectChangesAndExpectClassName('color-red'); + }); + + it('should allow classes with trailing and leading spaces in [ngClass]', () => { + @Component({ + template: ` +
+
+ ` + }) + class Cmp { + applyClasses = true; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const leading = fixture.nativeElement.querySelector('[leading-space]'); + const trailing = fixture.nativeElement.querySelector('[trailing-space]'); + expect(leading.className).toBe('foo'); + expect(trailing.className).toBe('foo'); + }); + + }); }); } @Component({selector: 'test-cmp', template: ''}) class TestComponent { condition: boolean = true; - // TODO(issue/24571): remove '!'. - items !: any[]; + items: any[]|undefined; arrExpr: string[] = ['foo']; setExpr: Set = new Set(); objExpr: {[klass: string]: any}|null = {'foo': true, 'bar': false}; diff --git a/packages/common/test/directives/ng_style_spec.ts b/packages/common/test/directives/ng_style_spec.ts index 3978fd7dac..aaba40cd80 100644 --- a/packages/common/test/directives/ng_style_spec.ts +++ b/packages/common/test/directives/ng_style_spec.ts @@ -12,7 +12,7 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; { describe('NgStyle', () => { - let fixture: ComponentFixture; + let fixture: ComponentFixture; function getComponent(): TestComponent { return fixture.componentInstance; } @@ -158,27 +158,37 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; expectNativeEl(fixture).toHaveCssStyle({'font-size': '12px'}); })); - it('should skip keys that are set to undefined values', async(() => { - const template = `
`; + it('should not write to the native node unless the bound expression has changed', () => { - fixture = createTestComponent(template); + const template = `
`; - getComponent().expr = { - 'border-top-color': undefined, - 'border-top-style': undefined, - 'border-color': 'red', - 'border-style': 'solid', - 'border-width': '1rem', - }; + fixture = createTestComponent(template); + fixture.componentInstance.expr = 'red'; - fixture.detectChanges(); + fixture.detectChanges(); + expectNativeEl(fixture).toHaveCssStyle({'color': 'red'}); - expectNativeEl(fixture).toHaveCssStyle({ - 'border-color': 'red', - 'border-style': 'solid', - 'border-width': '1rem', - }); - })); + // Overwrite native styles so that we can check if ngStyle has performed DOM manupulation to + // update it. + fixture.debugElement.children[0].nativeElement.style.color = 'blue'; + fixture.detectChanges(); + // Assert that the style hasn't been updated + expectNativeEl(fixture).toHaveCssStyle({'color': 'blue'}); + + fixture.componentInstance.expr = 'yellow'; + fixture.detectChanges(); + // Assert that the style has changed now that the model has changed + expectNativeEl(fixture).toHaveCssStyle({'color': 'yellow'}); + }); + + it('should correctly update style with units (.px) when the model is set to number', () => { + const template = `
`; + fixture = createTestComponent(template); + fixture.componentInstance.expr = 400; + + fixture.detectChanges(); + expectNativeEl(fixture).toHaveCssStyle({'width': '400px'}); + }); }); } diff --git a/packages/common/test/pipes/number_pipe_spec.ts b/packages/common/test/pipes/number_pipe_spec.ts index 97b7970a0e..c0a456451d 100644 --- a/packages/common/test/pipes/number_pipe_spec.ts +++ b/packages/common/test/pipes/number_pipe_spec.ts @@ -89,7 +89,7 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin describe('CurrencyPipe', () => { let pipe: CurrencyPipe; - beforeEach(() => { pipe = new CurrencyPipe('en-US'); }); + beforeEach(() => { pipe = new CurrencyPipe('en-US', 'USD'); }); describe('transform', () => { it('should return correct value for numbers', () => { diff --git a/packages/common/upgrade/src/params.ts b/packages/common/upgrade/src/params.ts index 8763964b57..ac9fe5f7d6 100644 --- a/packages/common/upgrade/src/params.ts +++ b/packages/common/upgrade/src/params.ts @@ -223,7 +223,6 @@ function _stripIndexHtml(url: string): string { /** * Tries to decode the URI component without throwing an exception. * - * @private * @param str value potential URI component to check. * @returns the decoded URI if it can be decoded or else `undefined`. */ diff --git a/packages/common/upgrade/test/BUILD.bazel b/packages/common/upgrade/test/BUILD.bazel index 12462680c8..64a6a6cd67 100644 --- a/packages/common/upgrade/test/BUILD.bazel +++ b/packages/common/upgrade/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/common/upgrade/index.js", + deps = ["//packages/common/upgrade"], +) ts_library( name = "test_lib", @@ -16,9 +23,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/compiler-cli/BUILD.bazel b/packages/compiler-cli/BUILD.bazel index 16b88b6f9c..3ad34b06c0 100644 --- a/packages/compiler-cli/BUILD.bazel +++ b/packages/compiler-cli/BUILD.bazel @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "npm_package", "ts_library") +load("//tools:defaults.bzl", "pkg_npm", "ts_library") load("@npm_bazel_typescript//:index.bzl", "ts_config") ts_config( @@ -23,29 +23,16 @@ ts_library( tsconfig = ":tsconfig", deps = [ "//packages/compiler", - "//packages/compiler-cli/src/ngtsc/annotations", - "//packages/compiler-cli/src/ngtsc/cycles", + "//packages/compiler-cli/src/ngtsc/core", + "//packages/compiler-cli/src/ngtsc/core:api", "//packages/compiler-cli/src/ngtsc/diagnostics", - "//packages/compiler-cli/src/ngtsc/entry_point", "//packages/compiler-cli/src/ngtsc/file_system", - "//packages/compiler-cli/src/ngtsc/imports", - "//packages/compiler-cli/src/ngtsc/incremental", "//packages/compiler-cli/src/ngtsc/indexer", - "//packages/compiler-cli/src/ngtsc/metadata", - "//packages/compiler-cli/src/ngtsc/modulewithproviders", - "//packages/compiler-cli/src/ngtsc/partial_evaluator", "//packages/compiler-cli/src/ngtsc/perf", - "//packages/compiler-cli/src/ngtsc/reflection", - "//packages/compiler-cli/src/ngtsc/routing", - "//packages/compiler-cli/src/ngtsc/scope", - "//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", "@npm//@bazel/typescript", "@npm//@types/chokidar", "@npm//@types/node", + "@npm//fs-extra", "@npm//minimist", "@npm//reflect-metadata", "@npm//tsickle", @@ -53,7 +40,7 @@ ts_library( ], ) -npm_package( +pkg_npm( name = "npm_package", srcs = [ "package.json", diff --git a/packages/compiler-cli/integrationtest/BUILD.bazel b/packages/compiler-cli/integrationtest/BUILD.bazel index 450a81d041..5774b13445 100644 --- a/packages/compiler-cli/integrationtest/BUILD.bazel +++ b/packages/compiler-cli/integrationtest/BUILD.bazel @@ -31,6 +31,7 @@ nodejs_test( "@nodejs//:node", "@npm//domino", "@npm//chokidar", + "@npm//fs-extra", "@npm//source-map-support", "@npm//shelljs", "@npm//typescript", diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/BUILD.bazel b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/BUILD.bazel index 6999d6c26a..0cb9a2f5b1 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/BUILD.bazel +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/BUILD.bazel @@ -21,12 +21,11 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", "//packages/platform-server", "//packages/platform-server/testing", "//packages/private/testing", - "//tools/testing:node", ], ) diff --git a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/BUILD.bazel b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/BUILD.bazel index ab1ed5eb0b..a2b69470bd 100644 --- a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/BUILD.bazel +++ b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/BUILD.bazel @@ -22,12 +22,11 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], tags = [ "ivy-only", ], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/compiler-cli/integrationtest/test_helpers.js b/packages/compiler-cli/integrationtest/test_helpers.js index a161c72957..2ab74b070a 100644 --- a/packages/compiler-cli/integrationtest/test_helpers.js +++ b/packages/compiler-cli/integrationtest/test_helpers.js @@ -47,6 +47,7 @@ const requiredNodeModules = { 'tslib': resolveNpmTreeArtifact('npm/node_modules/tslib'), 'domino': resolveNpmTreeArtifact('npm/node_modules/domino'), 'xhr2': resolveNpmTreeArtifact('npm/node_modules/xhr2'), + 'fs-extra': resolveNpmTreeArtifact('npm/node_modules/fs-extra'), // 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. diff --git a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts index 1fc2a48d9f..a4c5f105f6 100644 --- a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts @@ -15,20 +15,19 @@ import {FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../ import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, PrivateExportAliasingHost, Reexport, ReferenceEmitter} from '../../../src/ngtsc/imports'; import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../../src/ngtsc/metadata'; import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator'; -import {ClassDeclaration} from '../../../src/ngtsc/reflection'; import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../../src/ngtsc/scope'; -import {CompileResult, DecoratorHandler} from '../../../src/ngtsc/transform'; -import {NgccClassSymbol, NgccReflectionHost} from '../host/ngcc_host'; +import {DecoratorHandler} from '../../../src/ngtsc/transform'; +import {NgccReflectionHost} from '../host/ngcc_host'; import {Migration} from '../migrations/migration'; import {MissingInjectableMigration} from '../migrations/missing_injectable_migration'; import {UndecoratedChildMigration} from '../migrations/undecorated_child_migration'; import {UndecoratedParentMigration} from '../migrations/undecorated_parent_migration'; import {EntryPointBundle} from '../packages/entry_point_bundle'; -import {isDefined} from '../utils'; import {DefaultMigrationHost} from './migration_host'; -import {AnalyzedClass, AnalyzedFile, CompiledClass, CompiledFile, DecorationAnalyses} from './types'; -import {NOOP_DEPENDENCY_TRACKER, analyzeDecorators, isWithinPackage} from './util'; +import {NgccTraitCompiler} from './ngcc_trait_compiler'; +import {CompiledClass, CompiledFile, DecorationAnalyses} from './types'; +import {NOOP_DEPENDENCY_TRACKER, isWithinPackage} from './util'; @@ -57,10 +56,6 @@ export class DecorationAnalyzer { private packagePath = this.bundle.entryPoint.package; private isCore = this.bundle.isCore; - /** - * Map of NgModule declarations to the re-exports for that NgModule. - */ - private reexportMap = new Map>(); moduleResolver = new ModuleResolver(this.program, this.options, this.host, /* moduleResolutionCache */ null); resourceManager = new NgccResourceLoader(this.fs); @@ -118,6 +113,7 @@ export class DecorationAnalyzer { /* factoryTracker */ null, NOOP_DEFAULT_IMPORT_RECORDER, /* annotateForClosureCompiler */ false, this.injectableRegistry), ]; + compiler = new NgccTraitCompiler(this.handlers, this.reflectionHost); migrations: Migration[] = [ new UndecoratedParentMigration(), new UndecoratedChildMigration(), @@ -135,55 +131,54 @@ export class DecorationAnalyzer { * @returns a map of the source files to the analysis for those files. */ analyzeProgram(): DecorationAnalyses { + for (const sourceFile of this.program.getSourceFiles()) { + if (!sourceFile.isDeclarationFile && isWithinPackage(this.packagePath, sourceFile)) { + this.compiler.analyzeFile(sourceFile); + } + } + + this.applyMigrations(); + + this.compiler.resolve(); + + this.reportDiagnostics(); + const decorationAnalyses = new DecorationAnalyses(); - const analyzedFiles = this.program.getSourceFiles() - .filter(sourceFile => isWithinPackage(this.packagePath, sourceFile)) - .map(sourceFile => this.analyzeFile(sourceFile)) - .filter(isDefined); - - this.applyMigrations(analyzedFiles); - - analyzedFiles.forEach(analyzedFile => this.resolveFile(analyzedFile)); - const compiledFiles = analyzedFiles.map(analyzedFile => this.compileFile(analyzedFile)); - compiledFiles.forEach( - compiledFile => decorationAnalyses.set(compiledFile.sourceFile, compiledFile)); + for (const analyzedFile of this.compiler.analyzedFiles) { + const compiledFile = this.compileFile(analyzedFile); + decorationAnalyses.set(compiledFile.sourceFile, compiledFile); + } return decorationAnalyses; } - protected analyzeFile(sourceFile: ts.SourceFile): AnalyzedFile|undefined { - const analyzedClasses = this.reflectionHost.findClassSymbols(sourceFile) - .map(symbol => this.analyzeClass(symbol)) - .filter(isDefined); - return analyzedClasses.length ? {sourceFile, analyzedClasses} : undefined; - } - - protected analyzeClass(symbol: NgccClassSymbol): AnalyzedClass|null { - const decorators = this.reflectionHost.getDecoratorsOfSymbol(symbol); - const analyzedClass = analyzeDecorators(symbol, decorators, this.handlers); - if (analyzedClass !== null && analyzedClass.diagnostics !== undefined) { - for (const diagnostic of analyzedClass.diagnostics) { - this.diagnosticHandler(diagnostic); - } - } - return analyzedClass; - } - - protected applyMigrations(analyzedFiles: AnalyzedFile[]): void { + protected applyMigrations(): void { const migrationHost = new DefaultMigrationHost( - this.reflectionHost, this.fullMetaReader, this.evaluator, this.handlers, - this.bundle.entryPoint.path, analyzedFiles, this.diagnosticHandler); + this.reflectionHost, this.fullMetaReader, this.evaluator, this.compiler, + this.bundle.entryPoint.path); this.migrations.forEach(migration => { - analyzedFiles.forEach(analyzedFile => { - analyzedFile.analyzedClasses.forEach(({declaration}) => { + this.compiler.analyzedFiles.forEach(analyzedFile => { + const records = this.compiler.recordsFor(analyzedFile); + if (records === null) { + throw new Error('Assertion error: file to migrate must have records.'); + } + + records.forEach(record => { + const addDiagnostic = (diagnostic: ts.Diagnostic) => { + if (record.metaDiagnostics === null) { + record.metaDiagnostics = []; + } + record.metaDiagnostics.push(diagnostic); + }; + try { - const result = migration.apply(declaration, migrationHost); + const result = migration.apply(record.node, migrationHost); if (result !== null) { - this.diagnosticHandler(result); + addDiagnostic(result); } } catch (e) { if (isFatalDiagnosticError(e)) { - this.diagnosticHandler(e.toDiagnostic()); + addDiagnostic(e.toDiagnostic()); } else { throw e; } @@ -193,67 +188,45 @@ export class DecorationAnalyzer { }); } - protected compileFile(analyzedFile: AnalyzedFile): CompiledFile { + protected reportDiagnostics() { this.compiler.diagnostics.forEach(this.diagnosticHandler); } + + protected compileFile(sourceFile: ts.SourceFile): CompiledFile { const constantPool = new ConstantPool(); - const compiledClasses: CompiledClass[] = analyzedFile.analyzedClasses.map(analyzedClass => { - const compilation = this.compileClass(analyzedClass, constantPool); - const declaration = analyzedClass.declaration; - const reexports: Reexport[] = this.getReexportsForClass(declaration); - return {...analyzedClass, compilation, reexports}; - }); - return {constantPool, sourceFile: analyzedFile.sourceFile, compiledClasses}; - } - - protected compileClass(clazz: AnalyzedClass, constantPool: ConstantPool): CompileResult[] { - const compilations: CompileResult[] = []; - for (const {handler, analysis, resolution} of clazz.matches) { - const result = handler.compile(clazz.declaration, analysis, resolution, constantPool); - if (Array.isArray(result)) { - result.forEach(current => { - if (!compilations.some(compilation => compilation.name === current.name)) { - compilations.push(current); - } - }); - } else if (!compilations.some(compilation => compilation.name === result.name)) { - compilations.push(result); - } + const records = this.compiler.recordsFor(sourceFile); + if (records === null) { + throw new Error('Assertion error: file to compile must have records.'); } - return compilations; - } - protected resolveFile(analyzedFile: AnalyzedFile): void { - for (const {declaration, matches} of analyzedFile.analyzedClasses) { - for (const match of matches) { - const {handler, analysis} = match; - if ((handler.resolve !== undefined) && analysis) { - const {reexports, diagnostics, data} = handler.resolve(declaration, analysis); - if (reexports !== undefined) { - this.addReexports(reexports, declaration); - } - if (diagnostics !== undefined) { - diagnostics.forEach(error => this.diagnosticHandler(error)); - } - match.resolution = data as Readonly; - } + const compiledClasses: CompiledClass[] = []; + + for (const record of records) { + const compilation = this.compiler.compile(record.node, constantPool); + if (compilation === null) { + continue; } - } - } - private getReexportsForClass(declaration: ClassDeclaration) { - const reexports: Reexport[] = []; - if (this.reexportMap.has(declaration)) { - this.reexportMap.get(declaration) !.forEach(([fromModule, symbolName], asAlias) => { - reexports.push({asAlias, fromModule, symbolName}); + compiledClasses.push({ + name: record.node.name.text, + decorators: this.compiler.getAllDecorators(record.node), + declaration: record.node, compilation }); } - return reexports; + + const reexports = this.getReexportsForSourceFile(sourceFile); + return {constantPool, sourceFile: sourceFile, compiledClasses, reexports}; } - private addReexports(reexports: Reexport[], declaration: ClassDeclaration) { - const map = new Map(); - for (const reexport of reexports) { - map.set(reexport.asAlias, [reexport.fromModule, reexport.symbolName]); + private getReexportsForSourceFile(sf: ts.SourceFile): Reexport[] { + const exportStatements = this.compiler.exportStatements; + if (!exportStatements.has(sf.fileName)) { + return []; } - this.reexportMap.set(declaration, map); + const exports = exportStatements.get(sf.fileName) !; + + const reexports: Reexport[] = []; + exports.forEach(([fromModule, symbolName], asAlias) => { + reexports.push({asAlias, fromModule, symbolName}); + }); + return reexports; } } diff --git a/packages/compiler-cli/ngcc/src/analysis/migration_host.ts b/packages/compiler-cli/ngcc/src/analysis/migration_host.ts index 9ed169ece2..d52476f359 100644 --- a/packages/compiler-cli/ngcc/src/analysis/migration_host.ts +++ b/packages/compiler-cli/ngcc/src/analysis/migration_host.ts @@ -7,66 +7,40 @@ */ import * as ts from 'typescript'; -import {ErrorCode, FatalDiagnosticError} from '../../../src/ngtsc/diagnostics'; import {AbsoluteFsPath} from '../../../src/ngtsc/file_system'; import {MetadataReader} from '../../../src/ngtsc/metadata'; import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator'; import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection'; -import {DecoratorHandler, HandlerFlags} from '../../../src/ngtsc/transform'; +import {HandlerFlags, TraitState} from '../../../src/ngtsc/transform'; import {NgccReflectionHost} from '../host/ngcc_host'; import {MigrationHost} from '../migrations/migration'; -import {AnalyzedClass, AnalyzedFile} from './types'; -import {analyzeDecorators, isWithinPackage} from './util'; +import {NgccTraitCompiler} from './ngcc_trait_compiler'; +import {isWithinPackage} from './util'; /** - * The standard implementation of `MigrationHost`, which is created by the - * `DecorationAnalyzer`. + * The standard implementation of `MigrationHost`, which is created by the `DecorationAnalyzer`. */ export class DefaultMigrationHost implements MigrationHost { constructor( readonly reflectionHost: NgccReflectionHost, readonly metadata: MetadataReader, - readonly evaluator: PartialEvaluator, - private handlers: DecoratorHandler[], - private entryPointPath: AbsoluteFsPath, private analyzedFiles: AnalyzedFile[], - private diagnosticHandler: (error: ts.Diagnostic) => void) {} + readonly evaluator: PartialEvaluator, private compiler: NgccTraitCompiler, + private entryPointPath: AbsoluteFsPath) {} injectSyntheticDecorator(clazz: ClassDeclaration, decorator: Decorator, flags?: HandlerFlags): void { - const classSymbol = this.reflectionHost.getClassSymbol(clazz) !; - const newAnalyzedClass = analyzeDecorators(classSymbol, [decorator], this.handlers, flags); - if (newAnalyzedClass === null) { - return; - } + const migratedTraits = this.compiler.injectSyntheticDecorator(clazz, decorator, flags); - if (newAnalyzedClass.diagnostics !== undefined) { - for (const diagnostic of newAnalyzedClass.diagnostics) { - this.diagnosticHandler(createMigrationDiagnostic(diagnostic, clazz, decorator)); + for (const trait of migratedTraits) { + if (trait.state === TraitState.ERRORED) { + trait.diagnostics = + trait.diagnostics.map(diag => createMigrationDiagnostic(diag, clazz, decorator)); } } - - const analyzedFile = getOrCreateAnalyzedFile(this.analyzedFiles, clazz.getSourceFile()); - const oldAnalyzedClass = analyzedFile.analyzedClasses.find(c => c.declaration === clazz); - if (oldAnalyzedClass === undefined) { - analyzedFile.analyzedClasses.push(newAnalyzedClass); - } else { - mergeAnalyzedClasses(oldAnalyzedClass, newAnalyzedClass); - } } getAllDecorators(clazz: ClassDeclaration): Decorator[]|null { - const sourceFile = clazz.getSourceFile(); - const analyzedFile = this.analyzedFiles.find(file => file.sourceFile === sourceFile); - if (analyzedFile === undefined) { - return null; - } - - const analyzedClass = analyzedFile.analyzedClasses.find(c => c.declaration === clazz); - if (analyzedClass === undefined) { - return null; - } - - return analyzedClass.decorators; + return this.compiler.getAllDecorators(clazz); } isInScope(clazz: ClassDeclaration): boolean { @@ -74,43 +48,6 @@ export class DefaultMigrationHost implements MigrationHost { } } -function getOrCreateAnalyzedFile( - analyzedFiles: AnalyzedFile[], sourceFile: ts.SourceFile): AnalyzedFile { - const analyzedFile = analyzedFiles.find(file => file.sourceFile === sourceFile); - if (analyzedFile !== undefined) { - return analyzedFile; - } else { - const newAnalyzedFile: AnalyzedFile = {sourceFile, analyzedClasses: []}; - analyzedFiles.push(newAnalyzedFile); - return newAnalyzedFile; - } -} - -function mergeAnalyzedClasses(oldClass: AnalyzedClass, newClass: AnalyzedClass) { - if (newClass.decorators !== null) { - if (oldClass.decorators === null) { - oldClass.decorators = newClass.decorators; - } else { - for (const newDecorator of newClass.decorators) { - if (oldClass.decorators.some(d => d.name === newDecorator.name)) { - throw new FatalDiagnosticError( - ErrorCode.NGCC_MIGRATION_DECORATOR_INJECTION_ERROR, newClass.declaration, - `Attempted to inject "${newDecorator.name}" decorator over a pre-existing decorator with the same name on the "${newClass.name}" class.`); - } - } - oldClass.decorators.push(...newClass.decorators); - } - } - - if (newClass.diagnostics !== undefined) { - if (oldClass.diagnostics === undefined) { - oldClass.diagnostics = newClass.diagnostics; - } else { - oldClass.diagnostics.push(...newClass.diagnostics); - } - } -} - /** * Creates a diagnostic from another one, containing additional information about the synthetic * decorator. diff --git a/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts index fc9f6a7cac..8c6ad1ee83 100644 --- a/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts @@ -114,7 +114,7 @@ export class ModuleWithProvidersAnalyzer { `The referenced NgModule in ${fn.declaration.getText()} is not a named class declaration in the typings program; instead we get ${dtsNgModule.getText()}`); } - return {node: dtsNgModule, viaModule: null}; + return {node: dtsNgModule, known: null, viaModule: null}; } } diff --git a/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts b/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts new file mode 100644 index 0000000000..f4d7f80fba --- /dev/null +++ b/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts @@ -0,0 +1,85 @@ +/** + * @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 {IncrementalBuild} from '../../../src/ngtsc/incremental/api'; +import {NOOP_PERF_RECORDER} from '../../../src/ngtsc/perf'; +import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection'; +import {DecoratorHandler, DtsTransformRegistry, HandlerFlags, Trait, TraitCompiler} from '../../../src/ngtsc/transform'; +import {NgccReflectionHost} from '../host/ngcc_host'; +import {isDefined} from '../utils'; + +/** + * Specializes the `TraitCompiler` for ngcc purposes. Mainly, this includes an alternative way of + * scanning for classes to compile using the reflection host's `findClassSymbols`, together with + * support to inject synthetic decorators into the compilation for ad-hoc migrations that ngcc + * performs. + */ +export class NgccTraitCompiler extends TraitCompiler { + constructor( + handlers: DecoratorHandler[], + private ngccReflector: NgccReflectionHost) { + super( + handlers, ngccReflector, NOOP_PERF_RECORDER, new NoIncrementalBuild(), + /* compileNonExportedClasses */ true, new DtsTransformRegistry()); + } + + get analyzedFiles(): ts.SourceFile[] { return Array.from(this.fileToClasses.keys()); } + + /** + * Analyzes the source file in search for classes to process. For any class that is found in the + * file, a `ClassRecord` is created and the source file is included in the `analyzedFiles` array. + */ + analyzeFile(sf: ts.SourceFile): void { + const ngccClassSymbols = this.ngccReflector.findClassSymbols(sf); + for (const classSymbol of ngccClassSymbols) { + this.analyzeClass(classSymbol.declaration.valueDeclaration, null); + } + + return undefined; + } + + /** + * Associate a new synthesized decorator, which did not appear in the original source, with a + * given class. + * @param clazz the class to receive the new decorator. + * @param decorator the decorator to inject. + * @param flags optional bitwise flag to influence the compilation of the decorator. + */ + injectSyntheticDecorator(clazz: ClassDeclaration, decorator: Decorator, flags?: HandlerFlags): + Trait[] { + const migratedTraits = this.detectTraits(clazz, [decorator]); + if (migratedTraits === null) { + return []; + } + + for (const trait of migratedTraits) { + this.analyzeTrait(clazz, trait, flags); + } + + return migratedTraits; + } + + /** + * Returns all decorators that have been recognized for the provided class, including any + * synthetically injected decorators. + * @param clazz the declaration for which the decorators are returned. + */ + getAllDecorators(clazz: ClassDeclaration): Decorator[]|null { + const record = this.recordFor(clazz); + if (record === null) { + return null; + } + + return record.traits.map(trait => trait.detected.decorator).filter(isDefined); + } +} + +class NoIncrementalBuild implements IncrementalBuild { + priorWorkFor(sf: ts.SourceFile): any[]|null { return null; } +} diff --git a/packages/compiler-cli/ngcc/src/analysis/types.ts b/packages/compiler-cli/ngcc/src/analysis/types.ts index fd4859ea3b..19bb5f6ffa 100644 --- a/packages/compiler-cli/ngcc/src/analysis/types.ts +++ b/packages/compiler-cli/ngcc/src/analysis/types.ts @@ -9,23 +9,19 @@ import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; import {Reexport} from '../../../src/ngtsc/imports'; import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection'; -import {CompileResult, DecoratorHandler, DetectResult} from '../../../src/ngtsc/transform'; +import {CompileResult} from '../../../src/ngtsc/transform'; -export interface AnalyzedFile { - sourceFile: ts.SourceFile; - analyzedClasses: AnalyzedClass[]; -} - -export interface AnalyzedClass { +export interface CompiledClass { name: string; decorators: Decorator[]|null; declaration: ClassDeclaration; - diagnostics?: ts.Diagnostic[]; - matches: MatchingHandler[]; + compilation: CompileResult[]; } -export interface CompiledClass extends AnalyzedClass { - compilation: CompileResult[]; +export interface CompiledFile { + compiledClasses: CompiledClass[]; + sourceFile: ts.SourceFile; + constantPool: ConstantPool; /** * Any re-exports which should be added next to this class, both in .js and (if possible) .d.ts. @@ -33,18 +29,5 @@ export interface CompiledClass extends AnalyzedClass { reexports: Reexport[]; } -export interface CompiledFile { - compiledClasses: CompiledClass[]; - sourceFile: ts.SourceFile; - constantPool: ConstantPool; -} - export type DecorationAnalyses = Map; export const DecorationAnalyses = Map; - -export interface MatchingHandler { - handler: DecoratorHandler; - detected: DetectResult; - analysis: Readonly; - resolution: Readonly; -} diff --git a/packages/compiler-cli/ngcc/src/analysis/util.ts b/packages/compiler-cli/ngcc/src/analysis/util.ts index 59dc3e11d7..a953d4608c 100644 --- a/packages/compiler-cli/ngcc/src/analysis/util.ts +++ b/packages/compiler-cli/ngcc/src/analysis/util.ts @@ -7,104 +7,13 @@ */ import * as ts from 'typescript'; -import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics'; import {AbsoluteFsPath, absoluteFromSourceFile, relative} from '../../../src/ngtsc/file_system'; import {DependencyTracker} from '../../../src/ngtsc/incremental/api'; -import {Decorator} from '../../../src/ngtsc/reflection'; -import {DecoratorHandler, HandlerFlags, HandlerPrecedence} from '../../../src/ngtsc/transform'; -import {NgccClassSymbol} from '../host/ngcc_host'; - -import {AnalyzedClass, MatchingHandler} from './types'; export function isWithinPackage(packagePath: AbsoluteFsPath, sourceFile: ts.SourceFile): boolean { return !relative(packagePath, absoluteFromSourceFile(sourceFile)).startsWith('..'); } -const NOT_YET_KNOWN: Readonly = null as unknown as Readonly; - -export function analyzeDecorators( - classSymbol: NgccClassSymbol, decorators: Decorator[] | null, - handlers: DecoratorHandler[], flags?: HandlerFlags): AnalyzedClass| - null { - const declaration = classSymbol.declaration.valueDeclaration; - const matchingHandlers: MatchingHandler[] = []; - for (const handler of handlers) { - const detected = handler.detect(declaration, decorators); - if (detected !== undefined) { - matchingHandlers.push({ - handler, - detected, - analysis: NOT_YET_KNOWN, - resolution: NOT_YET_KNOWN, - }); - } - } - - if (matchingHandlers.length === 0) { - return null; - } - - const detections: MatchingHandler[] = []; - let hasWeakHandler: boolean = false; - let hasNonWeakHandler: boolean = false; - let hasPrimaryHandler: boolean = false; - - for (const match of matchingHandlers) { - const {handler} = match; - 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(match); - 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: MatchingHandler[] = []; - const allDiagnostics: ts.Diagnostic[] = []; - for (const match of detections) { - try { - const {analysis, diagnostics} = - match.handler.analyze(declaration, match.detected.metadata, flags); - if (diagnostics !== undefined) { - allDiagnostics.push(...diagnostics); - } - if (analysis !== undefined) { - match.analysis = analysis; - if (match.handler.register !== undefined) { - match.handler.register(declaration, analysis); - } - } - matches.push(match); - } catch (e) { - if (isFatalDiagnosticError(e)) { - allDiagnostics.push(e.toDiagnostic()); - } else { - throw e; - } - } - } - return { - name: classSymbol.name, - declaration, - decorators, - matches, - diagnostics: allDiagnostics.length > 0 ? allDiagnostics : undefined, - }; -} - class NoopDependencyTracker implements DependencyTracker { addDependency(): void {} addResourceDependency(): void {} diff --git a/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts b/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts index 9825e3a262..3d4ab17b8e 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; import {AbsoluteFsPath} from '../../../src/ngtsc/file_system'; -import {isRequireCall} from '../host/commonjs_umd_utils'; +import {RequireCall, isReexportStatement, isRequireCall} from '../host/commonjs_umd_utils'; import {DependencyHostBase} from './dependency_host'; import {ResolvedDeepImport, ResolvedRelativeModule} from './module_resolver'; @@ -40,33 +40,72 @@ export class CommonJsDependencyHost extends DependencyHostBase { // Parse the source into a TypeScript AST and then walk it looking for imports and re-exports. const sf = ts.createSourceFile(file, fromContents, ts.ScriptTarget.ES2015, false, ts.ScriptKind.JS); + const requireCalls: RequireCall[] = []; - for (const statement of sf.statements) { - const declarations = - ts.isVariableStatement(statement) ? statement.declarationList.declarations : []; - for (const declaration of declarations) { - if (declaration.initializer && isRequireCall(declaration.initializer)) { - const importPath = declaration.initializer.arguments[0].text; - const resolvedModule = this.moduleResolver.resolveModuleImport(importPath, file); - if (resolvedModule) { - if (resolvedModule instanceof ResolvedRelativeModule) { - const internalDependency = resolvedModule.modulePath; - if (!alreadySeen.has(internalDependency)) { - alreadySeen.add(internalDependency); - this.recursivelyCollectDependencies( - internalDependency, dependencies, missing, deepImports, alreadySeen); - } - } else { - if (resolvedModule instanceof ResolvedDeepImport) { - deepImports.add(resolvedModule.importPath); - } else { - dependencies.add(resolvedModule.entryPointPath); - } - } - } else { - missing.add(importPath); + for (const stmt of sf.statements) { + if (ts.isVariableStatement(stmt)) { + // Regular import(s): + // `var foo = require('...')` or `var foo = require('...'), bar = require('...')` + const declarations = stmt.declarationList.declarations; + for (const declaration of declarations) { + if ((declaration.initializer !== undefined) && isRequireCall(declaration.initializer)) { + requireCalls.push(declaration.initializer); } } + } else if (ts.isExpressionStatement(stmt)) { + if (isRequireCall(stmt.expression)) { + // Import for the side-effects only: + // `require('...')` + requireCalls.push(stmt.expression); + } else if (isReexportStatement(stmt)) { + // Re-export in one of the following formats: + // - `__export(require('...'))` + // - `__export()` + // - `tslib_1.__exportStar(require('...'), exports)` + // - `tslib_1.__exportStar(, exports)` + const firstExportArg = stmt.expression.arguments[0]; + + if (isRequireCall(firstExportArg)) { + // Re-export with `require()` call: + // `__export(require('...'))` or `tslib_1.__exportStar(require('...'), exports)` + requireCalls.push(firstExportArg); + } + } else if ( + ts.isBinaryExpression(stmt.expression) && + (stmt.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken)) { + if (isRequireCall(stmt.expression.right)) { + // Import with assignment. E.g.: + // `exports.foo = require('...')` + requireCalls.push(stmt.expression.right); + } else if (ts.isObjectLiteralExpression(stmt.expression.right)) { + // Import in object literal. E.g.: + // `module.exports = {foo: require('...')}` + stmt.expression.right.properties.forEach(prop => { + if (ts.isPropertyAssignment(prop) && isRequireCall(prop.initializer)) { + requireCalls.push(prop.initializer); + } + }); + } + } + } + } + + const importPaths = new Set(requireCalls.map(call => call.arguments[0].text)); + for (const importPath of importPaths) { + const resolvedModule = this.moduleResolver.resolveModuleImport(importPath, file); + if (resolvedModule === null) { + missing.add(importPath); + } else if (resolvedModule instanceof ResolvedRelativeModule) { + const internalDependency = resolvedModule.modulePath; + if (!alreadySeen.has(internalDependency)) { + alreadySeen.add(internalDependency); + this.recursivelyCollectDependencies( + internalDependency, dependencies, missing, deepImports, alreadySeen); + } + } else if (resolvedModule instanceof ResolvedDeepImport) { + deepImports.add(resolvedModule.importPath); + } else { + dependencies.add(resolvedModule.entryPointPath); } } } diff --git a/packages/compiler-cli/ngcc/src/dependencies/dts_dependency_host.ts b/packages/compiler-cli/ngcc/src/dependencies/dts_dependency_host.ts index 73efa1b744..5d23c596a7 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/dts_dependency_host.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/dts_dependency_host.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 {FileSystem} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system'; import {PathMappings} from '../utils'; import {EsmDependencyHost} from './esm_dependency_host'; import {ModuleResolver} from './module_resolver'; @@ -15,6 +15,18 @@ import {ModuleResolver} from './module_resolver'; */ export class DtsDependencyHost extends EsmDependencyHost { constructor(fs: FileSystem, pathMappings?: PathMappings) { - super(fs, new ModuleResolver(fs, pathMappings, ['', '.d.ts', '/index.d.ts'])); + super( + fs, new ModuleResolver(fs, pathMappings, ['', '.d.ts', '/index.d.ts', '.js', '/index.js'])); + } + + /** + * Attempts to process the `importPath` directly and also inside `@types/...`. + */ + protected processImport( + importPath: string, file: AbsoluteFsPath, dependencies: Set, + missing: Set, deepImports: Set, alreadySeen: Set): boolean { + return super.processImport(importPath, file, dependencies, missing, deepImports, alreadySeen) || + super.processImport( + `@types/${importPath}`, file, dependencies, missing, deepImports, alreadySeen); } } diff --git a/packages/compiler-cli/ngcc/src/dependencies/esm_dependency_host.ts b/packages/compiler-cli/ngcc/src/dependencies/esm_dependency_host.ts index 6b2c1226d1..3c4d6e80ee 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/esm_dependency_host.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/esm_dependency_host.ts @@ -44,29 +44,42 @@ export class EsmDependencyHost extends DependencyHostBase { .filter(isStringImportOrReexport) // Grab the id of the module that is being imported .map(stmt => stmt.moduleSpecifier.text) - // Resolve this module id into an absolute path .forEach(importPath => { - const resolvedModule = this.moduleResolver.resolveModuleImport(importPath, file); - if (resolvedModule) { - if (resolvedModule instanceof ResolvedRelativeModule) { - const internalDependency = resolvedModule.modulePath; - if (!alreadySeen.has(internalDependency)) { - alreadySeen.add(internalDependency); - this.recursivelyCollectDependencies( - internalDependency, dependencies, missing, deepImports, alreadySeen); - } - } else { - if (resolvedModule instanceof ResolvedDeepImport) { - deepImports.add(resolvedModule.importPath); - } else { - dependencies.add(resolvedModule.entryPointPath); - } - } - } else { + const resolved = + this.processImport(importPath, file, dependencies, missing, deepImports, alreadySeen); + if (!resolved) { missing.add(importPath); } }); } + + /** + * Resolve the given `importPath` from `file` and add it to the appropriate set. + * + * @returns `true` if the import was resolved (to an entry-point, a local import, or a + * deep-import). + */ + protected processImport( + importPath: string, file: AbsoluteFsPath, dependencies: Set, + missing: Set, deepImports: Set, alreadySeen: Set): boolean { + const resolvedModule = this.moduleResolver.resolveModuleImport(importPath, file); + if (resolvedModule === null) { + return false; + } + if (resolvedModule instanceof ResolvedRelativeModule) { + const internalDependency = resolvedModule.modulePath; + if (!alreadySeen.has(internalDependency)) { + alreadySeen.add(internalDependency); + this.recursivelyCollectDependencies( + internalDependency, dependencies, missing, deepImports, alreadySeen); + } + } else if (resolvedModule instanceof ResolvedDeepImport) { + deepImports.add(resolvedModule.importPath); + } else { + dependencies.add(resolvedModule.entryPointPath); + } + return true; + } } /** diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts index 58b698bc04..5cbf40ed3b 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -8,8 +8,9 @@ import {AbsoluteFsPath, FileSystem, PathSegment, join, relative, relativeFrom} from '../../../src/ngtsc/file_system'; import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; +import {hasBeenProcessed} from '../packages/build_marker'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, getEntryPointInfo} from '../packages/entry_point'; +import {EntryPoint, EntryPointJsonProperty, getEntryPointInfo} from '../packages/entry_point'; import {PathMappings} from '../utils'; import {EntryPointFinder} from './interface'; import {getBasePaths} from './utils'; @@ -37,8 +38,41 @@ export class TargetedEntryPointFinder implements EntryPointFinder { this.processNextPath(); } const targetEntryPoint = this.unsortedEntryPoints.get(this.targetPath); - return this.resolver.sortEntryPointsByDependency( + const entryPoints = this.resolver.sortEntryPointsByDependency( Array.from(this.unsortedEntryPoints.values()), targetEntryPoint); + + const invalidTarget = + entryPoints.invalidEntryPoints.find(i => i.entryPoint.path === this.targetPath); + if (invalidTarget !== undefined) { + throw new Error( + `The target entry-point "${invalidTarget.entryPoint.name}" has missing dependencies:\n` + + invalidTarget.missingDependencies.map(dep => ` - ${dep}\n`).join('')); + } + return entryPoints; + } + + targetNeedsProcessingOrCleaning( + propertiesToConsider: EntryPointJsonProperty[], compileAllFormats: boolean): boolean { + const entryPoint = this.getEntryPoint(this.targetPath); + if (entryPoint === null || !entryPoint.compiledByAngular) { + return false; + } + + for (const property of propertiesToConsider) { + if (entryPoint.packageJson[property]) { + // Here is a property that should be processed. + if (!hasBeenProcessed(entryPoint.packageJson, property)) { + return true; + } + if (!compileAllFormats) { + // This property has been processed, and we only need one. + return false; + } + } + } + // All `propertiesToConsider` that appear in this entry-point have been processed. + // In other words, there were no properties that need processing. + return false; } private processNextPath(): void { diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts b/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts index b0af89d6d0..8479c82625 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts @@ -13,6 +13,7 @@ import * as cluster from 'cluster'; import {Logger} from '../../logging/logger'; import {PackageJsonUpdater} from '../../writing/package_json_updater'; import {AnalyzeEntryPointsFn, CreateCompileFn, Executor} from '../api'; +import {LockFile} from '../lock_file'; import {ClusterMaster} from './master'; import {ClusterWorker} from './worker'; @@ -25,18 +26,19 @@ import {ClusterWorker} from './worker'; export class ClusterExecutor implements Executor { constructor( private workerCount: number, private logger: Logger, - private pkgJsonUpdater: PackageJsonUpdater) {} + private pkgJsonUpdater: PackageJsonUpdater, private lockFile: LockFile) {} async execute(analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn): Promise { if (cluster.isMaster) { - this.logger.debug( - `Running ngcc on ${this.constructor.name} (using ${this.workerCount} worker processes).`); - // This process is the cluster master. - const master = - new ClusterMaster(this.workerCount, this.logger, this.pkgJsonUpdater, analyzeEntryPoints); - return master.run(); + return this.lockFile.lock(() => { + this.logger.debug( + `Running ngcc on ${this.constructor.name} (using ${this.workerCount} worker processes).`); + const master = new ClusterMaster( + this.workerCount, this.logger, this.pkgJsonUpdater, analyzeEntryPoints); + return master.run(); + }); } else { // This process is a cluster worker. const worker = new ClusterWorker(this.logger, createCompileFn); diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts b/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts index aae19dd275..6014045507 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts @@ -44,7 +44,8 @@ export class ClusterPackageJsonUpdater implements PackageJsonUpdater { throw new Error(`Missing property path for writing value to '${packageJsonPath}'.`); } - applyChange(preExistingParsedJson, propPath, value); + // No need to take property positioning into account for in-memory representations. + applyChange(preExistingParsedJson, propPath, value, 'unimportant'); } } diff --git a/packages/compiler-cli/ngcc/src/execution/lock_file.ts b/packages/compiler-cli/ngcc/src/execution/lock_file.ts new file mode 100644 index 0000000000..30efb22f46 --- /dev/null +++ b/packages/compiler-cli/ngcc/src/execution/lock_file.ts @@ -0,0 +1,121 @@ +/** + * @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 process from 'process'; +import {FileSystem} from '../../../src/ngtsc/file_system'; + +/** + * The LockFile is used to prevent more than one instance of ngcc executing at the same time. + * + * When ngcc starts executing, it creates a file in the `compiler-cli/ngcc` folder. If it finds one + * is already there then it fails with a suitable error message. + * When ngcc completes executing, it removes the file so that future ngcc executions can start. + */ +export class LockFile { + lockFilePath = + this.fs.resolve(require.resolve('@angular/compiler-cli/ngcc'), '../__ngcc_lock_file__'); + + constructor(private fs: FileSystem) {} + + /** + * Run a function guarded by the lock file. + * + * Note that T can be a Promise. If so, we run the `remove()` call in the promise's `finally` + * handler. Otherwise we run the `remove()` call in the `try...finally` block. + * + * @param fn The function to run. + */ + lock(fn: () => T): T { + let isAsync = false; + this.create(); + try { + const result = fn(); + if (result instanceof Promise) { + isAsync = true; + // The cast is necessary because TS cannot deduce that T is now a promise here. + return result.finally(() => this.remove()) as unknown as T; + } else { + return result; + } + } finally { + if (!isAsync) { + this.remove(); + } + } + } + + /** + * Write a lock file to disk, or error if there is already one there. + */ + protected create() { + try { + this.addSignalHandlers(); + // To avoid race conditions, we check for existence of the lockfile + // by actually trying to create it exclusively + this.fs.writeFile(this.lockFilePath, process.pid.toString(), /* exclusive */ true); + } catch (e) { + this.removeSignalHandlers(); + if (e.code !== 'EEXIST') { + throw e; + } + + // The lockfile already exists so raise a helpful error. + // It is feasible that the lockfile was removed between the previous check for existence + // and this file-read. If so then we still error but as gracefully as possible. + let pid: string; + try { + pid = this.fs.readFile(this.lockFilePath); + } catch { + pid = '{unknown}'; + } + + throw new Error( + `ngcc is already running at process with id ${pid}.\n` + + `If you are running multiple builds in parallel then you should pre-process your node_modules via the command line ngcc tool before starting the builds;\n` + + `See https://v9.angular.io/guide/ivy#speeding-up-ngcc-compilation.\n` + + `(If you are sure no ngcc process is running then you should delete the lockfile at ${this.lockFilePath}.)`); + } + } + + /** + * Remove the lock file from disk. + */ + protected remove() { + this.removeSignalHandlers(); + if (this.fs.exists(this.lockFilePath)) { + this.fs.removeFile(this.lockFilePath); + } + } + + protected addSignalHandlers() { + process.once('SIGINT', this.signalHandler); + process.once('SIGHUP', this.signalHandler); + } + + protected removeSignalHandlers() { + process.removeListener('SIGINT', this.signalHandler); + process.removeListener('SIGHUP', this.signalHandler); + } + + /** + * This handle needs to be defined as a property rather than a method + * so that it can be passed around as a bound function. + */ + protected signalHandler = + () => { + this.remove(); + this.exit(1); + } + + /** + * This function wraps `process.exit()` which makes it easier to manage in unit tests, + * since it is not possible to mock out `process.exit()` when it is called from signal handlers. + */ + protected exit(code: number): void { + process.exit(code); + } +} diff --git a/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts b/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts index 205a8228ac..d06dceab3c 100644 --- a/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts +++ b/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts @@ -10,6 +10,7 @@ import {Logger} from '../logging/logger'; import {PackageJsonUpdater} from '../writing/package_json_updater'; import {AnalyzeEntryPointsFn, CreateCompileFn, Executor} from './api'; +import {LockFile} from './lock_file'; import {onTaskCompleted} from './utils'; @@ -17,27 +18,31 @@ import {onTaskCompleted} from './utils'; * An `Executor` that processes all tasks serially and completes synchronously. */ export class SingleProcessExecutor implements Executor { - constructor(private logger: Logger, private pkgJsonUpdater: PackageJsonUpdater) {} + constructor( + private logger: Logger, private pkgJsonUpdater: PackageJsonUpdater, + private lockFile: LockFile) {} execute(analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn): void { - this.logger.debug(`Running ngcc on ${this.constructor.name}.`); + this.lockFile.lock(() => { + this.logger.debug(`Running ngcc on ${this.constructor.name}.`); - const taskQueue = analyzeEntryPoints(); - const compile = - createCompileFn((task, outcome) => onTaskCompleted(this.pkgJsonUpdater, task, outcome)); + const taskQueue = analyzeEntryPoints(); + const compile = + createCompileFn((task, outcome) => onTaskCompleted(this.pkgJsonUpdater, task, outcome)); - // Process all tasks. - this.logger.debug('Processing tasks...'); - const startTime = Date.now(); + // Process all tasks. + this.logger.debug('Processing tasks...'); + const startTime = Date.now(); - while (!taskQueue.allTasksCompleted) { - const task = taskQueue.getNextTask() !; - compile(task); - taskQueue.markTaskCompleted(task); - } + while (!taskQueue.allTasksCompleted) { + const task = taskQueue.getNextTask() !; + compile(task); + taskQueue.markTaskCompleted(task); + } - const duration = Math.round((Date.now() - startTime) / 1000); - this.logger.debug(`Processed tasks in ${duration}s.`); + const duration = Math.round((Date.now() - startTime) / 1000); + this.logger.debug(`Processed tasks in ${duration}s.`); + }); } } diff --git a/packages/compiler-cli/ngcc/src/host/commonjs_host.ts b/packages/compiler-cli/ngcc/src/host/commonjs_host.ts index 296a14af03..aa73065ee3 100644 --- a/packages/compiler-cli/ngcc/src/host/commonjs_host.ts +++ b/packages/compiler-cli/ngcc/src/host/commonjs_host.ts @@ -126,6 +126,7 @@ export class CommonJsReflectionHost extends Esm5ReflectionHost { name, declaration: { node: null, + known: null, expression: exportExpression, viaModule: null, }, @@ -159,9 +160,10 @@ export class CommonJsReflectionHost extends Esm5ReflectionHost { const reexports: ExportDeclaration[] = []; importedExports.forEach((decl, name) => { if (decl.node !== null) { - reexports.push({name, declaration: {node: decl.node, viaModule}}); + reexports.push({name, declaration: {node: decl.node, known: null, viaModule}}); } else { - reexports.push({name, declaration: {node: null, expression: decl.expression, viaModule}}); + reexports.push( + {name, declaration: {node: null, known: null, expression: decl.expression, viaModule}}); } }); return reexports; @@ -186,7 +188,7 @@ export class CommonJsReflectionHost extends Esm5ReflectionHost { } const viaModule = !importInfo.from.startsWith('.') ? importInfo.from : null; - return {node: importedFile, viaModule}; + return {node: importedFile, known: null, viaModule}; } private resolveModuleName(moduleName: string, containingFile: ts.SourceFile): ts.SourceFile diff --git a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts index 13b5d1e9af..fe498123ec 100644 --- a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassDeclaration, ClassMember, ClassMemberKind, ConcreteDeclaration, CtorParameter, Declaration, Decorator, TypeScriptReflectionHost, TypeValueReference, isDecoratorIdentifier, reflectObjectLiteral} from '../../../src/ngtsc/reflection'; +import {ClassDeclaration, ClassMember, ClassMemberKind, ConcreteDeclaration, CtorParameter, Declaration, Decorator, KnownDeclaration, TypeScriptReflectionHost, TypeValueReference, isDecoratorIdentifier, reflectObjectLiteral,} from '../../../src/ngtsc/reflection'; import {isWithinPackage} from '../analysis/util'; import {Logger} from '../logging/logger'; import {BundleProgram} from '../packages/bundle_program'; @@ -50,7 +50,7 @@ export const CONSTRUCTOR_PARAMS = 'ctorParameters' as ts.__String; */ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements NgccReflectionHost { /** - * A mapping from source declarations typings declarations, which are both publicly exported. + * A mapping from source declarations to typings declarations, which are both publicly exported. * * There should be one entry for every public export visible from the root file of the source * tree. Note that by definition the key and value declarations will not be in the same TS @@ -353,6 +353,17 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N } } + // If the identifier resolves to the global JavaScript `Object`, return a + // declaration that denotes it as the known `JsGlobalObject` declaration. + if (superDeclaration !== null && this.isJavaScriptObjectDeclaration(superDeclaration)) { + return { + known: KnownDeclaration.JsGlobalObject, + expression: id, + viaModule: null, + node: null, + }; + } + return superDeclaration; } @@ -1562,14 +1573,14 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N Map { const declarationMap = new Map(); const dtsDeclarationMap = new Map(); - const dtsFiles = getNonRootFiles(dts); const typeChecker = dts.program.getTypeChecker(); + + const dtsFiles = getNonRootPackageFiles(dts); for (const dtsFile of dtsFiles) { - if (isWithinPackage(dts.package, dtsFile)) { - this.collectDtsExportedDeclarations(dtsDeclarationMap, dtsFile, typeChecker); - } + this.collectDtsExportedDeclarations(dtsDeclarationMap, dtsFile, typeChecker); } - const srcFiles = getNonRootFiles(src); + + const srcFiles = getNonRootPackageFiles(src); for (const srcFile of srcFiles) { this.collectSrcExportedDeclarations(declarationMap, dtsDeclarationMap, srcFile); } @@ -1697,6 +1708,30 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N const exportDecl = namespaceExports.get(expression.name.text) !; return {...exportDecl, viaModule: namespaceDecl.viaModule}; } + + /** Checks if the specified declaration resolves to the known JavaScript global `Object`. */ + protected isJavaScriptObjectDeclaration(decl: Declaration): boolean { + if (decl.node === null) { + return false; + } + const node = decl.node; + // The default TypeScript library types the global `Object` variable through + // a variable declaration with a type reference resolving to `ObjectConstructor`. + if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name) || + node.name.text !== 'Object' || node.type === undefined) { + return false; + } + const typeNode = node.type; + // If the variable declaration does not have a type resolving to `ObjectConstructor`, + // we cannot guarantee that the declaration resolves to the global `Object` variable. + if (!ts.isTypeReferenceNode(typeNode) || !ts.isIdentifier(typeNode.typeName) || + typeNode.typeName.text !== 'ObjectConstructor') { + return false; + } + // Finally, check if the type definition for `Object` originates from a default library + // definition file. This requires default types to be enabled for the host program. + return this.src.program.isSourceFileDefaultLibrary(node.getSourceFile()); + } } ///////////// Exported Helpers ///////////// @@ -2035,7 +2070,8 @@ function getRootFileOrFail(bundle: BundleProgram): ts.SourceFile { return rootFile; } -function getNonRootFiles(bundle: BundleProgram): ts.SourceFile[] { +function getNonRootPackageFiles(bundle: BundleProgram): ts.SourceFile[] { const rootFile = bundle.program.getSourceFile(bundle.path); - return bundle.program.getSourceFiles().filter(f => f !== rootFile); + return bundle.program.getSourceFiles().filter( + f => (f !== rootFile) && isWithinPackage(bundle.package, f)); } diff --git a/packages/compiler-cli/ngcc/src/host/esm5_host.ts b/packages/compiler-cli/ngcc/src/host/esm5_host.ts index e003921765..4307af7d23 100644 --- a/packages/compiler-cli/ngcc/src/host/esm5_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm5_host.ts @@ -14,6 +14,7 @@ import {getNameText, hasNameIdentifier, stripDollarSuffix} from '../utils'; import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignment, isAssignmentStatement} from './esm2015_host'; import {NgccClassSymbol} from './ngcc_host'; + /** * ESM5 packages contain ECMAScript IIFE functions that act like classes. For example: * @@ -655,6 +656,8 @@ function getTsHelperFn(node: ts.NamedDeclaration): TsHelperFn|null { null; switch (name) { + case '__assign': + return TsHelperFn.Assign; case '__spread': return TsHelperFn.Spread; case '__spreadArrays': diff --git a/packages/compiler-cli/ngcc/src/host/umd_host.ts b/packages/compiler-cli/ngcc/src/host/umd_host.ts index 8cd3458db4..5fea53102d 100644 --- a/packages/compiler-cli/ngcc/src/host/umd_host.ts +++ b/packages/compiler-cli/ngcc/src/host/umd_host.ts @@ -140,6 +140,7 @@ export class UmdReflectionHost extends Esm5ReflectionHost { name, declaration: { node: null, + known: null, expression: exportExpression, viaModule: null, }, @@ -182,9 +183,10 @@ export class UmdReflectionHost extends Esm5ReflectionHost { const reexports: ExportDeclaration[] = []; importedExports.forEach((decl, name) => { if (decl.node !== null) { - reexports.push({name, declaration: {node: decl.node, viaModule}}); + reexports.push({name, declaration: {node: decl.node, known: null, viaModule}}); } else { - reexports.push({name, declaration: {node: null, expression: decl.expression, viaModule}}); + reexports.push( + {name, declaration: {node: null, known: null, expression: decl.expression, viaModule}}); } }); return reexports; @@ -213,7 +215,7 @@ export class UmdReflectionHost extends Esm5ReflectionHost { // We need to add the `viaModule` because the `getExportsOfModule()` call // did not know that we were importing the declaration. - return {node: importedFile, viaModule: importInfo.from}; + return {node: importedFile, known: null, viaModule: importInfo.from}; } private resolveModuleName(moduleName: string, containingFile: ts.SourceFile): ts.SourceFile diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index 5cb77c0527..8f79b4afde 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -16,16 +16,18 @@ import {replaceTsWithNgInErrors} from '../../src/ngtsc/diagnostics'; import {AbsoluteFsPath, FileSystem, absoluteFrom, dirname, getFileSystem, resolve} from '../../src/ngtsc/file_system'; import {CommonJsDependencyHost} from './dependencies/commonjs_dependency_host'; -import {DependencyResolver, InvalidEntryPoint, PartiallyOrderedEntryPoints, SortedEntryPointsInfo} from './dependencies/dependency_resolver'; +import {DependencyResolver, InvalidEntryPoint} from './dependencies/dependency_resolver'; import {DtsDependencyHost} from './dependencies/dts_dependency_host'; import {EsmDependencyHost} from './dependencies/esm_dependency_host'; import {ModuleResolver} from './dependencies/module_resolver'; import {UmdDependencyHost} from './dependencies/umd_dependency_host'; import {DirectoryWalkerEntryPointFinder} from './entry_point_finder/directory_walker_entry_point_finder'; +import {EntryPointFinder} from './entry_point_finder/interface'; import {TargetedEntryPointFinder} from './entry_point_finder/targeted_entry_point_finder'; import {AnalyzeEntryPointsFn, CreateCompileFn, Executor, PartiallyOrderedTasks, Task, TaskProcessingOutcome, TaskQueue} from './execution/api'; import {ClusterExecutor} from './execution/cluster/executor'; import {ClusterPackageJsonUpdater} from './execution/cluster/package_json_updater'; +import {LockFile} from './execution/lock_file'; import {AsyncSingleProcessExecutor, SingleProcessExecutor} from './execution/single_process_executor'; import {ParallelTaskQueue} from './execution/task_selection/parallel_task_queue'; import {SerialTaskQueue} from './execution/task_selection/serial_task_queue'; @@ -37,12 +39,12 @@ import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FOR import {makeEntryPointBundle} from './packages/entry_point_bundle'; import {Transformer} from './packages/transformer'; import {PathMappings} from './utils'; +import {cleanOutdatedPackages} from './writing/cleaning/package_cleaner'; import {FileWriter} from './writing/file_writer'; import {InPlaceFileWriter} from './writing/in_place_file_writer'; import {NewEntryPointFileWriter} from './writing/new_entry_point_file_writer'; import {DirectPackageJsonUpdater, PackageJsonUpdater} from './writing/package_json_updater'; - /** * The options to configure the ngcc compiler for synchronous execution. */ @@ -124,8 +126,6 @@ export type AsyncNgccOptions = Omit& {async: true}; */ export type NgccOptions = AsyncNgccOptions | SyncNgccOptions; -const EMPTY_GRAPH = new DepGraph(); - /** * This is the main entry-point into ngcc (aNGular Compatibility Compiler). * @@ -148,6 +148,23 @@ export function mainNgcc( // NOTE: Avoid eagerly instantiating anything that might not be used when running sync/async or in // master/worker process. const fileSystem = getFileSystem(); + const absBasePath = absoluteFrom(basePath); + const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); + const dependencyResolver = getDependencyResolver(fileSystem, logger, pathMappings); + + // Bail out early if the work is already done. + const supportedPropertiesToConsider = ensureSupportedProperties(propertiesToConsider); + const absoluteTargetEntryPointPath = + targetEntryPointPath !== undefined ? resolve(basePath, targetEntryPointPath) : null; + const finder = getEntryPointFinder( + fileSystem, logger, dependencyResolver, config, absBasePath, absoluteTargetEntryPointPath, + pathMappings); + if (finder instanceof TargetedEntryPointFinder && + !finder.targetNeedsProcessingOrCleaning(supportedPropertiesToConsider, compileAllFormats)) { + logger.debug('The target entry-point has already been processed'); + return; + } + // NOTE: To avoid file corruption, ensure that each `ngcc` invocation only creates _one_ instance // of `PackageJsonUpdater` that actually writes to disk (across all processes). // This is hard to enforce automatically, when running on multiple processes, so needs to be @@ -159,27 +176,15 @@ export function mainNgcc( logger.debug('Analyzing entry-points...'); const startTime = Date.now(); - const supportedPropertiesToConsider = ensureSupportedProperties(propertiesToConsider); + let entryPointInfo = finder.findEntryPoints(); + const cleaned = cleanOutdatedPackages(fileSystem, entryPointInfo.entryPoints); + if (cleaned) { + // If we had to clean up one or more packages then we must read in the entry-points again. + entryPointInfo = finder.findEntryPoints(); + } - const moduleResolver = new ModuleResolver(fileSystem, pathMappings); - const esmDependencyHost = new EsmDependencyHost(fileSystem, moduleResolver); - const umdDependencyHost = new UmdDependencyHost(fileSystem, moduleResolver); - const commonJsDependencyHost = new CommonJsDependencyHost(fileSystem, moduleResolver); - const dtsDependencyHost = new DtsDependencyHost(fileSystem, pathMappings); - const dependencyResolver = new DependencyResolver( - fileSystem, logger, { - esm5: esmDependencyHost, - esm2015: esmDependencyHost, - umd: umdDependencyHost, - commonjs: commonJsDependencyHost - }, - dtsDependencyHost); - - const absBasePath = absoluteFrom(basePath); - const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); - const {entryPoints, graph} = getEntryPoints( - fileSystem, pkgJsonUpdater, logger, dependencyResolver, config, absBasePath, - targetEntryPointPath, pathMappings, supportedPropertiesToConsider, compileAllFormats); + const {entryPoints, invalidEntryPoints, graph} = entryPointInfo; + logInvalidEntryPoints(logger, invalidEntryPoints); const unprocessableEntryPointPaths: string[] = []; // The tasks are partially ordered by virtue of the entry-points being partially ordered too. @@ -187,7 +192,7 @@ export function mainNgcc( for (const entryPoint of entryPoints) { const packageJson = entryPoint.packageJson; - const hasProcessedTypings = hasBeenProcessed(packageJson, 'typings', entryPoint.path); + const hasProcessedTypings = hasBeenProcessed(packageJson, 'typings'); const {propertiesToProcess, equivalentPropertiesMap} = getPropertiesToProcess(packageJson, supportedPropertiesToConsider, compileAllFormats); let processDts = !hasProcessedTypings; @@ -252,7 +257,7 @@ export function mainNgcc( } // The format-path which the property maps to is already processed - nothing to do. - if (hasBeenProcessed(packageJson, formatProperty, entryPoint.path)) { + if (hasBeenProcessed(packageJson, formatProperty)) { logger.debug(`Skipping ${entryPoint.name} : ${formatProperty} (already compiled).`); onTaskCompleted(task, TaskProcessingOutcome.AlreadyProcessed); return; @@ -285,7 +290,7 @@ export function mainNgcc( }; // The executor for actually planning and getting the work done. - const executor = getExecutor(async, inParallel, logger, pkgJsonUpdater); + const executor = getExecutor(async, inParallel, logger, pkgJsonUpdater, new LockFile(fileSystem)); return executor.execute(analyzeEntryPoints, createCompileFn); } @@ -330,119 +335,49 @@ function getTaskQueue( } function getExecutor( - async: boolean, inParallel: boolean, logger: Logger, - pkgJsonUpdater: PackageJsonUpdater): Executor { + async: boolean, inParallel: boolean, logger: Logger, pkgJsonUpdater: PackageJsonUpdater, + lockFile: LockFile): Executor { if (inParallel) { // Execute in parallel (which implies async). // Use up to 8 CPU cores for workers, always reserving one for master. const workerCount = Math.min(8, os.cpus().length - 1); - return new ClusterExecutor(workerCount, logger, pkgJsonUpdater); + return new ClusterExecutor(workerCount, logger, pkgJsonUpdater, lockFile); } else { // Execute serially, on a single thread (either sync or async). - return async ? new AsyncSingleProcessExecutor(logger, pkgJsonUpdater) : - new SingleProcessExecutor(logger, pkgJsonUpdater); + return async ? new AsyncSingleProcessExecutor(logger, pkgJsonUpdater, lockFile) : + new SingleProcessExecutor(logger, pkgJsonUpdater, lockFile); } } -function getEntryPoints( - fs: FileSystem, pkgJsonUpdater: PackageJsonUpdater, logger: Logger, - resolver: DependencyResolver, config: NgccConfiguration, basePath: AbsoluteFsPath, - targetEntryPointPath: string | undefined, pathMappings: PathMappings | undefined, - propertiesToConsider: string[], compileAllFormats: boolean): - {entryPoints: PartiallyOrderedEntryPoints, graph: DepGraph} { - const {entryPoints, invalidEntryPoints, graph} = (targetEntryPointPath !== undefined) ? - getTargetedEntryPoints( - fs, pkgJsonUpdater, logger, resolver, config, basePath, targetEntryPointPath, - propertiesToConsider, compileAllFormats, pathMappings) : - getAllEntryPoints(fs, config, logger, resolver, basePath, pathMappings); - logInvalidEntryPoints(logger, invalidEntryPoints); - return {entryPoints, graph}; +function getDependencyResolver( + fileSystem: FileSystem, logger: Logger, + pathMappings: PathMappings | undefined): DependencyResolver { + const moduleResolver = new ModuleResolver(fileSystem, pathMappings); + const esmDependencyHost = new EsmDependencyHost(fileSystem, moduleResolver); + const umdDependencyHost = new UmdDependencyHost(fileSystem, moduleResolver); + const commonJsDependencyHost = new CommonJsDependencyHost(fileSystem, moduleResolver); + const dtsDependencyHost = new DtsDependencyHost(fileSystem, pathMappings); + return new DependencyResolver( + fileSystem, logger, { + esm5: esmDependencyHost, + esm2015: esmDependencyHost, + umd: umdDependencyHost, + commonjs: commonJsDependencyHost + }, + dtsDependencyHost); } -function getTargetedEntryPoints( - fs: FileSystem, pkgJsonUpdater: PackageJsonUpdater, logger: Logger, - resolver: DependencyResolver, config: NgccConfiguration, basePath: AbsoluteFsPath, - targetEntryPointPath: string, propertiesToConsider: string[], compileAllFormats: boolean, - pathMappings: PathMappings | undefined): SortedEntryPointsInfo { - const absoluteTargetEntryPointPath = resolve(basePath, targetEntryPointPath); - if (hasProcessedTargetEntryPoint( - fs, absoluteTargetEntryPointPath, propertiesToConsider, compileAllFormats)) { - logger.debug('The target entry-point has already been processed'); - return { - entryPoints: [] as unknown as PartiallyOrderedEntryPoints, - invalidEntryPoints: [], - ignoredDependencies: [], - graph: EMPTY_GRAPH, - }; +function getEntryPointFinder( + fs: FileSystem, logger: Logger, resolver: DependencyResolver, config: NgccConfiguration, + basePath: AbsoluteFsPath, absoluteTargetEntryPointPath: AbsoluteFsPath | null, + pathMappings: PathMappings | undefined): EntryPointFinder { + if (absoluteTargetEntryPointPath !== null) { + return new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings); + } else { + return new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, basePath, pathMappings); } - const finder = new TargetedEntryPointFinder( - fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings); - const entryPointInfo = finder.findEntryPoints(); - const invalidTarget = entryPointInfo.invalidEntryPoints.find( - i => i.entryPoint.path === absoluteTargetEntryPointPath); - if (invalidTarget !== undefined) { - throw new Error( - `The target entry-point "${invalidTarget.entryPoint.name}" has missing dependencies:\n` + - invalidTarget.missingDependencies.map(dep => ` - ${dep}\n`).join('')); - } - if (entryPointInfo.entryPoints.length === 0) { - markNonAngularPackageAsProcessed(fs, pkgJsonUpdater, absoluteTargetEntryPointPath); - } - return entryPointInfo; -} - -function getAllEntryPoints( - fs: FileSystem, config: NgccConfiguration, logger: Logger, resolver: DependencyResolver, - basePath: AbsoluteFsPath, pathMappings: PathMappings | undefined): SortedEntryPointsInfo { - const finder = - new DirectoryWalkerEntryPointFinder(fs, config, logger, resolver, basePath, pathMappings); - return finder.findEntryPoints(); -} - -function hasProcessedTargetEntryPoint( - fs: FileSystem, targetPath: AbsoluteFsPath, propertiesToConsider: string[], - compileAllFormats: boolean) { - const packageJsonPath = resolve(targetPath, 'package.json'); - // It might be that this target is configured in which case its package.json might not exist. - if (!fs.exists(packageJsonPath)) { - return false; - } - const packageJson = JSON.parse(fs.readFile(packageJsonPath)); - - for (const property of propertiesToConsider) { - if (packageJson[property]) { - // Here is a property that should be processed - if (hasBeenProcessed(packageJson, property as EntryPointJsonProperty, targetPath)) { - if (!compileAllFormats) { - // It has been processed and we only need one, so we are done. - return true; - } - } else { - // It has not been processed but we need all of them, so we are done. - return false; - } - } - } - // Either all formats need to be compiled and there were none that were unprocessed, - // Or only the one matching format needs to be compiled but there was at least one matching - // property before the first processed format that was unprocessed. - return true; -} - -/** - * If we get here, then the requested entry-point did not contain anything compiled by - * the old Angular compiler. Therefore there is nothing for ngcc to do. - * So mark all formats in this entry-point as processed so that clients of ngcc can avoid - * triggering ngcc for this entry-point in the future. - */ -function markNonAngularPackageAsProcessed( - fs: FileSystem, pkgJsonUpdater: PackageJsonUpdater, path: AbsoluteFsPath) { - const packageJsonPath = resolve(path, 'package.json'); - const packageJson = JSON.parse(fs.readFile(packageJsonPath)); - - // Note: We are marking all supported properties as processed, even if they don't exist in the - // `package.json` file. While this is redundant, it is also harmless. - markAsProcessed(pkgJsonUpdater, packageJson, packageJsonPath, SUPPORTED_FORMAT_PROPERTIES); } function logInvalidEntryPoints(logger: Logger, invalidEntryPoints: InvalidEntryPoint[]): void { diff --git a/packages/compiler-cli/ngcc/src/migrations/migration.ts b/packages/compiler-cli/ngcc/src/migrations/migration.ts index 2738dc3e53..b0da462538 100644 --- a/packages/compiler-cli/ngcc/src/migrations/migration.ts +++ b/packages/compiler-cli/ngcc/src/migrations/migration.ts @@ -43,6 +43,7 @@ export interface MigrationHost { * given class. * @param clazz the class to receive the new decorator. * @param decorator the decorator to inject. + * @param flags optional bitwise flag to influence the compilation of the decorator. */ injectSyntheticDecorator(clazz: ClassDeclaration, decorator: Decorator, flags?: HandlerFlags): void; diff --git a/packages/compiler-cli/ngcc/src/packages/build_marker.ts b/packages/compiler-cli/ngcc/src/packages/build_marker.ts index 26d96d44f7..3e214a63f0 100644 --- a/packages/compiler-cli/ngcc/src/packages/build_marker.ts +++ b/packages/compiler-cli/ngcc/src/packages/build_marker.ts @@ -5,42 +5,66 @@ * 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, basename, dirname, isRoot} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath} from '../../../src/ngtsc/file_system'; +import {NGCC_PROPERTY_EXTENSION} from '../writing/new_entry_point_file_writer'; import {PackageJsonUpdater} from '../writing/package_json_updater'; import {EntryPointPackageJson, PackageJsonFormatProperties} from './entry_point'; export const NGCC_VERSION = '0.0.0-PLACEHOLDER'; /** - * Check whether ngcc has already processed a given entry-point format. + * Returns true if there is a format in this entry-point that was compiled with an outdated version + * of ngcc. * - * The entry-point is defined by the package.json contents provided. - * The format is defined by the provided property name of the path to the bundle in the package.json + * @param packageJson The parsed contents of the package.json for the entry-point + */ +export function needsCleaning(packageJson: EntryPointPackageJson): boolean { + return Object.values(packageJson.__processed_by_ivy_ngcc__ || {}) + .some(value => value !== NGCC_VERSION); +} + +/** + * Clean any build marker artifacts from the given `packageJson` object. + * @param packageJson The parsed contents of the package.json to modify + * @returns true if the package was modified during cleaning + */ +export function cleanPackageJson(packageJson: EntryPointPackageJson): boolean { + if (packageJson.__processed_by_ivy_ngcc__ !== undefined) { + // Remove the actual marker + delete packageJson.__processed_by_ivy_ngcc__; + // Remove new format properties that have been added by ngcc + for (const prop of Object.keys(packageJson)) { + if (prop.endsWith(NGCC_PROPERTY_EXTENSION)) { + delete packageJson[prop]; + } + } + + // Also remove the prebulish script if we modified it + const scripts = packageJson.scripts; + if (scripts !== undefined && scripts.prepublishOnly) { + delete scripts.prepublishOnly; + if (scripts.prepublishOnly__ivy_ngcc_bak !== undefined) { + scripts.prepublishOnly = scripts.prepublishOnly__ivy_ngcc_bak; + delete scripts.prepublishOnly__ivy_ngcc_bak; + } + } + return true; + } + return false; +} + +/** + * Check whether ngcc has already processed a given entry-point format. * * @param packageJson The parsed contents of the package.json file for the entry-point. * @param format The entry-point format property in the package.json to check. - * @returns true if the entry-point and format have already been processed with this ngcc version. - * @throws Error if the `packageJson` property is not an object. - * @throws Error if the entry-point has already been processed with a different ngcc version. + * @returns true if the `format` in the entry-point has already been processed by this ngcc version, + * false otherwise. */ export function hasBeenProcessed( - packageJson: EntryPointPackageJson, format: PackageJsonFormatProperties, - entryPointPath: AbsoluteFsPath): boolean { - if (!packageJson.__processed_by_ivy_ngcc__) { - return false; - } - if (Object.keys(packageJson.__processed_by_ivy_ngcc__) - .some(property => packageJson.__processed_by_ivy_ngcc__ ![property] !== NGCC_VERSION)) { - let nodeModulesFolderPath = entryPointPath; - while (!isRoot(nodeModulesFolderPath) && basename(nodeModulesFolderPath) !== 'node_modules') { - nodeModulesFolderPath = dirname(nodeModulesFolderPath); - } - throw new Error( - `The ngcc compiler has changed since the last ngcc build.\n` + - `Please remove "${isRoot(nodeModulesFolderPath) ? entryPointPath : nodeModulesFolderPath}" and try again.`); - } - - return packageJson.__processed_by_ivy_ngcc__[format] === NGCC_VERSION; + packageJson: EntryPointPackageJson, format: PackageJsonFormatProperties): boolean { + return packageJson.__processed_by_ivy_ngcc__ !== undefined && + packageJson.__processed_by_ivy_ngcc__[format] === NGCC_VERSION; } /** @@ -60,7 +84,7 @@ export function markAsProcessed( // Update the format properties to mark them as processed. for (const prop of formatProperties) { - update.addChange(['__processed_by_ivy_ngcc__', prop], NGCC_VERSION); + update.addChange(['__processed_by_ivy_ngcc__', prop], NGCC_VERSION, 'alphabetic'); } // Update the `prepublishOnly` script (keeping a backup, if necessary) to prevent `ngcc`'d diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts index dd770ae792..89d28e2398 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import {AbsoluteFsPath, FileSystem, NgtscCompilerHost, absoluteFrom} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath, FileSystem, NgtscCompilerHost} from '../../../src/ngtsc/file_system'; import {PathMappings} from '../utils'; import {BundleProgram, makeBundleProgram} from './bundle_program'; import {EntryPoint, EntryPointFormat} from './entry_point'; @@ -50,8 +50,7 @@ export function makeEntryPointBundle( const rootDir = entryPoint.package; const options: ts.CompilerOptions = { allowJs: true, - maxNodeModuleJsDepth: Infinity, - noLib: true, rootDir, ...pathMappings + maxNodeModuleJsDepth: Infinity, rootDir, ...pathMappings }; const srcHost = new NgccSourcesCompilerHost(fs, options, entryPoint.path); const dtsHost = new NgtscCompilerHost(fs, options); diff --git a/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts b/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts index 9063070c55..789ba9d8d5 100644 --- a/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts +++ b/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts @@ -124,6 +124,7 @@ export class DtsRenderer { // Capture the rendering info from the decoration analyses decorationAnalyses.forEach(compiledFile => { + let appliedReexports = false; compiledFile.compiledClasses.forEach(compiledClass => { const dtsDeclaration = this.host.getDtsDeclaration(compiledClass.declaration); if (dtsDeclaration) { @@ -135,9 +136,11 @@ export class DtsRenderer { // to work, the typing file and JS file must be in parallel trees. This logic will detect // the simplest version of this case, which is sufficient to handle most commonjs // libraries. - if (compiledClass.declaration.getSourceFile().fileName === - dtsFile.fileName.replace(/\.d\.ts$/, '.js')) { - renderInfo.reexports.push(...compiledClass.reexports); + if (!appliedReexports && + compiledClass.declaration.getSourceFile().fileName === + dtsFile.fileName.replace(/\.d\.ts$/, '.js')) { + renderInfo.reexports.push(...compiledFile.reexports); + appliedReexports = true; } dtsMap.set(dtsFile, renderInfo); } diff --git a/packages/compiler-cli/ngcc/src/rendering/renderer.ts b/packages/compiler-cli/ngcc/src/rendering/renderer.ts index 0f30f7bc3a..fd2f873b46 100644 --- a/packages/compiler-cli/ngcc/src/rendering/renderer.ts +++ b/packages/compiler-cli/ngcc/src/rendering/renderer.ts @@ -88,13 +88,13 @@ export class Renderer { const renderedStatements = this.renderAdjacentStatements(compiledFile.sourceFile, clazz, importManager); this.srcFormatter.addAdjacentStatements(outputText, clazz, renderedStatements); - - if (!isEntryPoint && clazz.reexports.length > 0) { - this.srcFormatter.addDirectExports( - outputText, clazz.reexports, importManager, compiledFile.sourceFile); - } }); + if (!isEntryPoint && compiledFile.reexports.length > 0) { + this.srcFormatter.addDirectExports( + outputText, compiledFile.reexports, importManager, compiledFile.sourceFile); + } + this.srcFormatter.addConstants( outputText, renderConstantPool( diff --git a/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts b/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts new file mode 100644 index 0000000000..3bf1861955 --- /dev/null +++ b/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.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 {AbsoluteFsPath, FileSystem, PathSegment, absoluteFrom} from '../../../../src/ngtsc/file_system'; +import {cleanPackageJson} from '../../packages/build_marker'; +import {NGCC_BACKUP_EXTENSION} from '../in_place_file_writer'; +import {NGCC_DIRECTORY} from '../new_entry_point_file_writer'; +import {isLocalDirectory} from './utils'; + +/** +* Implement this interface to extend the cleaning strategies of the `PackageCleaner`. +*/ +export interface CleaningStrategy { + canClean(path: AbsoluteFsPath, basename: PathSegment): boolean; + clean(path: AbsoluteFsPath, basename: PathSegment): void; +} + +/** + * A CleaningStrategy that reverts changes to package.json files by removing the build marker and + * other properties. + */ +export class PackageJsonCleaner implements CleaningStrategy { + constructor(private fs: FileSystem) {} + canClean(_path: AbsoluteFsPath, basename: PathSegment): boolean { + return basename === 'package.json'; + } + clean(path: AbsoluteFsPath, _basename: PathSegment): void { + const packageJson = JSON.parse(this.fs.readFile(path)); + if (cleanPackageJson(packageJson)) { + this.fs.writeFile(path, `${JSON.stringify(packageJson, null, 2)}\n`); + } + } +} + +/** + * A CleaningStrategy that removes the extra directory containing generated entry-point formats. + */ +export class NgccDirectoryCleaner implements CleaningStrategy { + constructor(private fs: FileSystem) {} + canClean(path: AbsoluteFsPath, basename: PathSegment): boolean { + return basename === NGCC_DIRECTORY && isLocalDirectory(this.fs, path); + } + clean(path: AbsoluteFsPath, _basename: PathSegment): void { this.fs.removeDeep(path); } +} + +/** + * A CleaningStrategy that reverts files that were overwritten and removes the backup files that + * ngcc created. + */ +export class BackupFileCleaner implements CleaningStrategy { + constructor(private fs: FileSystem) {} + canClean(path: AbsoluteFsPath, basename: PathSegment): boolean { + return this.fs.extname(basename) === NGCC_BACKUP_EXTENSION && + this.fs.exists(absoluteFrom(path.replace(NGCC_BACKUP_EXTENSION, ''))); + } + clean(path: AbsoluteFsPath, _basename: PathSegment): void { + this.fs.moveFile(path, absoluteFrom(path.replace(NGCC_BACKUP_EXTENSION, ''))); + } +} diff --git a/packages/compiler-cli/ngcc/src/writing/cleaning/package_cleaner.ts b/packages/compiler-cli/ngcc/src/writing/cleaning/package_cleaner.ts new file mode 100644 index 0000000000..68917d41ff --- /dev/null +++ b/packages/compiler-cli/ngcc/src/writing/cleaning/package_cleaner.ts @@ -0,0 +1,80 @@ +/** + * @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, FileSystem} from '../../../../src/ngtsc/file_system'; +import {needsCleaning} from '../../packages/build_marker'; +import {EntryPoint} from '../../packages/entry_point'; + +import {BackupFileCleaner, CleaningStrategy, NgccDirectoryCleaner, PackageJsonCleaner} from './cleaning_strategies'; +import {isLocalDirectory} from './utils'; + +/** + * A class that can clean ngcc artifacts from a directory. + */ +export class PackageCleaner { + constructor(private fs: FileSystem, private cleaners: CleaningStrategy[]) {} + + /** + * Recurse through the file-system cleaning files and directories as determined by the configured + * cleaning-strategies. + * + * @param directory the current directory to clean + */ + clean(directory: AbsoluteFsPath) { + const basenames = this.fs.readdir(directory); + for (const basename of basenames) { + if (basename === 'node_modules') { + continue; + } + + const path = this.fs.resolve(directory, basename); + for (const cleaner of this.cleaners) { + if (cleaner.canClean(path, basename)) { + cleaner.clean(path, basename); + break; + } + } + // Recurse into subdirectories (note that a cleaner may have removed this path) + if (isLocalDirectory(this.fs, path)) { + this.clean(path); + } + } + } +} + + +/** + * Iterate through the given `entryPoints` identifying the package for each that has at least one + * outdated processed format, then cleaning those packages. + * + * Note that we have to clean entire packages because there is no clear file-system boundary + * between entry-points within a package. So if one entry-point is outdated we have to clean + * everything within that package. + * + * @param fileSystem the current file-system + * @param entryPoints the entry-points that have been collected for this run of ngcc + * @returns true if packages needed to be cleaned. + */ +export function cleanOutdatedPackages(fileSystem: FileSystem, entryPoints: EntryPoint[]): boolean { + const packagesToClean = new Set(); + for (const entryPoint of entryPoints) { + if (needsCleaning(entryPoint.packageJson)) { + packagesToClean.add(entryPoint.package); + } + } + + const cleaner = new PackageCleaner(fileSystem, [ + new PackageJsonCleaner(fileSystem), + new NgccDirectoryCleaner(fileSystem), + new BackupFileCleaner(fileSystem), + ]); + for (const packagePath of packagesToClean) { + cleaner.clean(packagePath); + } + + return packagesToClean.size > 0; +} diff --git a/packages/compiler-cli/ngcc/src/writing/cleaning/utils.ts b/packages/compiler-cli/ngcc/src/writing/cleaning/utils.ts new file mode 100644 index 0000000000..2afece08c6 --- /dev/null +++ b/packages/compiler-cli/ngcc/src/writing/cleaning/utils.ts @@ -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 + */ +import {AbsoluteFsPath, FileSystem} from '../../../../src/ngtsc/file_system'; + +/** + * Returns true if the given `path` is a directory (not a symlink) and actually exists. + * + * @param fs the current filesystem + * @param path the path to check + */ +export function isLocalDirectory(fs: FileSystem, path: AbsoluteFsPath): boolean { + if (fs.exists(path)) { + const stat = fs.lstat(path); + return stat.isDirectory(); + } else { + return false; + } +} diff --git a/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts b/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts index 118f256fed..8619b49c57 100644 --- a/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts +++ b/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts @@ -12,6 +12,7 @@ import {EntryPointBundle} from '../packages/entry_point_bundle'; import {FileToWrite} from '../rendering/utils'; import {FileWriter} from './file_writer'; +export const NGCC_BACKUP_EXTENSION = '.__ivy_ngcc_bak'; /** * This FileWriter overwrites the transformed file, in-place, while creating * a back-up of the original file with an extra `.__ivy_ngcc_bak` extension. @@ -27,7 +28,7 @@ export class InPlaceFileWriter implements FileWriter { protected writeFileAndBackup(file: FileToWrite): void { this.fs.ensureDir(dirname(file.path)); - const backPath = absoluteFrom(`${file.path}.__ivy_ngcc_bak`); + const backPath = absoluteFrom(`${file.path}${NGCC_BACKUP_EXTENSION}`); if (this.fs.exists(backPath)) { throw new Error( `Tried to overwrite ${backPath} with an ngcc back up file, which is disallowed.`); diff --git a/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts b/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts index f21d64b049..2c9b0570c8 100644 --- a/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts +++ b/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts @@ -15,7 +15,8 @@ import {FileToWrite} from '../rendering/utils'; import {InPlaceFileWriter} from './in_place_file_writer'; import {PackageJsonUpdater} from './package_json_updater'; -const NGCC_DIRECTORY = '__ivy_ngcc__'; +export const NGCC_DIRECTORY = '__ivy_ngcc__'; +export const NGCC_PROPERTY_EXTENSION = '_ivy_ngcc'; /** * This FileWriter creates a copy of the original entry-point, then writes the transformed @@ -93,7 +94,8 @@ export class NewEntryPointFileWriter extends InPlaceFileWriter { `(${formatProperties.join(', ')}) map to more than one format-path.`); } - update.addChange([`${formatProperty}_ivy_ngcc`], newFormatPath); + update.addChange( + [`${formatProperty}${NGCC_PROPERTY_EXTENSION}`], newFormatPath, {before: formatProperty}); } update.writeChanges(packageJsonPath, packageJson); diff --git a/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts b/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts index 9295191efd..bfd5295ad4 100644 --- a/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts +++ b/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts @@ -10,7 +10,8 @@ import {AbsoluteFsPath, FileSystem, dirname} from '../../../src/ngtsc/file_syste import {JsonObject, JsonValue} from '../packages/entry_point'; -export type PackageJsonChange = [string[], JsonValue]; +export type PackageJsonChange = [string[], JsonValue, PackageJsonPropertyPositioning]; +export type PackageJsonPropertyPositioning = 'unimportant' | 'alphabetic' | {before: string}; export type WritePackageJsonChangesFn = (changes: PackageJsonChange[], packageJsonPath: AbsoluteFsPath, parsedJson?: JsonObject) => void; @@ -23,8 +24,9 @@ export type WritePackageJsonChangesFn = * const updatePackageJson = packageJsonUpdater * .createUpdate() * .addChange(['name'], 'package-foo') - * .addChange(['scripts', 'foo'], 'echo FOOOO...') - * .addChange(['dependencies', 'bar'], '1.0.0') + * .addChange(['scripts', 'foo'], 'echo FOOOO...', 'unimportant') + * .addChange(['dependencies', 'baz'], '1.0.0', 'alphabetic') + * .addChange(['dependencies', 'bar'], '2.0.0', {before: 'baz'}) * .writeChanges('/foo/package.json'); * // or * // .writeChanges('/foo/package.json', inMemoryParsedJson); @@ -33,13 +35,13 @@ export type WritePackageJsonChangesFn = export interface PackageJsonUpdater { /** * Create a `PackageJsonUpdate` object, which provides a fluent API for batching updates to a - * `package.json` file. (Batching the updates is useful, because it avoid unnecessary I/O + * `package.json` file. (Batching the updates is useful, because it avoids unnecessary I/O * operations.) */ createUpdate(): PackageJsonUpdate; /** - * Write a set of changes to the specified `package.json` file and (and optionally a pre-existing, + * Write a set of changes to the specified `package.json` file (and optionally a pre-existing, * in-memory representation of it). * * @param changes The set of changes to apply. @@ -65,15 +67,27 @@ export class PackageJsonUpdate { constructor(private writeChangesImpl: WritePackageJsonChangesFn) {} /** - * Record a change to a `package.json` property. If the ancestor objects do not yet exist in the - * `package.json` file, they will be created. + * Record a change to a `package.json` property. * - * @param propertyPath The path of a (possibly nested) property to update. + * If the ancestor objects do not yet exist in the `package.json` file, they will be created. The + * positioning of the property can also be specified. (If the property already exists, it will be + * moved accordingly.) + * + * NOTE: Property positioning is only guaranteed to be respected in the serialized `package.json` + * file. Positioning will not be taken into account when updating in-memory representations. + * + * NOTE 2: Property positioning only affects the last property in `propertyPath`. Ancestor + * objects' positioning will not be affected. + * + * @param propertyPath The path of a (possibly nested) property to add/update. * @param value The new value to set the property to. + * @param position The desired position for the added/updated property. */ - addChange(propertyPath: string[], value: JsonValue): this { + addChange( + propertyPath: string[], value: JsonValue, + positioning: PackageJsonPropertyPositioning = 'unimportant'): this { this.ensureNotApplied(); - this.changes.push([propertyPath, value]); + this.changes.push([propertyPath, value, positioning]); return this; } @@ -121,15 +135,16 @@ export class DirectPackageJsonUpdater implements PackageJsonUpdater { // Apply all changes to both the canonical representation (read from disk) and any pre-existing, // in-memory representation. - for (const [propPath, value] of changes) { + for (const [propPath, value, positioning] of changes) { if (propPath.length === 0) { throw new Error(`Missing property path for writing value to '${packageJsonPath}'.`); } - applyChange(parsedJson, propPath, value); + applyChange(parsedJson, propPath, value, positioning); if (preExistingParsedJson) { - applyChange(preExistingParsedJson, propPath, value); + // No need to take property positioning into account for in-memory representations. + applyChange(preExistingParsedJson, propPath, value, 'unimportant'); } } @@ -141,7 +156,9 @@ export class DirectPackageJsonUpdater implements PackageJsonUpdater { } // Helpers -export function applyChange(ctx: JsonObject, propPath: string[], value: JsonValue): void { +export function applyChange( + ctx: JsonObject, propPath: string[], value: JsonValue, + positioning: PackageJsonPropertyPositioning): void { const lastPropIdx = propPath.length - 1; const lastProp = propPath[lastPropIdx]; @@ -157,4 +174,42 @@ export function applyChange(ctx: JsonObject, propPath: string[], value: JsonValu } ctx[lastProp] = value; + positionProperty(ctx, lastProp, positioning); +} + +function movePropBefore(ctx: JsonObject, prop: string, isNextProp: (p: string) => boolean): void { + const allProps = Object.keys(ctx); + const otherProps = allProps.filter(p => p !== prop); + const nextPropIdx = otherProps.findIndex(isNextProp); + const propsToShift = (nextPropIdx === -1) ? [] : otherProps.slice(nextPropIdx); + + movePropToEnd(ctx, prop); + propsToShift.forEach(p => movePropToEnd(ctx, p)); +} + +function movePropToEnd(ctx: JsonObject, prop: string): void { + const value = ctx[prop]; + delete ctx[prop]; + ctx[prop] = value; +} + +function positionProperty( + ctx: JsonObject, prop: string, positioning: PackageJsonPropertyPositioning): void { + switch (positioning) { + case 'alphabetic': + movePropBefore(ctx, prop, p => p > prop); + break; + case 'unimportant': + // Leave the property order unchanged; i.e. newly added properties will be last and existing + // ones will remain in their old position. + break; + default: + if ((typeof positioning !== 'object') || (positioning.before === undefined)) { + throw new Error( + `Unknown positioning (${JSON.stringify(positioning)}) for property '${prop}'.`); + } + + movePropBefore(ctx, prop, p => p === positioning.before); + break; + } } diff --git a/packages/compiler-cli/ngcc/test/BUILD.bazel b/packages/compiler-cli/ngcc/test/BUILD.bazel index 8166e70b85..bb5732b09a 100644 --- a/packages/compiler-cli/ngcc/test/BUILD.bazel +++ b/packages/compiler-cli/ngcc/test/BUILD.bazel @@ -33,13 +33,12 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], data = [ "//packages/compiler-cli/test/ngtsc/fake_core:npm_package", ], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) @@ -64,7 +63,7 @@ ts_library( jasmine_node_test( name = "integration", timeout = "long", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], data = [ "//packages/common:npm_package", "//packages/core:npm_package", @@ -77,7 +76,6 @@ jasmine_node_test( ], deps = [ ":integration_lib", - "//tools/testing:node_no_angular", "@npm//canonical-path", "@npm//convert-source-map", ], diff --git a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts index 0ecba3079d..12b4b62b21 100644 --- a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -11,7 +11,7 @@ import {FatalDiagnosticError, makeDiagnostic} from '../../../src/ngtsc/diagnosti import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection'; -import {DecoratorHandler, DetectResult} from '../../../src/ngtsc/transform'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../../src/ngtsc/transform'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; @@ -44,6 +44,7 @@ runInEachFileSystem(() => { const handler = jasmine.createSpyObj('TestDecoratorHandler', [ 'detect', 'analyze', + 'register', 'resolve', 'compile', ]); @@ -67,6 +68,7 @@ runInEachFileSystem(() => { } else { return { metadata, + decorator: metadata, trigger: metadata.node, }; } @@ -117,7 +119,9 @@ runInEachFileSystem(() => { getFileSystem(), bundle, reflectionHost, referencesRegistry, (error) => diagnosticLogs.push(error)); testHandler = createTestHandler(options); - analyzer.handlers = [testHandler]; + + // Replace the default handlers with the test handler in the original array of handlers + analyzer.handlers.splice(0, analyzer.handlers.length, testHandler); migrationLogs = []; const migration1 = new MockMigration('migration1', migrationLogs); const migration2 = new MockMigration('migration2', migrationLogs); @@ -372,25 +376,74 @@ runInEachFileSystem(() => { expect(diagnosticLogs[1]).toEqual(jasmine.objectContaining({code: -996666})); }); - it('should report analyze and resolve diagnostics to the `diagnosticHandler` callback', - () => { - const analyzer = setUpAnalyzer( - [ - { - name: _('/node_modules/test-package/index.js'), - contents: ` + it('should report analyze diagnostics to the `diagnosticHandler` callback', () => { + const analyzer = setUpAnalyzer( + [ + { + name: _('/node_modules/test-package/index.js'), + contents: ` import {Component, Directive, Injectable} from '@angular/core'; export class MyComponent {} MyComponent.decorators = [{type: Component}]; `, - }, - ], - {analyzeError: true, resolveError: true}); - analyzer.analyzeProgram(); - expect(diagnosticLogs.length).toEqual(2); - expect(diagnosticLogs[0]).toEqual(jasmine.objectContaining({code: -999999})); - expect(diagnosticLogs[1]).toEqual(jasmine.objectContaining({code: -999998})); - }); + }, + ], + {analyzeError: true, resolveError: true}); + analyzer.analyzeProgram(); + expect(diagnosticLogs.length).toEqual(1); + expect(diagnosticLogs[0]).toEqual(jasmine.objectContaining({code: -999999})); + expect(testHandler.analyze).toHaveBeenCalled(); + expect(testHandler.register).not.toHaveBeenCalled(); + expect(testHandler.resolve).not.toHaveBeenCalled(); + expect(testHandler.compile).not.toHaveBeenCalled(); + }); + + it('should report resolve diagnostics to the `diagnosticHandler` callback', () => { + const analyzer = setUpAnalyzer( + [ + { + name: _('/node_modules/test-package/index.js'), + contents: ` + import {Component, Directive, Injectable} from '@angular/core'; + export class MyComponent {} + MyComponent.decorators = [{type: Component}]; + `, + }, + ], + {analyzeError: false, resolveError: true}); + analyzer.analyzeProgram(); + expect(diagnosticLogs.length).toEqual(1); + expect(diagnosticLogs[0]).toEqual(jasmine.objectContaining({code: -999998})); + expect(testHandler.analyze).toHaveBeenCalled(); + expect(testHandler.register).toHaveBeenCalled(); + expect(testHandler.resolve).toHaveBeenCalled(); + expect(testHandler.compile).not.toHaveBeenCalled(); + }); + }); + + describe('declaration files', () => { + it('should not run decorator handlers against declaration files', () => { + class FakeDecoratorHandler implements DecoratorHandler<{}|null, unknown, unknown> { + name = 'FakeDecoratorHandler'; + precedence = HandlerPrecedence.PRIMARY; + + detect(): undefined { throw new Error('detect should not have been called'); } + analyze(): AnalysisOutput { + throw new Error('analyze should not have been called'); + } + compile(): CompileResult { throw new Error('compile should not have been called'); } + } + + const analyzer = setUpAnalyzer([{ + name: _('/node_modules/test-package/index.d.ts'), + contents: 'export declare class SomeDirective {}', + }]); + + // Replace the default handlers with the test handler in the original array of handlers + analyzer.handlers.splice(0, analyzer.handlers.length, new FakeDecoratorHandler()); + result = analyzer.analyzeProgram(); + expect(result.size).toBe(0); + }); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts b/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts index 3152dc9703..bceeadc9f3 100644 --- a/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts @@ -5,200 +5,86 @@ * 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, makeDiagnostic} from '../../../src/ngtsc/diagnostics'; -import {AbsoluteFsPath, absoluteFrom} from '../../../src/ngtsc/file_system'; +import {makeDiagnostic} from '../../../src/ngtsc/diagnostics'; +import {absoluteFrom} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection'; -import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../../src/ngtsc/transform'; +import {ClassDeclaration, Decorator, isNamedClassDeclaration} from '../../../src/ngtsc/reflection'; +import {getDeclaration} from '../../../src/ngtsc/testing'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence, TraitState} from '../../../src/ngtsc/transform'; +import {loadTestFiles} from '../../../test/helpers'; import {DefaultMigrationHost} from '../../src/analysis/migration_host'; -import {AnalyzedClass, AnalyzedFile} from '../../src/analysis/types'; -import {NgccClassSymbol} from '../../src/host/ngcc_host'; +import {NgccTraitCompiler} from '../../src/analysis/ngcc_trait_compiler'; +import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {createComponentDecorator} from '../../src/migrations/utils'; +import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; +import {MockLogger} from '../helpers/mock_logger'; +import {makeTestEntryPointBundle} from '../helpers/utils'; runInEachFileSystem(() => { describe('DefaultMigrationHost', () => { let _: typeof absoluteFrom; - let entryPointPath: AbsoluteFsPath; - let mockHost: any; let mockMetadata: any = {}; let mockEvaluator: any = {}; let mockClazz: any; - let mockDecorator: any = {name: 'MockDecorator'}; - let diagnosticHandler = () => {}; + let injectedDecorator: any = {name: 'InjectedDecorator'}; beforeEach(() => { _ = absoluteFrom; - entryPointPath = _('/node_modules/some-package/entry-point'); - mockHost = { - getClassSymbol: (node: any): NgccClassSymbol | undefined => { - const symbol = { valueDeclaration: node, name: node.name.text } as any; - return { - name: node.name.text, - declaration: symbol, - implementation: symbol, - }; - }, - }; const mockSourceFile: any = { fileName: _('/node_modules/some-package/entry-point/test-file.js'), }; mockClazz = { name: {text: 'MockClazz'}, getSourceFile: () => mockSourceFile, + getStart: () => 0, + getWidth: () => 0, }; }); + function createMigrationHost({entryPoint, handlers}: { + entryPoint: EntryPointBundle; handlers: DecoratorHandler[] + }) { + const reflectionHost = new Esm2015ReflectionHost(new MockLogger(), false, entryPoint.src); + const compiler = new NgccTraitCompiler(handlers, reflectionHost); + const host = new DefaultMigrationHost( + reflectionHost, mockMetadata, mockEvaluator, compiler, entryPoint.entryPoint.path); + return {compiler, host}; + } + describe('injectSyntheticDecorator()', () => { - it('should call `detect()` on each of the provided handlers', () => { - const log: string[] = []; - const handler1 = new TestHandler('handler1', log); - const handler2 = new TestHandler('handler2', log); - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler1, handler2], entryPointPath, [], - diagnosticHandler); - host.injectSyntheticDecorator(mockClazz, mockDecorator); - expect(log).toEqual([ - `handler1:detect:MockClazz:MockDecorator`, - `handler2:detect:MockClazz:MockDecorator`, - ]); + it('should add the injected decorator into the compilation', () => { + const handler = new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); + loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const {host, compiler} = createMigrationHost({entryPoint, handlers: [handler]}); + host.injectSyntheticDecorator(mockClazz, injectedDecorator); + + const record = compiler.recordFor(mockClazz) !; + expect(record).toBeDefined(); + expect(record.traits.length).toBe(1); + expect(record.traits[0].detected.decorator).toBe(injectedDecorator); }); - it('should call `analyze()` on each of the provided handlers whose `detect()` call returns a result', - () => { - const log: string[] = []; - const handler1 = new TestHandler('handler1', log); - const handler2 = new AlwaysDetectHandler('handler2', log); - const handler3 = new TestHandler('handler3', log); - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler1, handler2, handler3], - entryPointPath, [], diagnosticHandler); - host.injectSyntheticDecorator(mockClazz, mockDecorator); - expect(log).toEqual([ - `handler1:detect:MockClazz:MockDecorator`, - `handler2:detect:MockClazz:MockDecorator`, - `handler3:detect:MockClazz:MockDecorator`, - 'handler2:analyze:MockClazz', - ]); - }); - - it('should add a newly `AnalyzedFile` to the `analyzedFiles` object', () => { - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = []; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - host.injectSyntheticDecorator(mockClazz, mockDecorator); - expect(analyzedFiles.length).toEqual(1); - expect(analyzedFiles[0].analyzedClasses.length).toEqual(1); - expect(analyzedFiles[0].analyzedClasses[0].name).toEqual('MockClazz'); - }); - - it('should add a newly `AnalyzedClass` to an existing `AnalyzedFile` object', () => { - const DUMMY_CLASS_1: any = {}; - const DUMMY_CLASS_2: any = {}; - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = [{ - sourceFile: mockClazz.getSourceFile(), - analyzedClasses: [DUMMY_CLASS_1, DUMMY_CLASS_2], - }]; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - host.injectSyntheticDecorator(mockClazz, mockDecorator); - expect(analyzedFiles.length).toEqual(1); - expect(analyzedFiles[0].analyzedClasses.length).toEqual(3); - expect(analyzedFiles[0].analyzedClasses[2].name).toEqual('MockClazz'); - }); - - it('should add a new decorator into an already existing `AnalyzedClass`', () => { - const analyzedClass: AnalyzedClass = { - name: 'MockClazz', - declaration: mockClazz, - matches: [], - decorators: null, - }; - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = [{ - sourceFile: mockClazz.getSourceFile(), - analyzedClasses: [analyzedClass], - }]; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - host.injectSyntheticDecorator(mockClazz, mockDecorator); - expect(analyzedFiles.length).toEqual(1); - expect(analyzedFiles[0].analyzedClasses.length).toEqual(1); - expect(analyzedFiles[0].analyzedClasses[0]).toBe(analyzedClass); - expect(analyzedClass.decorators !.length).toEqual(1); - expect(analyzedClass.decorators ![0].name).toEqual('MockDecorator'); - }); - - it('should merge a new decorator into pre-existing decorators an already existing `AnalyzedClass`', - () => { - const analyzedClass: AnalyzedClass = { - name: 'MockClazz', - declaration: mockClazz, - matches: [], - decorators: [{name: 'OtherDecorator'} as Decorator], - }; - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = [{ - sourceFile: mockClazz.getSourceFile(), - analyzedClasses: [analyzedClass], - }]; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - host.injectSyntheticDecorator(mockClazz, mockDecorator); - expect(analyzedFiles.length).toEqual(1); - expect(analyzedFiles[0].analyzedClasses.length).toEqual(1); - expect(analyzedFiles[0].analyzedClasses[0]).toBe(analyzedClass); - expect(analyzedClass.decorators !.length).toEqual(2); - expect(analyzedClass.decorators ![1].name).toEqual('MockDecorator'); - }); - - it('should throw an error if the injected decorator already exists', () => { - const analyzedClass: AnalyzedClass = { - name: 'MockClazz', - declaration: mockClazz, - matches: [], - decorators: [{name: 'MockDecorator'} as Decorator], - }; - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = [{ - sourceFile: mockClazz.getSourceFile(), - analyzedClasses: [analyzedClass], - }]; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - expect(() => host.injectSyntheticDecorator(mockClazz, mockDecorator)) - .toThrow(jasmine.objectContaining( - {code: ErrorCode.NGCC_MIGRATION_DECORATOR_INJECTION_ERROR})); - }); - - it('should report diagnostics from handlers', () => { - const log: string[] = []; - const handler = new DiagnosticProducingHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = []; - const diagnostics: ts.Diagnostic[] = []; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnostic => diagnostics.push(diagnostic)); - mockClazz.getStart = () => 0; - mockClazz.getWidth = () => 0; - + it('should mention the migration that failed in the diagnostics message', () => { + const handler = new DiagnosticProducingHandler(); + loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const {host, compiler} = createMigrationHost({entryPoint, handlers: [handler]}); const decorator = createComponentDecorator(mockClazz, {selector: 'comp', exportAs: null}); host.injectSyntheticDecorator(mockClazz, decorator); - expect(diagnostics.length).toBe(1); - expect(ts.flattenDiagnosticMessageText(diagnostics[0].messageText, '\n')) + const record = compiler.recordFor(mockClazz) !; + const migratedTrait = record.traits[0]; + if (migratedTrait.state !== TraitState.ERRORED) { + return fail('Expected migrated class trait to be in an error state'); + } + + expect(migratedTrait.diagnostics.length).toBe(1); + expect(ts.flattenDiagnosticMessageText(migratedTrait.diagnostics[0].messageText, '\n')) .toEqual( `test diagnostic\n` + ` Occurs for @Component decorator inserted by an automatic migration\n` + @@ -206,125 +92,114 @@ runInEachFileSystem(() => { }); }); + + describe('getAllDecorators', () => { - it('should be null for unknown source files', () => { - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = []; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - - const decorators = host.getAllDecorators(mockClazz); - expect(decorators).toBeNull(); - }); - - it('should be null for unknown classes', () => { - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const analyzedFiles: AnalyzedFile[] = []; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - - const sourceFile: any = {}; - const unrelatedClass: any = { - getSourceFile: () => sourceFile, - }; - analyzedFiles.push({sourceFile, analyzedClasses: [unrelatedClass]}); - - const decorators = host.getAllDecorators(mockClazz); - expect(decorators).toBeNull(); - }); - it('should include injected decorators', () => { - const log: string[] = []; - const handler = new AlwaysDetectHandler('handler', log); - const existingDecorator = { name: 'ExistingDecorator' } as Decorator; - const analyzedClass: AnalyzedClass = { - name: 'MockClazz', - declaration: mockClazz, - matches: [], - decorators: [existingDecorator], - }; - const analyzedFiles: AnalyzedFile[] = [{ - sourceFile: mockClazz.getSourceFile(), - analyzedClasses: [analyzedClass], - }]; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [handler], entryPointPath, analyzedFiles, - diagnosticHandler); - host.injectSyntheticDecorator(mockClazz, mockDecorator); + const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); + const injectedHandler = + new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); + loadTestFiles([{ + name: _('/node_modules/test/index.js'), + contents: ` + import {Directive} from '@angular/core'; - const decorators = host.getAllDecorators(mockClazz) !; + export class MyClass {}; + MyClass.decorators = [{ type: Directive }]; + ` + }]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const {host, compiler} = + createMigrationHost({entryPoint, handlers: [directiveHandler, injectedHandler]}); + const myClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', + isNamedClassDeclaration); + + compiler.analyzeFile(entryPoint.src.file); + + host.injectSyntheticDecorator(myClass, injectedDecorator); + + const decorators = host.getAllDecorators(myClass) !; expect(decorators.length).toBe(2); - expect(decorators[0]).toBe(existingDecorator); - expect(decorators[1]).toBe(mockDecorator); + expect(decorators[0].name).toBe('Directive'); + expect(decorators[1].name).toBe('InjectedDecorator'); }); }); describe('isInScope', () => { it('should be true for nodes within the entry-point', () => { - const analyzedFiles: AnalyzedFile[] = []; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [], entryPointPath, analyzedFiles, - diagnosticHandler); + loadTestFiles([ + {name: _('/node_modules/test/index.js'), contents: `export * from './internal';`}, + {name: _('/node_modules/test/internal.js'), contents: `export class InternalClass {}`}, + ]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const {host} = createMigrationHost({entryPoint, handlers: []}); + const internalClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/internal.js'), 'InternalClass', + isNamedClassDeclaration); - const sourceFile: any = { - fileName: _('/node_modules/some-package/entry-point/relative.js'), - }; - const clazz: any = { - getSourceFile: () => sourceFile, - }; - expect(host.isInScope(clazz)).toBe(true); + expect(host.isInScope(internalClass)).toBe(true); }); it('should be false for nodes outside the entry-point', () => { - const analyzedFiles: AnalyzedFile[] = []; - const host = new DefaultMigrationHost( - mockHost, mockMetadata, mockEvaluator, [], entryPointPath, analyzedFiles, - diagnosticHandler); + loadTestFiles([ + {name: _('/node_modules/external/index.js'), contents: `export class ExternalClass {}`}, + { + name: _('/node_modules/test/index.js'), + contents: ` + export {ExternalClass} from 'external'; + export class InternalClass {} + ` + }, + ]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const {host} = createMigrationHost({entryPoint, handlers: []}); + const externalClass = getDeclaration( + entryPoint.src.program, _('/node_modules/external/index.js'), 'ExternalClass', + isNamedClassDeclaration); - const sourceFile: any = { - fileName: _('/node_modules/some-package/other-entry/index.js'), - }; - const clazz: any = { - getSourceFile: () => sourceFile, - }; - expect(host.isInScope(clazz)).toBe(false); + expect(host.isInScope(externalClass)).toBe(false); }); }); }); }); -class TestHandler implements DecoratorHandler { - constructor(readonly name: string, protected log: string[]) {} +class DetectDecoratorHandler implements DecoratorHandler { + readonly name = DetectDecoratorHandler.name; + + constructor(private decorator: string, readonly precedence: HandlerPrecedence) {} - precedence = HandlerPrecedence.PRIMARY; detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult|undefined { - this.log.push(`${this.name}:detect:${node.name.text}:${decorators !.map(d => d.name)}`); - return undefined; - } - analyze(node: ClassDeclaration): AnalysisOutput { - this.log.push(this.name + ':analyze:' + node.name.text); - return {}; - } - compile(node: ClassDeclaration): CompileResult|CompileResult[] { - this.log.push(this.name + ':compile:' + node.name.text); - return []; + if (decorators === null) { + return undefined; + } + const decorator = decorators.find(decorator => decorator.name === this.decorator); + if (decorator === undefined) { + return undefined; + } + return {trigger: node, decorator, metadata: {}}; } + + analyze(node: ClassDeclaration): AnalysisOutput { return {}; } + + compile(node: ClassDeclaration): CompileResult|CompileResult[] { return []; } } -class AlwaysDetectHandler extends TestHandler { - detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult|undefined { - super.detect(node, decorators); - return {trigger: node, metadata: {}}; - } -} +class DiagnosticProducingHandler implements DecoratorHandler { + readonly name = DiagnosticProducingHandler.name; + readonly precedence = HandlerPrecedence.PRIMARY; + + detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult|undefined { + const decorator = decorators !== null ? decorators[0] : null; + return {trigger: node, decorator, metadata: {}}; + } -class DiagnosticProducingHandler extends AlwaysDetectHandler { analyze(node: ClassDeclaration): AnalysisOutput { - super.analyze(node); return {diagnostics: [makeDiagnostic(9999, node, 'test diagnostic')]}; } + + compile(node: ClassDeclaration): CompileResult|CompileResult[] { return []; } } diff --git a/packages/compiler-cli/ngcc/test/analysis/ngcc_trait_compiler_spec.ts b/packages/compiler-cli/ngcc/test/analysis/ngcc_trait_compiler_spec.ts new file mode 100644 index 0000000000..c164a76a5e --- /dev/null +++ b/packages/compiler-cli/ngcc/test/analysis/ngcc_trait_compiler_spec.ts @@ -0,0 +1,351 @@ +/** + * @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 {ErrorCode, makeDiagnostic, ngErrorCode} from '../../../src/ngtsc/diagnostics'; +import {absoluteFrom} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {ClassDeclaration, Decorator, isNamedClassDeclaration} from '../../../src/ngtsc/reflection'; +import {getDeclaration} from '../../../src/ngtsc/testing'; +import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence, TraitState} from '../../../src/ngtsc/transform'; +import {loadTestFiles} from '../../../test/helpers'; +import {NgccTraitCompiler} from '../../src/analysis/ngcc_trait_compiler'; +import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; +import {createComponentDecorator} from '../../src/migrations/utils'; +import {EntryPointBundle} from '../../src/packages/entry_point_bundle'; +import {MockLogger} from '../helpers/mock_logger'; +import {makeTestEntryPointBundle} from '../helpers/utils'; + +runInEachFileSystem(() => { + describe('NgccTraitCompiler', () => { + let _: typeof absoluteFrom; + let mockClazz: any; + let injectedDecorator: any = {name: 'InjectedDecorator'}; + beforeEach(() => { + _ = absoluteFrom; + const mockSourceFile: any = { + fileName: _('/node_modules/some-package/entry-point/test-file.js'), + }; + mockClazz = { + name: {text: 'MockClazz'}, + getSourceFile: () => mockSourceFile, + getStart: () => 0, + getWidth: () => 0, + }; + }); + + function createCompiler({entryPoint, handlers}: { + entryPoint: EntryPointBundle; handlers: DecoratorHandler[] + }) { + const reflectionHost = new Esm2015ReflectionHost(new MockLogger(), false, entryPoint.src); + return new NgccTraitCompiler(handlers, reflectionHost); + } + + describe('injectSyntheticDecorator()', () => { + it('should call `detect()` on each of the provided handlers', () => { + const log: string[] = []; + const handler1 = new TestHandler('handler1', log); + const handler2 = new TestHandler('handler2', log); + loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = createCompiler({entryPoint, handlers: [handler1, handler2]}); + compiler.injectSyntheticDecorator(mockClazz, injectedDecorator); + expect(log).toEqual([ + `handler1:detect:MockClazz:InjectedDecorator`, + `handler2:detect:MockClazz:InjectedDecorator`, + ]); + }); + + it('should call `analyze()` on each of the provided handlers whose `detect()` call returns a result', + () => { + const log: string[] = []; + const handler1 = new TestHandler('handler1', log); + const handler2 = new AlwaysDetectHandler('handler2', log); + const handler3 = new TestHandler('handler3', log); + loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); + const entryPoint = makeTestEntryPointBundle( + 'test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = createCompiler({entryPoint, handlers: [handler1, handler2, handler3]}); + compiler.injectSyntheticDecorator(mockClazz, injectedDecorator); + expect(log).toEqual([ + `handler1:detect:MockClazz:InjectedDecorator`, + `handler2:detect:MockClazz:InjectedDecorator`, + `handler3:detect:MockClazz:InjectedDecorator`, + 'handler2:analyze:MockClazz', + ]); + }); + + it('should inject a new class record into the compilation', () => { + const injectedHandler = + new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); + loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = createCompiler({entryPoint, handlers: [injectedHandler]}); + compiler.injectSyntheticDecorator(mockClazz, injectedDecorator); + + const record = compiler.recordFor(mockClazz); + expect(record).toBeDefined(); + expect(record !.traits.length).toBe(1); + }); + + it('should add a new trait to an existing class record', () => { + const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); + const injectedHandler = + new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); + loadTestFiles([{ + name: _('/node_modules/test/index.js'), + contents: ` + import {Directive} from '@angular/core'; + + export class MyClass {}; + MyClass.decorators = [{ type: Directive }]; + ` + }]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = + createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); + const myClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', + isNamedClassDeclaration); + + compiler.analyzeFile(entryPoint.src.file); + compiler.injectSyntheticDecorator(myClass, injectedDecorator); + + const record = compiler.recordFor(myClass) !; + expect(record).toBeDefined(); + expect(record.traits.length).toBe(2); + expect(record.traits[0].detected.decorator !.name).toBe('Directive'); + expect(record.traits[1].detected.decorator !.name).toBe('InjectedDecorator'); + }); + + it('should not add a weak handler when a primary handler already exists', () => { + const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.PRIMARY); + const injectedHandler = + new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); + loadTestFiles([{ + name: _('/node_modules/test/index.js'), + contents: ` + import {Directive} from '@angular/core'; + + export class MyClass {}; + MyClass.decorators = [{ type: Directive }]; + ` + }]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = + createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); + const myClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', + isNamedClassDeclaration); + + compiler.analyzeFile(entryPoint.src.file); + + compiler.injectSyntheticDecorator(myClass, injectedDecorator); + + const record = compiler.recordFor(myClass) !; + expect(record).toBeDefined(); + expect(record.traits.length).toBe(1); + expect(record.traits[0].detected.decorator !.name).toBe('Directive'); + }); + + it('should replace an existing weak handler when injecting a primary handler', () => { + const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); + const injectedHandler = + new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.PRIMARY); + loadTestFiles([{ + name: _('/node_modules/test/index.js'), + contents: ` + import {Directive} from '@angular/core'; + + export class MyClass {}; + MyClass.decorators = [{ type: Directive }]; + ` + }]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = + createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); + const myClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', + isNamedClassDeclaration); + + compiler.analyzeFile(entryPoint.src.file); + + compiler.injectSyntheticDecorator(myClass, injectedDecorator); + + const record = compiler.recordFor(myClass) !; + expect(record).toBeDefined(); + expect(record.traits.length).toBe(1); + expect(record.traits[0].detected.decorator !.name).toBe('InjectedDecorator'); + }); + + it('should produce an error when a primary handler is added when a primary handler is already present', + () => { + const directiveHandler = + new DetectDecoratorHandler('Directive', HandlerPrecedence.PRIMARY); + const injectedHandler = + new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.PRIMARY); + loadTestFiles([{ + name: _('/node_modules/test/index.js'), + contents: ` + import {Directive} from '@angular/core'; + + export class MyClass {}; + MyClass.decorators = [{ type: Directive }]; + ` + }]); + const entryPoint = makeTestEntryPointBundle( + 'test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = + createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); + const myClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', + isNamedClassDeclaration); + + compiler.analyzeFile(entryPoint.src.file); + + compiler.injectSyntheticDecorator(myClass, injectedDecorator); + + const record = compiler.recordFor(myClass) !; + expect(record).toBeDefined(); + expect(record.metaDiagnostics).toBeDefined(); + expect(record.metaDiagnostics !.length).toBe(1); + expect(record.metaDiagnostics ![0].code) + .toBe(ngErrorCode(ErrorCode.DECORATOR_COLLISION)); + expect(record.traits.length).toBe(0); + }); + + it('should report diagnostics from handlers', () => { + const log: string[] = []; + const handler = new DiagnosticProducingHandler('handler', log); + loadTestFiles([{name: _('/node_modules/test/index.js'), contents: ``}]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = createCompiler({entryPoint, handlers: [handler]}); + const decorator = createComponentDecorator(mockClazz, {selector: 'comp', exportAs: null}); + compiler.injectSyntheticDecorator(mockClazz, decorator); + + const record = compiler.recordFor(mockClazz) !; + const migratedTrait = record.traits[0]; + if (migratedTrait.state !== TraitState.ERRORED) { + return fail('Expected migrated class trait to be in an error state'); + } + + expect(migratedTrait.diagnostics.length).toBe(1); + expect(migratedTrait.diagnostics[0].messageText).toEqual(`test diagnostic`); + }); + }); + + + + describe('getAllDecorators', () => { + it('should be null for classes without decorators', () => { + loadTestFiles( + [{name: _('/node_modules/test/index.js'), contents: `export class MyClass {};`}]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = createCompiler({entryPoint, handlers: []}); + const myClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', + isNamedClassDeclaration); + + const decorators = compiler.getAllDecorators(myClass); + expect(decorators).toBeNull(); + }); + + it('should include injected decorators', () => { + const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); + const injectedHandler = + new DetectDecoratorHandler('InjectedDecorator', HandlerPrecedence.WEAK); + loadTestFiles([{ + name: _('/node_modules/test/index.js'), + contents: ` + import {Directive} from '@angular/core'; + + export class MyClass {}; + MyClass.decorators = [{ type: Directive }]; + ` + }]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const compiler = + createCompiler({entryPoint, handlers: [directiveHandler, injectedHandler]}); + const myClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/index.js'), 'MyClass', + isNamedClassDeclaration); + + compiler.analyzeFile(entryPoint.src.file); + + compiler.injectSyntheticDecorator(myClass, injectedDecorator); + + const decorators = compiler.getAllDecorators(myClass) !; + expect(decorators.length).toBe(2); + expect(decorators[0].name).toBe('Directive'); + expect(decorators[1].name).toBe('InjectedDecorator'); + }); + }); + + }); +}); + +class TestHandler implements DecoratorHandler { + constructor(readonly name: string, protected log: string[]) {} + + precedence = HandlerPrecedence.PRIMARY; + + detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult|undefined { + this.log.push(`${this.name}:detect:${node.name.text}:${decorators !.map(d => d.name)}`); + return undefined; + } + + analyze(node: ClassDeclaration): AnalysisOutput { + this.log.push(this.name + ':analyze:' + node.name.text); + return {}; + } + + compile(node: ClassDeclaration): CompileResult|CompileResult[] { + this.log.push(this.name + ':compile:' + node.name.text); + return []; + } +} + +class AlwaysDetectHandler extends TestHandler { + detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult|undefined { + super.detect(node, decorators); + const decorator = decorators !== null ? decorators[0] : null; + return {trigger: node, decorator, metadata: {}}; + } +} + +class DetectDecoratorHandler extends TestHandler { + constructor(private decorator: string, readonly precedence: HandlerPrecedence) { + super(decorator, []); + } + + detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult|undefined { + super.detect(node, decorators); + if (decorators === null) { + return undefined; + } + const decorator = decorators.find(decorator => decorator.name === this.decorator); + if (decorator === undefined) { + return undefined; + } + return {trigger: node, decorator, metadata: {}}; + } +} + +class DiagnosticProducingHandler extends AlwaysDetectHandler { + analyze(node: ClassDeclaration): AnalysisOutput { + super.analyze(node); + return {diagnostics: [makeDiagnostic(9999, node, 'test diagnostic')]}; + } +} diff --git a/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts index 05eb30e462..e0966c775e 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts @@ -25,25 +25,25 @@ runInEachFileSystem(() => { name: _('/no/imports/or/re-exports/index.js'), contents: '// some text but no import-like statements' }, - {name: _('/no/imports/or/re-exports/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/no/imports/or/re-exports/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/no/imports/or/re-exports/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/external/imports/index.js'), contents: commonJs(['lib_1', 'lib_1/sub_1'])}, - {name: _('/external/imports/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/imports/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/external/imports/index.metadata.json'), contents: 'MOCK METADATA'}, { name: _('/external/re-exports/index.js'), contents: commonJs(['lib_1', 'lib_1/sub_1'], ['lib_1.X', 'lib_1sub_1.Y']) }, - {name: _('/external/re-exports/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/re-exports/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/external/re-exports/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/external/imports-missing/index.js'), contents: commonJs(['lib_1', 'missing'])}, - {name: _('/external/imports-missing/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/imports-missing/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/external/imports-missing/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/external/deep-import/index.js'), contents: commonJs(['lib_1/deep/import'])}, - {name: _('/external/deep-import/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/deep-import/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/external/deep-import/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/internal/outer/index.js'), contents: commonJs(['../inner'])}, - {name: _('/internal/outer/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/internal/outer/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/internal/outer/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/internal/inner/index.js'), contents: commonJs(['lib_1/sub_1'], ['X'])}, { @@ -54,16 +54,16 @@ runInEachFileSystem(() => { name: _('/internal/circular_b/index.js'), contents: commonJs(['../circular_a', 'lib_1'], ['X']) }, - {name: _('/internal/circular_a/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/internal/circular_a/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/internal/circular_a/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/re-directed/index.js'), contents: commonJs(['lib_1/sub_2'])}, - {name: _('/re-directed/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/re-directed/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/re-directed/index.metadata.json'), contents: 'MOCK METADATA'}, { name: _('/path-alias/index.js'), contents: commonJs(['@app/components', '@app/shared', '@lib/shared/test', 'lib_1']) }, - {name: _('/path-alias/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/path-alias/package.json'), contents: '{"main": "./index.js"}'}, {name: _('/path-alias/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/node_modules/lib_1/index.d.ts'), contents: 'export declare class X {}'}, { @@ -114,7 +114,7 @@ runInEachFileSystem(() => { host = new CommonJsDependencyHost(fs, new ModuleResolver(fs)); }); - describe('getDependencies()', () => { + describe('collectDependencies()', () => { it('should not generate a TS AST if the source does not contain any require calls', () => { spyOn(ts, 'createSourceFile'); host.collectDependencies(_('/no/imports/or/re-exports/index.js'), createDependencyInfo()); @@ -143,6 +143,142 @@ runInEachFileSystem(() => { expect(dependencies.has(_('/node_modules/lib_1/sub_1'))).toBe(true); }); + it('should recognize imports in a variable declaration list', () => { + loadTestFiles([ + { + name: _('/test/index.js'), + contents: commonJs({ + varDeclarations: [ + ['lib_1/sub_1', 'lib_1/sub_2'], + ], + }), + }, + {name: _('/test/package.json'), contents: '{"main": "./index.js"}'}, + {name: _('/test/index.metadata.json'), contents: 'MOCK METADATA'}, + ]); + + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies(_('/test/index.js'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib_1/sub_1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib_1/sub_2'))).toBe(true); + }); + + it('should recognize imports as property assignments (on existing object)', () => { + loadTestFiles([ + { + name: _('/test/index.js'), + contents: commonJs({ + propAssignment: ['lib_1/sub_1', 'lib_1/sub_2'], + }), + }, + {name: _('/test/package.json'), contents: '{"main": "./index.js"}'}, + {name: _('/test/index.metadata.json'), contents: 'MOCK METADATA'}, + ]); + + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies(_('/test/index.js'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib_1/sub_1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib_1/sub_2'))).toBe(true); + }); + + it('should recognize imports as property assignments (in object literal)', () => { + loadTestFiles([ + { + name: _('/test/index.js'), + contents: commonJs({ + inObjectLiteral: ['lib_1/sub_1', 'lib_1/sub_2'], + }), + }, + {name: _('/test/package.json'), contents: '{"main": "./index.js"}'}, + {name: _('/test/index.metadata.json'), contents: 'MOCK METADATA'}, + ]); + + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies(_('/test/index.js'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib_1/sub_1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib_1/sub_2'))).toBe(true); + }); + + it('should recognize imports used for their side-effects only', () => { + loadTestFiles([ + { + name: _('/test/index.js'), + contents: commonJs({ + forSideEffects: ['lib_1/sub_1', 'lib_1/sub_2'], + }), + }, + {name: _('/test/package.json'), contents: '{"main": "./index.js"}'}, + {name: _('/test/index.metadata.json'), contents: 'MOCK METADATA'}, + ]); + + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies(_('/test/index.js'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib_1/sub_1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib_1/sub_2'))).toBe(true); + }); + + it('should recognize star re-exports (with both emitted and imported helpers)', () => { + loadTestFiles([ + { + name: _('/test/index.js'), + contents: commonJs({ + reExportsWithEmittedHelper: ['lib_1', 'lib_1/sub_1'], + reExportsWithImportedHelper: ['lib_1', 'lib_1/sub_2'], + }), + }, + {name: _('/test/package.json'), contents: '{"main": "./index.js"}'}, + {name: _('/test/index.metadata.json'), contents: 'MOCK METADATA'}, + ]); + + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies(_('/test/index.js'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(3); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib_1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib_1/sub_1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib_1/sub_2'))).toBe(true); + }); + + it('should not get confused by re-exports with a separate `require()` call', () => { + loadTestFiles([ + { + name: _('/test/index.js'), + contents: commonJs({ + reExportsWithoutRequire: ['lib_1', 'lib_1/sub_2'], + }), + }, + {name: _('/test/package.json'), contents: '{"main": "./index.js"}'}, + {name: _('/test/index.metadata.json'), contents: 'MOCK METADATA'}, + ]); + + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies(_('/test/index.js'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib_1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib_1/sub_2'))).toBe(true); + }); + it('should capture missing external imports', () => { const {dependencies, missing, deepImports} = createDependencyInfo(); host.collectDependencies( @@ -224,16 +360,102 @@ runInEachFileSystem(() => { }); }); - function commonJs(importPaths: string[], exportNames: string[] = []) { - const commonJsRequires = - importPaths - .map( - p => - `var ${p.replace('@angular/', '').replace(/\.?\.?\//g, '').replace(/@/,'')} = require('${p}');`) - .join('\n'); + interface ImportsPerType { + // var foo = require('...'); + varDeclaration?: string[]; + + // var foo = require('...'), bar = require('...'); + varDeclarations?: string[][]; + + // exports.foo = require('...'); + propAssignment?: string[]; + + // module.exports = {foo: require('...')}; + inObjectLiteral?: string[]; + + // require('...'); + forSideEffects?: string[]; + + // __export(require('...')); + reExportsWithEmittedHelper?: string[]; + + // tslib_1.__exportStar(require('...'), exports); + reExportsWithImportedHelper?: string[]; + + // var foo = require('...'); + // __export(foo); + reExportsWithoutRequire?: string[]; + } + + function commonJs(importsPerType: ImportsPerType | string[], exportNames: string[] = []): string { + if (Array.isArray(importsPerType)) { + importsPerType = {varDeclaration: importsPerType}; + } + + const importStatements = generateImportStatements(importsPerType); const exportStatements = - exportNames.map(e => ` exports.${e.replace(/.+\./, '')} = ${e};`).join('\n'); - return `${commonJsRequires} -${exportStatements}`; + exportNames.map(e => `exports.${e.replace(/.+\./, '')} = ${e};`).join('\n'); + + return `${importStatements}\n\n${exportStatements}`; + } + + function generateImportStatements(importsPerType: ImportsPerType): string { + const importStatements: string[] = []; + + const { + varDeclaration: importsOfTypeVarDeclaration = [], + varDeclarations: importsOfTypeVarDeclarations = [], + propAssignment: importsOfTypePropAssignment = [], + inObjectLiteral: importsOfTypeInObjectLiteral = [], + forSideEffects: importsOfTypeForSideEffects = [], + reExportsWithEmittedHelper: importsOfTypeReExportsWithEmittedHelper = [], + reExportsWithImportedHelper: importsOfTypeReExportsWithImportedHelper = [], + reExportsWithoutRequire: importsOfTypeReExportsWithoutRequire = [], + } = importsPerType; + + // var foo = require('...'); + importsOfTypeVarDeclaration.forEach( + p => { importStatements.push(`var ${pathToVarName(p)} = require('${p}');`); }); + + // var foo = require('...'), bar = require('...'); + importsOfTypeVarDeclarations.forEach(pp => { + const declarations = pp.map(p => `${pathToVarName(p)} = require('${p}')`); + importStatements.push(`var ${declarations.join(', ')};`); + }); + + // exports.foo = require('...'); + importsOfTypePropAssignment.forEach( + p => { importStatements.push(`exports.${pathToVarName(p)} = require('${p}');`); }); + + // module.exports = {foo: require('...')}; + const propAssignments = + importsOfTypeInObjectLiteral.map(p => `\n ${pathToVarName(p)}: require('${p}')`) + .join(', '); + importStatements.push(`module.exports = {${propAssignments}\n};`); + + // require('...'); + importsOfTypeForSideEffects.forEach(p => { importStatements.push(`require('${p}');`); }); + + // __export(require('...')); + importsOfTypeReExportsWithEmittedHelper.forEach( + p => { importStatements.push(`__export(require('${p}'));`); }); + + // tslib_1.__exportStar(require('...'), exports); + importsOfTypeReExportsWithImportedHelper.forEach( + p => { importStatements.push(`tslib_1.__exportStar(require('${p}'), exports);`); }); + + // var foo = require('...'); + // __export(foo); + importsOfTypeReExportsWithoutRequire.forEach(p => { + const varName = pathToVarName(p); + importStatements.push(`var ${varName} = require('${p}');`); + importStatements.push(`__export(varName);`); + }); + + return importStatements.join('\n'); + } + + function pathToVarName(path: string): string { + return path.replace(/^@(angular\/)?/, '').replace(/\.{0,2}\//g, ''); } }); diff --git a/packages/compiler-cli/ngcc/test/dependencies/dts_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/dts_dependency_host_spec.ts new file mode 100644 index 0000000000..eb7986c8f8 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/dependencies/dts_dependency_host_spec.ts @@ -0,0 +1,253 @@ +/** + * @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 {absoluteFrom, getFileSystem, relativeFrom} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {loadTestFiles} from '../../../test/helpers'; +import {createDependencyInfo} from '../../src/dependencies/dependency_host'; +import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host'; + +runInEachFileSystem(() => { + + describe('DtsDependencyHost', () => { + let _: typeof absoluteFrom; + let host: DtsDependencyHost; + beforeEach(() => { + _ = absoluteFrom; + setupMockFileSystem(); + const fs = getFileSystem(); + host = new DtsDependencyHost(fs); + }); + + describe('collectDependencies()', () => { + it('should not generate a TS AST if the source does not contain any imports or re-exports', + () => { + spyOn(ts, 'createSourceFile'); + host.collectDependencies( + _('/no/imports/or/re-exports/index.d.ts'), createDependencyInfo()); + expect(ts.createSourceFile).not.toHaveBeenCalled(); + }); + + it('should resolve all the external imports of the source file', () => { + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/external/imports/index.d.ts'), {dependencies, missing, deepImports}); + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib-1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib-1/sub-1'))).toBe(true); + }); + + it('should resolve all the external re-exports of the source file', () => { + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/external/re-exports/index.d.ts'), {dependencies, missing, deepImports}); + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib-1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib-1/sub-1'))).toBe(true); + }); + + it('should capture missing external imports', () => { + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/external/imports-missing/index.d.ts'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(1); + expect(dependencies.has(_('/node_modules/lib-1'))).toBe(true); + expect(missing.size).toBe(1); + expect(missing.has(relativeFrom('missing'))).toBe(true); + expect(deepImports.size).toBe(0); + }); + + it('should not register deep imports as missing', () => { + // This scenario verifies the behavior of the dependency analysis when an external import + // is found that does not map to an entry-point but still exists on disk, i.e. a deep + // import. Such deep imports are captured for diagnostics purposes. + // Note that in the DTS version, the deep import may not map to a .d.ts file, but instead + // a .js file. This test exercises this particular scenario. + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/external/deep-import/index.d.ts'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(0); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(1); + expect(deepImports.has(_('/node_modules/lib-1/deep/import'))).toBe(true); + }); + + it('should not register deep imports as missing, if available in `@types/...`', () => { + // This scenario verifies the behavior of the dependency analysis when an external import + // is found that does not map to an entry-point but still exists in an `@types/...` package, + // i.e. a type-only deep import. Such deep imports are captured for diagnostics purposes. + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/external/deep-import-2/index.d.ts'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(0); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(1); + expect(deepImports.has(_('/node_modules/@types/type-only/deep/import'))).toBe(true); + }); + + it('should recurse into internal dependencies', () => { + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/internal/outer/index.d.ts'), {dependencies, missing, deepImports}); + + expect(dependencies.size).toBe(1); + expect(dependencies.has(_('/node_modules/lib-1/sub-1'))).toBe(true); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + }); + + it('should handle circular internal dependencies', () => { + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/internal/circular-a/index.d.ts'), {dependencies, missing, deepImports}); + expect(dependencies.size).toBe(2); + expect(dependencies.has(_('/node_modules/lib-1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib-1/sub-1'))).toBe(true); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + }); + + it('should support `paths` alias mappings when resolving modules', () => { + const fs = getFileSystem(); + host = new DtsDependencyHost(fs, { + baseUrl: '/dist', + paths: { + '@app/*': ['*'], + '@lib/*/test': ['lib/*/test'], + } + }); + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies(_('/path-alias/index.d.ts'), {dependencies, missing, deepImports}); + expect(dependencies.size).toBe(4); + expect(dependencies.has(_('/dist/components'))).toBe(true); + expect(dependencies.has(_('/dist/shared'))).toBe(true); + expect(dependencies.has(_('/dist/lib/shared/test'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib-1'))).toBe(true); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + }); + + it('should handle entry-point paths with no extension', () => { + const {dependencies, missing, deepImports} = createDependencyInfo(); + host.collectDependencies( + _('/external/imports/index'), {dependencies, missing, deepImports}); + expect(dependencies.size).toBe(2); + expect(missing.size).toBe(0); + expect(deepImports.size).toBe(0); + expect(dependencies.has(_('/node_modules/lib-1'))).toBe(true); + expect(dependencies.has(_('/node_modules/lib-1/sub-1'))).toBe(true); + }); + }); + + function setupMockFileSystem(): void { + loadTestFiles([ + { + name: _('/no/imports/or/re-exports/index.d.ts'), + contents: '// some text but no import-like statements' + }, + {name: _('/no/imports/or/re-exports/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/no/imports/or/re-exports/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/external/imports/index.d.ts'), + contents: `import {X} from 'lib-1';\nimport {Y} from 'lib-1/sub-1';` + }, + {name: _('/external/imports/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/imports/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/external/re-exports/index.d.ts'), + contents: `export {X} from 'lib-1';\nexport {Y} from 'lib-1/sub-1';` + }, + {name: _('/external/re-exports/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/re-exports/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/external/imports-missing/index.d.ts'), + contents: `import {X} from 'lib-1';\nimport {Y} from 'missing';` + }, + {name: _('/external/imports-missing/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/imports-missing/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/external/deep-import/index.d.ts'), + contents: `import {Y} from 'lib-1/deep/import';` + }, + {name: _('/external/deep-import/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/external/deep-import/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/external/deep-import-2/index.d.ts'), + contents: `import {Y} from 'type-only/deep/import';` + }, + { + name: _('/node_modules/@types/type-only/deep/import/index.d.ts'), + contents: `export declare class Y {}` + }, + {name: _('/internal/outer/index.d.ts'), contents: `import {X} from '../inner';`}, + {name: _('/internal/outer/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/internal/outer/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/internal/inner/index.d.ts'), + contents: `import {Y} from 'lib-1/sub-1'; export declare class X {}` + }, + { + name: _('/internal/circular-a/index.d.ts'), + contents: + `import {B} from '../circular-b'; import {X} from '../circular-b'; export {Y} from 'lib-1/sub-1';` + }, + { + name: _('/internal/circular-b/index.d.ts'), + contents: + `import {A} from '../circular-a'; import {Y} from '../circular-a'; export {X} from 'lib-1';` + }, + {name: _('/internal/circular-a/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/internal/circular-a/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/path-alias/index.d.ts'), + contents: + `import {TestHelper} from '@app/components';\nimport {Service} from '@app/shared';\nimport {TestHelper} from '@lib/shared/test';\nimport {X} from 'lib-1';` + }, + {name: _('/path-alias/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/path-alias/index.metadata.json'), contents: 'MOCK METADATA'}, + {name: _('/node_modules/lib-1/index.d.ts'), contents: 'export declare class X {}'}, + {name: _('/node_modules/lib-1/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/node_modules/lib-1/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/node_modules/lib-1/deep/import/index.js'), + contents: 'export class DeepImport {}' + }, + {name: _('/node_modules/lib-1/sub-1/index.d.ts'), contents: 'export declare class Y {}'}, + {name: _('/node_modules/lib-1/sub-1/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/node_modules/lib-1/sub-1/index.metadata.json'), contents: 'MOCK METADATA'}, + {name: _('/node_modules/lib-1/sub-2.d.ts'), contents: `export * from './sub-2/sub-2';`}, + {name: _('/node_modules/lib-1/sub-2/sub-2.d.ts'), contents: `export declare class Z {}';`}, + {name: _('/node_modules/lib-1/sub-2/package.json'), contents: '{"esm2015": "./sub-2.js"}'}, + {name: _('/node_modules/lib-1/sub-2/sub-2.metadata.json'), contents: 'MOCK METADATA'}, + {name: _('/dist/components/index.d.ts'), contents: `class MyComponent {};`}, + {name: _('/dist/components/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/dist/components/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/dist/shared/index.d.ts'), + contents: `import {X} from 'lib-1';\nexport declare class Service {}` + }, + {name: _('/dist/shared/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/dist/shared/index.metadata.json'), contents: 'MOCK METADATA'}, + { + name: _('/dist/lib/shared/test/index.d.ts'), + contents: `export declare class TestHelper {}` + }, + {name: _('/dist/lib/shared/test/package.json'), contents: '{"esm2015": "./index.js"}'}, + {name: _('/dist/lib/shared/test/index.metadata.json'), contents: 'MOCK METADATA'}, + ]); + } + }); +}); diff --git a/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts index 7f26d20569..259e8d5cac 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts @@ -27,7 +27,7 @@ runInEachFileSystem(() => { host = new EsmDependencyHost(fs, new ModuleResolver(fs)); }); - describe('getDependencies()', () => { + describe('collectDependencies()', () => { it('should not generate a TS AST if the source does not contain any imports or re-exports', () => { spyOn(ts, 'createSourceFile'); @@ -208,7 +208,7 @@ runInEachFileSystem(() => { {name: _('/internal/outer/index.metadata.json'), contents: 'MOCK METADATA'}, { name: _('/internal/inner/index.js'), - contents: `import {Y} from 'lib-1/sub-1'; export declare class X {}` + contents: `import {Y} from 'lib-1/sub-1'; export class X {}` }, { name: _('/internal/circular-a/index.js'), @@ -232,18 +232,18 @@ runInEachFileSystem(() => { }, {name: _('/path-alias/package.json'), contents: '{"esm2015": "./index.js"}'}, {name: _('/path-alias/index.metadata.json'), contents: 'MOCK METADATA'}, - {name: _('/node_modules/lib-1/index.js'), contents: 'export declare class X {}'}, + {name: _('/node_modules/lib-1/index.js'), contents: 'export class X {}'}, {name: _('/node_modules/lib-1/package.json'), contents: '{"esm2015": "./index.js"}'}, {name: _('/node_modules/lib-1/index.metadata.json'), contents: 'MOCK METADATA'}, { name: _('/node_modules/lib-1/deep/import/index.js'), - contents: 'export declare class DeepImport {}' + contents: 'export class DeepImport {}' }, - {name: _('/node_modules/lib-1/sub-1/index.js'), contents: 'export declare class Y {}'}, + {name: _('/node_modules/lib-1/sub-1/index.js'), contents: 'export class Y {}'}, {name: _('/node_modules/lib-1/sub-1/package.json'), contents: '{"esm2015": "./index.js"}'}, {name: _('/node_modules/lib-1/sub-1/index.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/node_modules/lib-1/sub-2.js'), contents: `export * from './sub-2/sub-2';`}, - {name: _('/node_modules/lib-1/sub-2/sub-2.js'), contents: `export declare class Z {}';`}, + {name: _('/node_modules/lib-1/sub-2/sub-2.js'), contents: `export class Z {}';`}, {name: _('/node_modules/lib-1/sub-2/package.json'), contents: '{"esm2015": "./sub-2.js"}'}, {name: _('/node_modules/lib-1/sub-2/sub-2.metadata.json'), contents: 'MOCK METADATA'}, {name: _('/dist/components/index.js'), contents: `class MyComponent {};`}, diff --git a/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts index 41e52ecdc3..f778abfca3 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts @@ -26,7 +26,7 @@ runInEachFileSystem(() => { host = new UmdDependencyHost(fs, new ModuleResolver(fs)); }); - describe('getDependencies()', () => { + describe('collectDependencies()', () => { it('should not generate a TS AST if the source does not contain any require calls', () => { spyOn(ts, 'createSourceFile'); host.collectDependencies(_('/no/imports/or/re-exports/index.js'), createDependencyInfo()); diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts index 521748d5a1..647a4dca63 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts @@ -13,6 +13,7 @@ import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host'; import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; import {ModuleResolver} from '../../src/dependencies/module_resolver'; import {TargetedEntryPointFinder} from '../../src/entry_point_finder/targeted_entry_point_finder'; +import {NGCC_VERSION} from '../../src/packages/build_marker'; import {NgccConfiguration} from '../../src/packages/configuration'; import {EntryPoint} from '../../src/packages/entry_point'; import {PathMappings} from '../../src/utils'; @@ -227,32 +228,252 @@ runInEachFileSystem(() => { ]); }); - function createPackage( - basePath: AbsoluteFsPath, packageName: string, deps: string[] = []): TestFile[] { - return [ - { - name: _Abs(`${basePath}/${packageName}/package.json`), - contents: JSON.stringify({ - typings: `./${packageName}.d.ts`, - fesm2015: `./fesm2015/${packageName}.js`, - }) - }, - { - name: _Abs(`${basePath}/${packageName}/${packageName}.metadata.json`), - contents: 'metadata info' - }, - { - name: _Abs(`${basePath}/${packageName}/fesm2015/${packageName}.js`), - contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), - }, - ]; - } - function dumpEntryPointPaths( basePath: AbsoluteFsPath, entryPoints: EntryPoint[]): [string, string][] { return entryPoints.map(x => [relative(basePath, x.package), relative(basePath, x.path)]); } }); + + describe('targetNeedsProcessingOrCleaning()', () => { + it('should return false if there is no entry-point', () => { + const targetPath = _Abs('/no_packages/node_modules/should_not_be_found'); + fs.ensureDir(targetPath); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_packages/node_modules'), targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + it('should return false if the target path is not a valid entry-point', () => { + const targetPath = _Abs('/no_valid_entry_points/node_modules/some_package'); + loadTestFiles([ + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/package.json'), + contents: '{}' + }, + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_valid_entry_points/node_modules'), targetPath, + undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + it('should false if the target path has no typings', () => { + const targetPath = _Abs('/no_valid_entry_points/node_modules/some_package'); + loadTestFiles([ + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/package.json'), + contents: '{"fesm2015": "./index.js"}' + }, + { + name: + _Abs('/no_valid_entry_points/node_modules/some_package/some_package.metadata.json'), + contents: 'metadata info' + }, + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/index.js'), + contents: 'export class MyClass {}' + }, + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_valid_entry_points/node_modules'), targetPath, + undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + it('should false if the target path is not compiled by Angular - i.e has no metadata file', + () => { + const targetPath = _Abs('/no_valid_entry_points/node_modules/some_package'); + loadTestFiles([ + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/package.json'), + contents: '{"typings": "./index.d.ts", "fesm2015": "./index.js"}' + }, + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/index.d.ts'), + contents: 'export declare class MyClass {}' + }, + { + name: _Abs('/no_valid_entry_points/node_modules/some_package/index.js'), + contents: 'export class MyClass {}' + }, + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, _Abs('/no_valid_entry_points/node_modules'), + targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015'], true)).toBe(false); + }); + + describe('[compileAllFormats: true]', () => { + it('should return true if none of the properties to consider have been processed', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], true)).toBe(true); + }); + + it('should return true if at least one of the properties to consider has not been processed', + () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', + ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add a build marker to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + esm5: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], true)).toBe(true); + }); + + it('should return false if all of the properties to consider have been processed', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add build markers to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + fesm2015: NGCC_VERSION, + esm5: NGCC_VERSION, + main: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], true)).toBe(false); + }); + }); + + describe('[compileAllFormats: false]', () => { + it('should return true if none of the properties to consider have been processed', () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], false)).toBe(true); + }); + + it('should return true if the first of the properties to consider that is in the package.json has not been processed', + () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', + ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add build markers to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + esm5: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], false)).toBe(true); + }); + + it('should return false if the first of the properties to consider (that actually appear in the package.json) has been processed', + () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + const targetPath = _Abs('/sub_entry_points/node_modules/common/http/testing'); + loadTestFiles([ + ...createPackage(fs.resolve(basePath, ''), 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', + ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + ]); + + // Add build markers to the package.json + const packageJsonPath = _Abs(`${targetPath}/package.json`); + const packageJson = JSON.parse(fs.readFile(packageJsonPath)); + packageJson.__processed_by_ivy_ngcc__ = { + fesm2015: NGCC_VERSION, + }; + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + expect(finder.targetNeedsProcessingOrCleaning(['fesm2015', 'esm5'], false)) + .toBe(false); + }); + }); + }); + + function createPackage( + basePath: AbsoluteFsPath, packageName: string, deps: string[] = []): TestFile[] { + return [ + { + name: _Abs(`${basePath}/${packageName}/package.json`), + contents: JSON.stringify({ + typings: `./${packageName}.d.ts`, + fesm2015: `./fesm2015/${packageName}.js`, + esm5: `./esm5/${packageName}.js`, + main: `./common/${packageName}.js`, + }) + }, + { + name: _Abs(`${basePath}/${packageName}/${packageName}.metadata.json`), + contents: 'metadata info' + }, + { + name: _Abs(`${basePath}/${packageName}/fesm2015/${packageName}.js`), + contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), + }, + { + name: _Abs(`${basePath}/${packageName}/esm5/${packageName}.js`), + contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), + }, + { + name: _Abs(`${basePath}/${packageName}/commonjs/${packageName}.js`), + contents: deps.map((dep, i) => `var i${i} = require('${dep}');`).join('\n'), + }, + ]; + } }); }); diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts index 41b8a6ce0b..6c6609f313 100644 --- a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts @@ -14,6 +14,7 @@ import {ClusterExecutor} from '../../../src/execution/cluster/executor'; import {ClusterMaster} from '../../../src/execution/cluster/master'; import {ClusterWorker} from '../../../src/execution/cluster/worker'; import {PackageJsonUpdater} from '../../../src/writing/package_json_updater'; +import {MockLockFile} from '../../helpers/mock_lock_file'; import {MockLogger} from '../../helpers/mock_logger'; import {mockProperty} from '../../helpers/spy_utils'; @@ -23,14 +24,19 @@ describe('ClusterExecutor', () => { let masterRunSpy: jasmine.Spy; let workerRunSpy: jasmine.Spy; let mockLogger: MockLogger; + let mockLockFile: MockLockFile; let executor: ClusterExecutor; beforeEach(() => { - masterRunSpy = spyOn(ClusterMaster.prototype, 'run'); - workerRunSpy = spyOn(ClusterWorker.prototype, 'run'); + masterRunSpy = spyOn(ClusterMaster.prototype, 'run') + .and.returnValue(Promise.resolve('CusterMaster#run()')); + workerRunSpy = spyOn(ClusterWorker.prototype, 'run') + .and.returnValue(Promise.resolve('CusterWorker#run()')); mockLogger = new MockLogger(); - executor = new ClusterExecutor(42, mockLogger, null as unknown as PackageJsonUpdater); + mockLockFile = new MockLockFile(); + executor = + new ClusterExecutor(42, mockLogger, null as unknown as PackageJsonUpdater, mockLockFile); }); describe('execute()', () => { @@ -47,7 +53,6 @@ describe('ClusterExecutor', () => { }); it('should delegate to `ClusterMaster#run()`', async() => { - masterRunSpy.and.returnValue('CusterMaster#run()'); const analyzeEntryPointsSpy = jasmine.createSpy('analyzeEntryPoints'); const createCompilerFnSpy = jasmine.createSpy('createCompilerFn'); @@ -60,6 +65,58 @@ describe('ClusterExecutor', () => { expect(analyzeEntryPointsSpy).toHaveBeenCalledWith(); expect(createCompilerFnSpy).not.toHaveBeenCalled(); }); + + it('should call LockFile.create() and LockFile.remove() if master runner completes successfully', + async() => { + const anyFn: () => any = () => undefined; + await executor.execute(anyFn, anyFn); + expect(mockLockFile.log).toEqual(['create()', 'remove()']); + }); + + it('should call LockFile.create() and LockFile.remove() if master runner fails', async() => { + const anyFn: () => any = () => undefined; + masterRunSpy.and.returnValue(Promise.reject(new Error('master runner error'))); + let error = ''; + try { + await executor.execute(anyFn, anyFn); + } catch (e) { + error = e.message; + } + expect(error).toEqual('master runner error'); + expect(mockLockFile.log).toEqual(['create()', 'remove()']); + }); + + it('should not call master runner if Lockfile.create() fails', async() => { + const anyFn: () => any = () => undefined; + const lockFile = new MockLockFile({throwOnCreate: true}); + executor = + new ClusterExecutor(42, mockLogger, null as unknown as PackageJsonUpdater, lockFile); + let error = ''; + try { + await executor.execute(anyFn, anyFn); + } catch (e) { + error = e.message; + } + expect(error).toEqual('LockFile.create() error'); + expect(lockFile.log).toEqual(['create()']); + expect(masterRunSpy).not.toHaveBeenCalled(); + }); + + it('should fail if Lockfile.remove() fails', async() => { + const anyFn: () => any = () => undefined; + const lockFile = new MockLockFile({throwOnRemove: true}); + executor = + new ClusterExecutor(42, mockLogger, null as unknown as PackageJsonUpdater, lockFile); + let error = ''; + try { + await executor.execute(anyFn, anyFn); + } catch (e) { + error = e.message; + } + expect(error).toEqual('LockFile.remove() error'); + expect(lockFile.log).toEqual(['create()', 'remove()']); + expect(masterRunSpy).toHaveBeenCalled(); + }); }); describe('(on cluster worker)', () => { @@ -73,7 +130,6 @@ describe('ClusterExecutor', () => { }); it('should delegate to `ClusterWorker#run()`', async() => { - workerRunSpy.and.returnValue('CusterWorker#run()'); const analyzeEntryPointsSpy = jasmine.createSpy('analyzeEntryPoints'); const createCompilerFnSpy = jasmine.createSpy('createCompilerFn'); @@ -86,6 +142,12 @@ describe('ClusterExecutor', () => { expect(analyzeEntryPointsSpy).not.toHaveBeenCalled(); expect(createCompilerFnSpy).toHaveBeenCalledWith(jasmine.any(Function)); }); + + it('should not call LockFile.create() or LockFile.remove()', async() => { + const anyFn: () => any = () => undefined; + await executor.execute(anyFn, anyFn); + expect(mockLockFile.log).toEqual([]); + }); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts index c1f743cb0d..d2cea43299 100644 --- a/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts @@ -14,7 +14,7 @@ import {absoluteFrom as _} from '../../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing'; import {ClusterPackageJsonUpdater} from '../../../src/execution/cluster/package_json_updater'; import {JsonObject} from '../../../src/packages/entry_point'; -import {PackageJsonUpdate, PackageJsonUpdater} from '../../../src/writing/package_json_updater'; +import {PackageJsonPropertyPositioning, PackageJsonUpdate, PackageJsonUpdater} from '../../../src/writing/package_json_updater'; import {mockProperty} from '../../helpers/spy_utils'; @@ -48,10 +48,18 @@ runInEachFileSystem(() => { const update = updater.createUpdate(); update.addChange(['foo'], 'updated'); + update.addChange(['baz'], 'updated 2', 'alphabetic'); + update.addChange(['bar'], 'updated 3', {before: 'bar'}); update.writeChanges(jsonPath); expect(writeChangesSpy) - .toHaveBeenCalledWith([[['foo'], 'updated']], jsonPath, undefined); + .toHaveBeenCalledWith( + [ + [['foo'], 'updated', 'unimportant'], + [['baz'], 'updated 2', 'alphabetic'], + [['bar'], 'updated 3', {before: 'bar'}], + ], + jsonPath, undefined); }); })); }); @@ -65,10 +73,18 @@ runInEachFileSystem(() => { const jsonPath = _('/foo/package.json'); const parsedJson = {foo: 'bar'}; - updater.createUpdate().addChange(['foo'], 'updated').writeChanges(jsonPath, parsedJson); + updater.createUpdate() + .addChange(['foo'], 'updated') + .addChange(['bar'], 'updated too', 'alphabetic') + .writeChanges(jsonPath, parsedJson); expect(delegate.writeChanges) - .toHaveBeenCalledWith([[['foo'], 'updated']], jsonPath, parsedJson); + .toHaveBeenCalledWith( + [ + [['foo'], 'updated', 'unimportant'], + [['bar'], 'updated too', 'alphabetic'], + ], + jsonPath, parsedJson); }); it('should throw, if trying to re-apply an already applied update', () => { @@ -84,25 +100,36 @@ runInEachFileSystem(() => { describe('(on cluster worker)', () => { beforeEach(() => runAsClusterMaster(false)); + afterEach(() => expect(delegate.writeChanges).not.toHaveBeenCalled()); it('should send an `update-package-json` message to the master process', () => { const jsonPath = _('/foo/package.json'); - const writeToProp = (propPath: string[], parsed?: JsonObject) => - updater.createUpdate().addChange(propPath, 'updated').writeChanges(jsonPath, parsed); + const writeToProp = + (propPath: string[], positioning?: PackageJsonPropertyPositioning, + parsed?: JsonObject) => updater.createUpdate() + .addChange(propPath, 'updated', positioning) + .writeChanges(jsonPath, parsed); writeToProp(['foo']); expect(processSendSpy).toHaveBeenCalledWith({ type: 'update-package-json', packageJsonPath: jsonPath, - changes: [[['foo'], 'updated']], + changes: [[['foo'], 'updated', 'unimportant']], }); - writeToProp(['bar', 'baz', 'qux'], {}); + writeToProp(['bar'], {before: 'foo'}); expect(processSendSpy).toHaveBeenCalledWith({ type: 'update-package-json', packageJsonPath: jsonPath, - changes: [[['bar', 'baz', 'qux'], 'updated']], + changes: [[['bar'], 'updated', {before: 'foo'}]], + }); + + writeToProp(['bar', 'baz', 'qux'], 'alphabetic', {}); + expect(processSendSpy).toHaveBeenCalledWith({ + type: 'update-package-json', + packageJsonPath: jsonPath, + changes: [[['bar', 'baz', 'qux'], 'updated', 'alphabetic']], }); }); diff --git a/packages/compiler-cli/ngcc/test/execution/lock_file_spec.ts b/packages/compiler-cli/ngcc/test/execution/lock_file_spec.ts new file mode 100644 index 0000000000..78da66fae0 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/execution/lock_file_spec.ts @@ -0,0 +1,208 @@ +/** + * @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 process from 'process'; +import {FileSystem, getFileSystem} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {LockFile} from '../../src/execution/lock_file'; + +/** + * This class allows us to test the protected methods of LockFile directly, + * which are normally hidden as "protected". + * + * We also add logging in here to track what is being called and in what order. + * + * Finally this class stubs out the `exit()` method to prevent unit tests from exiting the process. + */ +class LockFileUnderTest extends LockFile { + log: string[] = []; + constructor(fs: FileSystem, private handleSignals = false) { + super(fs); + fs.ensureDir(fs.dirname(this.lockFilePath)); + } + create() { + this.log.push('create()'); + super.create(); + } + remove() { + this.log.push('remove()'); + super.remove(); + } + addSignalHandlers() { + if (this.handleSignals) { + super.addSignalHandlers(); + } + } + removeSignalHandlers() { super.removeSignalHandlers(); } + exit(code: number) { this.log.push(`exit(${code})`); } +} + +runInEachFileSystem(() => { + describe('LockFile', () => { + describe('lock() - synchronous', () => { + it('should guard the `fn()` with calls to `create()` and `remove()`', () => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + + lockFile.lock(() => lockFile.log.push('fn()')); + expect(lockFile.log).toEqual(['create()', 'fn()', 'remove()']); + }); + + it('should guard the `fn()` with calls to `create()` and `remove()`, even if it throws', + () => { + let error: string = ''; + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + + try { + lockFile.lock(() => { + lockFile.log.push('fn()'); + throw new Error('ERROR'); + }); + } catch (e) { + error = e.message; + } + expect(error).toEqual('ERROR'); + expect(lockFile.log).toEqual(['create()', 'fn()', 'remove()']); + }); + + it('should remove the lockfile if CTRL-C is triggered', () => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs, /* handleSignals */ true); + + lockFile.lock(() => { + lockFile.log.push('SIGINT'); + process.emit('SIGINT', 'SIGINT'); + }); + // Since the test does not actually exit process, the `remove()` is called one more time. + expect(lockFile.log).toEqual(['create()', 'SIGINT', 'remove()', 'exit(1)', 'remove()']); + // Clean up the signal handlers. In practice this is not needed since the process would have + // been terminated already. + lockFile.removeSignalHandlers(); + }); + + it('should remove the lockfile if terminal is closed', () => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs, /* handleSignals */ true); + + lockFile.lock(() => { + lockFile.log.push('SIGHUP'); + process.emit('SIGHUP', 'SIGHUP'); + }); + // Since this does not actually exit process, the `remove()` is called one more time. + expect(lockFile.log).toEqual(['create()', 'SIGHUP', 'remove()', 'exit(1)', 'remove()']); + // Clean up the signal handlers. In practice this is not needed since the process would have + // been terminated already. + lockFile.removeSignalHandlers(); + }); + }); + + describe('lock() - asynchronous', () => { + it('should guard the `fn()` with calls to `create()` and `remove()`', async() => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + + await lockFile.lock(async() => { + lockFile.log.push('fn() - before'); + // This promise forces node to do a tick in this function, ensuring that we are truly + // testing an async scenario. + await Promise.resolve(); + lockFile.log.push('fn() - after'); + }); + expect(lockFile.log).toEqual(['create()', 'fn() - before', 'fn() - after', 'remove()']); + }); + + it('should guard the `fn()` with calls to `create()` and `remove()`, even if it throws', + async() => { + let error: string = ''; + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + lockFile.create = () => lockFile.log.push('create()'); + lockFile.remove = () => lockFile.log.push('remove()'); + + try { + await lockFile.lock(async() => { + lockFile.log.push('fn()'); + throw new Error('ERROR'); + }); + } catch (e) { + error = e.message; + } + expect(error).toEqual('ERROR'); + expect(lockFile.log).toEqual(['create()', 'fn()', 'remove()']); + }); + + it('should remove the lockfile if CTRL-C is triggered', async() => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs, /* handleSignals */ true); + + await lockFile.lock(async() => { + lockFile.log.push('SIGINT'); + process.emit('SIGINT', 'SIGINT'); + }); + // Since the test does not actually exit process, the `remove()` is called one more time. + expect(lockFile.log).toEqual(['create()', 'SIGINT', 'remove()', 'exit(1)', 'remove()']); + // Clean up the signal handlers. In practice this is not needed since the process would have + // been terminated already. + lockFile.removeSignalHandlers(); + }); + + it('should remove the lockfile if terminal is closed', async() => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs, /* handleSignals */ true); + + await lockFile.lock(async() => { + lockFile.log.push('SIGHUP'); + process.emit('SIGHUP', 'SIGHUP'); + }); + // Since this does not actually exit process, the `remove()` is called one more time. + expect(lockFile.log).toEqual(['create()', 'SIGHUP', 'remove()', 'exit(1)', 'remove()']); + // Clean up the signal handlers. In practice this is not needed since the process would have + // been terminated already. + lockFile.removeSignalHandlers(); + }); + }); + + describe('create()', () => { + it('should write a lock file to the file-system', () => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + expect(fs.exists(lockFile.lockFilePath)).toBe(false); + lockFile.create(); + expect(fs.exists(lockFile.lockFilePath)).toBe(true); + }); + + it('should error if a lock file already exists', () => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + fs.writeFile(lockFile.lockFilePath, '188'); + expect(() => lockFile.create()) + .toThrowError( + `ngcc is already running at process with id 188.\n` + + `If you are running multiple builds in parallel then you should pre-process your node_modules via the command line ngcc tool before starting the builds;\n` + + `See https://v9.angular.io/guide/ivy#speeding-up-ngcc-compilation.\n` + + `(If you are sure no ngcc process is running then you should delete the lockfile at ${lockFile.lockFilePath}.)`); + }); + }); + + describe('remove()', () => { + it('should remove the lock file from the file-system', () => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + fs.writeFile(lockFile.lockFilePath, '188'); + lockFile.remove(); + expect(fs.exists(lockFile.lockFilePath)).toBe(false); + }); + + it('should not error if the lock file does not exist', () => { + const fs = getFileSystem(); + const lockFile = new LockFileUnderTest(fs); + expect(() => lockFile.remove()).not.toThrow(); + }); + }); + }); +}); diff --git a/packages/compiler-cli/ngcc/test/execution/single_processor_executor_spec.ts b/packages/compiler-cli/ngcc/test/execution/single_processor_executor_spec.ts new file mode 100644 index 0000000000..e55b26b531 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/execution/single_processor_executor_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 {SingleProcessExecutor} from '../../src/execution/single_process_executor'; +import {SerialTaskQueue} from '../../src/execution/task_selection/serial_task_queue'; +import {PackageJsonUpdater} from '../../src/writing/package_json_updater'; +import {MockLockFile} from '../helpers/mock_lock_file'; +import {MockLogger} from '../helpers/mock_logger'; + + +describe('SingleProcessExecutor', () => { + let mockLogger: MockLogger; + let mockLockFile: MockLockFile; + let executor: SingleProcessExecutor; + + beforeEach(() => { + mockLogger = new MockLogger(); + mockLockFile = new MockLockFile(); + executor = + new SingleProcessExecutor(mockLogger, null as unknown as PackageJsonUpdater, mockLockFile); + }); + + describe('execute()', () => { + it('should call LockFile.create() and LockFile.remove() if processing completes successfully', + () => { + const noTasks = () => new SerialTaskQueue([] as any); + const createCompileFn: () => any = () => undefined; + executor.execute(noTasks, createCompileFn); + expect(mockLockFile.log).toEqual(['create()', 'remove()']); + }); + + it('should call LockFile.create() and LockFile.remove() if `analyzeEntryPoints` fails', () => { + const errorFn: () => never = () => { throw new Error('analyze error'); }; + const createCompileFn: () => any = () => undefined; + let error: string = ''; + try { + executor.execute(errorFn, createCompileFn); + } catch (e) { + error = e.message; + } + expect(error).toEqual('analyze error'); + expect(mockLockFile.log).toEqual(['create()', 'remove()']); + }); + + it('should call LockFile.create() and LockFile.remove() if `createCompileFn` fails', () => { + const oneTask = () => new SerialTaskQueue([{}] as any); + const createErrorCompileFn: () => any = () => { throw new Error('compile error'); }; + let error: string = ''; + try { + executor.execute(oneTask, createErrorCompileFn); + } catch (e) { + error = e.message; + } + expect(error).toEqual('compile error'); + expect(mockLockFile.log).toEqual(['create()', 'remove()']); + }); + + it('should not call `analyzeEntryPoints` if Lockfile.create() fails', () => { + const lockFile = new MockLockFile({throwOnCreate: true}); + const analyzeFn: () => any = () => { lockFile.log.push('analyzeFn'); }; + const anyFn: () => any = () => undefined; + executor = + new SingleProcessExecutor(mockLogger, null as unknown as PackageJsonUpdater, lockFile); + let error = ''; + try { + executor.execute(analyzeFn, anyFn); + } catch (e) { + error = e.message; + } + expect(error).toEqual('LockFile.create() error'); + expect(lockFile.log).toEqual(['create()']); + }); + + it('should fail if Lockfile.remove() fails', () => { + const noTasks = () => new SerialTaskQueue([] as any); + const anyFn: () => any = () => undefined; + const lockFile = new MockLockFile({throwOnRemove: true}); + executor = + new SingleProcessExecutor(mockLogger, null as unknown as PackageJsonUpdater, lockFile); + let error = ''; + try { + executor.execute(noTasks, anyFn); + } catch (e) { + error = e.message; + } + expect(error).toEqual('LockFile.remove() error'); + expect(lockFile.log).toEqual(['create()', 'remove()']); + }); + }); +}); diff --git a/packages/compiler-cli/ngcc/test/helpers/mock_lock_file.ts b/packages/compiler-cli/ngcc/test/helpers/mock_lock_file.ts new file mode 100644 index 0000000000..77b2040fb5 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/helpers/mock_lock_file.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 {MockFileSystemNative} from '../../../src/ngtsc/file_system/testing'; +import {LockFile} from '../../src/execution/lock_file'; + +export class MockLockFile extends LockFile { + log: string[] = []; + constructor(private options: {throwOnCreate?: boolean, throwOnRemove?: boolean} = {}) { + // This `MockLockFile` is not used in tests that are run via `runInEachFileSystem()` + // So we cannot use `getFileSystem()` but instead just instantiate a mock file-system. + super(new MockFileSystemNative()); + } + create() { + this.log.push('create()'); + if (this.options.throwOnCreate) throw new Error('LockFile.create() error'); + } + remove() { + this.log.push('remove()'); + if (this.options.throwOnRemove) throw new Error('LockFile.remove() error'); + } +} diff --git a/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts b/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts index cba513de17..25457342f7 100644 --- a/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts @@ -2184,7 +2184,7 @@ exports.ExternalModule = ExternalModule; }); }); - describe('getDtsDeclarationsOfClass()', () => { + describe('getDtsDeclaration()', () => { it('should find the dts declaration that has the same relative path to the source file', () => { loadTestFiles(TYPINGS_SRC_FILES); diff --git a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts index 35b3c20cf3..6f086011db 100644 --- a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts @@ -547,6 +547,7 @@ runInEachFileSystem(() => { name: _('/ep/src/index.js'), contents: ` import 'an_external_lib'; + import 'an_external_lib_without_typings'; import {InternalClass} from './internal'; import * as func1 from './func1'; import * as missing from './missing-class'; @@ -579,6 +580,10 @@ runInEachFileSystem(() => { name: _('/ep/src/shadow-class.js'), contents: 'export class ShadowClass {}', }, + { + name: _('/an_external_lib_without_typings/index.js'), + contents: '// Some content.', + }, ]; TYPINGS_DTS_FILES = [ @@ -1958,7 +1963,7 @@ runInEachFileSystem(() => { }); }); - describe('getDtsDeclarationsOfClass()', () => { + describe('getDtsDeclaration()', () => { it('should find the dts declaration that has the same relative path to the source file', () => { loadTestFiles(TYPINGS_SRC_FILES); @@ -2019,15 +2024,41 @@ runInEachFileSystem(() => { getRootFiles(TYPINGS_SRC_FILES)[0], false, [_('/ep/src/shadow-class.js')]); const dts = makeTestBundleProgram( getRootFiles(TYPINGS_DTS_FILES)[0], false, [_('/ep/typings/shadow-class.d.ts')]); - const missingClass = getDeclaration( + const shadowClass = getDeclaration( bundle.program, _('/ep/src/shadow-class.js'), 'ShadowClass', isNamedClassDeclaration); const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); - const dtsDecl = host.getDtsDeclaration(missingClass) !; + const dtsDecl = host.getDtsDeclaration(shadowClass) !; expect(dtsDecl).not.toBeNull(); expect(dtsDecl.getSourceFile().fileName).toEqual(_('/ep/typings/shadow-class.d.ts')); }); + it('should ignore source files outside of the entrypoint', () => { + const externalLibWithoutTypingsIndex = _('/an_external_lib_without_typings/index.js'); + + class TestEsm2015ReflectionHost extends Esm2015ReflectionHost { + getExportsOfModule(node: ts.Node) { + if (ts.isSourceFile(node) && (node.fileName === externalLibWithoutTypingsIndex)) { + throw new Error( + `'getExportsOfModule()' called on '${externalLibWithoutTypingsIndex}'.`); + } + return super.getExportsOfModule(node); + } + } + + loadTestFiles(TYPINGS_SRC_FILES); + loadTestFiles(TYPINGS_DTS_FILES); + const bundle = makeTestBundleProgram( + getRootFiles(TYPINGS_SRC_FILES)[0], false, [externalLibWithoutTypingsIndex]); + const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); + const missingClass = getDeclaration( + bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2', + isNamedClassDeclaration); + const host = new TestEsm2015ReflectionHost(new MockLogger(), false, bundle, dts); + + expect(host.getDtsDeclaration(missingClass)).toBeNull(); + }); + it('should find the dts file that contains a matching class declaration, even if the source files do not match', () => { loadTestFiles(TYPINGS_SRC_FILES); diff --git a/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts b/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts index fa67d84d48..845e5358f5 100644 --- a/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts @@ -1814,6 +1814,86 @@ runInEachFileSystem(() => { expect(definition.helper).toBe(TsHelperFn.SpreadArrays); expect(definition.parameters.length).toEqual(0); }); + + it('should recognize TypeScript __assign helper function declaration', () => { + const file: TestFile = { + name: _('/declaration.d.ts'), + contents: `export declare function __assign(...args: object[]): object;`, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + + const node = + getDeclaration(bundle.program, file.name, '__assign', isNamedFunctionDeclaration) !; + + const definition = host.getDefinitionOfFunction(node) !; + expect(definition.node).toBe(node); + expect(definition.body).toBeNull(); + expect(definition.helper).toBe(TsHelperFn.Assign); + expect(definition.parameters.length).toEqual(0); + }); + + it('should recognize TypeScript __assign helper function implementation', () => { + const file: TestFile = { + name: _('/implementation.js'), + contents: ` + var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + };`, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + + const node = + getDeclaration(bundle.program, file.name, '__assign', ts.isVariableDeclaration) !; + + const definition = host.getDefinitionOfFunction(node) !; + expect(definition.node).toBe(node); + expect(definition.body).toBeNull(); + expect(definition.helper).toBe(TsHelperFn.Assign); + expect(definition.parameters.length).toEqual(0); + }); + + it('should recognize TypeScript __assign helper function implementation when suffixed', + () => { + const file: TestFile = { + name: _('/implementation.js'), + contents: ` + var __assign$2 = (this && this.__assign$2) || function () { + __assign$2 = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign$2.apply(this, arguments); + };`, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + + const node = + getDeclaration(bundle.program, file.name, '__assign$2', ts.isVariableDeclaration) !; + + const definition = host.getDefinitionOfFunction(node) !; + expect(definition.node).toBe(node); + expect(definition.body).toBeNull(); + expect(definition.helper).toBe(TsHelperFn.Assign); + expect(definition.parameters.length).toEqual(0); + }); }); describe('getImportOfIdentifier()', () => { @@ -2370,7 +2450,7 @@ runInEachFileSystem(() => { }); }); - describe('getDtsDeclarationsOfClass()', () => { + describe('getDtsDeclaration()', () => { it('should find the dts declaration that has the same relative path to the source file', () => { loadTestFiles(TYPINGS_SRC_FILES); diff --git a/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts b/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts index 9ecf3b4042..cb3ffc8d7e 100644 --- a/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts @@ -2360,7 +2360,7 @@ runInEachFileSystem(() => { }); }); - describe('getDtsDeclarationsOfClass()', () => { + describe('getDtsDeclaration()', () => { it('should find the dts declaration that has the same relative path to the source file', () => { loadTestFiles(TYPINGS_SRC_FILES); diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index d571f16952..56bd9064b5 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -13,6 +13,7 @@ import * as os from 'os'; import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, join} from '../../../src/ngtsc/file_system'; import {Folder, MockFileSystem, TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadStandardTestFiles, loadTestFiles} from '../../../test/helpers'; +import {LockFile} from '../../src/execution/lock_file'; import {mainNgcc} from '../../src/main'; import {markAsProcessed} from '../../src/packages/build_marker'; import {EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point'; @@ -145,6 +146,49 @@ runInEachFileSystem(() => { '{ bar: [{ type: Input }] }); })();'); }); + ['esm5', 'esm2015'].forEach(target => { + it(`should be able to process spread operator inside objects for ${target} format`, () => { + compileIntoApf( + 'test-package', { + '/index.ts': ` + import {Directive, Input, NgModule} from '@angular/core'; + + const a = { '[class.a]': 'true' }; + const b = { '[class.b]': 'true' }; + + @Directive({ + selector: '[foo]', + host: {...a, ...b, '[class.c]': 'false'} + }) + export class FooDirective {} + + @NgModule({ + declarations: [FooDirective], + }) + export class FooModule {} + `, + }, + {importHelpers: true}); + + // TODO: add test with import helpers disabled. This currently won't work because + // inlined TS helper functions are not detected. For more details, see PR: + // https://github.com/angular/angular/pull/34169 + fs.writeFile( + _('/node_modules/tslib/index.d.ts'), + `export declare function __assign(...args: object[]): object;`); + + mainNgcc({ + basePath: '/node_modules', + targetEntryPointPath: 'test-package', + propertiesToConsider: [target], + }); + + const jsContents = fs.readFile(_(`/node_modules/test-package/${target}/src/index.js`)) + .replace(/\s+/g, ' '); + expect(jsContents).toContain('ngcc0.ɵɵclassProp("a", true)("b", true)("c", false)'); + }); + }); + it('should not add `const` in ES5 generated code', () => { compileIntoFlatEs5Package('test-package', { '/index.ts': ` @@ -172,7 +216,6 @@ runInEachFileSystem(() => { const jsContents = fs.readFile(_(`/node_modules/test-package/index.js`)); expect(jsContents).not.toMatch(/\bconst \w+\s*=/); - expect(jsContents).toMatch(/\bvar _c0 =/); }); it('should add ɵfac but not duplicate ɵprov properties on injectables', () => { @@ -245,22 +288,23 @@ runInEachFileSystem(() => { propertiesToConsider: ['esm2015'] }); - // In `@angular/common` the `NgClassR3Impl` class gets exported as something like + // In `@angular/common` the `BrowserPlatformLocation` class gets exported as something like // `ɵangular_packages_common_common_a`. const jsContents = fs.readFile(_(`/node_modules/@angular/common/fesm2015/common.js`)); - const exportedNameMatch = jsContents.match(/export.* NgClassR3Impl as ([^ ,}]+)/); + const exportedNameMatch = + jsContents.match(/export.* BrowserPlatformLocation as ([^ ,}]+)/); if (exportedNameMatch === null) { return fail( - 'Expected `/node_modules/@angular/common/fesm2015/common.js` to export `NgClassR3Impl` via an alias'); + 'Expected `/node_modules/@angular/common/fesm2015/common.js` to export `BrowserPlatformLocation` via an alias'); } const exportedName = exportedNameMatch[1]; // We need to make sure that the flat typings file exports this directly const dtsContents = fs.readFile(_('/node_modules/@angular/common/common.d.ts')); expect(dtsContents) - .toContain(`export declare class ${exportedName} implements ɵNgClassImpl`); + .toContain(`export declare class ${exportedName} extends PlatformLocation`); // And that ngcc's modifications to that class use the correct (exported) name - expect(dtsContents).toContain(`static ɵprov: ɵngcc0.ɵɵInjectableDef<${exportedName}>`); + expect(dtsContents).toContain(`static ɵfac: ɵngcc0.ɵɵFactoryDef<${exportedName}>`); }); it('should add generic type for ModuleWithProviders and generate exports for private modules', @@ -436,22 +480,50 @@ runInEachFileSystem(() => { expect(loadPackage('@angular/common/testing').__processed_by_ivy_ngcc__).toBeUndefined(); }); - it('should mark a non-Angular package target as processed', () => { + it('should not mark a non-Angular package as processed if it is the target', () => { mainNgcc({basePath: '/node_modules', targetEntryPointPath: 'test-package'}); - // `test-package` has no Angular but is marked as processed. - expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toEqual({ + // * `test-package` has no Angular and is not marked as processed. + expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toBeUndefined(); + + // * `core` is a dependency of `test-package`, but it is also not processed, since + // `test-package` was not processed. + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined(); + }); + + it('should not mark a non-Angular package as processed if it is a dependency', () => { + // `test-package-user` is a valid Angular package that depends upon `test-package`. + loadTestFiles([ + { + name: _('/node_modules/test-package-user/package.json'), + contents: + '{"name": "test-package-user", "es2015": "./index.js", "typings": "./index.d.ts"}' + }, + { + name: _('/node_modules/test-package-user/index.js'), + contents: 'import * as x from \'test-package\';' + }, + { + name: _('/node_modules/test-package-user/index.d.ts'), + contents: 'import * as x from \'test-package\';' + }, + {name: _('/node_modules/test-package-user/index.metadata.json'), contents: 'DUMMY DATA'}, + ]); + + mainNgcc({basePath: '/node_modules', targetEntryPointPath: 'test-package-user'}); + + // * `test-package-user` is processed because it is compiled by Angular + expect(loadPackage('test-package-user').__processed_by_ivy_ngcc__).toEqual({ es2015: '0.0.0-PLACEHOLDER', - esm2015: '0.0.0-PLACEHOLDER', - esm5: '0.0.0-PLACEHOLDER', - fesm2015: '0.0.0-PLACEHOLDER', - fesm5: '0.0.0-PLACEHOLDER', - main: '0.0.0-PLACEHOLDER', - module: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', }); - // * `core` is a dependency of `test-package`, but it is not processed, since test-package - // was not processed. + // * `test-package` is a dependency of `test-package-user` but has not been compiled by + // Angular, and so is not marked as processed + expect(loadPackage('test-package').__processed_by_ivy_ngcc__).toBeUndefined(); + + // * `core` is a dependency of `test-package`, but it is not processed, because + // `test-package` was not processed. expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toBeUndefined(); }); @@ -546,7 +618,6 @@ runInEachFileSystem(() => { }); }); - function markPropertiesAsProcessed(packagePath: string, properties: EntryPointJsonProperty[]) { const basePath = _('/node_modules'); const targetPackageJsonPath = join(basePath, packagePath, 'package.json'); @@ -555,6 +626,49 @@ runInEachFileSystem(() => { pkgJsonUpdater, targetPackage, targetPackageJsonPath, ['typings', ...properties]); } + it('should clean up outdated artifacts', () => { + compileIntoFlatEs5Package('test-package', { + 'index.ts': ` + import {Directive} from '@angular/core'; + + @Directive({selector: '[foo]'}) + export class FooDirective { + } + `, + }); + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['main'], + logger: new MockLogger(), + }); + + // Now hack the files to look like it was processed by an outdated version of ngcc + const packageJson = loadPackage('test-package', _('/node_modules')); + packageJson.__processed_by_ivy_ngcc__ !.typings = '8.0.0'; + packageJson.main_ivy_ngcc = '__ivy_ngcc__/main.js'; + fs.writeFile(_('/node_modules/test-package/package.json'), JSON.stringify(packageJson)); + fs.writeFile(_('/node_modules/test-package/x.js'), 'processed content'); + fs.writeFile(_('/node_modules/test-package/x.js.__ivy_ngcc_bak'), 'original content'); + fs.ensureDir(_('/node_modules/test-package/__ivy_ngcc__/foo')); + + // Now run ngcc again to see that it cleans out the outdated artifacts + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['main'], + logger: new MockLogger(), + }); + const newPackageJson = loadPackage('test-package', _('/node_modules')); + expect(newPackageJson.__processed_by_ivy_ngcc__).toEqual({ + main: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(newPackageJson.main_ivy_ngcc).toBeUndefined(); + expect(fs.exists(_('/node_modules/test-package/x.js'))).toBe(true); + expect(fs.exists(_('/node_modules/test-package/x.js.__ivy_ngcc_bak'))).toBe(false); + expect(fs.readFile(_('/node_modules/test-package/x.js'))).toEqual('original content'); + expect(fs.exists(_('/node_modules/test-package/__ivy_ngcc__'))).toBe(false); + }); + describe('with propertiesToConsider', () => { it('should complain if none of the properties in the `propertiesToConsider` list is supported', @@ -760,6 +874,79 @@ runInEachFileSystem(() => { expect(pkg.fesm5_ivy_ngcc).toEqual('__ivy_ngcc__/fesm5/core.js'); expect(pkg.module_ivy_ngcc).toEqual('__ivy_ngcc__/fesm5/core.js'); }); + + it('should update `package.json` deterministically (regardless of entry-point processing order)', + () => { + // Ensure formats are not marked as processed in `package.json` at the beginning. + let pkg = loadPackage('@angular/core'); + expectNotToHaveProp(pkg, 'esm5_ivy_ngcc'); + expectNotToHaveProp(pkg, 'fesm2015_ivy_ngcc'); + expectNotToHaveProp(pkg, 'fesm5_ivy_ngcc'); + expectNotToHaveProp(pkg, '__processed_by_ivy_ngcc__'); + + // Process `fesm2015` and update `package.json`. + pkg = processFormatAndUpdatePackageJson('fesm2015'); + expectNotToHaveProp(pkg, 'esm5_ivy_ngcc'); + expectToHaveProp(pkg, 'fesm2015_ivy_ngcc'); + expectNotToHaveProp(pkg, 'fesm5_ivy_ngcc'); + expectToHaveProp(pkg.__processed_by_ivy_ngcc__ !, 'fesm2015'); + + // Process `fesm5` and update `package.json`. + pkg = processFormatAndUpdatePackageJson('fesm5'); + expectNotToHaveProp(pkg, 'esm5_ivy_ngcc'); + expectToHaveProp(pkg, 'fesm2015_ivy_ngcc'); + expectToHaveProp(pkg, 'fesm5_ivy_ngcc'); + expectToHaveProp(pkg.__processed_by_ivy_ngcc__ !, 'fesm5'); + + // Process `esm5` and update `package.json`. + pkg = processFormatAndUpdatePackageJson('esm5'); + expectToHaveProp(pkg, 'esm5_ivy_ngcc'); + expectToHaveProp(pkg, 'fesm2015_ivy_ngcc'); + expectToHaveProp(pkg, 'fesm5_ivy_ngcc'); + expectToHaveProp(pkg.__processed_by_ivy_ngcc__ !, 'esm5'); + + // Ensure the properties are in deterministic order (regardless of processing order). + const pkgKeys = stringifyKeys(pkg); + expect(pkgKeys).toContain('|esm5_ivy_ngcc|esm5|'); + expect(pkgKeys).toContain('|fesm2015_ivy_ngcc|fesm2015|'); + expect(pkgKeys).toContain('|fesm5_ivy_ngcc|fesm5|'); + + // NOTE: + // Along with the first format that is processed, the typings are processed as well. + // Also, once a property has been processed, alias properties as also marked as + // processed. Aliases properties are properties that point to the same entry-point file. + // For example: + // - `fesm2015` <=> `es2015` + // - `fesm5` <=> `module` + expect(stringifyKeys(pkg.__processed_by_ivy_ngcc__ !)) + .toBe('|es2015|esm5|fesm2015|fesm5|module|typings|'); + + // Helpers + function expectNotToHaveProp(obj: object, prop: string) { + expect(obj.hasOwnProperty(prop)) + .toBe( + false, + `Expected object not to have property '${prop}': ${JSON.stringify(obj, null, 2)}`); + } + + function expectToHaveProp(obj: object, prop: string) { + expect(obj.hasOwnProperty(prop)) + .toBe( + true, + `Expected object to have property '${prop}': ${JSON.stringify(obj, null, 2)}`); + } + + function processFormatAndUpdatePackageJson(formatProp: string) { + mainNgcc({ + basePath: '/node_modules/@angular/core', + createNewEntryPointFormats: true, + propertiesToConsider: [formatProp], + }); + return loadPackage('@angular/core'); + } + + function stringifyKeys(obj: object) { return `|${Object.keys(obj).join('|')}|`; } + }); }); describe('diagnostics', () => { @@ -1320,6 +1507,7 @@ runInEachFileSystem(() => { function initMockFileSystem(fs: FileSystem, testFiles: Folder) { if (fs instanceof MockFileSystem) { fs.init(testFiles); + fs.ensureDir(fs.dirname(new LockFile(fs).lockFilePath)); } // a random test package that no metadata.json file so not compiled by Angular. diff --git a/packages/compiler-cli/ngcc/test/integration/util.ts b/packages/compiler-cli/ngcc/test/integration/util.ts index 0f5bd9161f..32a42a2078 100644 --- a/packages/compiler-cli/ngcc/test/integration/util.ts +++ b/packages/compiler-cli/ngcc/test/integration/util.ts @@ -109,13 +109,15 @@ function compileIntoFlatPackage( * All generated code is written into the `node_modules` in the top-level filesystem, ready for use * in testing ngcc. */ -export function compileIntoApf(pkgName: string, sources: PackageSources): void { +export function compileIntoApf( + pkgName: string, sources: PackageSources, extraCompilerOptions: ts.CompilerOptions = {}): void { const fs = getFileSystem(); const {rootNames, compileFs} = setupCompileFs(sources); const emit = (options: ts.CompilerOptions) => { const host = new MockCompilerHost(compileFs); - const program = ts.createProgram({host, rootNames, options}); + const program = + ts.createProgram({host, rootNames, options: {...extraCompilerOptions, ...options}}); program.emit(); }; diff --git a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts index 1f0e145d45..e6637cf99d 100644 --- a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts @@ -5,10 +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 {AbsoluteFsPath, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; -import {hasBeenProcessed, markAsProcessed} from '../../src/packages/build_marker'; +import {NGCC_VERSION, cleanPackageJson, hasBeenProcessed, markAsProcessed, needsCleaning} from '../../src/packages/build_marker'; +import {EntryPointPackageJson} from '../../src/packages/entry_point'; import {DirectPackageJsonUpdater} from '../../src/writing/package_json_updater'; runInEachFileSystem(() => { @@ -177,97 +178,126 @@ runInEachFileSystem(() => { }); describe('hasBeenProcessed', () => { - let entryPointPath: AbsoluteFsPath; - let nodeModulesPath: AbsoluteFsPath; - - beforeEach(() => { - entryPointPath = _('/node_modules/test'); - nodeModulesPath = _('/node_modules'); - }); - it('should return true if the marker exists for the given format property', () => { expect(hasBeenProcessed( {name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': '0.0.0-PLACEHOLDER'}}, - 'fesm2015', entryPointPath)) + 'fesm2015')) .toBe(true); }); it('should return false if the marker does not exist for the given format property', () => { expect(hasBeenProcessed( {name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': '0.0.0-PLACEHOLDER'}}, - 'module', entryPointPath)) + 'module')) .toBe(false); }); it('should return false if no markers exist', - () => { expect(hasBeenProcessed({name: 'test'}, 'module', entryPointPath)).toBe(false); }); + () => { expect(hasBeenProcessed({name: 'test'}, 'module')).toBe(false); }); + }); - it('should throw an Error if the format has been compiled with a different version.', () => { - expect( - () => hasBeenProcessed( - {name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}}, 'fesm2015', - entryPointPath)) - .toThrowError( - 'The ngcc compiler has changed since the last ngcc build.\n' + - `Please remove "${nodeModulesPath}" and try again.`); + describe('needsCleaning()', () => { + it('should return true if any format has been compiled with a different version', () => { + expect(needsCleaning({ + name: 'test', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0', 'esm5': NGCC_VERSION} + })).toBe(true); }); - it('should throw an Error if any format has been compiled with a different version.', () => { - expect( - () => hasBeenProcessed( - {name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}}, 'module', - entryPointPath)) - .toThrowError( - 'The ngcc compiler has changed since the last ngcc build.\n' + - `Please remove "${nodeModulesPath}" and try again.`); - expect( - () => hasBeenProcessed( - { - name: 'test', - __processed_by_ivy_ngcc__: {'module': '0.0.0-PLACEHOLDER', 'fesm2015': '8.0.0'} - }, - 'module', entryPointPath)) - .toThrowError( - 'The ngcc compiler has changed since the last ngcc build.\n' + - `Please remove "${nodeModulesPath}" and try again.`); - expect( - () => hasBeenProcessed( - { - name: 'test', - __processed_by_ivy_ngcc__: {'module': '0.0.0-PLACEHOLDER', 'fesm2015': '8.0.0'} - }, - 'fesm2015', entryPointPath)) - .toThrowError( - 'The ngcc compiler has changed since the last ngcc build.\n' + - `Please remove "${nodeModulesPath}" and try again.`); + it('should return false if all formats have been compiled with the current version', () => { + expect(needsCleaning({name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': NGCC_VERSION}})) + .toBe(false); }); - it('should throw an Error, with the appropriate path to remove, if the format has been compiled with a different version', + it('should return false if no formats have been compiled', () => { + expect(needsCleaning({name: 'test', __processed_by_ivy_ngcc__: {}})).toBe(false); + expect(needsCleaning({name: 'test'})).toBe(false); + }); + }); + + describe('cleanPackageJson()', () => { + it('should not touch the object if there is no build marker', () => { + const packageJson: EntryPointPackageJson = {name: 'test-package'}; + const result = cleanPackageJson(packageJson); + expect(result).toBe(false); + expect(packageJson).toEqual({name: 'test-package'}); + }); + + it('should remove the processed marker', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'} + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({name: 'test-package'}); + }); + + it('should remove new entry-point format properties', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + fesm2015: 'index.js', + fesm2015_ivy_ngcc: '__ivy_ngcc__/index.js' + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({name: 'test-package', fesm2015: 'index.js'}); + }); + + it('should remove the prepublish script if there was a processed marker', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + scripts: {prepublishOnly: 'added by ngcc', test: 'do testing'}, + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({ + name: 'test-package', + scripts: {test: 'do testing'}, + }); + }); + + it('should revert and remove the backup for the prepublish script if there was a processed marker', () => { - expect( - () => hasBeenProcessed( - {name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}}, 'fesm2015', - _('/node_modules/test'))) - .toThrowError( - 'The ngcc compiler has changed since the last ngcc build.\n' + - `Please remove "${_('/node_modules')}" and try again.`); - - expect( - () => hasBeenProcessed( - {name: 'nested', __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}}, 'fesm2015', - _('/node_modules/test/node_modules/nested'))) - .toThrowError( - 'The ngcc compiler has changed since the last ngcc build.\n' + - `Please remove "${_('/node_modules/test/node_modules')}" and try again.`); - - expect( - () => hasBeenProcessed( - {name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}}, 'fesm2015', - _('/dist/test'))) - .toThrowError( - 'The ngcc compiler has changed since the last ngcc build.\n' + - `Please remove "${_('/dist/test')}" and try again.`); + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + }, + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({ + name: 'test-package', + scripts: {prepublishOnly: 'original', test: 'do testing'}, + }); }); + + it('should not touch the scripts if there was no processed marker', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + }, + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(false); + expect(packageJson).toEqual({ + name: 'test-package', + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + } + }); + }); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts index ad96ba569b..2071a8555e 100644 --- a/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts @@ -335,10 +335,10 @@ SOME DEFINITION TEXT ` { type: core.Directive, args: [{ selector: '[a]' }] },\n` + ` { type: OtherA }\n` + ` ];\n` + - ` SomeDirective.ctorParameters = () => [\n` + + ` SomeDirective.ctorParameters = function() { return [\n` + ` { type: core.NgZone },\n` + ` { type: core.Console }\n` + - ` ];\n` + + ` ]; };\n` + ` return SomeDirective;\n` + `}());\n` + `export {SomeDirective};`; @@ -352,10 +352,10 @@ SOME DEFINITION TEXT renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); expect(output.toString()) .toContain( - ` SomeDirective.ctorParameters = () => [\n` + + ` SomeDirective.ctorParameters = function() { return [\n` + ` { type: core.NgZone },\n` + ` { type: core.Console }\n` + - ` ];\n` + + ` ]; };\n` + `SOME STATEMENTS\n` + ` return SomeDirective;\n`); }); diff --git a/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts index d98f4d73cc..8a4c4e0bc5 100644 --- a/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts @@ -338,10 +338,10 @@ SOME DEFINITION TEXT ` { type: Directive, args: [{ selector: '[a]' }] },\n` + ` { type: OtherA }\n` + ` ];\n` + - ` SomeDirective.ctorParameters = () => [\n` + + ` SomeDirective.ctorParameters = function() { return [\n` + ` { type: NgZone },\n` + ` { type: Console }\n` + - ` ];\n` + + ` ]; };\n` + ` return SomeDirective;\n` + `}());\n` + `export {SomeDirective};`; @@ -355,10 +355,10 @@ SOME DEFINITION TEXT renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); expect(output.toString()) .toContain( - ` SomeDirective.ctorParameters = () => [\n` + + ` SomeDirective.ctorParameters = function() { return [\n` + ` { type: NgZone },\n` + ` { type: Console }\n` + - ` ];\n` + + ` ]; };\n` + `SOME STATEMENTS\n` + ` return SomeDirective;\n`); }); diff --git a/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts index 7d5cac130d..e56f777511 100644 --- a/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts @@ -505,10 +505,10 @@ SOME DEFINITION TEXT ` { type: core.Directive, args: [{ selector: '[a]' }] },\n` + ` { type: OtherA }\n` + ` ];\n` + - ` SomeDirective.ctorParameters = () => [\n` + + ` SomeDirective.ctorParameters = function() { return [\n` + ` { type: core.NgZone },\n` + ` { type: core.Console }\n` + - ` ];\n` + + ` ]; };\n` + ` return SomeDirective;\n` + ` }());\n` + ` exports.SomeDirective = SomeDirective;\n` + @@ -523,10 +523,10 @@ SOME DEFINITION TEXT renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); expect(output.toString()) .toContain( - ` SomeDirective.ctorParameters = () => [\n` + + ` SomeDirective.ctorParameters = function() { return [\n` + ` { type: core.NgZone },\n` + ` { type: core.Console }\n` + - ` ];\n` + + ` ]; };\n` + `SOME STATEMENTS\n` + ` return SomeDirective;\n`); }); diff --git a/packages/compiler-cli/ngcc/test/writing/cleaning/cleaning_strategies_spec.ts b/packages/compiler-cli/ngcc/test/writing/cleaning/cleaning_strategies_spec.ts new file mode 100644 index 0000000000..e8b2b5ec71 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/writing/cleaning/cleaning_strategies_spec.ts @@ -0,0 +1,236 @@ +/** + * @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, FileSystem, PathSegment, absoluteFrom, getFileSystem} from '../../../../src/ngtsc/file_system'; +import {runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing'; +import {EntryPointPackageJson} from '../../../src/packages/entry_point'; +import {BackupFileCleaner, NgccDirectoryCleaner, PackageJsonCleaner} from '../../../src/writing/cleaning/cleaning_strategies'; + +runInEachFileSystem(() => { + describe('cleaning strategies', () => { + let fs: FileSystem; + let _abs: typeof absoluteFrom; + + beforeEach(() => { + fs = getFileSystem(); + _abs = absoluteFrom; + }); + + describe('PackageJsonCleaner', () => { + + let packageJsonPath: AbsoluteFsPath; + beforeEach(() => { packageJsonPath = _abs('/node_modules/pkg/package.json'); }); + + describe('canClean()', () => { + it('should return true if the basename is package.json', () => { + const strategy = new PackageJsonCleaner(fs); + expect(strategy.canClean(packageJsonPath, fs.basename(packageJsonPath))).toBe(true); + }); + + it('should return false if the basename is not package.json', () => { + const filePath = _abs('/node_modules/pkg/index.js'); + const fileName = fs.basename(filePath); + const strategy = new PackageJsonCleaner(fs); + expect(strategy.canClean(filePath, fileName)).toBe(false); + }); + }); + + describe('clean()', () => { + it('should not touch the file if there is no build marker', () => { + const strategy = new PackageJsonCleaner(fs); + const packageJson: EntryPointPackageJson = {name: 'test-package'}; + fs.ensureDir(fs.dirname(packageJsonPath)); + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + strategy.clean(packageJsonPath, fs.basename(packageJsonPath)); + const newPackageJson: EntryPointPackageJson = JSON.parse(fs.readFile(packageJsonPath)); + expect(newPackageJson).toEqual({name: 'test-package'}); + }); + + it('should remove the processed marker', () => { + const strategy = new PackageJsonCleaner(fs); + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'} + }; + fs.ensureDir(fs.dirname(packageJsonPath)); + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + strategy.clean(packageJsonPath, fs.basename(packageJsonPath)); + const newPackageJson: EntryPointPackageJson = JSON.parse(fs.readFile(packageJsonPath)); + expect(newPackageJson).toEqual({name: 'test-package'}); + }); + + it('should remove the new entry points', () => { + const strategy = new PackageJsonCleaner(fs); + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'} + }; + fs.ensureDir(fs.dirname(packageJsonPath)); + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + strategy.clean(packageJsonPath, fs.basename(packageJsonPath)); + const newPackageJson: EntryPointPackageJson = JSON.parse(fs.readFile(packageJsonPath)); + expect(newPackageJson).toEqual({name: 'test-package'}); + }); + + it('should remove the prepublish script if there was a processed marker', () => { + const strategy = new PackageJsonCleaner(fs); + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + scripts: {prepublishOnly: 'added by ngcc', test: 'do testing'}, + }; + fs.ensureDir(fs.dirname(packageJsonPath)); + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + strategy.clean(packageJsonPath, fs.basename(packageJsonPath)); + const newPackageJson: EntryPointPackageJson = JSON.parse(fs.readFile(packageJsonPath)); + expect(newPackageJson).toEqual({ + name: 'test-package', + scripts: {test: 'do testing'}, + }); + }); + + it('should revert and remove the backup for the prepublish script if there was a processed marker', + () => { + const strategy = new PackageJsonCleaner(fs); + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + }, + }; + fs.ensureDir(fs.dirname(packageJsonPath)); + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + strategy.clean(packageJsonPath, fs.basename(packageJsonPath)); + const newPackageJson: EntryPointPackageJson = JSON.parse(fs.readFile(packageJsonPath)); + expect(newPackageJson).toEqual({ + name: 'test-package', + scripts: {prepublishOnly: 'original', test: 'do testing'}, + }); + }); + + it('should not touch the scripts if there was not processed marker', () => { + const strategy = new PackageJsonCleaner(fs); + const packageJson: EntryPointPackageJson = { + name: 'test-package', + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + }, + }; + fs.ensureDir(fs.dirname(packageJsonPath)); + fs.writeFile(packageJsonPath, JSON.stringify(packageJson)); + strategy.clean(packageJsonPath, fs.basename(packageJsonPath)); + const newPackageJson: EntryPointPackageJson = JSON.parse(fs.readFile(packageJsonPath)); + expect(newPackageJson).toEqual({ + name: 'test-package', + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + } + }); + }); + }); + }); + + describe('BackupFileCleaner', () => { + let filePath: AbsoluteFsPath; + let backupFilePath: AbsoluteFsPath; + beforeEach(() => { + filePath = _abs('/node_modules/pkg/index.js'); + backupFilePath = _abs('/node_modules/pkg/index.js.__ivy_ngcc_bak'); + }); + + describe('canClean()', () => { + + it('should return true if the file name ends in .__ivy_ngcc_bak and the processed file exists', + () => { + const strategy = new BackupFileCleaner(fs); + fs.ensureDir(fs.dirname(filePath)); + fs.writeFile(filePath, 'processed file'); + fs.writeFile(backupFilePath, 'original file'); + expect(strategy.canClean(backupFilePath, fs.basename(backupFilePath))).toBe(true); + }); + + it('should return false if the file does not end in .__ivy_ngcc_bak', () => { + const strategy = new BackupFileCleaner(fs); + fs.ensureDir(fs.dirname(filePath)); + fs.writeFile(filePath, 'processed file'); + fs.writeFile(backupFilePath, 'original file'); + expect(strategy.canClean(filePath, fs.basename(filePath))).toBe(false); + }); + + it('should return false if the file ends in .__ivy_ngcc_bak but the processed file does not exist', + () => { + const strategy = new BackupFileCleaner(fs); + fs.ensureDir(fs.dirname(filePath)); + fs.writeFile(backupFilePath, 'original file'); + expect(strategy.canClean(backupFilePath, fs.basename(backupFilePath))).toBe(false); + }); + }); + + describe('clean()', () => { + it('should move the backup file back to its original file path', () => { + const strategy = new BackupFileCleaner(fs); + fs.ensureDir(fs.dirname(filePath)); + fs.writeFile(filePath, 'processed file'); + fs.writeFile(backupFilePath, 'original file'); + strategy.clean(backupFilePath, fs.basename(backupFilePath)); + expect(fs.exists(backupFilePath)).toBe(false); + expect(fs.readFile(filePath)).toEqual('original file'); + }); + }); + }); + + describe('NgccDirectoryCleaner', () => { + let ivyDirectory: AbsoluteFsPath; + beforeEach(() => { ivyDirectory = _abs('/node_modules/pkg/__ivy_ngcc__'); }); + + describe('canClean()', () => { + it('should return true if the path is a directory and is called __ivy_ngcc__', () => { + const strategy = new NgccDirectoryCleaner(fs); + fs.ensureDir(ivyDirectory); + expect(strategy.canClean(ivyDirectory, fs.basename(ivyDirectory))).toBe(true); + }); + + it('should return false if the path is a directory and not called __ivy_ngcc__', () => { + const strategy = new NgccDirectoryCleaner(fs); + const filePath = _abs('/node_modules/pkg/other'); + fs.ensureDir(ivyDirectory); + expect(strategy.canClean(filePath, fs.basename(filePath))).toBe(false); + }); + + it('should return false if the path is called __ivy_ngcc__ but does not exist', () => { + const strategy = new NgccDirectoryCleaner(fs); + expect(strategy.canClean(ivyDirectory, fs.basename(ivyDirectory))).toBe(false); + }); + + it('should return false if the path is called __ivy_ngcc__ but is not a directory', () => { + const strategy = new NgccDirectoryCleaner(fs); + fs.ensureDir(fs.dirname(ivyDirectory)); + fs.writeFile(ivyDirectory, 'some contents'); + expect(strategy.canClean(ivyDirectory, fs.basename(ivyDirectory))).toBe(false); + }); + }); + + describe('clean()', () => { + it('should remove the __ivy_ngcc__ directory', () => { + const strategy = new NgccDirectoryCleaner(fs); + fs.ensureDir(ivyDirectory); + fs.ensureDir(fs.resolve(ivyDirectory, 'subfolder')); + fs.writeFile(fs.resolve(ivyDirectory, 'subfolder', 'file.txt'), 'file contents'); + strategy.clean(ivyDirectory, fs.basename(ivyDirectory)); + expect(fs.exists(ivyDirectory)).toBe(false); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/packages/compiler-cli/ngcc/test/writing/cleaning/package_cleaner_spec.ts b/packages/compiler-cli/ngcc/test/writing/cleaning/package_cleaner_spec.ts new file mode 100644 index 0000000000..762d024461 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/writing/cleaning/package_cleaner_spec.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 {AbsoluteFsPath, FileSystem, PathSegment, absoluteFrom, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system'; + +import {runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing'; +import {CleaningStrategy} from '../../../src/writing/cleaning/cleaning_strategies'; +import {PackageCleaner} from '../../../src/writing/cleaning/package_cleaner'; + +runInEachFileSystem(() => { + describe('PackageCleaner', () => { + let fs: FileSystem; + let _: typeof absoluteFrom; + beforeEach(() => { + fs = getFileSystem(); + _ = absoluteFrom; + }); + + describe('clean()', () => { + it('should call `canClean()` on each cleaner for each directory and file below the given one', + () => { + const log: string[] = []; + fs.ensureDir(_('/a/b/c')); + fs.writeFile(_('/a/b/d.txt'), 'd contents'); + fs.writeFile(_('/a/b/c/e.txt'), 'e contents'); + const a = new MockCleaningStrategy(log, 'a', false); + const b = new MockCleaningStrategy(log, 'b', false); + const c = new MockCleaningStrategy(log, 'c', false); + const cleaner = new PackageCleaner(fs, [a, b, c]); + cleaner.clean(_('/a/b')); + expect(log).toEqual([ + `a:canClean('${_('/a/b/c')}', 'c')`, + `b:canClean('${_('/a/b/c')}', 'c')`, + `c:canClean('${_('/a/b/c')}', 'c')`, + `a:canClean('${_('/a/b/c/e.txt')}', 'e.txt')`, + `b:canClean('${_('/a/b/c/e.txt')}', 'e.txt')`, + `c:canClean('${_('/a/b/c/e.txt')}', 'e.txt')`, + `a:canClean('${_('/a/b/d.txt')}', 'd.txt')`, + `b:canClean('${_('/a/b/d.txt')}', 'd.txt')`, + `c:canClean('${_('/a/b/d.txt')}', 'd.txt')`, + ]); + }); + + it('should call `clean()` for the first cleaner that returns true for `canClean()`', () => { + const log: string[] = []; + fs.ensureDir(_('/a/b/c')); + fs.writeFile(_('/a/b/d.txt'), 'd contents'); + fs.writeFile(_('/a/b/c/e.txt'), 'e contents'); + const a = new MockCleaningStrategy(log, 'a', false); + const b = new MockCleaningStrategy(log, 'b', true); + const c = new MockCleaningStrategy(log, 'c', false); + const cleaner = new PackageCleaner(fs, [a, b, c]); + cleaner.clean(_('/a/b')); + expect(log).toEqual([ + `a:canClean('${_('/a/b/c')}', 'c')`, + `b:canClean('${_('/a/b/c')}', 'c')`, + `b:clean('${_('/a/b/c')}', 'c')`, + `a:canClean('${_('/a/b/c/e.txt')}', 'e.txt')`, + `b:canClean('${_('/a/b/c/e.txt')}', 'e.txt')`, + `b:clean('${_('/a/b/c/e.txt')}', 'e.txt')`, + `a:canClean('${_('/a/b/d.txt')}', 'd.txt')`, + `b:canClean('${_('/a/b/d.txt')}', 'd.txt')`, + `b:clean('${_('/a/b/d.txt')}', 'd.txt')`, + ]); + }); + }); + }); +}); + + +class MockCleaningStrategy implements CleaningStrategy { + constructor(private log: string[], private label: string, private _canClean: boolean) {} + + canClean(path: AbsoluteFsPath, basename: PathSegment) { + this.log.push(`${this.label}:canClean('${path}', '${basename}')`); + return this._canClean; + } + + clean(path: AbsoluteFsPath, basename: PathSegment): void { + this.log.push(`${this.label}:clean('${path}', '${basename}')`); + } +} \ No newline at end of file diff --git a/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts b/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts index 1a3c5dd346..56f6a9a643 100644 --- a/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts @@ -8,6 +8,7 @@ import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; +import {JsonObject} from '../../src/packages/entry_point'; import {DirectPackageJsonUpdater, PackageJsonUpdater} from '../../src/writing/package_json_updater'; runInEachFileSystem(() => { @@ -151,5 +152,137 @@ runInEachFileSystem(() => { expect(() => update.writeChanges(_('/bar/package.json'))) .toThrowError('Trying to apply a `PackageJsonUpdate` that has already been applied.'); }); + + describe('(property positioning)', () => { + // Helpers + const createJsonFile = (jsonObj: JsonObject) => { + const jsonPath = _('/foo/package.json'); + loadTestFiles([{name: jsonPath, contents: JSON.stringify(jsonObj)}]); + return jsonPath; + }; + const expectJsonEquals = (jsonFilePath: AbsoluteFsPath, jsonObj: JsonObject) => + expect(fs.readFile(jsonFilePath).trim()).toBe(JSON.stringify(jsonObj, null, 2)); + + it('should not change property positioning by default', () => { + const jsonPath = createJsonFile({ + p2: '2', + p1: {p12: '1.2', p11: '1.1'}, + }); + + updater.createUpdate() + .addChange(['p1', 'p11'], '1.1-updated') + .addChange(['p1', 'p10'], '1.0-added') + .addChange(['p2'], '2-updated') + .addChange(['p0'], '0-added') + .writeChanges(jsonPath); + + expectJsonEquals(jsonPath, { + p2: '2-updated', + p1: {p12: '1.2', p11: '1.1-updated', p10: '1.0-added'}, + p0: '0-added', + }); + }); + + it('should not change property positioning with `positioning: unimportant`', () => { + const jsonPath = createJsonFile({ + p2: '2', + p1: {p12: '1.2', p11: '1.1'}, + }); + + updater.createUpdate() + .addChange(['p1', 'p11'], '1.1-updated', 'unimportant') + .addChange(['p1', 'p10'], '1.0-added', 'unimportant') + .addChange(['p2'], '2-updated', 'unimportant') + .addChange(['p0'], '0-added', 'unimportant') + .writeChanges(jsonPath); + + expectJsonEquals(jsonPath, { + p2: '2-updated', + p1: {p12: '1.2', p11: '1.1-updated', p10: '1.0-added'}, + p0: '0-added', + }); + }); + + it('should position added/updated properties alphabetically with `positioning: alphabetic`', + () => { + const jsonPath = createJsonFile({ + p2: '2', + p1: {p12: '1.2', p11: '1.1'}, + }); + + updater.createUpdate() + .addChange(['p1', 'p11'], '1.1-updated', 'alphabetic') + .addChange(['p1', 'p10'], '1.0-added', 'alphabetic') + .addChange(['p0'], '0-added', 'alphabetic') + .addChange(['p3'], '3-added', 'alphabetic') + .writeChanges(jsonPath); + + expectJsonEquals(jsonPath, { + p0: '0-added', + p2: '2', + p1: {p10: '1.0-added', p11: '1.1-updated', p12: '1.2'}, + p3: '3-added', + }); + }); + + it('should position added/updated properties correctly with `positioning: {before: ...}`', + () => { + const jsonPath = createJsonFile({ + p2: '2', + p1: {p12: '1.2', p11: '1.1'}, + }); + + updater.createUpdate() + .addChange(['p0'], '0-added', {before: 'p1'}) + .addChange(['p1', 'p10'], '1.0-added', {before: 'p11'}) + .addChange(['p1', 'p12'], '1.2-updated', {before: 'p11'}) + .writeChanges(jsonPath); + + expectJsonEquals(jsonPath, { + p2: '2', + p0: '0-added', + p1: {p10: '1.0-added', p12: '1.2-updated', p11: '1.1'}, + }); + + // Verify that trying to add before non-existent property, puts updated property at the + // end. + updater.createUpdate() + .addChange(['p3'], '3-added', {before: 'non-existent'}) + .addChange(['p1', 'p10'], '1.0-updated', {before: 'non-existent'}) + .writeChanges(jsonPath); + + expectJsonEquals(jsonPath, { + p2: '2', + p0: '0-added', + p1: {p12: '1.2-updated', p11: '1.1', p10: '1.0-updated'}, + p3: '3-added', + }); + }); + + it('should ignore positioning when updating an in-memory representation', () => { + const jsonObj = { + p20: '20', + p10: {p102: '10.2', p101: '10.1'}, + }; + const jsonPath = createJsonFile(jsonObj); + + updater.createUpdate() + .addChange(['p0'], '0-added', 'alphabetic') + .addChange(['p1'], '1-added', 'unimportant') + .addChange(['p2'], '2-added') + .addChange(['p20'], '20-updated', 'alphabetic') + .addChange(['p10', 'p103'], '10.3-added', {before: 'p102'}) + .addChange(['p10', 'p102'], '10.2-updated', {before: 'p103'}) + .writeChanges(jsonPath, jsonObj); + + expect(JSON.stringify(jsonObj)).toBe(JSON.stringify({ + p20: '20-updated', + p10: {p102: '10.2-updated', p101: '10.1', p103: '10.3-added'}, + p0: '0-added', + p1: '1-added', + p2: '2-added', + })); + }); + }); }); }); diff --git a/packages/compiler-cli/package.json b/packages/compiler-cli/package.json index bc70281ad6..c6624b3e5b 100644 --- a/packages/compiler-cli/package.json +++ b/packages/compiler-cli/package.json @@ -14,9 +14,10 @@ "reflect-metadata": "^0.1.2", "minimist": "^1.2.0", "canonical-path": "1.0.0", - "chokidar": "^2.1.1", + "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", "dependency-graph": "^0.7.2", + "fs-extra": "4.0.2", "magic-string": "^0.25.0", "semver": "^6.3.0", "source-map": "^0.6.1", @@ -25,10 +26,10 @@ "peerDependencies": { "@angular/compiler": "0.0.0-PLACEHOLDER", "tslib": "^1.10.0", - "typescript": ">=3.6 <3.7" + "typescript": ">=3.6 <3.8" }, "engines": { - "node": ">=8.0" + "node": ">=10.0" }, "repository": { "type": "git", diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 258e850489..246b1ab031 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -79,11 +79,11 @@ export class ComponentDecoratorHandler implements private reflector: ReflectionHost, private evaluator: PartialEvaluator, private metaRegistry: MetadataRegistry, private metaReader: MetadataReader, private scopeReader: ComponentScopeReader, private scopeRegistry: LocalModuleScopeRegistry, - private isCore: boolean, private resourceLoader: ResourceLoader, private rootDirs: string[], - private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean, - private enableI18nLegacyMessageIdFormat: boolean, private moduleResolver: ModuleResolver, - private cycleAnalyzer: CycleAnalyzer, private refEmitter: ReferenceEmitter, - private defaultImportRecorder: DefaultImportRecorder, + private isCore: boolean, private resourceLoader: ResourceLoader, + private rootDirs: ReadonlyArray, private defaultPreserveWhitespaces: boolean, + private i18nUseExternalIds: boolean, private enableI18nLegacyMessageIdFormat: boolean, + private moduleResolver: ModuleResolver, private cycleAnalyzer: CycleAnalyzer, + private refEmitter: ReferenceEmitter, private defaultImportRecorder: DefaultImportRecorder, private depTracker: DependencyTracker|null, private injectableRegistry: InjectableClassRegistry, private annotateForClosureCompiler: boolean) {} @@ -109,6 +109,7 @@ export class ComponentDecoratorHandler implements if (decorator !== undefined) { return { trigger: decorator.node, + decorator, metadata: decorator, }; } else { @@ -272,7 +273,7 @@ export class ComponentDecoratorHandler implements const resourceStr = this.resourceLoader.load(resourceUrl); styles.push(resourceStr); if (this.depTracker !== null) { - this.depTracker.addResourceDependency(node.getSourceFile(), resourceUrl); + this.depTracker.addResourceDependency(node.getSourceFile(), absoluteFrom(resourceUrl)); } } } @@ -674,7 +675,7 @@ export class ComponentDecoratorHandler implements resourceUrl: string): ParsedTemplateWithSource { const templateStr = this.resourceLoader.load(resourceUrl); if (this.depTracker !== null) { - this.depTracker.addResourceDependency(node.getSourceFile(), resourceUrl); + this.depTracker.addResourceDependency(node.getSourceFile(), absoluteFrom(resourceUrl)); } const template = this._parseTemplate( diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index c9d51d2d6e..9e2ed4fbdb 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -55,10 +55,6 @@ export class DirectiveDecoratorHandler implements detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult|undefined { - // Compiling declaration files is invalid. - if (node.getSourceFile().isDeclarationFile) { - return undefined; - } // If the class is undecorated, check if any of the fields have Angular decorators or lifecycle // hooks, and if they do, label the class as an abstract directive. if (!decorators) { @@ -74,10 +70,11 @@ export class DirectiveDecoratorHandler implements } return false; }); - return angularField ? {trigger: angularField.node, metadata: null} : undefined; + return angularField ? {trigger: angularField.node, decorator: null, metadata: null} : + undefined; } else { const decorator = findAngularDecorator(decorators, 'Directive', this.isCore); - return decorator ? {trigger: decorator.node, metadata: decorator} : undefined; + return decorator ? {trigger: decorator.node, decorator, metadata: decorator} : undefined; } } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index 978bf693e2..9785798910 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -54,6 +54,7 @@ export class InjectableDecoratorHandler implements if (decorator !== undefined) { return { trigger: decorator.node, + decorator: decorator, metadata: decorator, }; } else { 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 1abeb1d9e8..940ef2458c 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts @@ -71,6 +71,7 @@ export class NgModuleDecoratorHandler implements if (decorator !== undefined) { return { trigger: decorator.node, + decorator: decorator, metadata: decorator, }; } else { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts index c328cde05c..cc99211d16 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts @@ -44,6 +44,7 @@ export class PipeDecoratorHandler implements DecoratorHandler` it is assumed the user of the corresponding `Program` will call + * `loadNgStructureAsync()`. Returning `Promise` outside `loadNgStructureAsync()` will + * cause a diagnostics diagnostic error or an exception to be thrown. + */ + readResource(fileName: string): Promise|string; + + /** + * Get the absolute paths to the changed files that triggered the current compilation + * or `undefined` if this is not an incremental build. + */ + getModifiedResourceFiles?(): Set|undefined; +} + +/** + * A `ts.CompilerHost` interface which supports some number of optional methods in addition to the + * core interface. + */ +export interface ExtendedTsCompilerHost extends ts.CompilerHost, Partial, + Partial {} + +/** + * Options supported by the legacy View Engine compiler, which are still consumed by the Angular Ivy + * compiler for backwards compatibility. + * + * These are expected to be removed at some point in the future. + */ +export interface LegacyNgcOptions { + /** generate all possible generated files */ + allowEmptyCodegenFiles?: boolean; + + /** + * Whether to type check the entire template. + * + * This flag currently controls a couple aspects of template type-checking, including + * whether embedded views are checked. + * + * For maximum type-checking, set this to `true`, and set `strictTemplates` to `true`. + * + * It is an error for this flag to be `false`, while `strictTemplates` is set to `true`. + */ + fullTemplateTypeCheck?: boolean; + + /** + * Whether to generate a flat module index of the given name and the corresponding + * flat module metadata. This option is intended to be used when creating flat + * modules similar to how `@angular/core` and `@angular/common` are packaged. + * When this option is used the `package.json` for the library should refer to the + * generated flat module index instead of the library index file. When using this + * option only one .metadata.json file is produced that contains all the metadata + * necessary for symbols exported from the library index. + * In the generated .ngfactory.ts files flat module index is used to import symbols + * including both the public API from the library index as well as shrowded internal + * symbols. + * By default the .ts file supplied in the `files` field is assumed to be the + * library index. If more than one is specified, uses `libraryIndex` to select the + * file to use. If more than one .ts file is supplied and no `libraryIndex` is supplied + * an error is produced. + * A flat module index .d.ts and .js will be created with the given `flatModuleOutFile` + * name in the same location as the library index .d.ts file is emitted. + * For example, if a library uses `public_api.ts` file as the library index of the + * module the `tsconfig.json` `files` field would be `["public_api.ts"]`. The + * `flatModuleOutFile` options could then be set to, for example `"index.js"`, which + * produces `index.d.ts` and `index.metadata.json` files. The library's + * `package.json`'s `module` field would be `"index.js"` and the `typings` field would + * be `"index.d.ts"`. + */ + flatModuleOutFile?: string; + + /** + * Preferred module id to use for importing flat module. References generated by `ngc` + * will use this module name when importing symbols from the flat module. This is only + * meaningful when `flatModuleOutFile` is also supplied. It is otherwise ignored. + */ + flatModuleId?: string; + + /** + * Always report errors a parameter is supplied whose injection type cannot + * be determined. When this value option is not provided or is `false`, constructor + * parameters of classes marked with `@Injectable` whose type cannot be resolved will + * produce a warning. With this option `true`, they produce an error. When this option is + * not provided is treated as if it were `false`. + */ + strictInjectionParameters?: boolean; + + /** + * Whether to remove blank text nodes from compiled templates. It is `false` by default starting + * from Angular 6. + */ + preserveWhitespaces?: boolean; +} + +/** + * Options which were added to the Angular Ivy compiler to support backwards compatibility with + * existing View Engine applications. + * + * These are expected to be removed at some point in the future. + */ +export interface NgcCompatibilityOptions { + /** + * Controls whether ngtsc will emit `.ngfactory.js` shims for each compiled `.ts` file. + * + * These shims support legacy imports from `ngfactory` files, by exporting a factory shim + * for each component or NgModule in the original `.ts` file. + */ + generateNgFactoryShims?: boolean; + + /** + * Controls whether ngtsc will emit `.ngsummary.js` shims for each compiled `.ts` file. + * + * These shims support legacy imports from `ngsummary` files, by exporting an empty object + * for each NgModule in the original `.ts` file. The only purpose of summaries is to feed them to + * `TestBed`, which is a no-op in Ivy. + */ + generateNgSummaryShims?: boolean; + + /** + * Tells the compiler to generate definitions using the Render3 style code generation. + * This option defaults to `true`. + * + * Acceptable values are as follows: + * + * `false` - run ngc normally + * `true` - run the ngtsc compiler instead of the normal ngc compiler + * `ngtsc` - alias for `true` + */ + enableIvy?: boolean|'ngtsc'; +} + +/** + * Options related to template type-checking and its strictness. + */ +export interface StrictTemplateOptions { + /** + * If `true`, implies all template strictness flags below (unless individually disabled). + * + * Has no effect unless `fullTemplateTypeCheck` is also enabled. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. + */ + strictTemplates?: boolean; + + + /** + * Whether to check the type of a binding to a directive/component input against the type of the + * field on the directive/component. + * + * For example, if this is `false` then the expression `[input]="expr"` will have `expr` type- + * checked, but not the assignment of the resulting type to the `input` property of whichever + * directive or component is receiving the binding. If set to `true`, both sides of the assignment + * are checked. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. + */ + strictInputTypes?: boolean; + + /** + * Whether to use strict null types for input bindings for directives. + * + * If this is `true`, applications that are compiled with TypeScript's `strictNullChecks` enabled + * will produce type errors for bindings which can evaluate to `undefined` or `null` where the + * inputs's type does not include `undefined` or `null` in its type. If set to `false`, all + * binding expressions are wrapped in a non-null assertion operator to effectively disable strict + * null checks. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. Note that if `strictInputTypes` is + * not set, or set to `false`, this flag has no effect. + */ + strictNullInputTypes?: boolean; + + /** + * Whether to check text attributes that happen to be consumed by a directive or component. + * + * For example, in a template containing `` the `disabled` attribute ends + * up being consumed as an input with type `boolean` by the `matInput` directive. At runtime, the + * input will be set to the attribute's string value, which is an empty string for attributes + * without a value, so with this flag set to `true`, an error would be reported. If set to + * `false`, text attributes will never report an error. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. Note that if `strictInputTypes` is + * not set, or set to `false`, this flag has no effect. + */ + strictAttributeTypes?: boolean; + + /** + * Whether to use a strict type for null-safe navigation operations. + * + * If this is `false`, then the return type of `a?.b` or `a?()` will be `any`. If set to `true`, + * then the return type of `a?.b` for example will be the same as the type of the ternary + * expression `a != null ? a.b : a`. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. + */ + strictSafeNavigationTypes?: boolean; + + /** + * Whether to infer the type of local references. + * + * If this is `true`, the type of a `#ref` variable on a DOM node in the template will be + * determined by the type of `document.createElement` for the given DOM node. If set to `false`, + * the type of `ref` for DOM nodes will be `any`. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. + */ + strictDomLocalRefTypes?: boolean; + + /** + * Whether to infer the type of the `$event` variable in event bindings for directive outputs or + * animation events. + * + * If this is `true`, the type of `$event` will be inferred based on the generic type of + * `EventEmitter`/`Subject` of the output. If set to `false`, the `$event` variable will be of + * type `any`. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. + */ + strictOutputEventTypes?: boolean; + + /** + * Whether to infer the type of the `$event` variable in event bindings to DOM events. + * + * If this is `true`, the type of `$event` will be inferred based on TypeScript's + * `HTMLElementEventMap`, with a fallback to the native `Event` type. If set to `false`, the + * `$event` variable will be of type `any`. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. + */ + strictDomEventTypes?: boolean; + + /** + * Whether to include the generic type of components when type-checking the template. + * + * If no component has generic type parameters, this setting has no effect. + * + * If a component has generic type parameters and this setting is `true`, those generic parameters + * will be included in the context type for the template. If `false`, any generic parameters will + * be set to `any` in the template context type. + * + * Defaults to `false`, even if "fullTemplateTypeCheck" is set. + */ + strictContextGenerics?: boolean; +} + +/** + * Options which control behavior useful for "monorepo" build cases using Bazel (such as the + * internal Google monorepo, g3). + */ +export interface BazelAndG3Options { + /** + * Enables the generation of alias re-exports of directives/pipes that are visible from an + * NgModule from that NgModule's file. + * + * This option should be disabled for application builds or for Angular Package Format libraries + * (where NgModules along with their directives/pipes are exported via a single entrypoint). + * + * For other library compilations which are intended to be path-mapped into an application build + * (or another library), enabling this option enables the resulting deep imports to work + * correctly. + * + * A consumer of such a path-mapped library will write an import like: + * + * ```typescript + * import {LibModule} from 'lib/deep/path/to/module'; + * ``` + * + * The compiler will attempt to generate imports of directives/pipes from that same module + * specifier (the compiler does not rewrite the user's given import path, unlike View Engine). + * + * ```typescript + * import {LibDir, LibCmp, LibPipe} from 'lib/deep/path/to/module'; + * ``` + * + * It would be burdensome for users to have to re-export all directives/pipes alongside each + * NgModule to support this import model. Enabling this option tells the compiler to generate + * private re-exports alongside the NgModule of all the directives/pipes it makes available, to + * support these future imports. + */ + generateDeepReexports?: boolean; + + /** + * Insert JSDoc type annotations needed by Closure Compiler + */ + annotateForClosureCompiler?: boolean; +} + +/** + * Options related to i18n compilation support. + */ +export interface I18nOptions { + /** + * Locale of the imported translations + */ + i18nInLocale?: string; + + /** + * Render `$localize` messages with legacy format ids. + * + * This is only active if we are building with `enableIvy: true`. + * The default value for now is `true`. + * + * Use this option when use are using the `$localize` based localization messages but + * have not migrated the translation files to use the new `$localize` message id format. + */ + enableI18nLegacyMessageIdFormat?: boolean; + + /** + * Whether translation variable name should contain external message id + * (used by Closure Compiler's output of `goog.getMsg` for transition period) + */ + i18nUseExternalIds?: boolean; +} + +/** + * Non-public options which are useful during testing of the compiler. + */ +export interface TestOnlyOptions { + /** + * 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. + * + * @internal + */ + _useHostForImportGeneration?: boolean; + + /** + * Turn on template type-checking in the Ivy compiler. + * + * This is an internal flag being used to roll out template type-checking in ngtsc. Turning it on + * by default before it's ready might break other users attempting to test the new compiler's + * behavior. + * + * @internal + */ + ivyTemplateTypeCheck?: boolean; +} + +/** + * A merged interface of all of the various Angular compiler options, as well as the standard + * `ts.CompilerOptions`. + * + * Also includes a few miscellaneous options. + */ +export interface NgCompilerOptions extends ts.CompilerOptions, LegacyNgcOptions, BazelAndG3Options, + NgcCompatibilityOptions, StrictTemplateOptions, TestOnlyOptions, I18nOptions { + /** + * Whether the compiler should avoid generating code for classes that haven't been exported. + * This is only active when building with `enableIvy: true`. Defaults to `true`. + */ + compileNonExportedClasses?: boolean; + + /** + * Whether to remove blank text nodes from compiled templates. It is `false` by default starting + * from Angular 6. + */ + preserveWhitespaces?: boolean; + + /** + * Disable TypeScript Version Check. + */ + disableTypeScriptVersionCheck?: boolean; + + /** An option to enable ngtsc's internal performance tracing. + * + * This should be a path to a JSON file where trace information will be written. An optional 'ts:' + * prefix will cause the trace to be written via the TS host instead of directly to the filesystem + * (not all hosts support this mode of operation). + * + * This is currently not exposed to users as the trace format is still unstable. + */ + tracePerformance?: string; +} + +export interface LazyRoute { + route: string; + module: {name: string, filePath: string}; + referencedModule: {name: string, filePath: string}; +} diff --git a/packages/compiler-cli/src/ngtsc/core/index.ts b/packages/compiler-cli/src/ngtsc/core/index.ts new file mode 100644 index 0000000000..7951f82bfb --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/core/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 {NgCompiler} from './src/compiler'; +export {NgCompilerHost} from './src/host'; diff --git a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts new file mode 100644 index 0000000000..3d09f22f31 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts @@ -0,0 +1,813 @@ +/** + * @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 '@angular/compiler'; +import * as ts from 'typescript'; + +import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from '../../annotations'; +import {CycleAnalyzer, ImportGraph} from '../../cycles'; +import {ErrorCode, ngErrorCode} from '../../diagnostics'; +import {ReferenceGraph, checkForPrivateExports} from '../../entry_point'; +import {LogicalFileSystem, getSourceFileOrError} from '../../file_system'; +import {AbsoluteModuleStrategy, AliasStrategy, AliasingHost, DefaultImportTracker, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, PrivateExportAliasingHost, R3SymbolsImportRewriter, Reference, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesAliasingHost, UnifiedModulesStrategy} from '../../imports'; +import {IncrementalDriver} from '../../incremental'; +import {IndexedComponent, IndexingContext, generateAnalysis} from '../../indexer'; +import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, MetadataReader} from '../../metadata'; +import {ModuleWithProvidersScanner} from '../../modulewithproviders'; +import {PartialEvaluator} from '../../partial_evaluator'; +import {NOOP_PERF_RECORDER, PerfRecorder} from '../../perf'; +import {TypeScriptReflectionHost} from '../../reflection'; +import {HostResourceLoader} from '../../resource'; +import {NgModuleRouteAnalyzer, entryPointKeyFor} from '../../routing'; +import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope'; +import {generatedFactoryTransform} from '../../shims'; +import {ivySwitchTransform} from '../../switch'; +import {DecoratorHandler, DtsTransformRegistry, TraitCompiler, aliasTransformFactory, declarationTransformFactory, ivyTransformFactory} from '../../transform'; +import {TypeCheckContext, TypeCheckingConfig, isTemplateDiagnostic} from '../../typecheck'; +import {getSourceFileOrNull, isDtsPath, resolveModuleName} from '../../util/src/typescript'; +import {LazyRoute, NgCompilerOptions} from '../api'; + +import {NgCompilerHost} from './host'; + + + +/** + * State information about a compilation which is only generated once some data is requested from + * the `NgCompiler` (for example, by calling `getDiagnostics`). + */ +interface LazyCompilationState { + isCore: boolean; + traitCompiler: TraitCompiler; + reflector: TypeScriptReflectionHost; + metaReader: MetadataReader; + scopeRegistry: LocalModuleScopeRegistry; + exportReferenceGraph: ReferenceGraph|null; + routeAnalyzer: NgModuleRouteAnalyzer; + dtsTransforms: DtsTransformRegistry; + mwpScanner: ModuleWithProvidersScanner; + defaultImportTracker: DefaultImportTracker; + aliasingHost: AliasingHost|null; + refEmitter: ReferenceEmitter; +} + +/** + * The heart of the Angular Ivy compiler. + * + * The `NgCompiler` provides an API for performing Angular compilation within a custom TypeScript + * compiler. Each instance of `NgCompiler` supports a single compilation, which might be + * incremental. + * + * `NgCompiler` is lazy, and does not perform any of the work of the compilation until one of its + * output methods (e.g. `getDiagnostics`) is called. + * + * See the README.md for more information. + */ +export class NgCompiler { + /** + * Lazily evaluated state of the compilation. + * + * This is created on demand by calling `ensureAnalyzed`. + */ + private compilation: LazyCompilationState|null = null; + + /** + * Any diagnostics related to the construction of the compilation. + * + * These are diagnostics which arose during setup of the host and/or program. + */ + private constructionDiagnostics: ts.Diagnostic[] = []; + + /** + * Semantic diagnostics related to the program itself. + * + * This is set by (and memoizes) `getDiagnostics`. + */ + private diagnostics: ts.Diagnostic[]|null = null; + + private closureCompilerEnabled: boolean; + private typeCheckFile: ts.SourceFile; + private nextProgram: ts.Program; + private entryPoint: ts.SourceFile|null; + private moduleResolver: ModuleResolver; + private resourceManager: HostResourceLoader; + private cycleAnalyzer: CycleAnalyzer; + readonly incrementalDriver: IncrementalDriver; + + constructor( + private host: NgCompilerHost, private options: NgCompilerOptions, + private tsProgram: ts.Program, oldProgram: ts.Program|null = null, + private perfRecorder: PerfRecorder = NOOP_PERF_RECORDER) { + this.constructionDiagnostics.push(...this.host.diagnostics); + const incompatibleTypeCheckOptionsDiagnostic = verifyCompatibleTypeCheckOptions(this.options); + if (incompatibleTypeCheckOptionsDiagnostic !== null) { + this.constructionDiagnostics.push(incompatibleTypeCheckOptionsDiagnostic); + } + + this.nextProgram = tsProgram; + this.closureCompilerEnabled = !!this.options.annotateForClosureCompiler; + + this.entryPoint = + host.entryPoint !== null ? getSourceFileOrNull(tsProgram, host.entryPoint) : null; + + this.typeCheckFile = getSourceFileOrError(tsProgram, host.typeCheckFile); + const moduleResolutionCache = ts.createModuleResolutionCache( + this.host.getCurrentDirectory(), fileName => this.host.getCanonicalFileName(fileName)); + this.moduleResolver = + new ModuleResolver(tsProgram, this.options, this.host, moduleResolutionCache); + this.resourceManager = new HostResourceLoader(host, this.options); + this.cycleAnalyzer = new CycleAnalyzer(new ImportGraph(this.moduleResolver)); + + let modifiedResourceFiles: Set|null = null; + if (this.host.getModifiedResourceFiles !== undefined) { + modifiedResourceFiles = this.host.getModifiedResourceFiles() || null; + } + + if (oldProgram === null) { + this.incrementalDriver = IncrementalDriver.fresh(tsProgram); + } else { + const oldDriver = getIncrementalDriver(oldProgram); + if (oldDriver !== null) { + this.incrementalDriver = + IncrementalDriver.reconcile(oldProgram, oldDriver, tsProgram, modifiedResourceFiles); + } else { + // A previous ts.Program was used to create the current one, but it wasn't from an + // `NgCompiler`. That doesn't hurt anything, but the Angular analysis will have to start + // from a fresh state. + this.incrementalDriver = IncrementalDriver.fresh(tsProgram); + } + } + setIncrementalDriver(tsProgram, this.incrementalDriver); + } + + /** + * Get all Angular-related diagnostics for this compilation. + * + * If a `ts.SourceFile` is passed, only diagnostics related to that file are returned. + */ + getDiagnostics(file?: ts.SourceFile): ts.Diagnostic[] { + if (this.diagnostics === null) { + const compilation = this.ensureAnalyzed(); + this.diagnostics = + [...compilation.traitCompiler.diagnostics, ...this.getTemplateDiagnostics()]; + if (this.entryPoint !== null && compilation.exportReferenceGraph !== null) { + this.diagnostics.push(...checkForPrivateExports( + this.entryPoint, this.tsProgram.getTypeChecker(), compilation.exportReferenceGraph)); + } + } + + if (file === undefined) { + return this.diagnostics; + } else { + return this.diagnostics.filter(diag => { + if (diag.file === file) { + return true; + } else if (isTemplateDiagnostic(diag) && diag.componentFile === file) { + // Template diagnostics are reported when diagnostics for the component file are + // requested (since no consumer of `getDiagnostics` would ever ask for diagnostics from + // the fake ts.SourceFile for templates). + return true; + } else { + return false; + } + }); + } + } + + /** + * Get all setup-related diagnostics for this compilation. + */ + getOptionDiagnostics(): ts.Diagnostic[] { return this.constructionDiagnostics; } + + /** + * Get the `ts.Program` to use as a starting point when spawning a subsequent incremental + * compilation. + * + * The `NgCompiler` spawns an internal incremental TypeScript compilation (inheriting the + * consumer's `ts.Program` into a new one for the purposes of template type-checking). After this + * operation, the consumer's `ts.Program` is no longer usable for starting a new incremental + * compilation. `getNextProgram` retrieves the `ts.Program` which can be used instead. + */ + getNextProgram(): ts.Program { return this.nextProgram; } + + /** + * Perform Angular's analysis step (as a precursor to `getDiagnostics` or `prepareEmit`) + * asynchronously. + * + * Normally, this operation happens lazily whenever `getDiagnostics` or `prepareEmit` are called. + * However, certain consumers may wish to allow for an asynchronous phase of analysis, where + * resources such as `styleUrls` are resolved asynchonously. In these cases `analyzeAsync` must be + * called first, and its `Promise` awaited prior to calling any other APIs of `NgCompiler`. + */ + async analyzeAsync(): Promise { + if (this.compilation !== null) { + return; + } + this.compilation = this.makeCompilation(); + + const analyzeSpan = this.perfRecorder.start('analyze'); + const promises: Promise[] = []; + for (const sf of this.tsProgram.getSourceFiles()) { + if (sf.isDeclarationFile) { + continue; + } + + const analyzeFileSpan = this.perfRecorder.start('analyzeFile', sf); + let analysisPromise = this.compilation.traitCompiler.analyzeAsync(sf); + this.scanForMwp(sf); + if (analysisPromise === undefined) { + this.perfRecorder.stop(analyzeFileSpan); + } else if (this.perfRecorder.enabled) { + analysisPromise = analysisPromise.then(() => this.perfRecorder.stop(analyzeFileSpan)); + } + if (analysisPromise !== undefined) { + promises.push(analysisPromise); + } + } + + await Promise.all(promises); + + this.perfRecorder.stop(analyzeSpan); + + this.resolveCompilation(this.compilation.traitCompiler); + } + + /** + * List lazy routes detected during analysis. + * + * This can be called for one specific route, or to retrieve all top-level routes. + */ + listLazyRoutes(entryRoute?: string): 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( + `Failed 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 resolvedModule = + resolveModuleName(entryPath, containingFile, this.options, this.host, null); + + if (resolvedModule) { + entryRoute = entryPointKeyFor(resolvedModule.resolvedFileName, moduleName); + } + } + + const compilation = this.ensureAnalyzed(); + return compilation.routeAnalyzer.listLazyRoutes(entryRoute); + } + + /** + * Fetch transformers and other information which is necessary for a consumer to `emit` the + * program with Angular-added definitions. + */ + prepareEmit(): { + transformers: ts.CustomTransformers, + ignoreFiles: Set, + } { + const compilation = this.ensureAnalyzed(); + + const coreImportsFrom = compilation.isCore ? getR3SymbolsFile(this.tsProgram) : null; + let importRewriter: ImportRewriter; + if (coreImportsFrom !== null) { + importRewriter = new R3SymbolsImportRewriter(coreImportsFrom.fileName); + } else { + importRewriter = new NoopImportRewriter(); + } + + const before = [ + ivyTransformFactory( + compilation.traitCompiler, compilation.reflector, importRewriter, + compilation.defaultImportTracker, compilation.isCore, this.closureCompilerEnabled), + aliasTransformFactory(compilation.traitCompiler.exportStatements), + compilation.defaultImportTracker.importPreservingTransformer(), + ]; + + const afterDeclarations: ts.TransformerFactory[] = []; + if (compilation.dtsTransforms !== null) { + afterDeclarations.push( + declarationTransformFactory(compilation.dtsTransforms, importRewriter)); + } + + // Only add aliasing re-exports to the .d.ts output if the `AliasingHost` requests it. + if (compilation.aliasingHost !== null && compilation.aliasingHost.aliasExportsInDts) { + afterDeclarations.push(aliasTransformFactory(compilation.traitCompiler.exportStatements)); + } + + if (this.host.factoryTracker !== null) { + before.push(generatedFactoryTransform(this.host.factoryTracker.sourceInfo, importRewriter)); + } + before.push(ivySwitchTransform); + + const ignoreFiles = new Set([this.typeCheckFile]); + + return {transformers: {before, afterDeclarations} as ts.CustomTransformers, ignoreFiles}; + } + + /** + * Run the indexing process and return a `Map` of all indexed components. + * + * See the `indexing` package for more details. + */ + getIndexedComponents(): Map { + const compilation = this.ensureAnalyzed(); + const context = new IndexingContext(); + compilation.traitCompiler.index(context); + return generateAnalysis(context); + } + + private ensureAnalyzed(this: NgCompiler): LazyCompilationState { + if (this.compilation === null) { + this.analyzeSync(); + } + return this.compilation !; + } + + private analyzeSync(): void { + const analyzeSpan = this.perfRecorder.start('analyze'); + this.compilation = this.makeCompilation(); + for (const sf of this.tsProgram.getSourceFiles()) { + if (sf.isDeclarationFile) { + continue; + } + const analyzeFileSpan = this.perfRecorder.start('analyzeFile', sf); + this.compilation.traitCompiler.analyzeSync(sf); + this.scanForMwp(sf); + this.perfRecorder.stop(analyzeFileSpan); + } + this.perfRecorder.stop(analyzeSpan); + + this.resolveCompilation(this.compilation.traitCompiler); + } + + private resolveCompilation(traitCompiler: TraitCompiler): void { + traitCompiler.resolve(); + + this.recordNgModuleScopeDependencies(); + + // At this point, analysis is complete and the compiler can now calculate which files need to + // be emitted, so do that. + this.incrementalDriver.recordSuccessfulAnalysis(traitCompiler); + } + + private getTemplateDiagnostics(): ReadonlyArray { + const host = this.host; + + // Determine the strictness level of type checking based on compiler options. As + // `strictTemplates` is a superset of `fullTemplateTypeCheck`, the former implies the latter. + // Also see `verifyCompatibleTypeCheckOptions` where it is verified that `fullTemplateTypeCheck` + // is not disabled when `strictTemplates` is enabled. + const strictTemplates = !!this.options.strictTemplates; + const fullTemplateTypeCheck = strictTemplates || !!this.options.fullTemplateTypeCheck; + + // Skip template type-checking if it's disabled. + if (this.options.ivyTemplateTypeCheck === false && !fullTemplateTypeCheck) { + return []; + } + + const compilation = this.ensureAnalyzed(); + // Run template type-checking. + + // First select a type-checking configuration, based on whether full template type-checking is + // requested. + let typeCheckingConfig: TypeCheckingConfig; + if (fullTemplateTypeCheck) { + typeCheckingConfig = { + applyTemplateContextGuards: strictTemplates, + checkQueries: false, + checkTemplateBodies: true, + checkTypeOfInputBindings: strictTemplates, + strictNullInputBindings: strictTemplates, + checkTypeOfAttributes: strictTemplates, + // Even in full template type-checking mode, DOM binding checks are not quite ready yet. + checkTypeOfDomBindings: false, + checkTypeOfOutputEvents: strictTemplates, + checkTypeOfAnimationEvents: strictTemplates, + // Checking of DOM events currently has an adverse effect on developer experience, + // e.g. for `` enabling this check results in: + // - error TS2531: Object is possibly 'null'. + // - error TS2339: Property 'value' does not exist on type 'EventTarget'. + checkTypeOfDomEvents: strictTemplates, + checkTypeOfDomReferences: strictTemplates, + // Non-DOM references have the correct type in View Engine so there is no strictness flag. + checkTypeOfNonDomReferences: true, + // Pipes are checked in View Engine so there is no strictness flag. + checkTypeOfPipes: true, + strictSafeNavigationTypes: strictTemplates, + useContextGenericType: strictTemplates, + }; + } else { + typeCheckingConfig = { + applyTemplateContextGuards: false, + checkQueries: false, + checkTemplateBodies: false, + checkTypeOfInputBindings: false, + strictNullInputBindings: false, + checkTypeOfAttributes: false, + checkTypeOfDomBindings: false, + checkTypeOfOutputEvents: false, + checkTypeOfAnimationEvents: false, + checkTypeOfDomEvents: false, + checkTypeOfDomReferences: false, + checkTypeOfNonDomReferences: false, + checkTypeOfPipes: false, + strictSafeNavigationTypes: false, + useContextGenericType: false, + }; + } + + // Apply explicitly configured strictness flags on top of the default configuration + // based on "fullTemplateTypeCheck". + if (this.options.strictInputTypes !== undefined) { + typeCheckingConfig.checkTypeOfInputBindings = this.options.strictInputTypes; + typeCheckingConfig.applyTemplateContextGuards = this.options.strictInputTypes; + } + if (this.options.strictNullInputTypes !== undefined) { + typeCheckingConfig.strictNullInputBindings = this.options.strictNullInputTypes; + } + if (this.options.strictOutputEventTypes !== undefined) { + typeCheckingConfig.checkTypeOfOutputEvents = this.options.strictOutputEventTypes; + typeCheckingConfig.checkTypeOfAnimationEvents = this.options.strictOutputEventTypes; + } + if (this.options.strictDomEventTypes !== undefined) { + typeCheckingConfig.checkTypeOfDomEvents = this.options.strictDomEventTypes; + } + if (this.options.strictSafeNavigationTypes !== undefined) { + typeCheckingConfig.strictSafeNavigationTypes = this.options.strictSafeNavigationTypes; + } + if (this.options.strictDomLocalRefTypes !== undefined) { + typeCheckingConfig.checkTypeOfDomReferences = this.options.strictDomLocalRefTypes; + } + if (this.options.strictAttributeTypes !== undefined) { + typeCheckingConfig.checkTypeOfAttributes = this.options.strictAttributeTypes; + } + if (this.options.strictContextGenerics !== undefined) { + typeCheckingConfig.useContextGenericType = this.options.strictContextGenerics; + } + + // Execute the typeCheck phase of each decorator in the program. + const prepSpan = this.perfRecorder.start('typeCheckPrep'); + const ctx = new TypeCheckContext( + typeCheckingConfig, compilation.refEmitter !, compilation.reflector, host.typeCheckFile); + compilation.traitCompiler.typeCheck(ctx); + this.perfRecorder.stop(prepSpan); + + // Get the diagnostics. + const typeCheckSpan = this.perfRecorder.start('typeCheckDiagnostics'); + const {diagnostics, program} = + ctx.calculateTemplateDiagnostics(this.tsProgram, this.host, this.options); + this.perfRecorder.stop(typeCheckSpan); + setIncrementalDriver(program, this.incrementalDriver); + this.nextProgram = program; + + return diagnostics; + } + + /** + * Reifies the inter-dependencies of NgModules and the components within their compilation scopes + * into the `IncrementalDriver`'s dependency graph. + */ + private recordNgModuleScopeDependencies() { + const recordSpan = this.perfRecorder.start('recordDependencies'); + const depGraph = this.incrementalDriver.depGraph; + + for (const scope of this.compilation !.scopeRegistry !.getCompilationScopes()) { + const file = scope.declaration.getSourceFile(); + const ngModuleFile = scope.ngModule.getSourceFile(); + + // A change to any dependency of the declaration causes the declaration to be invalidated, + // which requires the NgModule to be invalidated as well. + depGraph.addTransitiveDependency(ngModuleFile, file); + + // A change to the NgModule file should cause the declaration itself to be invalidated. + depGraph.addDependency(file, ngModuleFile); + + const meta = + this.compilation !.metaReader.getDirectiveMetadata(new Reference(scope.declaration)); + if (meta !== null && meta.isComponent) { + // If a component's template changes, it might have affected the import graph, and thus the + // remote scoping feature which is activated in the event of potential import cycles. Thus, + // the module depends not only on the transitive dependencies of the component, but on its + // resources as well. + depGraph.addTransitiveResources(ngModuleFile, file); + + // A change to any directive/pipe in the compilation scope should cause the component to be + // invalidated. + for (const directive of scope.directives) { + // When a directive in scope is updated, the component needs to be recompiled as e.g. a + // selector may have changed. + depGraph.addTransitiveDependency(file, directive.ref.node.getSourceFile()); + } + for (const pipe of scope.pipes) { + // When a pipe in scope is updated, the component needs to be recompiled as e.g. the + // pipe's name may have changed. + depGraph.addTransitiveDependency(file, pipe.ref.node.getSourceFile()); + } + } + } + this.perfRecorder.stop(recordSpan); + } + + private scanForMwp(sf: ts.SourceFile): void { + this.compilation !.mwpScanner.scan(sf, { + addTypeReplacement: (node: ts.Declaration, type: Type): void => { + // Only obtain the return type transform for the source file once there's a type to replace, + // so that no transform is allocated when there's nothing to do. + this.compilation !.dtsTransforms !.getReturnTypeTransform(sf).addTypeReplacement( + node, type); + } + }); + } + + private makeCompilation(): LazyCompilationState { + const checker = this.tsProgram.getTypeChecker(); + + const reflector = new TypeScriptReflectionHost(checker); + + // Construct the ReferenceEmitter. + let refEmitter: ReferenceEmitter; + let aliasingHost: AliasingHost|null = null; + if (this.host.unifiedModulesHost === null || !this.options._useHostForImportGeneration) { + let localImportStrategy: ReferenceEmitStrategy; + + // The strategy used for local, in-project imports depends on whether TS has been configured + // with rootDirs. If so, then multiple directories may be mapped in the same "module + // namespace" and the logic of `LogicalProjectStrategy` is required to generate correct + // imports which may cross these multiple directories. Otherwise, plain relative imports are + // sufficient. + if (this.options.rootDir !== undefined || + (this.options.rootDirs !== undefined && this.options.rootDirs.length > 0)) { + // rootDirs logic is in effect - use the `LogicalProjectStrategy` for in-project relative + // imports. + localImportStrategy = + new LogicalProjectStrategy(reflector, new LogicalFileSystem([...this.host.rootDirs])); + } else { + // Plain relative imports are all that's needed. + localImportStrategy = new RelativePathStrategy(reflector); + } + + // The CompilerHost doesn't have fileNameToModuleName, so build an NPM-centric reference + // resolution strategy. + 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.moduleResolver, reflector), + // Finally, check if the reference is being written into a file within the project's .ts + // sources, and use a relative import if so. If this fails, ReferenceEmitter will throw + // an error. + localImportStrategy, + ]); + + // If an entrypoint is present, then all user imports should be directed through the + // entrypoint and private exports are not needed. The compiler will validate that all publicly + // visible directives/pipes are importable via this entrypoint. + if (this.entryPoint === null && this.options.generateDeepReexports === true) { + // No entrypoint is present and deep re-exports were requested, so configure the aliasing + // system to generate them. + aliasingHost = new PrivateExportAliasingHost(reflector); + } + } else { + // The CompilerHost supports fileNameToModuleName, so use that to emit imports. + refEmitter = new ReferenceEmitter([ + // First, try to use local identifiers if available. + new LocalIdentifierStrategy(), + // Then use aliased references (this is a workaround to StrictDeps checks). + new AliasStrategy(), + // Then use fileNameToModuleName to emit imports. + new UnifiedModulesStrategy(reflector, this.host.unifiedModulesHost), + ]); + aliasingHost = new UnifiedModulesAliasingHost(this.host.unifiedModulesHost); + } + + const evaluator = new PartialEvaluator(reflector, checker, this.incrementalDriver.depGraph); + const dtsReader = new DtsMetadataReader(checker, reflector); + const localMetaRegistry = new LocalMetadataRegistry(); + const localMetaReader: MetadataReader = localMetaRegistry; + const depScopeReader = new MetadataDtsModuleScopeResolver(dtsReader, aliasingHost); + const scopeRegistry = + new LocalModuleScopeRegistry(localMetaReader, depScopeReader, refEmitter, aliasingHost); + const scopeReader: ComponentScopeReader = scopeRegistry; + const metaRegistry = new CompoundMetadataRegistry([localMetaRegistry, scopeRegistry]); + const injectableRegistry = new InjectableClassRegistry(reflector); + + const metaReader = new CompoundMetadataReader([localMetaReader, dtsReader]); + + + // 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; + let exportReferenceGraph: ReferenceGraph|null = null; + if (this.entryPoint !== null) { + exportReferenceGraph = new ReferenceGraph(); + referencesRegistry = new ReferenceGraphAdapter(exportReferenceGraph); + } else { + referencesRegistry = new NoopReferencesRegistry(); + } + + const routeAnalyzer = new NgModuleRouteAnalyzer(this.moduleResolver, evaluator); + + const dtsTransforms = new DtsTransformRegistry(); + + const mwpScanner = new ModuleWithProvidersScanner(reflector, evaluator, refEmitter); + + const isCore = isAngularCorePackage(this.tsProgram); + + const defaultImportTracker = new DefaultImportTracker(); + + // Set up the IvyCompilation, which manages state for the Ivy transformer. + const handlers: DecoratorHandler[] = [ + new ComponentDecoratorHandler( + reflector, evaluator, metaRegistry, metaReader, scopeReader, scopeRegistry, isCore, + this.resourceManager, this.host.rootDirs, this.options.preserveWhitespaces || false, + this.options.i18nUseExternalIds !== false, + this.options.enableI18nLegacyMessageIdFormat !== false, this.moduleResolver, + this.cycleAnalyzer, refEmitter, defaultImportTracker, this.incrementalDriver.depGraph, + injectableRegistry, this.closureCompilerEnabled), + // TODO(alxhub): understand why the cast here is necessary (something to do with `null` + // not being assignable to `unknown` when wrapped in `Readonly`). + // clang-format off + new DirectiveDecoratorHandler( + reflector, evaluator, metaRegistry, scopeRegistry, metaReader, + defaultImportTracker, injectableRegistry, isCore, this.closureCompilerEnabled + ) as Readonly>, + // clang-format on + // Pipe handler must be before injectable handler in list so pipe factories are printed + // before injectable factories (so injectable factories can delegate to them) + new PipeDecoratorHandler( + reflector, evaluator, metaRegistry, scopeRegistry, defaultImportTracker, + injectableRegistry, isCore), + new InjectableDecoratorHandler( + reflector, defaultImportTracker, isCore, this.options.strictInjectionParameters || false, + injectableRegistry), + new NgModuleDecoratorHandler( + reflector, evaluator, metaReader, metaRegistry, scopeRegistry, referencesRegistry, isCore, + routeAnalyzer, refEmitter, this.host.factoryTracker, defaultImportTracker, + this.closureCompilerEnabled, injectableRegistry, this.options.i18nInLocale), + ]; + + const traitCompiler = new TraitCompiler( + handlers, reflector, this.perfRecorder, this.incrementalDriver, + this.options.compileNonExportedClasses !== false, dtsTransforms); + + return { + isCore, traitCompiler, reflector, scopeRegistry, + dtsTransforms, exportReferenceGraph, routeAnalyzer, mwpScanner, + metaReader, defaultImportTracker, aliasingHost, refEmitter, + }; + } +} + +/** + * Determine if the given `Program` is @angular/core. + */ +function isAngularCorePackage(program: ts.Program): boolean { + // Look for its_just_angular.ts somewhere in the program. + const r3Symbols = getR3SymbolsFile(program); + if (r3Symbols === null) { + return false; + } + + // Look for the constant ITS_JUST_ANGULAR in that file. + return r3Symbols.statements.some(stmt => { + // The statement must be a variable declaration statement. + if (!ts.isVariableStatement(stmt)) { + return false; + } + // It must be exported. + if (stmt.modifiers === undefined || + !stmt.modifiers.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) { + return false; + } + // It must declare ITS_JUST_ANGULAR. + return stmt.declarationList.declarations.some(decl => { + // The declaration must match the name. + if (!ts.isIdentifier(decl.name) || decl.name.text !== 'ITS_JUST_ANGULAR') { + return false; + } + // It must initialize the variable to true. + if (decl.initializer === undefined || decl.initializer.kind !== ts.SyntaxKind.TrueKeyword) { + return false; + } + // This definition matches. + return true; + }); + }); +} + +/** + * Find the 'r3_symbols.ts' file in the given `Program`, or return `null` if it wasn't there. + */ +function getR3SymbolsFile(program: ts.Program): ts.SourceFile|null { + return program.getSourceFiles().find(file => file.fileName.indexOf('r3_symbols.ts') >= 0) || null; +} + +/** + * Symbol under which the `IncrementalDriver` is stored on a `ts.Program`. + * + * The TS model of incremental compilation is based around reuse of a previous `ts.Program` in the + * construction of a new one. The `NgCompiler` follows this abstraction - passing in a previous + * `ts.Program` is sufficient to trigger incremental compilation. This previous `ts.Program` need + * not be from an Angular compilation (that is, it need not have been created from `NgCompiler`). + * + * If it is, though, Angular can benefit from reusing previous analysis work. This reuse is managed + * by the `IncrementalDriver`, which is inherited from the old program to the new program. To + * support this behind the API of passing an old `ts.Program`, the `IncrementalDriver` is stored on + * the `ts.Program` under this symbol. + */ +const SYM_INCREMENTAL_DRIVER = Symbol('NgIncrementalDriver'); + +/** + * Get an `IncrementalDriver` from the given `ts.Program` if one is present. + * + * See `SYM_INCREMENTAL_DRIVER` for more details. + */ +function getIncrementalDriver(program: ts.Program): IncrementalDriver|null { + const driver = (program as any)[SYM_INCREMENTAL_DRIVER]; + if (driver === undefined || !(driver instanceof IncrementalDriver)) { + return null; + } + return driver; +} + +/** + * Save the given `IncrementalDriver` onto the given `ts.Program`, for retrieval in a subsequent + * incremental compilation. + * + * See `SYM_INCREMENTAL_DRIVER` for more details. + */ +function setIncrementalDriver(program: ts.Program, driver: IncrementalDriver): void { + (program as any)[SYM_INCREMENTAL_DRIVER] = driver; +} + +/** + * Since "strictTemplates" is a true superset of type checking capabilities compared to + * "strictTemplateTypeCheck", it is required that the latter is not explicitly disabled if the + * former is enabled. + */ +function verifyCompatibleTypeCheckOptions(options: NgCompilerOptions): ts.Diagnostic|null { + if (options.fullTemplateTypeCheck === false && options.strictTemplates === true) { + return { + category: ts.DiagnosticCategory.Error, + code: ngErrorCode(ErrorCode.CONFIG_STRICT_TEMPLATES_IMPLIES_FULL_TEMPLATE_TYPECHECK), + file: undefined, + start: undefined, + length: undefined, + messageText: + `Angular compiler option "strictTemplates" is enabled, however "fullTemplateTypeCheck" is disabled. + +Having the "strictTemplates" flag enabled implies that "fullTemplateTypeCheck" is also enabled, so +the latter can not be explicitly disabled. + +One of the following actions is required: +1. Remove the "fullTemplateTypeCheck" option. +2. Remove "strictTemplates" or set it to 'false'. + +More information about the template type checking compiler options can be found in the documentation: +https://v9.angular.io/guide/template-typecheck#template-type-checking`, + }; + } + + return null; +} + +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/core/src/host.ts b/packages/compiler-cli/src/ngtsc/core/src/host.ts new file mode 100644 index 0000000000..5cb7a2d855 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/core/src/host.ts @@ -0,0 +1,246 @@ +/** + * @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 {FlatIndexGenerator, findFlatIndexEntryPoint} from '../../entry_point'; +import {AbsoluteFsPath, resolve} from '../../file_system'; +import {FactoryGenerator, FactoryTracker, ShimGenerator, SummaryGenerator, TypeCheckShimGenerator} from '../../shims'; +import {typeCheckFilePath} from '../../typecheck'; +import {normalizeSeparators} from '../../util/src/path'; +import {getRootDirs} from '../../util/src/typescript'; +import {ExtendedTsCompilerHost, NgCompilerOptions, UnifiedModulesHost} from '../api'; + +// A persistent source of bugs in CompilerHost delegation has been the addition by TS of new, +// optional methods on ts.CompilerHost. Since these methods are optional, it's not a type error that +// the delegating host doesn't implement or delegate them. This causes subtle runtime failures. No +// more. This infrastructure ensures that failing to delegate a method is a compile-time error. + +/** + * Represents the `ExtendedTsCompilerHost` interface, with a transformation applied that turns all + * methods (even optional ones) into required fields (which may be `undefined`, if the method was + * optional). + */ +export type RequiredCompilerHostDelegations = { + [M in keyof Required]: ExtendedTsCompilerHost[M]; +}; + +/** + * Delegates all methods of `ExtendedTsCompilerHost` to a delegate, with the exception of + * `getSourceFile` and `fileExists` which are implemented in `NgCompilerHost`. + * + * If a new method is added to `ts.CompilerHost` which is not delegated, a type error will be + * generated for this class. + */ +export class DelegatingCompilerHost implements + Omit { + constructor(protected delegate: ExtendedTsCompilerHost) {} + + private delegateMethod(name: M): + ExtendedTsCompilerHost[M] { + return this.delegate[name] !== undefined ? (this.delegate[name] as any).bind(this.delegate) : + undefined; + } + + // Excluded are 'getSourceFile' and 'fileExists', which are actually implemented by NgCompilerHost + // below. + createHash = this.delegateMethod('createHash'); + directoryExists = this.delegateMethod('directoryExists'); + fileNameToModuleName = this.delegateMethod('fileNameToModuleName'); + getCancellationToken = this.delegateMethod('getCancellationToken'); + getCanonicalFileName = this.delegateMethod('getCanonicalFileName'); + getCurrentDirectory = this.delegateMethod('getCurrentDirectory'); + getDefaultLibFileName = this.delegateMethod('getDefaultLibFileName'); + getDefaultLibLocation = this.delegateMethod('getDefaultLibLocation'); + getDirectories = this.delegateMethod('getDirectories'); + getEnvironmentVariable = this.delegateMethod('getEnvironmentVariable'); + getModifiedResourceFiles = this.delegateMethod('getModifiedResourceFiles'); + getNewLine = this.delegateMethod('getNewLine'); + getParsedCommandLine = this.delegateMethod('getParsedCommandLine'); + getSourceFileByPath = this.delegateMethod('getSourceFileByPath'); + readDirectory = this.delegateMethod('readDirectory'); + readFile = this.delegateMethod('readFile'); + readResource = this.delegateMethod('readResource'); + realpath = this.delegateMethod('realpath'); + resolveModuleNames = this.delegateMethod('resolveModuleNames'); + resolveTypeReferenceDirectives = this.delegateMethod('resolveTypeReferenceDirectives'); + resourceNameToFileName = this.delegateMethod('resourceNameToFileName'); + trace = this.delegateMethod('trace'); + useCaseSensitiveFileNames = this.delegateMethod('useCaseSensitiveFileNames'); + writeFile = this.delegateMethod('writeFile'); +} + +/** + * A wrapper around `ts.CompilerHost` (plus any extension methods from `ExtendedTsCompilerHost`). + * + * In order for a consumer to include Angular compilation in their TypeScript compiler, the + * `ts.Program` must be created with a host that adds Angular-specific files (e.g. factories, + * summaries, the template type-checking file, etc) to the compilation. `NgCompilerHost` is the + * host implementation which supports this. + * + * The interface implementations here ensure that `NgCompilerHost` fully delegates to + * `ExtendedTsCompilerHost` methods whenever present. + */ +export class NgCompilerHost extends DelegatingCompilerHost implements + RequiredCompilerHostDelegations, + ExtendedTsCompilerHost { + readonly factoryTracker: FactoryTracker|null = null; + readonly entryPoint: AbsoluteFsPath|null = null; + readonly diagnostics: ts.Diagnostic[]; + + readonly inputFiles: ReadonlyArray; + readonly rootDirs: ReadonlyArray; + readonly typeCheckFile: AbsoluteFsPath; + + constructor( + delegate: ExtendedTsCompilerHost, inputFiles: ReadonlyArray, + rootDirs: ReadonlyArray, private shims: ShimGenerator[], + entryPoint: AbsoluteFsPath|null, typeCheckFile: AbsoluteFsPath, + factoryTracker: FactoryTracker|null, diagnostics: ts.Diagnostic[]) { + super(delegate); + + this.factoryTracker = factoryTracker; + this.entryPoint = entryPoint; + this.typeCheckFile = typeCheckFile; + this.diagnostics = diagnostics; + this.inputFiles = inputFiles; + this.rootDirs = rootDirs; + } + + /** + * Create an `NgCompilerHost` from a delegate host, an array of input filenames, and the full set + * of TypeScript and Angular compiler options. + */ + static wrap( + delegate: ts.CompilerHost, inputFiles: ReadonlyArray, + options: NgCompilerOptions): NgCompilerHost { + // TODO(alxhub): remove the fallback to allowEmptyCodegenFiles after verifying that the rest of + // our build tooling is no longer relying on it. + const allowEmptyCodegenFiles = options.allowEmptyCodegenFiles || false; + const shouldGenerateFactoryShims = options.generateNgFactoryShims !== undefined ? + options.generateNgFactoryShims : + allowEmptyCodegenFiles; + + const shouldGenerateSummaryShims = options.generateNgSummaryShims !== undefined ? + options.generateNgSummaryShims : + allowEmptyCodegenFiles; + + let rootFiles = [...inputFiles]; + let normalizedInputFiles = inputFiles.map(n => resolve(n)); + + const generators: ShimGenerator[] = []; + let summaryGenerator: SummaryGenerator|null = null; + + if (shouldGenerateSummaryShims) { + // Summary generation. + summaryGenerator = SummaryGenerator.forRootFiles(normalizedInputFiles); + generators.push(summaryGenerator); + } + + let factoryTracker: FactoryTracker|null = null; + if (shouldGenerateFactoryShims) { + // Factory generation. + const factoryGenerator = FactoryGenerator.forRootFiles(normalizedInputFiles); + const factoryFileMap = factoryGenerator.factoryFileMap; + + const factoryFileNames = Array.from(factoryFileMap.keys()); + rootFiles.push(...factoryFileNames); + generators.push(factoryGenerator); + + factoryTracker = new FactoryTracker(factoryGenerator); + } + + // Done separately to preserve the order of factory files before summary files in rootFiles. + // TODO(alxhub): validate that this is necessary. + if (summaryGenerator !== null) { + rootFiles.push(...summaryGenerator.getSummaryFileNames()); + } + + + const rootDirs = getRootDirs(delegate, options as ts.CompilerOptions); + + const typeCheckFile = typeCheckFilePath(rootDirs); + generators.push(new TypeCheckShimGenerator(typeCheckFile)); + rootFiles.push(typeCheckFile); + + let diagnostics: ts.Diagnostic[] = []; + + let entryPoint: AbsoluteFsPath|null = null; + if (options.flatModuleOutFile != null && options.flatModuleOutFile !== '') { + entryPoint = findFlatIndexEntryPoint(normalizedInputFiles); + 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 + // module entry point instead. If neither of these conditions apply, the error below is + // given. + // + // The user is not informed about the "index.ts" option as this behavior is deprecated - + // an explicit entrypoint should always be specified. + diagnostics.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); + const flatIndexGenerator = + new FlatIndexGenerator(entryPoint, flatModuleOutFile, flatModuleId); + generators.push(flatIndexGenerator); + rootFiles.push(flatIndexGenerator.flatIndexPath); + } + } + + return new NgCompilerHost( + delegate, rootFiles, rootDirs, generators, entryPoint, typeCheckFile, factoryTracker, + diagnostics); + } + + getSourceFile( + fileName: string, languageVersion: ts.ScriptTarget, + onError?: ((message: string) => void)|undefined, + shouldCreateNewSourceFile?: boolean|undefined): ts.SourceFile|undefined { + for (let i = 0; i < this.shims.length; i++) { + const generator = this.shims[i]; + // TypeScript internal paths are guaranteed to be POSIX-like absolute file paths. + const absoluteFsPath = resolve(fileName); + if (generator.recognize(absoluteFsPath)) { + const readFile = (originalFile: string) => { + return this.delegate.getSourceFile( + originalFile, languageVersion, onError, shouldCreateNewSourceFile) || + null; + }; + + return generator.generate(absoluteFsPath, readFile) || undefined; + } + } + + return this.delegate.getSourceFile( + fileName, languageVersion, onError, shouldCreateNewSourceFile); + } + + fileExists(fileName: string): boolean { + // Consider the file as existing whenever + // 1) it really does exist in the delegate host, or + // 2) at least one of the shim generators recognizes it + // Note that we can pass the file name as branded absolute fs path because TypeScript + // internally only passes POSIX-like paths. + return this.delegate.fileExists(fileName) || + this.shims.some(shim => shim.recognize(resolve(fileName))); + } + + get unifiedModulesHost(): UnifiedModulesHost|null { + return this.fileNameToModuleName !== undefined ? this as UnifiedModulesHost : null; + } +} diff --git a/packages/compiler-cli/src/ngtsc/core/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/core/test/BUILD.bazel new file mode 100644 index 0000000000..2c097d2865 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/core/test/BUILD.bazel @@ -0,0 +1,27 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob([ + "**/*.ts", + ]), + deps = [ + "//packages:types", + "//packages/compiler-cli/src/ngtsc/core", + "//packages/compiler-cli/src/ngtsc/core:api", + "//packages/compiler-cli/src/ngtsc/file_system", + "//packages/compiler-cli/src/ngtsc/file_system/testing", + "@npm//typescript", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["//tools/testing:node_no_angular_es5"], + deps = [ + ":test_lib", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/core/test/compiler_test.ts b/packages/compiler-cli/src/ngtsc/core/test/compiler_test.ts new file mode 100644 index 0000000000..493f0a8860 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/core/test/compiler_test.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 {FileSystem, NgtscCompilerHost, absoluteFrom as _, getFileSystem, getSourceFileOrError, setFileSystem} from '../../file_system'; +import {runInEachFileSystem} from '../../file_system/testing'; +import {NgCompilerOptions} from '../api'; +import {NgCompiler} from '../src/compiler'; +import {NgCompilerHost} from '../src/host'; + + +runInEachFileSystem(() => { + + describe('NgCompiler', () => { + let fs: FileSystem; + + beforeEach(() => { + fs = getFileSystem(); + fs.ensureDir(_('/node_modules/@angular/core')); + fs.writeFile(_('/node_modules/@angular/core/index.d.ts'), ` + export declare const Component: any; + `); + }); + + it('should also return template diagnostics when asked for component diagnostics', () => { + const COMPONENT = _('/cmp.ts'); + fs.writeFile(COMPONENT, ` + import {Component} from '@angular/core'; + @Component({ + selector: 'test-cmp', + templateUrl: './template.html', + }) + export class Cmp {} + `); + fs.writeFile(_('/template.html'), `{{does_not_exist.foo}}`); + + const options: NgCompilerOptions = { + strictTemplates: true, + }; + const baseHost = new NgtscCompilerHost(getFileSystem(), options); + const host = NgCompilerHost.wrap(baseHost, [COMPONENT], options); + const program = ts.createProgram({host, options, rootNames: host.inputFiles}); + const compiler = new NgCompiler(host, options, program); + + const diags = compiler.getDiagnostics(getSourceFileOrError(program, COMPONENT)); + expect(diags.length).toBe(1); + expect(diags[0].messageText).toContain('does_not_exist'); + }); + }); +}); diff --git a/packages/compiler-cli/src/ngtsc/cycles/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/cycles/test/BUILD.bazel index e95443472f..81efd86e91 100644 --- a/packages/compiler-cli/src/ngtsc/cycles/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/cycles/test/BUILD.bazel @@ -21,9 +21,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/index.ts b/packages/compiler-cli/src/ngtsc/diagnostics/index.ts index 1f1cabc93d..660c12a1d0 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, ngErrorCode} from './src/code'; export {FatalDiagnosticError, isFatalDiagnosticError, makeDiagnostic} from './src/error'; +export {ErrorCode, ngErrorCode} from './src/error_code'; export {replaceTsWithNgInErrors} from './src/util'; diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts b/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts index 59c0886f38..2454c86418 100644 --- a/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts +++ b/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ErrorCode} from './code'; +import {ErrorCode} from './error_code'; export class FatalDiagnosticError { constructor(readonly code: ErrorCode, readonly node: ts.Node, readonly message: string) {} diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/src/code.ts b/packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts similarity index 95% rename from packages/compiler-cli/src/ngtsc/diagnostics/src/code.ts rename to packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts index cceeb2cc88..b306ecc00b 100644 --- a/packages/compiler-cli/src/ngtsc/diagnostics/src/code.ts +++ b/packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts @@ -6,6 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ +/** + * @publicApi + */ export enum ErrorCode { DECORATOR_ARG_NOT_LITERAL = 1001, DECORATOR_ARITY_WRONG = 1002, @@ -85,11 +88,6 @@ export enum ErrorCode { */ NGMODULE_DECLARATION_NOT_UNIQUE = 6007, - /** - * Raised when ngcc tries to inject a synthetic decorator over one that already exists. - */ - NGCC_MIGRATION_DECORATOR_INJECTION_ERROR = 7001, - /** * An element name failed validation against the DOM schema. */ @@ -130,6 +128,9 @@ export enum ErrorCode { INJECTABLE_DUPLICATE_PROV = 9001, } +/** + * @internal + */ export function ngErrorCode(code: ErrorCode): number { return parseInt('-99' + code); } diff --git a/packages/compiler-cli/src/ngtsc/entry_point/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/entry_point/test/BUILD.bazel index 03c4b93867..7895a91330 100644 --- a/packages/compiler-cli/src/ngtsc/entry_point/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/entry_point/test/BUILD.bazel @@ -19,9 +19,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/file_system/BUILD.bazel b/packages/compiler-cli/src/ngtsc/file_system/BUILD.bazel index 206189e03c..00aad64ac8 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/file_system/BUILD.bazel @@ -9,7 +9,9 @@ ts_library( ]), deps = [ "//packages:types", + "@npm//@types/fs-extra", "@npm//@types/node", + "@npm//fs-extra", "@npm//typescript", ], ) diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts index 26481d46cf..92030c58c7 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts @@ -48,12 +48,18 @@ export class CachedFileSystem implements FileSystem { } } - writeFile(path: AbsoluteFsPath, data: string): void { - this.delegate.writeFile(path, data); + writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { + this.delegate.writeFile(path, data, exclusive); this.readFileCache.set(path, data); this.existsCache.set(path, true); } + removeFile(path: AbsoluteFsPath): void { + this.delegate.removeFile(path); + this.readFileCache.delete(path); + this.existsCache.set(path, false); + } + symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { this.delegate.symlink(target, path); this.existsCache.set(path, true); @@ -66,12 +72,16 @@ export class CachedFileSystem implements FileSystem { moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { this.delegate.moveFile(from, to); + this.existsCache.set(from, false); + this.existsCache.set(to, true); + if (this.readFileCache.has(from)) { this.readFileCache.set(to, this.readFileCache.get(from)); this.readFileCache.delete(from); + } else { + this.readFileCache.delete(to); } - this.existsCache.set(to, true); } ensureDir(path: AbsoluteFsPath): void { @@ -82,6 +92,25 @@ export class CachedFileSystem implements FileSystem { } } + removeDeep(path: AbsoluteFsPath): void { + this.delegate.removeDeep(path); + + // Clear out this directory and all its children from the `exists` cache. + for (const p of this.existsCache.keys()) { + if (p.startsWith(path)) { + this.existsCache.set(p, false); + } + } + + // Clear out this directory and all its children from the `readFile` cache. + for (const p of this.readFileCache.keys()) { + if (p.startsWith(path)) { + this.readFileCache.delete(p); + } + } + } + + lstat(path: AbsoluteFsPath): FileStats { const stat = this.delegate.lstat(path); // if the `path` does not exist then `lstat` will thrown an error. diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts index 36e7858caa..2fcf235afe 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts @@ -18,7 +18,8 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './ export class InvalidFileSystem implements FileSystem { exists(path: AbsoluteFsPath): boolean { throw makeError(); } readFile(path: AbsoluteFsPath): string { throw makeError(); } - writeFile(path: AbsoluteFsPath, data: string): void { throw makeError(); } + writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { throw makeError(); } + removeFile(path: AbsoluteFsPath): void { throw makeError(); } symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); } readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); } lstat(path: AbsoluteFsPath): FileStats { throw makeError(); } @@ -29,6 +30,7 @@ export class InvalidFileSystem implements FileSystem { copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); } moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); } ensureDir(path: AbsoluteFsPath): void { throw makeError(); } + removeDeep(path: AbsoluteFsPath): void { throw makeError(); } isCaseSensitive(): boolean { throw makeError(); } resolve(...paths: string[]): AbsoluteFsPath { throw makeError(); } dirname(file: T): T { throw makeError(); } diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts index 891426f969..b373e8e567 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts @@ -7,6 +7,7 @@ */ /// import * as fs from 'fs'; +import * as fsExtra from 'fs-extra'; import * as p from 'path'; import {absoluteFrom, relativeFrom} from './helpers'; import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './types'; @@ -18,9 +19,10 @@ export class NodeJSFileSystem implements FileSystem { private _caseSensitive: boolean|undefined = undefined; exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); } readFile(path: AbsoluteFsPath): string { return fs.readFileSync(path, 'utf8'); } - writeFile(path: AbsoluteFsPath, data: string): void { - return fs.writeFileSync(path, data, 'utf8'); + writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void { + fs.writeFileSync(path, data, exclusive ? {flag: 'wx'} : undefined); } + removeFile(path: AbsoluteFsPath): void { fs.unlinkSync(path); } symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); } readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; } lstat(path: AbsoluteFsPath): FileStats { return fs.lstatSync(path); } @@ -39,6 +41,7 @@ export class NodeJSFileSystem implements FileSystem { this.safeMkdir(parents.pop() !); } } + removeDeep(path: AbsoluteFsPath): void { fsExtra.removeSync(path); } isCaseSensitive(): boolean { if (this._caseSensitive === undefined) { this._caseSensitive = this.exists(togglePathCase(__filename)); diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/types.ts b/packages/compiler-cli/src/ngtsc/file_system/src/types.ts index 9c3dc11bf6..520b41bead 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/types.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/types.ts @@ -37,7 +37,8 @@ export type PathSegment = BrandedPath<'PathSegment'>; export interface FileSystem { exists(path: AbsoluteFsPath): boolean; readFile(path: AbsoluteFsPath): string; - writeFile(path: AbsoluteFsPath, data: string): void; + writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void; + removeFile(path: AbsoluteFsPath): void; symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void; readdir(path: AbsoluteFsPath): PathSegment[]; lstat(path: AbsoluteFsPath): FileStats; @@ -48,6 +49,7 @@ export interface FileSystem { copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void; moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void; ensureDir(path: AbsoluteFsPath): void; + removeDeep(path: AbsoluteFsPath): void; isCaseSensitive(): boolean; isRoot(path: AbsoluteFsPath): boolean; isRooted(path: string): boolean; diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/file_system/test/BUILD.bazel index 84ea6a2849..36575562ed 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/file_system/test/BUILD.bazel @@ -12,15 +12,15 @@ ts_library( "//packages:types", "//packages/compiler-cli/src/ngtsc/file_system", "//packages/compiler-cli/src/ngtsc/file_system/testing", + "@npm//@types/fs-extra", "@npm//typescript", ], ) jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts index d817045c57..04610ddaa1 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {CachedFileSystem} from '../src/cached_file_system'; -import {absoluteFrom, setFileSystem} from '../src/helpers'; +import {absoluteFrom, join, setFileSystem} from '../src/helpers'; import {NodeJSFileSystem} from '../src/node_js_file_system'; import {AbsoluteFsPath, FileSystem} from '../src/types'; @@ -94,7 +94,10 @@ describe('CachedFileSystem', () => { it('should call delegate', () => { const spy = spyOn(delegate, 'writeFile'); fs.writeFile(abcPath, 'Some contents'); - expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents'); + expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', undefined); + spy.calls.reset(); + fs.writeFile(abcPath, 'Some contents', /* exclusive */ true); + expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', true); }); it('should update the exists and "readFile" caches', () => { @@ -110,6 +113,23 @@ describe('CachedFileSystem', () => { }); }); + describe('removeFile()', () => { + it('should call delegate', () => { + const spy = spyOn(delegate, 'removeFile'); + fs.removeFile(abcPath); + expect(spy).toHaveBeenCalledWith(abcPath); + }); + + it('should update the exists cache', () => { + spyOn(delegate, 'removeFile'); + const existsSpy = spyOn(delegate, 'exists'); + + fs.removeFile(abcPath); + expect(fs.exists(abcPath)).toBe(false); + expect(existsSpy).not.toHaveBeenCalled(); + }); + }); + describe('readdir()', () => { it('should call delegate', () => { const spy = spyOn(delegate, 'readdir'); @@ -216,7 +236,7 @@ describe('CachedFileSystem', () => { expect(readFileSpy).toHaveBeenCalledWith(abcPath); }); - it('should update the `to` "readFile" cache', () => { + it('should update the `to` "readFile" cache (if `from` was cached)', () => { spyOn(delegate, 'moveFile'); const readFileSpy = spyOn(delegate, 'readFile'); @@ -232,6 +252,24 @@ describe('CachedFileSystem', () => { expect(fs.readFile(xyzPath)).toEqual('abc content'); expect(readFileSpy).not.toHaveBeenCalled(); }); + + it('should delete the `to` "readFile" cache (if `from` was not cached)', () => { + spyOn(delegate, 'moveFile'); + const readFileSpy = spyOn(delegate, 'readFile'); + + // Fill the xyz "readFile" cache + readFileSpy.and.returnValue('xyz content'); + fs.readFile(xyzPath); + readFileSpy.calls.reset(); + + // Move the file + fs.moveFile(abcPath, xyzPath); + + // Show that the cache was not hit for the xyz file + readFileSpy.and.returnValue('abc content'); + expect(fs.readFile(xyzPath)).toBe('abc content'); + expect(readFileSpy).toHaveBeenCalledWith(xyzPath); + }); }); describe('ensureDir()', () => { @@ -252,4 +290,50 @@ describe('CachedFileSystem', () => { expect(existsSpy).not.toHaveBeenCalled(); }); }); + + describe('removeDeep()', () => { + it('should call delegate', () => { + const spy = spyOn(delegate, 'removeDeep'); + fs.removeDeep(abcPath); + expect(spy).toHaveBeenCalledWith(abcPath); + }); + + it('should update the exists cache', () => { + spyOn(delegate, 'writeFile'); + spyOn(delegate, 'removeDeep'); + const existsSpy = spyOn(delegate, 'exists').and.returnValue(true); + expect(fs.exists(abcPath)).toBe(true); + existsSpy.calls.reset(); + + // Create a file inside `/a/b/c`. + const abcdPath = join(abcPath, 'd'); + fs.writeFile(abcdPath, 'content'); + expect(fs.exists(abcdPath)).toBe(true); + expect(existsSpy).not.toHaveBeenCalled(); + + // Remove the `/a/b/c` directory and ensure it is removed from cache (along with its content). + fs.removeDeep(abcPath); + expect(fs.exists(abcPath)).toBeFalsy(); + expect(fs.exists(abcdPath)).toBeFalsy(); + expect(existsSpy).not.toHaveBeenCalled(); + }); + + it('should update the readFile cache', () => { + spyOn(delegate, 'writeFile'); + spyOn(delegate, 'removeDeep'); + spyOn(delegate, 'lstat').and.throwError('ENOENT: no such file or directory'); + const readFileSpy = spyOn(delegate, 'readFile'); + + // Create a file inside `/a/b/c`. + const abcdPath = join(abcPath, 'd'); + fs.writeFile(abcdPath, 'content from cache'); + expect(fs.readFile(abcdPath)).toBe('content from cache'); + expect(readFileSpy).not.toHaveBeenCalled(); + + // Remove the `/a/b/c` directory and ensure it is removed from cache (along with its content). + fs.removeDeep(abcPath); + expect(() => fs.readFile(abcdPath)).toThrowError('ENOENT: no such file or directory'); + expect(() => fs.readFile(abcPath)).toThrowError('ENOENT: no such file or directory'); + }); + }); }); diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts index 34fe48dfd6..a2c0adc236 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import * as realFs from 'fs'; +import * as fsExtra from 'fs-extra'; import {absoluteFrom, dirname, relativeFrom, setFileSystem} from '../src/helpers'; import {NodeJSFileSystem} from '../src/node_js_file_system'; import {AbsoluteFsPath} from '../src/types'; @@ -47,7 +48,18 @@ describe('NodeJSFileSystem', () => { it('should delegate to fs.writeFileSync()', () => { const spy = spyOn(realFs, 'writeFileSync'); fs.writeFile(abcPath, 'Some contents'); - expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', 'utf8'); + expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', undefined); + spy.calls.reset(); + fs.writeFile(abcPath, 'Some contents', /* exclusive */ true); + expect(spy).toHaveBeenCalledWith(abcPath, 'Some contents', {flag: 'wx'}); + }); + }); + + describe('removeFile()', () => { + it('should delegate to fs.unlink()', () => { + const spy = spyOn(realFs, 'unlinkSync'); + fs.removeFile(abcPath); + expect(spy).toHaveBeenCalledWith(abcPath); }); }); @@ -137,6 +149,14 @@ describe('NodeJSFileSystem', () => { expect(mkdirCalls).toEqual([xPath, xyPath, xyzPath]); }); + describe('removeDeep()', () => { + it('should delegate to fsExtra.remove()', () => { + const spy = spyOn(fsExtra, 'removeSync'); + fs.removeDeep(abcPath); + expect(spy).toHaveBeenCalledWith(abcPath); + }); + }); + it('should not fail if a directory (that did not exist before) does exist when trying to create it', () => { let abcPathExists = false; diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts index a1609ab28c..cf3c625878 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts @@ -34,16 +34,34 @@ export abstract class MockFileSystem implements FileSystem { } } - writeFile(path: AbsoluteFsPath, data: string): void { + writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void { const [folderPath, basename] = this.splitIntoFolderAndFile(path); const {entity} = this.findFromPath(folderPath); if (entity === null || !isFolder(entity)) { throw new MockFileSystemError( 'ENOENT', path, `Unable to write file "${path}". The containing folder does not exist.`); } + if (exclusive && entity[basename] !== undefined) { + throw new MockFileSystemError( + 'EEXIST', path, `Unable to exclusively write file "${path}". The file already exists.`); + } entity[basename] = data; } + removeFile(path: AbsoluteFsPath): void { + const [folderPath, basename] = this.splitIntoFolderAndFile(path); + const {entity} = this.findFromPath(folderPath); + if (entity === null || !isFolder(entity)) { + throw new MockFileSystemError( + 'ENOENT', path, `Unable to remove file "${path}". The containing folder does not exist.`); + } + if (isFolder(entity[basename])) { + throw new MockFileSystemError( + 'EISDIR', path, `Unable to remove file "${path}". The path to remove is a folder.`); + } + delete entity[basename]; + } + symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { const [folderPath, basename] = this.splitIntoFolderAndFile(path); const {entity} = this.findFromPath(folderPath); @@ -113,6 +131,17 @@ export abstract class MockFileSystem implements FileSystem { } } + removeDeep(path: AbsoluteFsPath): void { + const [folderPath, basename] = this.splitIntoFolderAndFile(path); + const {entity} = this.findFromPath(folderPath); + if (entity === null || !isFolder(entity)) { + throw new MockFileSystemError( + 'ENOENT', path, + `Unable to remove folder "${path}". The containing folder does not exist.`); + } + delete entity[basename]; + } + isRoot(path: AbsoluteFsPath): boolean { return this.dirname(path) === path; } extname(path: AbsoluteFsPath|PathSegment): string { diff --git a/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel b/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel index a7907091e9..026cfb7b0b 100644 --- a/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/imports/BUILD.bazel @@ -10,6 +10,7 @@ ts_library( deps = [ "//packages:types", "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/core:api", "//packages/compiler-cli/src/ngtsc/file_system", "//packages/compiler-cli/src/ngtsc/reflection", "//packages/compiler-cli/src/ngtsc/util", diff --git a/packages/compiler-cli/src/ngtsc/imports/README.md b/packages/compiler-cli/src/ngtsc/imports/README.md index 08f31632b6..67b6c87e83 100644 --- a/packages/compiler-cli/src/ngtsc/imports/README.md +++ b/packages/compiler-cli/src/ngtsc/imports/README.md @@ -18,9 +18,9 @@ It's important to note that this logic is transitive. If the user instead import This logic of course breaks down for non-Angular Package Format libraries, such as "internal" libraries within a monorepo, which frequently don't use `index.ts` files or entrypoints. In this case, the user will likely import NgModules directly from their declaration (e.g. via a 'lib/module' specifier), and the compiler cannot simply assume that the user has exported all of the directives/pipes from the NgModule via this same specifier. In this case a compiler feature called "aliasing" kicks in (see below) and generates private exports from the NgModule file. -2. Using a `FileToModuleHost` +2. Using a `UnifiedModulesHost` -The `ts.CompilerHost` given to the compiler may optionally implement an interface called `FileToModuleHost`, which allows an absolute module specifier to be generated for any file. If a `FileToModuleHost` is present, the compiler will attempt to directly import all directives and pipes from the file which declares them, instead of going via the specifier of the NgModule as in the first mode described above. This logic is used internally in the Google monorepo. +The `ts.CompilerHost` given to the compiler may optionally implement an interface called `UnifiedModulesHost`, which allows an absolute module specifier to be generated for any file. If a `UnifiedModulesHost` is present, the compiler will attempt to directly import all directives and pipes from the file which declares them, instead of going via the specifier of the NgModule as in the first mode described above. This logic is used internally in the Google monorepo. This approach comes with a significant caveat: the build system may prevent importing from files which are not directly declared dependencies of the current compilation (this is known as "strict dependency checking"). This is a problem when attempting to consume a re-exported directive. For example, if the user depends only on '@angular/platform-browser', imports `BrowserModule` from '@angular/platform-browser' and attempts to use the re-exported `NgIf`, the compiler cannot import `NgIf` directly from its declaration within '@angular/common', which is a transitive (but not direct) dependency. @@ -86,19 +86,19 @@ This `ReferenceEmitStrategy` uses the `bestGuessOwningModule` of a `Reference` t Note that the `bestGuessOwningModule` only gives the module specifier for the import, not the symbol name. The user may have renamed the class as part of re-exporting it from an entrypoint, so the `AbsoluteModuleStrategy` searches the exports of the target module and finds the symbol name by which the class is re-exported, if it exists. -### `FileToModuleStrategy` +### `UnifiedModulesStrategy` -This `ReferenceEmitStrategy` uses a `FileToModuleHost` to implement the major import mode #2 described at the beginning of this document. +This `ReferenceEmitStrategy` uses a `UnifiedModulesHost` to implement the major import mode #2 described at the beginning of this document. -Under this strategy, direct imports to referenced classes are constructed using globally valid absolute module specifiers determined by the `FileToModuleHost`. +Under this strategy, direct imports to referenced classes are constructed using globally valid absolute module specifiers determined by the `UnifiedModulesHost`. -Like with `AbsoluteModuleStrategy`, the `FileToModuleHost` only gives the module specifier and not the symbol name, so an appropriate symbol name must be determined by searching the exports of the module. +Like with `AbsoluteModuleStrategy`, the `UnifiedModulesHost` only gives the module specifier and not the symbol name, so an appropriate symbol name must be determined by searching the exports of the module. ### `AliasStrategy` -The `AliasStrategy` will choose the alias `Expression` of a `Reference`. This strategy is used before the `FileToModuleStrategy` to guarantee aliases are preferred to direct imports when available. +The `AliasStrategy` will choose the alias `Expression` of a `Reference`. This strategy is used before the `UnifiedModulesStrategy` to guarantee aliases are preferred to direct imports when available. -See the description of aliasing in the case of `FileToModuleAliasingHost` below. +See the description of aliasing in the case of `UnifiedModulesAliasingHost` below. ## Aliasing and re-exports @@ -120,14 +120,14 @@ Because the first import of an NgModule from a user library to a `.d.ts` is alwa Aliasing is currently used in two cases: -1. To address strict dependency checking issues when using a `FileToModuleHost`. +1. To address strict dependency checking issues when using a `UnifiedModulesHost`. 2. To support dependening on non-Angular Package Format packages (e.g. private libraries in monorepos) which do not have an entrypoint file through which all directives/pipes/modules are exported. In environments with "strict dependency checking" as described above, an NgModule which exports another NgModule from one of its dependencies needs to export its directives/pipes as well, in order to make them available to the downstream compiler. -### Aliasing under `FileToModuleHost` +### Aliasing under `UnifiedModulesHost` -A `FileToModuleAliasingHost` implements `AliasingHost` and makes full use of the aliasing system in the case of a `FileToModuleHost`. +A `UnifiedModulesAliasingHost` implements `AliasingHost` and makes full use of the aliasing system in the case of a `UnifiedModulesHost`. When compiling an NgModule, re-exports are added under a stable name for each directive/pipe that's re-exported by the NgModule. diff --git a/packages/compiler-cli/src/ngtsc/imports/index.ts b/packages/compiler-cli/src/ngtsc/imports/index.ts index 446aa54cc7..d43beaaa30 100644 --- a/packages/compiler-cli/src/ngtsc/imports/index.ts +++ b/packages/compiler-cli/src/ngtsc/imports/index.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -export {AliasStrategy, AliasingHost, FileToModuleAliasingHost, PrivateExportAliasingHost} from './src/alias'; +export {AliasStrategy, AliasingHost, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias'; export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core'; export {DefaultImportRecorder, DefaultImportTracker, NOOP_DEFAULT_IMPORT_RECORDER} from './src/default'; -export {AbsoluteModuleStrategy, FileToModuleHost, FileToModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy} from './src/emitter'; +export {AbsoluteModuleStrategy, ImportFlags, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesStrategy} from './src/emitter'; export {Reexport} from './src/reexport'; -export {ImportMode, OwningModule, Reference} from './src/references'; +export {OwningModule, Reference} from './src/references'; export {ModuleResolver} from './src/resolver'; diff --git a/packages/compiler-cli/src/ngtsc/imports/src/alias.ts b/packages/compiler-cli/src/ngtsc/imports/src/alias.ts index 79ba0f668b..6795705e2f 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/alias.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/alias.ts @@ -9,9 +9,13 @@ import {Expression, ExternalExpr} from '@angular/compiler'; import * as ts from 'typescript'; +import {UnifiedModulesHost} from '../../core/api'; import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection'; -import {FileToModuleHost, ReferenceEmitStrategy} from './emitter'; -import {ImportMode, Reference} from './references'; + +import {ImportFlags, ReferenceEmitStrategy} from './emitter'; +import {Reference} from './references'; + + // Escape anything that isn't alphanumeric, '/' or '_'. const CHARS_TO_ESCAPE = /[^a-zA-Z0-9/_]/g; @@ -31,8 +35,8 @@ const CHARS_TO_ESCAPE = /[^a-zA-Z0-9/_]/g; * * 1) It can be used to create "alias" re-exports from different files, which can be used when the * user hasn't exported the directive(s) from the ES module containing the NgModule. These re- - * exports can also be helpful when using a `FileToModuleHost`, which overrides the import logic - * described above. + * exports can also be helpful when using a `UnifiedModulesHost`, which overrides the import + * logic described above. * * 2) It can be used to get an alternative import expression for a directive or pipe, instead of * the import that the normal logic would apply. The alias used depends on the provenance of the @@ -83,16 +87,16 @@ export interface AliasingHost { /** * An `AliasingHost` which generates and consumes alias re-exports when module names for each file - * are determined by a `FileToModuleHost`. + * are determined by a `UnifiedModulesHost`. * - * When using a `FileToModuleHost`, aliasing prevents issues with transitive dependencies. See the + * When using a `UnifiedModulesHost`, aliasing prevents issues with transitive dependencies. See the * README.md for more details. */ -export class FileToModuleAliasingHost implements AliasingHost { - constructor(private fileToModuleHost: FileToModuleHost) {} +export class UnifiedModulesAliasingHost implements AliasingHost { + constructor(private unifiedModulesHost: UnifiedModulesHost) {} /** - * With a `FileToModuleHost`, aliases are chosen automatically without the need to look through + * With a `UnifiedModulesHost`, aliases are chosen automatically without the need to look through * the exports present in a .d.ts file, so we can avoid cluttering the .d.ts files. */ readonly aliasExportsInDts = false; @@ -101,7 +105,8 @@ export class FileToModuleAliasingHost implements AliasingHost { ref: Reference, context: ts.SourceFile, ngModuleName: string, isReExport: boolean): string|null { if (!isReExport) { - // Aliasing is used with a FileToModuleHost to prevent transitive dependencies. Thus, aliases + // Aliasing is used with a UnifiedModulesHost to prevent transitive dependencies. Thus, + // aliases // only need to be created for directives/pipes which are not direct declarations of an // NgModule which exports them. return null; @@ -120,7 +125,7 @@ export class FileToModuleAliasingHost implements AliasingHost { return null; } // viaModule is the module it'll actually be imported from. - const moduleName = this.fileToModuleHost.fileNameToModuleName(via.fileName, via.fileName); + const moduleName = this.unifiedModulesHost.fileNameToModuleName(via.fileName, via.fileName); return new ExternalExpr({moduleName, name: this.aliasName(decl, via)}); } @@ -130,8 +135,8 @@ export class FileToModuleAliasingHost implements AliasingHost { */ private aliasName(decl: ClassDeclaration, context: ts.SourceFile): string { // The declared module is used to get the name of the alias. - const declModule = - this.fileToModuleHost.fileNameToModuleName(decl.getSourceFile().fileName, context.fileName); + const declModule = this.unifiedModulesHost.fileNameToModuleName( + decl.getSourceFile().fileName, context.fileName); const replaced = declModule.replace(CHARS_TO_ESCAPE, '_').replace(/\//g, '$'); return 'ɵng$' + replaced + '$$' + decl.name.text; @@ -206,7 +211,11 @@ export class PrivateExportAliasingHost implements AliasingHost { * directive or pipe, if it exists. */ export class AliasStrategy implements ReferenceEmitStrategy { - emit(ref: Reference, context: ts.SourceFile, importMode: ImportMode): Expression|null { + emit(ref: Reference, context: ts.SourceFile, importMode: ImportFlags): Expression|null { + if (importMode & ImportFlags.NoAliasing) { + return null; + } + return ref.alias; } } diff --git a/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts index 4606d49ec9..6515cf49aa 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts @@ -8,25 +8,47 @@ import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; +import {UnifiedModulesHost} from '../../core/api'; import {LogicalFileSystem, LogicalProjectPath, PathSegment, absoluteFromSourceFile, dirname, relative} from '../../file_system'; import {stripExtension} from '../../file_system/src/util'; import {ReflectionHost} from '../../reflection'; -import {getSourceFile, isDeclaration, nodeNameForError} from '../../util/src/typescript'; +import {getSourceFile, isDeclaration, isTypeDeclaration, nodeNameForError} from '../../util/src/typescript'; import {findExportedNameOfNode} from './find_export'; -import {ImportMode, Reference} from './references'; +import {Reference} from './references'; import {ModuleResolver} from './resolver'; - /** - * 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. + * Flags which alter the imports generated by the `ReferenceEmitter`. */ -export interface FileToModuleHost { - fileNameToModuleName(importedFilePath: string, containingFilePath: string): string; +export enum ImportFlags { + None = 0x00, + + /** + * Force the generation of a new import when generating a reference, even if an identifier already + * exists in the target file which could be used instead. + * + * This is sometimes required if there's a risk TypeScript might remove imports during emit. + */ + ForceNewImport = 0x01, + + /** + * Don't make use of any aliasing information when emitting a reference. + * + * This is sometimes required if emitting into a context where generated references will be fed + * into TypeScript and type-checked (such as in template type-checking). + */ + NoAliasing = 0x02, + + /** + * Indicates that an import to a type-only declaration is allowed. + * + * For references that occur in type-positions, the referred declaration may be a type-only + * declaration that is not retained during emit. Including this flag allows to emit references to + * type-only declarations as used in e.g. template type-checking. + */ + AllowTypeImports = 0x04, } /** @@ -48,10 +70,10 @@ export interface ReferenceEmitStrategy { * * @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 + * @param importFlags 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; + emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags): Expression|null; } /** @@ -63,11 +85,10 @@ export interface ReferenceEmitStrategy { export class ReferenceEmitter { constructor(private strategies: ReferenceEmitStrategy[]) {} - emit( - ref: Reference, context: ts.SourceFile, - importMode: ImportMode = ImportMode.UseExistingImport): Expression { + emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags = ImportFlags.None): + Expression { for (const strategy of this.strategies) { - const emitted = strategy.emit(ref, context, importMode); + const emitted = strategy.emit(ref, context, importFlags); if (emitted !== null) { return emitted; } @@ -82,10 +103,10 @@ export class ReferenceEmitter { * such identifiers are available. */ export class LocalIdentifierStrategy implements ReferenceEmitStrategy { - emit(ref: Reference, context: ts.SourceFile, importMode: ImportMode): Expression|null { + emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags): 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 && + if (importFlags & ImportFlags.ForceNewImport && getSourceFile(ref.node) !== getSourceFile(context)) { return null; } @@ -121,14 +142,18 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy { protected program: ts.Program, protected checker: ts.TypeChecker, protected moduleResolver: ModuleResolver, private reflectionHost: ReflectionHost) {} - emit(ref: Reference, context: ts.SourceFile, importMode: ImportMode): Expression|null { + emit(ref: Reference, context: ts.SourceFile, importFlags: ImportFlags): 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?'); + throw new Error( + `Debug assert: unable to import a Reference to non-declaration of type ${ts.SyntaxKind[ref.node.kind]}.`); + } else if ((importFlags & ImportFlags.AllowTypeImports) === 0 && isTypeDeclaration(ref.node)) { + throw new Error( + `Importing a type-only declaration of type ${ts.SyntaxKind[ref.node.kind]} in a value position is not allowed.`); } // Try to find the exported name of the declaration, if one is available. @@ -255,10 +280,11 @@ export class RelativePathStrategy implements ReferenceEmitStrategy { } /** - * A `ReferenceEmitStrategy` which uses a `FileToModuleHost` to generate absolute import references. + * A `ReferenceEmitStrategy` which uses a `UnifiedModulesHost` to generate absolute import + * references. */ -export class FileToModuleStrategy implements ReferenceEmitStrategy { - constructor(private reflector: ReflectionHost, private fileToModuleHost: FileToModuleHost) {} +export class UnifiedModulesStrategy implements ReferenceEmitStrategy { + constructor(private reflector: ReflectionHost, private unifiedModulesHost: UnifiedModulesHost) {} emit(ref: Reference, context: ts.SourceFile): Expression|null { const destSf = getSourceFile(ref.node); @@ -268,7 +294,7 @@ export class FileToModuleStrategy implements ReferenceEmitStrategy { } const moduleName = - this.fileToModuleHost.fileNameToModuleName(destSf.fileName, context.fileName); + this.unifiedModulesHost.fileNameToModuleName(destSf.fileName, context.fileName); return new ExternalExpr({moduleName, name}); } diff --git a/packages/compiler-cli/src/ngtsc/imports/src/references.ts b/packages/compiler-cli/src/ngtsc/imports/src/references.ts index f2432d9c3f..8b1df442cc 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/references.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/references.ts @@ -11,11 +11,6 @@ import * as ts from 'typescript'; import {identifierOfNode} from '../../util/src/typescript'; -export enum ImportMode { - UseExistingImport, - ForceNewImport, -} - export interface OwningModule { specifier: string; resolutionContext: string; diff --git a/packages/compiler-cli/src/ngtsc/imports/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/imports/test/BUILD.bazel index 7b36f38e5e..44f7f734c1 100644 --- a/packages/compiler-cli/src/ngtsc/imports/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/imports/test/BUILD.bazel @@ -22,9 +22,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts b/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts index d67667e5ab..567c6143fa 100644 --- a/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts +++ b/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts @@ -8,18 +8,128 @@ import {ExternalExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {LogicalFileSystem, absoluteFrom} from '../../file_system'; -import {runInEachFileSystem} from '../../file_system/testing'; +import {LogicalFileSystem, absoluteFrom as _} from '../../file_system'; +import {TestFile, runInEachFileSystem} from '../../file_system/testing'; import {Declaration, TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing'; -import {LogicalProjectStrategy} from '../src/emitter'; +import {AbsoluteModuleStrategy, ImportFlags, LogicalProjectStrategy} from '../src/emitter'; import {Reference} from '../src/references'; +import {ModuleResolver} from '../src/resolver'; runInEachFileSystem(() => { - describe('LogicalProjectStrategy', () => { - let _: typeof absoluteFrom; - beforeEach(() => _ = absoluteFrom); + describe('AbsoluteModuleStrategy', () => { + function makeStrategy(files: TestFile[]) { + const {program, host} = makeProgram(files); + const checker = program.getTypeChecker(); + const moduleResolver = new ModuleResolver( + program, program.getCompilerOptions(), host, /* moduleResolutionCache */ null); + const strategy = new AbsoluteModuleStrategy( + program, checker, moduleResolver, new TypeScriptReflectionHost(checker)); + return {strategy, program}; + } + + it('should not generate an import for a reference without owning module', () => { + const {strategy, program} = makeStrategy([ + { + name: _('/node_modules/external.d.ts'), + contents: `export declare class Foo {}`, + }, + { + name: _('/context.ts'), + contents: 'export class Context {}', + }, + ]); + const decl = + getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration); + const context = program.getSourceFile(_('/context.ts')) !; + + const reference = new Reference(decl); + const emitted = strategy.emit(reference, context, ImportFlags.None); + expect(emitted).toBeNull(); + }); + + it('should generate an import using the exported name of the declaration', () => { + const {strategy, program} = makeStrategy([ + { + name: _('/node_modules/external.d.ts'), + contents: ` + declare class Foo {} + export {Foo as Bar}; + `, + }, + { + name: _('/context.ts'), + contents: 'export class Context {}', + }, + ]); + const decl = + getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration); + const context = program.getSourceFile(_('/context.ts')) !; + + const reference = new Reference(decl, { + specifier: 'external', + resolutionContext: context.fileName, + }); + const emitted = strategy.emit(reference, context, ImportFlags.None); + if (!(emitted instanceof ExternalExpr)) { + return fail('Reference should be emitted as ExternalExpr'); + } + expect(emitted.value.name).toEqual('Bar'); + expect(emitted.value.moduleName).toEqual('external'); + }); + + it('should throw when generating an import to a type-only declaration when not allowed', () => { + const {strategy, program} = makeStrategy([ + { + name: _('/node_modules/external.d.ts'), + contents: `export declare interface Foo {}`, + }, + { + name: _('/context.ts'), + contents: 'export class Context {}', + }, + ]); + const decl = getDeclaration( + program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration); + const context = program.getSourceFile(_('/context.ts')) !; + + const reference = new Reference(decl, { + specifier: 'external', + resolutionContext: context.fileName, + }); + expect(() => strategy.emit(reference, context, ImportFlags.None)) + .toThrowError( + 'Importing a type-only declaration of type InterfaceDeclaration in a value position is not allowed.'); + }); + + it('should generate an import to a type-only declaration when allowed', () => { + const {strategy, program} = makeStrategy([ + { + name: _('/node_modules/external.d.ts'), + contents: `export declare interface Foo {}`, + }, + { + name: _('/context.ts'), + contents: 'export class Context {}', + }, + ]); + const decl = getDeclaration( + program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration); + const context = program.getSourceFile(_('/context.ts')) !; + + const reference = + new Reference(decl, {specifier: 'external', resolutionContext: context.fileName}); + const emitted = strategy.emit(reference, context, ImportFlags.AllowTypeImports); + if (!(emitted instanceof ExternalExpr)) { + return fail('Reference should be emitted as ExternalExpr'); + } + expect(emitted.value.name).toEqual('Foo'); + expect(emitted.value.moduleName).toEqual('external'); + }); + }); + + describe('LogicalProjectStrategy', () => { it('should enumerate exports with the ReflectionHost', () => { // Use a modified ReflectionHost that prefixes all export names that it enumerates. class TestHost extends TypeScriptReflectionHost { diff --git a/packages/compiler-cli/src/ngtsc/incremental/BUILD.bazel b/packages/compiler-cli/src/ngtsc/incremental/BUILD.bazel index 2c162e8c23..9894e3e96e 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/incremental/BUILD.bazel @@ -9,6 +9,7 @@ ts_library( ]), deps = [ ":api", + "//packages/compiler-cli/src/ngtsc/file_system", "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/metadata", "//packages/compiler-cli/src/ngtsc/partial_evaluator", @@ -24,6 +25,7 @@ ts_library( name = "api", srcs = ["api.ts"], deps = [ + "//packages/compiler-cli/src/ngtsc/file_system", "@npm//typescript", ], ) diff --git a/packages/compiler-cli/src/ngtsc/incremental/src/README.md b/packages/compiler-cli/src/ngtsc/incremental/README.md similarity index 91% rename from packages/compiler-cli/src/ngtsc/incremental/src/README.md rename to packages/compiler-cli/src/ngtsc/incremental/README.md index 3c58db1b5a..6e0b4d5ed2 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/src/README.md +++ b/packages/compiler-cli/src/ngtsc/incremental/README.md @@ -88,9 +88,9 @@ On every invocation, the compiler receives (or can easily determine) several pie With this information, the compiler can perform rebuild optimizations: -1. The compiler uses the last good compilation's dependency graph to determine which parts of its analysis work can be reused. +1. The compiler uses the last good compilation's dependency graph to determine which parts of its analysis work can be reused, and an initial set of files which need to be re-emitted. 2. The compiler analyzes the rest of the program and generates an updated dependency graph, which describes the relationships between files in the program as they are currently. -3. Based on this graph, the compiler can make a determination for each TS file whether it needs to be re-emitted or can safely be skipped. This produces a set called `pendingEmit` of every file which requires a re-emit. +3. Based on this graph, the compiler can make a final determination for each TS file whether it needs to be re-emitted or can safely be skipped. This produces a set called `pendingEmit` of every file which requires a re-emit. 4. The compiler cycles through the files and emits those which are necessary, removing them from `pendingEmit`. Theoretically, after this process `pendingEmit` should be empty. As a precaution against errors which might happen in the future, `pendingEmit` is also passed into future compilations, so any files which previously were determined to need an emit (but have not been successfully produced yet) will be retried on subsequent compilations. This is mostly relevant if a client of `ngtsc` attempts to implement emit-on-error functionality. @@ -113,6 +113,12 @@ After analysis is successfully performed, the compiler uses its dependency graph If a new build is started after a successful build, only `pendingEmit` from the `AnalyzedBuildState` needs to be merged into the new build's `PendingBuildState`. +## Component to NgModule dependencies + +The dependency of a component on its NgModule is slightly problematic, because its arrow is in the opposite direction of the source dependency (which is from NgModule to the component, via `declarations`). This creates a scenario where, if the NgModule is changed to no longer include the component, the component still needs to be re-emitted because the module has changed. + +This is one of very few cases where `pendingEmit` must be populated with the logical changes from the previous program (those files determined to be changed in step 1 under "Tracking of changes" above), and cannot simply be created from the current dependency graph. + # What optimizations are possible in the future? There is plenty of room for improvement here, with diminishing returns for the work involved. diff --git a/packages/compiler-cli/src/ngtsc/incremental/api.ts b/packages/compiler-cli/src/ngtsc/incremental/api.ts index ec105ef17d..e987cd59ec 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/api.ts +++ b/packages/compiler-cli/src/ngtsc/incremental/api.ts @@ -7,6 +7,7 @@ */ import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../file_system'; /** * Interface of the incremental build engine. @@ -33,7 +34,7 @@ export interface DependencyTracker /** * Record that the file `from` depends on the resource file `on`. */ - addResourceDependency(from: T, on: string): void; + addResourceDependency(from: T, on: AbsoluteFsPath): void; /** * Record that the file `from` depends on the file `on` as well as `on`'s direct dependencies. diff --git a/packages/compiler-cli/src/ngtsc/incremental/index.ts b/packages/compiler-cli/src/ngtsc/incremental/index.ts index e4a3ff8580..506dd2bbfe 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/index.ts +++ b/packages/compiler-cli/src/ngtsc/incremental/index.ts @@ -6,4 +6,5 @@ * found in the LICENSE file at https://angular.io/license */ +export {NOOP_INCREMENTAL_BUILD} from './src/noop'; export {IncrementalDriver} from './src/state'; diff --git a/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts b/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts index 7fc810447c..fdd2f8ce1c 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts +++ b/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts @@ -8,6 +8,7 @@ import * as ts from 'typescript'; +import {AbsoluteFsPath} from '../../file_system'; import {DependencyTracker} from '../api'; /** @@ -28,7 +29,7 @@ export class FileDependencyGraph im addDependency(from: T, on: T): void { this.nodeFor(from).dependsOn.add(on.fileName); } - addResourceDependency(from: T, resource: string): void { + addResourceDependency(from: T, resource: AbsoluteFsPath): void { this.nodeFor(from).usesResources.add(resource); } @@ -50,7 +51,7 @@ export class FileDependencyGraph im } } - isStale(sf: T, changedTsPaths: Set, changedResources: Set): boolean { + isStale(sf: T, changedTsPaths: Set, changedResources: Set): boolean { return isLogicallyChanged(sf, this.nodeFor(sf), changedTsPaths, EMPTY_SET, changedResources); } @@ -77,7 +78,7 @@ export class FileDependencyGraph im */ updateWithPhysicalChanges( previous: FileDependencyGraph, changedTsPaths: Set, deletedTsPaths: Set, - changedResources: Set): Set { + changedResources: Set): Set { const logicallyChanged = new Set(); for (const sf of previous.nodes.keys()) { @@ -99,7 +100,7 @@ export class FileDependencyGraph im if (!this.nodes.has(sf)) { this.nodes.set(sf, { dependsOn: new Set(), - usesResources: new Set(), + usesResources: new Set(), }); } return this.nodes.get(sf) !; @@ -112,13 +113,13 @@ export class FileDependencyGraph im */ function isLogicallyChanged( sf: T, node: FileNode, changedTsPaths: ReadonlySet, deletedTsPaths: ReadonlySet, - changedResources: ReadonlySet): boolean { + changedResources: ReadonlySet): boolean { // A file is logically changed if it has physically changed itself (including being deleted). if (changedTsPaths.has(sf.fileName) || deletedTsPaths.has(sf.fileName)) { return true; } - // A file is logically changed if one of its dependencies has physically cxhanged. + // A file is logically changed if one of its dependencies has physically changed. for (const dep of node.dependsOn) { if (changedTsPaths.has(dep) || deletedTsPaths.has(dep)) { return true; @@ -136,7 +137,7 @@ function isLogicallyChanged( interface FileNode { dependsOn: Set; - usesResources: Set; + usesResources: Set; } const EMPTY_SET: ReadonlySet = new Set(); diff --git a/packages/compiler-cli/src/ngtsc/incremental/src/noop.ts b/packages/compiler-cli/src/ngtsc/incremental/src/noop.ts new file mode 100644 index 0000000000..3ad486d2c4 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/incremental/src/noop.ts @@ -0,0 +1,13 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {IncrementalBuild} from '../api'; + +export const NOOP_INCREMENTAL_BUILD: IncrementalBuild = { + priorWorkFor: () => null +}; diff --git a/packages/compiler-cli/src/ngtsc/incremental/src/state.ts b/packages/compiler-cli/src/ngtsc/incremental/src/state.ts index 529e0bda46..21f3ef680b 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/src/state.ts +++ b/packages/compiler-cli/src/ngtsc/incremental/src/state.ts @@ -8,6 +8,7 @@ import * as ts from 'typescript'; +import {AbsoluteFsPath, absoluteFrom} from '../../file_system'; import {ClassRecord, TraitCompiler} from '../../transform'; import {IncrementalBuild} from '../api'; @@ -52,7 +53,7 @@ export class IncrementalDriver implements IncrementalBuild { state = { kind: BuildStateKind.Pending, pendingEmit: oldDriver.state.pendingEmit, - changedResourcePaths: new Set(), + changedResourcePaths: new Set(), changedTsPaths: new Set(), lastGood: oldDriver.state.lastGood, }; @@ -61,7 +62,7 @@ export class IncrementalDriver implements IncrementalBuild { // Merge the freshly modified resource files with any prior ones. if (modifiedResourceFiles !== null) { for (const resFile of modifiedResourceFiles) { - state.changedResourcePaths.add(resFile); + state.changedResourcePaths.add(absoluteFrom(resFile)); } } @@ -127,6 +128,16 @@ export class IncrementalDriver implements IncrementalBuild { for (const fileName of state.changedTsPaths) { logicalChanges.add(fileName); } + + // Any logically changed files need to be re-emitted. Most of the time this would happen + // regardless because the new dependency graph would _also_ identify the file as stale. + // However there are edge cases such as removing a component from an NgModule without adding + // it to another one, where the previous graph identifies the file as logically changed, but + // the new graph (which does not have that edge) fails to identify that the file should be + // re-emitted. + for (const change of logicalChanges) { + state.pendingEmit.add(change); + } } // `state` now reflects the initial pending state of the current compilation. @@ -143,7 +154,7 @@ export class IncrementalDriver implements IncrementalBuild { const state: PendingBuildState = { kind: BuildStateKind.Pending, pendingEmit: new Set(tsFiles.map(sf => sf.fileName)), - changedResourcePaths: new Set(), + changedResourcePaths: new Set(), changedTsPaths: new Set(), lastGood: null, }; @@ -277,7 +288,7 @@ interface PendingBuildState extends BaseBuildState { /** * Set of resource file paths which have changed since the last successfully analyzed build. */ - changedResourcePaths: Set; + changedResourcePaths: Set; } interface AnalyzedBuildState extends BaseBuildState { diff --git a/packages/compiler-cli/src/ngtsc/indexer/index.ts b/packages/compiler-cli/src/ngtsc/indexer/index.ts index ba903a8a61..12028775bd 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/index.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/index.ts @@ -8,3 +8,4 @@ export * from './src/api'; export {IndexingContext} from './src/context'; +export {generateAnalysis} from './src/transform'; diff --git a/packages/compiler-cli/src/ngtsc/indexer/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/indexer/test/BUILD.bazel index cc98a4fbab..0fa0fc3270 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/indexer/test/BUILD.bazel @@ -23,9 +23,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts b/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts index bb85d24aa4..137151ed5b 100644 --- a/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts +++ b/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts @@ -9,7 +9,7 @@ import {ExpressionType, ExternalExpr, R3Identifiers as Identifiers, Type} from '@angular/compiler'; import * as ts from 'typescript'; -import {ImportMode, Reference, ReferenceEmitter} from '../../imports'; +import {ImportFlags, Reference, ReferenceEmitter} from '../../imports'; import {PartialEvaluator, ResolvedValueMap} from '../../partial_evaluator'; import {ReflectionHost} from '../../reflection'; @@ -98,7 +98,7 @@ export class ModuleWithProvidersScanner { } const ngModuleExpr = - this.emitter.emit(ngModule, decl.getSourceFile(), ImportMode.ForceNewImport); + this.emitter.emit(ngModule, decl.getSourceFile(), ImportFlags.ForceNewImport); const ngModuleType = new ExpressionType(ngModuleExpr); const mwpNgType = new ExpressionType( new ExternalExpr(Identifiers.ModuleWithProviders), /* modifiers */ null, [ngModuleType]); diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts index 6e40825840..36636f7919 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts @@ -12,25 +12,25 @@ import {DynamicValue} from './dynamic'; import {BuiltinFn, ResolvedValue, ResolvedValueArray} from './result'; export class ArraySliceBuiltinFn extends BuiltinFn { - constructor(private node: ts.Node, private lhs: ResolvedValueArray) { super(); } + constructor(private lhs: ResolvedValueArray) { super(); } - evaluate(args: ResolvedValueArray): ResolvedValue { + evaluate(node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue { if (args.length === 0) { return this.lhs; } else { - return DynamicValue.fromUnknown(this.node); + return DynamicValue.fromUnknown(node); } } } export class ArrayConcatBuiltinFn extends BuiltinFn { - constructor(private node: ts.Node, private lhs: ResolvedValueArray) { super(); } + constructor(private lhs: ResolvedValueArray) { super(); } - evaluate(args: ResolvedValueArray): ResolvedValue { + evaluate(node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue { const result: ResolvedValueArray = [...this.lhs]; for (const arg of args) { if (arg instanceof DynamicValue) { - result.push(DynamicValue.fromDynamicInput(this.node, arg)); + result.push(DynamicValue.fromDynamicInput(node, arg)); } else if (Array.isArray(arg)) { result.push(...arg); } else { @@ -40,3 +40,23 @@ export class ArrayConcatBuiltinFn extends BuiltinFn { return result; } } + +export class ObjectAssignBuiltinFn extends BuiltinFn { + evaluate(node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue { + if (args.length === 0) { + return DynamicValue.fromUnsupportedSyntax(node); + } + for (const arg of args) { + if (arg instanceof DynamicValue) { + return DynamicValue.fromDynamicInput(node, arg); + } else if (!(arg instanceof Map)) { + return DynamicValue.fromUnsupportedSyntax(node); + } + } + const [target, ...sources] = args as Map[]; + for (const source of sources) { + source.forEach((value, key) => target.set(key, value)); + } + return target; + } +} diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts index f038b74e70..21e3e04985 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts @@ -17,6 +17,7 @@ import {isDeclaration} from '../../util/src/typescript'; import {ArrayConcatBuiltinFn, ArraySliceBuiltinFn} from './builtin'; import {DynamicValue} from './dynamic'; import {ForeignFunctionResolver} from './interface'; +import {resolveKnownDeclaration} from './known_declaration'; import {BuiltinFn, EnumValue, ResolvedModule, ResolvedValue, ResolvedValueArray, ResolvedValueMap} from './result'; import {evaluateTsHelperInline} from './ts_helpers'; @@ -229,6 +230,9 @@ export class StaticInterpreter { return DynamicValue.fromUnknownIdentifier(node); } } + if (decl.known !== null) { + return resolveKnownDeclaration(decl.known); + } const declContext = {...context, ...joinModuleContext(context, node, decl)}; // The identifier's declaration is either concrete (a ts.Declaration exists for it) or inline // (a direct reference to a ts.Expression). @@ -357,9 +361,9 @@ export class StaticInterpreter { if (rhs === 'length') { return lhs.length; } else if (rhs === 'slice') { - return new ArraySliceBuiltinFn(node, lhs); + return new ArraySliceBuiltinFn(lhs); } else if (rhs === 'concat') { - return new ArrayConcatBuiltinFn(node, lhs); + return new ArrayConcatBuiltinFn(lhs); } if (typeof rhs !== 'number' || !Number.isInteger(rhs)) { return DynamicValue.fromInvalidExpressionType(node, rhs); @@ -401,7 +405,7 @@ export class StaticInterpreter { // If the call refers to a builtin function, attempt to evaluate the function. if (lhs instanceof BuiltinFn) { - return lhs.evaluate(this.evaluateFunctionArguments(node, context)); + return lhs.evaluate(node, this.evaluateFunctionArguments(node, context)); } if (!(lhs instanceof Reference)) { diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/known_declaration.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/known_declaration.ts new file mode 100644 index 0000000000..0ba3484afe --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/known_declaration.ts @@ -0,0 +1,29 @@ +/** + * @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 {KnownDeclaration} from '../../reflection/src/host'; + +import {ObjectAssignBuiltinFn} from './builtin'; +import {ResolvedValue} from './result'; + +/** Resolved value for the JavaScript global `Object` declaration .*/ +export const jsGlobalObjectValue = new Map([['assign', new ObjectAssignBuiltinFn()]]); + +/** + * Resolves the specified known declaration to a resolved value. For example, + * the known JavaScript global `Object` will resolve to a `Map` that provides the + * `assign` method with a builtin function. This enables evaluation of `Object.assign`. + */ +export function resolveKnownDeclaration(decl: KnownDeclaration): ResolvedValue { + switch (decl) { + case KnownDeclaration.JsGlobalObject: + return jsGlobalObjectValue; + default: + throw new Error(`Cannot resolve known declaration. Received: ${KnownDeclaration[decl]}.`); + } +} diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts index 0cacefbc74..aafd8b31dd 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts @@ -78,4 +78,6 @@ export class EnumValue { /** * An implementation of a builtin function, such as `Array.prototype.slice`. */ -export abstract class BuiltinFn { abstract evaluate(args: ResolvedValueArray): ResolvedValue; } +export abstract class BuiltinFn { + abstract evaluate(node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue; +} diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/ts_helpers.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/ts_helpers.ts index 055586b327..c4e894bfb1 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/ts_helpers.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/ts_helpers.ts @@ -10,17 +10,29 @@ import * as ts from 'typescript'; import {TsHelperFn} from '../../reflection'; +import {ObjectAssignBuiltinFn} from './builtin'; import {DynamicValue} from './dynamic'; import {ResolvedValue, ResolvedValueArray} from './result'; + +/** + * Instance of the `Object.assign` builtin function. Used for evaluating + * the "__assign" TypeScript helper. + */ +const objectAssignBuiltinFn = new ObjectAssignBuiltinFn(); + export function evaluateTsHelperInline( - helper: TsHelperFn, node: ts.Node, args: ResolvedValueArray): ResolvedValue { + helper: TsHelperFn, node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue { switch (helper) { + case TsHelperFn.Assign: + // Use the same implementation we use for `Object.assign`. Semantically these + // functions are the same, so they can also share the same evaluation code. + return objectAssignBuiltinFn.evaluate(node, args); case TsHelperFn.Spread: case TsHelperFn.SpreadArrays: return evaluateTsSpreadHelper(node, args); default: - throw new Error(`Cannot evaluate unknown helper ${helper} inline`); + throw new Error(`Cannot evaluate TypeScript helper function: ${TsHelperFn[helper]}`); } } diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel index 11c584fa0f..fce987b98d 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/BUILD.bazel @@ -24,9 +24,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index 218a371ee1..68495ddb08 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -580,6 +580,29 @@ runInEachFileSystem(() => { expect(value).toEqual([1, 2, 3]); }); + it('should evaluate TypeScript __assign helper', () => { + const {checker, expression} = makeExpression( + ` + import * as tslib from 'tslib'; + const a = {a: true}; + const b = {b: true}; + `, + 'tslib.__assign(a, b)', [ + { + name: _('/node_modules/tslib/index.d.ts'), + contents: ` + export declare function __assign(...args: object[]): object; + ` + }, + ]); + const reflectionHost = new TsLibAwareReflectionHost(checker); + const evaluator = new PartialEvaluator(reflectionHost, checker, null); + const map = evaluator.evaluate(expression) as Map; + const obj: {[key: string]: boolean} = {}; + map.forEach((value, key) => obj[key] = value); + expect(obj).toEqual({a: true, b: true}); + }); + describe('(visited file tracking)', () => { it('should track each time a source file is visited', () => { const addDependency = jasmine.createSpy('DependencyTracker'); @@ -666,6 +689,8 @@ runInEachFileSystem(() => { const name = node.name !== undefined && ts.isIdentifier(node.name) && node.name.text; switch (name) { + case '__assign': + return TsHelperFn.Assign; case '__spread': return TsHelperFn.Spread; case '__spreadArrays': diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index d086b7f694..6a3e22925d 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -6,371 +6,147 @@ * found in the LICENSE file at https://angular.io/license */ -import {GeneratedFile, Type} from '@angular/compiler'; +import {GeneratedFile} from '@angular/compiler'; import * as ts from 'typescript'; import * as api from '../transformers/api'; import {nocollapseHack} from '../transformers/nocollapse_hack'; import {verifySupportedTypeScriptVersion} from '../typescript_support'; -import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from './annotations'; -import {CycleAnalyzer, ImportGraph} from './cycles'; -import {ErrorCode, ngErrorCode} from './diagnostics'; -import {FlatIndexGenerator, ReferenceGraph, checkForPrivateExports, findFlatIndexEntryPoint} from './entry_point'; -import {AbsoluteFsPath, LogicalFileSystem, absoluteFrom} from './file_system'; -import {AbsoluteModuleStrategy, AliasStrategy, AliasingHost, DefaultImportTracker, FileToModuleAliasingHost, FileToModuleHost, FileToModuleStrategy, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, PrivateExportAliasingHost, R3SymbolsImportRewriter, Reference, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy} from './imports'; -import {IncrementalDriver} from './incremental'; -import {IndexedComponent, IndexingContext} from './indexer'; -import {generateAnalysis} from './indexer/src/transform'; -import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, LocalMetadataRegistry, MetadataReader} from './metadata'; -import {InjectableClassRegistry} from './metadata/src/registry'; -import {ModuleWithProvidersScanner} from './modulewithproviders'; -import {PartialEvaluator} from './partial_evaluator'; +import {NgCompilerHost} from './core'; +import {NgCompilerOptions} from './core/api'; +import {NgCompiler} from './core/src/compiler'; +import {IndexedComponent} from './indexer'; import {NOOP_PERF_RECORDER, PerfRecorder, PerfTracker} from './perf'; -import {TypeScriptReflectionHost} from './reflection'; -import {HostResourceLoader} from './resource_loader'; -import {NgModuleRouteAnalyzer, entryPointKeyFor} from './routing'; -import {ComponentScopeReader, CompoundComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from './scope'; -import {FactoryGenerator, FactoryTracker, GeneratedShimsHostWrapper, ShimGenerator, SummaryGenerator, TypeCheckShimGenerator, generatedFactoryTransform} from './shims'; -import {ivySwitchTransform} from './switch'; -import {DecoratorHandler, DtsTransformRegistry, TraitCompiler, declarationTransformFactory, ivyTransformFactory} from './transform'; -import {aliasTransformFactory} from './transform/src/alias'; -import {TypeCheckContext, TypeCheckingConfig, typeCheckFilePath} from './typecheck'; -import {normalizeSeparators} from './util/src/path'; -import {getRootDirs, getSourceFileOrNull, isDtsPath, resolveModuleName} from './util/src/typescript'; + + +/** + * Entrypoint to the Angular Compiler (Ivy+) which sits behind the `api.Program` interface, allowing + * it to be a drop-in replacement for the legacy View Engine compiler to tooling such as the + * command-line main() function or the Angular CLI. + */ export class NgtscProgram implements api.Program { + private compiler: NgCompiler; + + /** + * The primary TypeScript program, which is used for analysis and emit. + */ private tsProgram: ts.Program; + + /** + * The TypeScript program to use for the next incremental compilation. + * + * Once a TS program is used to create another (an incremental compilation operation), it can no + * longer be used to do so again. + * + * Since template type-checking uses the primary program to create a type-checking program, after + * this happens the primary program is no longer suitable for starting a subsequent compilation, + * and the template type-checking program should be used instead. + * + * Thus, the program which should be used for the next incremental compilation is tracked in + * `reuseTsProgram`, separately from the "primary" program which is always used for emit. + */ private reuseTsProgram: ts.Program; - private resourceManager: HostResourceLoader; - private compilation: TraitCompiler|undefined = undefined; - private _coreImportsFrom: ts.SourceFile|null|undefined = undefined; - private _importRewriter: ImportRewriter|undefined = undefined; - private _reflector: TypeScriptReflectionHost|undefined = undefined; - private _isCore: boolean|undefined = undefined; - 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 scopeRegistry: LocalModuleScopeRegistry|null = null; - - private constructionDiagnostics: ts.Diagnostic[] = []; - private moduleResolver: ModuleResolver; - private cycleAnalyzer: CycleAnalyzer; - private metaReader: MetadataReader|null = null; - - private aliasingHost: AliasingHost|null = null; - private refEmitter: ReferenceEmitter|null = null; - private fileToModuleHost: FileToModuleHost|null = null; - private defaultImportTracker: DefaultImportTracker; + private host: NgCompilerHost; private perfRecorder: PerfRecorder = NOOP_PERF_RECORDER; private perfTracker: PerfTracker|null = null; - private incrementalDriver: IncrementalDriver; - private typeCheckFilePath: AbsoluteFsPath; - private factoryTracker: FactoryTracker|null = null; - - private modifiedResourceFiles: Set|null; - private dtsTransforms: DtsTransformRegistry|null = null; - private mwpScanner: ModuleWithProvidersScanner|null = null; constructor( - rootNames: ReadonlyArray, private options: api.CompilerOptions, - private host: api.CompilerHost, oldProgram?: NgtscProgram) { + rootNames: ReadonlyArray, private options: NgCompilerOptions, + delegateHost: api.CompilerHost, oldProgram?: NgtscProgram) { + // First, check whether the current TS version is supported. if (!options.disableTypeScriptVersionCheck) { verifySupportedTypeScriptVersion(); } - const incompatibleTypeCheckOptionsDiagnostic = verifyCompatibleTypeCheckOptions(options); - if (incompatibleTypeCheckOptionsDiagnostic !== null) { - this.constructionDiagnostics.push(incompatibleTypeCheckOptionsDiagnostic); - } - - if (shouldEnablePerfTracing(options)) { + if (options.tracePerformance !== undefined) { this.perfTracker = PerfTracker.zeroedToNow(); this.perfRecorder = this.perfTracker; } - - this.modifiedResourceFiles = - this.host.getModifiedResourceFiles && this.host.getModifiedResourceFiles() || null; - this.rootDirs = getRootDirs(host, options); this.closureCompilerEnabled = !!options.annotateForClosureCompiler; - this.resourceManager = new HostResourceLoader(host, options); - // TODO(alxhub): remove the fallback to allowEmptyCodegenFiles after verifying that the rest of - // our build tooling is no longer relying on it. - const allowEmptyCodegenFiles = options.allowEmptyCodegenFiles || false; - const shouldGenerateFactoryShims = options.generateNgFactoryShims !== undefined ? - options.generateNgFactoryShims : - allowEmptyCodegenFiles; - const shouldGenerateSummaryShims = options.generateNgSummaryShims !== undefined ? - options.generateNgSummaryShims : - allowEmptyCodegenFiles; - const normalizedRootNames = rootNames.map(n => absoluteFrom(n)); - if (host.fileNameToModuleName !== undefined) { - this.fileToModuleHost = host as FileToModuleHost; - } - let rootFiles = [...rootNames]; - const generators: ShimGenerator[] = []; - let summaryGenerator: SummaryGenerator|null = null; - if (shouldGenerateSummaryShims) { - // Summary generation. - summaryGenerator = SummaryGenerator.forRootFiles(normalizedRootNames); - generators.push(summaryGenerator); - } + this.host = NgCompilerHost.wrap(delegateHost, rootNames, options); - if (shouldGenerateFactoryShims) { - // Factory generation. - const factoryGenerator = FactoryGenerator.forRootFiles(normalizedRootNames); - const factoryFileMap = factoryGenerator.factoryFileMap; - - const factoryFileNames = Array.from(factoryFileMap.keys()); - rootFiles.push(...factoryFileNames); - generators.push(factoryGenerator); - - this.factoryTracker = new FactoryTracker(factoryGenerator); - } - - // Done separately to preserve the order of factory files before summary files in rootFiles. - // TODO(alxhub): validate that this is necessary. - if (shouldGenerateSummaryShims) { - rootFiles.push(...summaryGenerator !.getSummaryFileNames()); - } - - this.typeCheckFilePath = typeCheckFilePath(this.rootDirs); - generators.push(new TypeCheckShimGenerator(this.typeCheckFilePath)); - rootFiles.push(this.typeCheckFilePath); - - let entryPoint: AbsoluteFsPath|null = null; - if (options.flatModuleOutFile != null && options.flatModuleOutFile !== '') { - entryPoint = findFlatIndexEntryPoint(normalizedRootNames); - 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 - // module entry point instead. If neither of these conditions apply, the error below is - // given. - // - // The user is not informed about the "index.ts" option as this behavior is deprecated - - // an explicit entrypoint should always be specified. - 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); - } - } - - if (generators.length > 0) { - // FIXME: Remove the any cast once google3 is fully on TS3.6. - this.host = (new GeneratedShimsHostWrapper(host, generators) as any); - } - - this.tsProgram = - ts.createProgram(rootFiles, options, this.host, oldProgram && oldProgram.reuseTsProgram); + const reuseProgram = oldProgram && oldProgram.reuseTsProgram; + this.tsProgram = ts.createProgram(this.host.inputFiles, options, this.host, reuseProgram); this.reuseTsProgram = this.tsProgram; - this.entryPoint = entryPoint !== null ? getSourceFileOrNull(this.tsProgram, entryPoint) : null; - const moduleResolutionCache = ts.createModuleResolutionCache( - this.host.getCurrentDirectory(), fileName => this.host.getCanonicalFileName(fileName)); - this.moduleResolver = - new ModuleResolver(this.tsProgram, options, this.host, moduleResolutionCache); - this.cycleAnalyzer = new CycleAnalyzer(new ImportGraph(this.moduleResolver)); - this.defaultImportTracker = new DefaultImportTracker(); - if (oldProgram === undefined) { - this.incrementalDriver = IncrementalDriver.fresh(this.tsProgram); - } else { - this.incrementalDriver = IncrementalDriver.reconcile( - oldProgram.reuseTsProgram, oldProgram.incrementalDriver, this.tsProgram, - this.modifiedResourceFiles); - } + // Create the NgCompiler which will drive the rest of the compilation. + this.compiler = + new NgCompiler(this.host, options, this.tsProgram, reuseProgram, this.perfRecorder); } getTsProgram(): ts.Program { return this.tsProgram; } getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken| - undefined): ReadonlyArray { + undefined): readonly ts.Diagnostic[] { return this.tsProgram.getOptionsDiagnostics(cancellationToken); } - getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken| - undefined): ReadonlyArray { - return this.constructionDiagnostics; - } - getTsSyntacticDiagnostics( sourceFile?: ts.SourceFile|undefined, - cancellationToken?: ts.CancellationToken|undefined): ReadonlyArray { + cancellationToken?: ts.CancellationToken|undefined): readonly ts.Diagnostic[] { return this.tsProgram.getSyntacticDiagnostics(sourceFile, cancellationToken); } - getNgStructuralDiagnostics(cancellationToken?: ts.CancellationToken| - undefined): ReadonlyArray { - return []; - } - getTsSemanticDiagnostics( sourceFile?: ts.SourceFile|undefined, - cancellationToken?: ts.CancellationToken|undefined): ReadonlyArray { + cancellationToken?: ts.CancellationToken|undefined): readonly ts.Diagnostic[] { return this.tsProgram.getSemanticDiagnostics(sourceFile, cancellationToken); } + getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken| + undefined): readonly(ts.Diagnostic|api.Diagnostic)[] { + return this.compiler.getOptionDiagnostics(); + } + + getNgStructuralDiagnostics(cancellationToken?: ts.CancellationToken| + undefined): readonly api.Diagnostic[] { + return []; + } + getNgSemanticDiagnostics( - fileName?: string|undefined, - cancellationToken?: ts.CancellationToken|undefined): ReadonlyArray { - const compilation = this.ensureAnalyzed(); - const diagnostics = [...compilation.diagnostics, ...this.getTemplateDiagnostics()]; - if (this.entryPoint !== null && this.exportReferenceGraph !== null) { - diagnostics.push(...checkForPrivateExports( - this.entryPoint, this.tsProgram.getTypeChecker(), this.exportReferenceGraph)); + fileName?: string|undefined, cancellationToken?: ts.CancellationToken| + undefined): readonly(ts.Diagnostic|api.Diagnostic)[] { + let sf: ts.SourceFile|undefined = undefined; + if (fileName !== undefined) { + sf = this.tsProgram.getSourceFile(fileName); + if (sf === undefined) { + // There are no diagnostics for files which don't exist in the program - maybe the caller + // has stale data? + return []; + } } + + const diagnostics = this.compiler.getDiagnostics(sf); + this.reuseTsProgram = this.compiler.getNextProgram(); return diagnostics; } - async loadNgStructureAsync(): Promise { - if (this.compilation === undefined) { - this.compilation = this.makeCompilation(); - } - const analyzeSpan = this.perfRecorder.start('analyze'); - const promises: Promise[] = []; - for (const sf of this.tsProgram.getSourceFiles()) { - if (sf.isDeclarationFile) { - continue; - } - - const analyzeFileSpan = this.perfRecorder.start('analyzeFile', sf); - let analysisPromise = this.compilation !.analyzeAsync(sf); - this.scanForMwp(sf); - if (analysisPromise === undefined) { - this.perfRecorder.stop(analyzeFileSpan); - } else if (this.perfRecorder.enabled) { - analysisPromise = analysisPromise.then(() => this.perfRecorder.stop(analyzeFileSpan)); - } - if (analysisPromise !== undefined) { - promises.push(analysisPromise); - } - } - - await Promise.all(promises); - - this.perfRecorder.stop(analyzeSpan); - - this.resolveCompilation(this.compilation); - } + /** + * Ensure that the `NgCompiler` has properly analyzed the program, and allow for the asynchronous + * loading of any resources during the process. + * + * This is used by the Angular CLI to allow for spawning (async) child compilations for things + * like SASS files used in `styleUrls`. + */ + loadNgStructureAsync(): Promise { return this.compiler.analyzeAsync(); } 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( - `Failed 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 resolvedModule = - resolveModuleName(entryPath, containingFile, this.options, this.host, null); - - if (resolvedModule) { - entryRoute = entryPointKeyFor(resolvedModule.resolvedFileName, moduleName); - } - } - - this.ensureAnalyzed(); - return this.routeAnalyzer !.listLazyRoutes(entryRoute); - } - - getLibrarySummaries(): Map { - throw new Error('Method not implemented.'); - } - - getEmittedGeneratedFiles(): Map { - throw new Error('Method not implemented.'); - } - - getEmittedSourceFiles(): Map { - throw new Error('Method not implemented.'); - } - - private scanForMwp(sf: ts.SourceFile): void { - this.mwpScanner !.scan(sf, { - addTypeReplacement: (node: ts.Declaration, type: Type): void => { - // Only obtain the return type transform for the source file once there's a type to replace, - // so that no transform is allocated when there's nothing to do. - this.dtsTransforms !.getReturnTypeTransform(sf).addTypeReplacement(node, type); - } - }); - } - - private ensureAnalyzed(): TraitCompiler { - if (this.compilation === undefined) { - const analyzeSpan = this.perfRecorder.start('analyze'); - this.compilation = this.makeCompilation(); - for (const sf of this.tsProgram.getSourceFiles()) { - if (sf.isDeclarationFile) { - continue; - } - const analyzeFileSpan = this.perfRecorder.start('analyzeFile', sf); - this.compilation !.analyzeSync(sf); - this.scanForMwp(sf); - this.perfRecorder.stop(analyzeFileSpan); - } - this.perfRecorder.stop(analyzeSpan); - - this.resolveCompilation(this.compilation); - } - return this.compilation; - } - - private resolveCompilation(compilation: TraitCompiler): void { - compilation.resolve(); - - this.recordNgModuleScopeDependencies(); - - // At this point, analysis is complete and the compiler can now calculate which files need to - // be emitted, so do that. - this.incrementalDriver.recordSuccessfulAnalysis(compilation); + return this.compiler.listLazyRoutes(entryRoute); } emit(opts?: { - emitFlags?: api.EmitFlags, - cancellationToken?: ts.CancellationToken, - customTransformers?: api.CustomTransformers, - emitCallback?: api.TsEmitCallback, - mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback - }): ts.EmitResult { + emitFlags?: api.EmitFlags | undefined; cancellationToken?: ts.CancellationToken | undefined; + customTransformers?: api.CustomTransformers | undefined; + emitCallback?: api.TsEmitCallback | undefined; + mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback | undefined; + }|undefined): ts.EmitResult { + const {transformers, ignoreFiles} = this.compiler.prepareEmit(); const emitCallback = opts && opts.emitCallback || defaultEmitCallback; - const compilation = this.ensureAnalyzed(); - const writeFile: ts.WriteFileCallback = (fileName: string, data: string, writeByteOrderMark: boolean, onError: ((message: string) => void) | undefined, @@ -383,9 +159,16 @@ export class NgtscProgram implements api.Program { continue; } - this.incrementalDriver.recordSuccessfulEmit(writtenSf); + this.compiler.incrementalDriver.recordSuccessfulEmit(writtenSf); } } + + // If Closure annotations are being produced, tsickle should be adding `@nocollapse` to + // any static fields present. However, tsickle doesn't yet handle synthetic fields added + // during other transformations, so this hack is in place to ensure Ivy definitions get + // properly annotated, pending an upstream fix in tsickle. + // + // TODO(alxhub): remove when tsickle properly annotates synthetic fields. if (this.closureCompilerEnabled && fileName.endsWith('.js')) { data = nocollapseHack(data); } @@ -393,46 +176,22 @@ export class NgtscProgram implements api.Program { }; const customTransforms = opts && opts.customTransformers; + const beforeTransforms = transformers.before || []; + const afterDeclarationsTransforms = transformers.afterDeclarations; - const beforeTransforms = [ - ivyTransformFactory( - compilation, this.reflector, this.importRewriter, this.defaultImportTracker, this.isCore, - this.closureCompilerEnabled), - aliasTransformFactory(compilation.exportStatements) as ts.TransformerFactory, - this.defaultImportTracker.importPreservingTransformer(), - ]; - - const afterDeclarationsTransforms: ts.TransformerFactory[] = []; - if (this.dtsTransforms !== null) { - afterDeclarationsTransforms.push( - declarationTransformFactory(this.dtsTransforms, this.importRewriter)); - } - - // Only add aliasing re-exports to the .d.ts output if the `AliasingHost` requests it. - if (this.aliasingHost !== null && this.aliasingHost.aliasExportsInDts) { - afterDeclarationsTransforms.push(aliasTransformFactory(compilation.exportStatements)); - } - - if (this.factoryTracker !== null) { - beforeTransforms.push( - generatedFactoryTransform(this.factoryTracker.sourceInfo, this.importRewriter)); - } - beforeTransforms.push(ivySwitchTransform); - if (customTransforms && customTransforms.beforeTs) { + if (customTransforms !== undefined && customTransforms.beforeTs !== undefined) { beforeTransforms.push(...customTransforms.beforeTs); } const emitSpan = this.perfRecorder.start('emit'); const emitResults: ts.EmitResult[] = []; - const typeCheckFile = getSourceFileOrNull(this.tsProgram, this.typeCheckFilePath); - for (const targetSourceFile of this.tsProgram.getSourceFiles()) { - if (targetSourceFile.isDeclarationFile || targetSourceFile === typeCheckFile) { + if (targetSourceFile.isDeclarationFile || ignoreFiles.has(targetSourceFile)) { continue; } - if (this.incrementalDriver.safeToSkipEmit(targetSourceFile)) { + if (this.compiler.incrementalDriver.safeToSkipEmit(targetSourceFile)) { continue; } @@ -447,7 +206,7 @@ export class NgtscProgram implements api.Program { before: beforeTransforms, after: customTransforms && customTransforms.afterTs, afterDeclarations: afterDeclarationsTransforms, - }, + } as any, })); this.perfRecorder.stop(fileEmitSpan); } @@ -461,318 +220,20 @@ export class NgtscProgram implements api.Program { return ((opts && opts.mergeEmitResultsCallback) || mergeEmitResults)(emitResults); } - private getTemplateDiagnostics(): ReadonlyArray { - // Determine the strictness level of type checking based on compiler options. As - // `strictTemplates` is a superset of `fullTemplateTypeCheck`, the former implies the latter. - // Also see `verifyCompatibleTypeCheckOptions` where it is verified that `fullTemplateTypeCheck` - // is not disabled when `strictTemplates` is enabled. - const strictTemplates = !!this.options.strictTemplates; - const fullTemplateTypeCheck = strictTemplates || !!this.options.fullTemplateTypeCheck; - - // Skip template type-checking if it's disabled. - if (this.options.ivyTemplateTypeCheck === false && !fullTemplateTypeCheck) { - return []; - } - - const compilation = this.ensureAnalyzed(); - - // Run template type-checking. - - // First select a type-checking configuration, based on whether full template type-checking is - // requested. - let typeCheckingConfig: TypeCheckingConfig; - if (fullTemplateTypeCheck) { - typeCheckingConfig = { - applyTemplateContextGuards: strictTemplates, - checkQueries: false, - checkTemplateBodies: true, - checkTypeOfInputBindings: strictTemplates, - strictNullInputBindings: strictTemplates, - checkTypeOfAttributes: strictTemplates, - // Even in full template type-checking mode, DOM binding checks are not quite ready yet. - checkTypeOfDomBindings: false, - checkTypeOfOutputEvents: strictTemplates, - checkTypeOfAnimationEvents: strictTemplates, - // Checking of DOM events currently has an adverse effect on developer experience, - // e.g. for `` enabling this check results in: - // - error TS2531: Object is possibly 'null'. - // - error TS2339: Property 'value' does not exist on type 'EventTarget'. - checkTypeOfDomEvents: strictTemplates, - checkTypeOfDomReferences: strictTemplates, - // Non-DOM references have the correct type in View Engine so there is no strictness flag. - checkTypeOfNonDomReferences: true, - // Pipes are checked in View Engine so there is no strictness flag. - checkTypeOfPipes: true, - strictSafeNavigationTypes: strictTemplates, - }; - } else { - typeCheckingConfig = { - applyTemplateContextGuards: false, - checkQueries: false, - checkTemplateBodies: false, - checkTypeOfInputBindings: false, - strictNullInputBindings: false, - checkTypeOfAttributes: false, - checkTypeOfDomBindings: false, - checkTypeOfOutputEvents: false, - checkTypeOfAnimationEvents: false, - checkTypeOfDomEvents: false, - checkTypeOfDomReferences: false, - checkTypeOfNonDomReferences: false, - checkTypeOfPipes: false, - strictSafeNavigationTypes: false, - }; - } - - // Apply explicitly configured strictness flags on top of the default configuration - // based on "fullTemplateTypeCheck". - if (this.options.strictInputTypes !== undefined) { - typeCheckingConfig.checkTypeOfInputBindings = this.options.strictInputTypes; - typeCheckingConfig.applyTemplateContextGuards = this.options.strictInputTypes; - } - if (this.options.strictNullInputTypes !== undefined) { - typeCheckingConfig.strictNullInputBindings = this.options.strictNullInputTypes; - } - if (this.options.strictOutputEventTypes !== undefined) { - typeCheckingConfig.checkTypeOfOutputEvents = this.options.strictOutputEventTypes; - typeCheckingConfig.checkTypeOfAnimationEvents = this.options.strictOutputEventTypes; - } - if (this.options.strictDomEventTypes !== undefined) { - typeCheckingConfig.checkTypeOfDomEvents = this.options.strictDomEventTypes; - } - if (this.options.strictSafeNavigationTypes !== undefined) { - typeCheckingConfig.strictSafeNavigationTypes = this.options.strictSafeNavigationTypes; - } - if (this.options.strictDomLocalRefTypes !== undefined) { - typeCheckingConfig.checkTypeOfDomReferences = this.options.strictDomLocalRefTypes; - } - if (this.options.strictAttributeTypes !== undefined) { - typeCheckingConfig.checkTypeOfAttributes = this.options.strictAttributeTypes; - } - - // Execute the typeCheck phase of each decorator in the program. - const prepSpan = this.perfRecorder.start('typeCheckPrep'); - const ctx = new TypeCheckContext( - typeCheckingConfig, this.refEmitter !, this.reflector, this.typeCheckFilePath); - compilation.typeCheck(ctx); - this.perfRecorder.stop(prepSpan); - - // Get the diagnostics. - const typeCheckSpan = this.perfRecorder.start('typeCheckDiagnostics'); - const {diagnostics, program} = - ctx.calculateTemplateDiagnostics(this.tsProgram, this.host, this.options); - this.perfRecorder.stop(typeCheckSpan); - this.reuseTsProgram = program; - - return diagnostics; - } - getIndexedComponents(): Map { - const compilation = this.ensureAnalyzed(); - const context = new IndexingContext(); - compilation.index(context); - return generateAnalysis(context); + return this.compiler.getIndexedComponents(); } - private makeCompilation(): TraitCompiler { - const checker = this.tsProgram.getTypeChecker(); - - // Construct the ReferenceEmitter. - if (this.fileToModuleHost === null || !this.options._useHostForImportGeneration) { - let localImportStrategy: ReferenceEmitStrategy; - - // The strategy used for local, in-project imports depends on whether TS has been configured - // with rootDirs. If so, then multiple directories may be mapped in the same "module - // namespace" and the logic of `LogicalProjectStrategy` is required to generate correct - // imports which may cross these multiple directories. Otherwise, plain relative imports are - // sufficient. - if (this.options.rootDir !== undefined || - (this.options.rootDirs !== undefined && this.options.rootDirs.length > 0)) { - // rootDirs logic is in effect - use the `LogicalProjectStrategy` for in-project relative - // imports. - localImportStrategy = - new LogicalProjectStrategy(this.reflector, new LogicalFileSystem(this.rootDirs)); - } else { - // Plain relative imports are all that's needed. - localImportStrategy = new RelativePathStrategy(this.reflector); - } - - // 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.moduleResolver, this.reflector), - // Finally, check if the reference is being written into a file within the project's .ts - // sources, and use a relative import if so. If this fails, ReferenceEmitter will throw - // an error. - localImportStrategy, - ]); - - // If an entrypoint is present, then all user imports should be directed through the - // entrypoint and private exports are not needed. The compiler will validate that all publicly - // visible directives/pipes are importable via this entrypoint. - if (this.entryPoint === null && this.options.generateDeepReexports === true) { - // No entrypoint is present and deep re-exports were requested, so configure the aliasing - // system to generate them. - this.aliasingHost = new PrivateExportAliasingHost(this.reflector); - } - } 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 aliased references (this is a workaround to StrictDeps checks). - new AliasStrategy(), - // Then use fileNameToModuleName to emit imports. - new FileToModuleStrategy(this.reflector, this.fileToModuleHost), - ]); - this.aliasingHost = new FileToModuleAliasingHost(this.fileToModuleHost); - } - - const evaluator = - new PartialEvaluator(this.reflector, checker, this.incrementalDriver.depGraph); - const dtsReader = new DtsMetadataReader(checker, this.reflector); - const localMetaRegistry = new LocalMetadataRegistry(); - const localMetaReader: MetadataReader = localMetaRegistry; - const depScopeReader = new MetadataDtsModuleScopeResolver(dtsReader, this.aliasingHost); - this.scopeRegistry = new LocalModuleScopeRegistry( - localMetaReader, depScopeReader, this.refEmitter, this.aliasingHost); - const scopeReader: ComponentScopeReader = this.scopeRegistry; - const metaRegistry = new CompoundMetadataRegistry([localMetaRegistry, this.scopeRegistry]); - const injectableRegistry = new InjectableClassRegistry(this.reflector); - - this.metaReader = new CompoundMetadataReader([localMetaReader, dtsReader]); - - - // 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); - - this.dtsTransforms = new DtsTransformRegistry(); - - this.mwpScanner = new ModuleWithProvidersScanner(this.reflector, evaluator, this.refEmitter); - - // Set up the IvyCompilation, which manages state for the Ivy transformer. - const handlers: DecoratorHandler[] = [ - new ComponentDecoratorHandler( - this.reflector, evaluator, metaRegistry, this.metaReader !, scopeReader, - this.scopeRegistry, this.isCore, this.resourceManager, this.rootDirs, - this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false, - this.options.enableI18nLegacyMessageIdFormat !== false, this.moduleResolver, - this.cycleAnalyzer, this.refEmitter, this.defaultImportTracker, - this.incrementalDriver.depGraph, injectableRegistry, this.closureCompilerEnabled), - // TODO(alxhub): understand why the cast here is necessary (something to do with `null` not - // being assignable to `unknown` when wrapped in `Readonly`). - // clang-format off - new DirectiveDecoratorHandler( - this.reflector, evaluator, metaRegistry, this.scopeRegistry, this.metaReader, - this.defaultImportTracker, injectableRegistry, this.isCore, this.closureCompilerEnabled - ) as Readonly>, - // clang-format on - // Pipe handler must be before injectable handler in list so pipe factories are printed - // before injectable factories (so injectable factories can delegate to them) - new PipeDecoratorHandler( - this.reflector, evaluator, metaRegistry, this.scopeRegistry, this.defaultImportTracker, - injectableRegistry, this.isCore), - new InjectableDecoratorHandler( - this.reflector, this.defaultImportTracker, this.isCore, - this.options.strictInjectionParameters || false, injectableRegistry), - new NgModuleDecoratorHandler( - this.reflector, evaluator, this.metaReader, metaRegistry, this.scopeRegistry, - referencesRegistry, this.isCore, this.routeAnalyzer, this.refEmitter, this.factoryTracker, - this.defaultImportTracker, this.closureCompilerEnabled, injectableRegistry, - this.options.i18nInLocale), - ]; - - return new TraitCompiler( - handlers, this.reflector, this.perfRecorder, this.incrementalDriver, - this.options.compileNonExportedClasses !== false, this.dtsTransforms); + getLibrarySummaries(): Map { + throw new Error('Method not implemented.'); } - /** - * Reifies the inter-dependencies of NgModules and the components within their compilation scopes - * into the `IncrementalDriver`'s dependency graph. - */ - private recordNgModuleScopeDependencies() { - const recordSpan = this.perfRecorder.start('recordDependencies'); - const depGraph = this.incrementalDriver.depGraph; - - for (const scope of this.scopeRegistry !.getCompilationScopes()) { - const file = scope.declaration.getSourceFile(); - const ngModuleFile = scope.ngModule.getSourceFile(); - - // A change to any dependency of the declaration causes the declaration to be invalidated, - // which requires the NgModule to be invalidated as well. - depGraph.addTransitiveDependency(ngModuleFile, file); - - // A change to the NgModule file should cause the declaration itself to be invalidated. - depGraph.addDependency(file, ngModuleFile); - - const meta = this.metaReader !.getDirectiveMetadata(new Reference(scope.declaration)); - if (meta !== null && meta.isComponent) { - // If a component's template changes, it might have affected the import graph, and thus the - // remote scoping feature which is activated in the event of potential import cycles. Thus, - // the module depends not only on the transitive dependencies of the component, but on its - // resources as well. - depGraph.addTransitiveResources(ngModuleFile, file); - - // A change to any directive/pipe in the compilation scope should cause the component to be - // invalidated. - for (const directive of scope.directives) { - // When a directive in scope is updated, the component needs to be recompiled as e.g. a - // selector may have changed. - depGraph.addTransitiveDependency(file, directive.ref.node.getSourceFile()); - } - for (const pipe of scope.pipes) { - // When a pipe in scope is updated, the component needs to be recompiled as e.g. the - // pipe's name may have changed. - depGraph.addTransitiveDependency(file, pipe.ref.node.getSourceFile()); - } - } - } - this.perfRecorder.stop(recordSpan); + getEmittedGeneratedFiles(): Map { + throw new Error('Method not implemented.'); } - private get reflector(): TypeScriptReflectionHost { - if (this._reflector === undefined) { - this._reflector = new TypeScriptReflectionHost(this.tsProgram.getTypeChecker()); - } - return this._reflector; - } - - private get coreImportsFrom(): ts.SourceFile|null { - if (this._coreImportsFrom === undefined) { - this._coreImportsFrom = this.isCore && getR3SymbolsFile(this.tsProgram) || null; - } - return this._coreImportsFrom; - } - - private get isCore(): boolean { - if (this._isCore === undefined) { - this._isCore = isAngularCorePackage(this.tsProgram); - } - 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; + getEmittedSourceFiles(): Map { + throw new Error('Method not implemented.'); } } @@ -794,100 +255,3 @@ function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult { return {diagnostics, emitSkipped, emittedFiles}; } - -/** - * Find the 'r3_symbols.ts' file in the given `Program`, or return `null` if it wasn't there. - */ -function getR3SymbolsFile(program: ts.Program): ts.SourceFile|null { - return program.getSourceFiles().find(file => file.fileName.indexOf('r3_symbols.ts') >= 0) || null; -} - -/** - * Determine if the given `Program` is @angular/core. - */ -function isAngularCorePackage(program: ts.Program): boolean { - // Look for its_just_angular.ts somewhere in the program. - const r3Symbols = getR3SymbolsFile(program); - if (r3Symbols === null) { - return false; - } - - // Look for the constant ITS_JUST_ANGULAR in that file. - return r3Symbols.statements.some(stmt => { - // The statement must be a variable declaration statement. - if (!ts.isVariableStatement(stmt)) { - return false; - } - // It must be exported. - if (stmt.modifiers === undefined || - !stmt.modifiers.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword)) { - return false; - } - // It must declare ITS_JUST_ANGULAR. - return stmt.declarationList.declarations.some(decl => { - // The declaration must match the name. - if (!ts.isIdentifier(decl.name) || decl.name.text !== 'ITS_JUST_ANGULAR') { - return false; - } - // It must initialize the variable to true. - if (decl.initializer === undefined || decl.initializer.kind !== ts.SyntaxKind.TrueKeyword) { - return false; - } - // This definition matches. - return true; - }); - }); -} - -/** - * Since "strictTemplates" is a true superset of type checking capabilities compared to - * "strictTemplateTypeCheck", it is required that the latter is not explicitly disabled if the - * former is enabled. - */ -function verifyCompatibleTypeCheckOptions(options: api.CompilerOptions): ts.Diagnostic|null { - if (options.fullTemplateTypeCheck === false && options.strictTemplates === true) { - return { - category: ts.DiagnosticCategory.Error, - code: ngErrorCode(ErrorCode.CONFIG_STRICT_TEMPLATES_IMPLIES_FULL_TEMPLATE_TYPECHECK), - file: undefined, - start: undefined, - length: undefined, - messageText: - `Angular compiler option "strictTemplates" is enabled, however "fullTemplateTypeCheck" is disabled. - -Having the "strictTemplates" flag enabled implies that "fullTemplateTypeCheck" is also enabled, so -the latter can not be explicitly disabled. - -One of the following actions is required: -1. Remove the "fullTemplateTypeCheck" option. -2. Remove "strictTemplates" or set it to 'false'. - -More information about the template type checking compiler options can be found in the documentation: -https://v9.angular.io/guide/template-typecheck#template-type-checking`, - }; - } - - return null; -} - -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); - } - } - } -} - -function shouldEnablePerfTracing(options: api.CompilerOptions): boolean { - return options.tracePerformance !== undefined; -} diff --git a/packages/compiler-cli/src/ngtsc/reflection/src/host.ts b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts index 74c0a5e598..431930550b 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts @@ -332,6 +332,10 @@ export interface FunctionDefinition { * Possible functions from TypeScript's helper library. */ export enum TsHelperFn { + /** + * Indicates the `__assign` function. + */ + Assign, /** * Indicates the `__spread` function. */ @@ -342,6 +346,16 @@ export enum TsHelperFn { SpreadArrays, } +/** + * Possible declarations which are known. + */ +export enum KnownDeclaration { + /** + * Indicates the JavaScript global `Object` class. + */ + JsGlobalObject, +} + /** * A parameter to a function or method. */ @@ -395,6 +409,11 @@ export interface BaseDeclaration { * TypeScript reference to the declaration itself, if one exists. */ node: T|null; + + /** + * If set, describes the type of the known declaration this declaration resolves to. + */ + known: KnownDeclaration|null; } /** diff --git a/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts index 7fddda5784..d1f8b424b5 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts @@ -35,8 +35,12 @@ export class TypeScriptReflectionHost implements ReflectionHost { getConstructorParameters(clazz: ClassDeclaration): CtorParameter[]|null { const tsClazz = castDeclarationToClassOrDie(clazz); - // First, find the constructor. - const ctor = tsClazz.members.find(ts.isConstructorDeclaration); + // First, find the constructor with a `body`. The constructors without a `body` are overloads + // whereas we want the implementation since it's the one that'll be executed and which can + // have decorators. + const ctor = tsClazz.members.find( + (member): member is ts.ConstructorDeclaration => + ts.isConstructorDeclaration(member) && member.body !== undefined); if (ctor === undefined) { return null; } @@ -94,7 +98,7 @@ export class TypeScriptReflectionHost implements ReflectionHost { getExportsOfModule(node: ts.Node): Map|null { // In TypeScript code, modules are only ts.SourceFiles. Throw if the node isn't a module. if (!ts.isSourceFile(node)) { - throw new Error(`getDeclarationsOfModule() called on non-SourceFile in TS code`); + throw new Error(`getExportsOfModule() called on non-SourceFile in TS code`); } const map = new Map(); @@ -304,12 +308,12 @@ export class TypeScriptReflectionHost implements ReflectionHost { if (symbol.valueDeclaration !== undefined) { return { node: symbol.valueDeclaration, - viaModule, + known: null, viaModule, }; } else if (symbol.declarations !== undefined && symbol.declarations.length > 0) { return { node: symbol.declarations[0], - viaModule, + known: null, viaModule, }; } else { return null; @@ -564,4 +568,4 @@ function getExportedName(decl: ts.Declaration, originalId: ts.Identifier): strin return ts.isImportSpecifier(decl) ? (decl.propertyName !== undefined ? decl.propertyName : decl.name).text : originalId.text; -} \ No newline at end of file +} diff --git a/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel index b786eade07..0ef634cd56 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/reflection/test/BUILD.bazel @@ -20,9 +20,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts index 8f2bfe8615..9427afb376 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts @@ -211,6 +211,29 @@ runInEachFileSystem(() => { expect(args.length).toBe(1); expectParameter(args[0], 'bar', {moduleName: './bar', name: 'Bar'}); }); + + it('should reflect the arguments from an overloaded constructor', () => { + const {program} = makeProgram([{ + name: _('/entry.ts'), + contents: ` + class Bar {} + class Baz {} + + class Foo { + constructor(bar: Bar); + constructor(bar: Bar, baz?: Baz) {} + } + ` + }]); + const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); + const checker = program.getTypeChecker(); + const host = new TypeScriptReflectionHost(checker); + const args = host.getConstructorParameters(clazz) !; + expect(args.length).toBe(2); + expectParameter(args[0], 'bar', 'Bar'); + expectParameter(args[1], 'baz', 'Baz'); + }); + }); @@ -339,6 +362,7 @@ runInEachFileSystem(() => { const decl = host.getDeclarationOfIdentifier(Target); expect(decl).toEqual({ node: targetDecl, + known: null, viaModule: 'absolute', }); }); @@ -368,6 +392,7 @@ runInEachFileSystem(() => { const decl = host.getDeclarationOfIdentifier(Target); expect(decl).toEqual({ node: targetDecl, + known: null, viaModule: 'absolute', }); }); diff --git a/packages/compiler-cli/src/ngtsc/resource/BUILD.bazel b/packages/compiler-cli/src/ngtsc/resource/BUILD.bazel new file mode 100644 index 0000000000..bc36525bb9 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/resource/BUILD.bazel @@ -0,0 +1,19 @@ +load("//tools:defaults.bzl", "ts_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "resource", + srcs = ["index.ts"] + glob([ + "src/*.ts", + ]), + module_name = "@angular/compiler-cli/src/ngtsc/resource", + deps = [ + "//packages:types", + "//packages/compiler-cli/src/ngtsc/annotations", + "//packages/compiler-cli/src/ngtsc/core:api", + "//packages/compiler-cli/src/ngtsc/file_system", + "//packages/compiler-cli/src/ngtsc/util", + "@npm//typescript", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/resource/index.ts b/packages/compiler-cli/src/ngtsc/resource/index.ts new file mode 100644 index 0000000000..8a2e80db12 --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/resource/index.ts @@ -0,0 +1,9 @@ +/** + * @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 {HostResourceLoader} from './src/loader'; diff --git a/packages/compiler-cli/src/ngtsc/resource_loader.ts b/packages/compiler-cli/src/ngtsc/resource/src/loader.ts similarity index 94% rename from packages/compiler-cli/src/ngtsc/resource_loader.ts rename to packages/compiler-cli/src/ngtsc/resource/src/loader.ts index a4fa568017..041b8f0594 100644 --- a/packages/compiler-cli/src/ngtsc/resource_loader.ts +++ b/packages/compiler-cli/src/ngtsc/resource/src/loader.ts @@ -8,13 +8,12 @@ import * as ts from 'typescript'; -import {CompilerHost} from '../transformers/api'; +import {ResourceLoader} from '../../annotations'; +import {ExtendedTsCompilerHost} from '../../core/api'; +import {AbsoluteFsPath, PathSegment, join} from '../../file_system'; +import {getRootDirs} from '../../util/src/typescript'; -import {ResourceLoader} from './annotations'; -import {AbsoluteFsPath, PathSegment, join} from './file_system'; -import {getRootDirs} from './util/src/typescript'; - -const CSS_PREPROCESSOR_EXT = /(\.scss|\.less|\.styl)$/; +const CSS_PREPROCESSOR_EXT = /(\.scss|\.sass|\.less|\.styl)$/; /** * `ResourceLoader` which delegates to a `CompilerHost` resource loading method. @@ -27,7 +26,7 @@ export class HostResourceLoader implements ResourceLoader { canPreload = !!this.host.readResource; - constructor(private host: CompilerHost, private options: ts.CompilerOptions) { + constructor(private host: ExtendedTsCompilerHost, private options: ts.CompilerOptions) { this.rootDirs = getRootDirs(host, options); } diff --git a/packages/compiler-cli/src/ngtsc/scope/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/scope/test/BUILD.bazel index 4869bbf684..3dbf78b9d8 100644 --- a/packages/compiler-cli/src/ngtsc/scope/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/scope/test/BUILD.bazel @@ -11,6 +11,7 @@ ts_library( deps = [ "//packages:types", "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/core:api", "//packages/compiler-cli/src/ngtsc/file_system", "//packages/compiler-cli/src/ngtsc/file_system/testing", "//packages/compiler-cli/src/ngtsc/imports", @@ -24,9 +25,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts b/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts index 22251c8351..5e5e36522a 100644 --- a/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts +++ b/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts @@ -8,9 +8,10 @@ import {ExternalExpr, ExternalReference} from '@angular/compiler'; import * as ts from 'typescript'; +import {UnifiedModulesHost} from '../../core/api'; import {absoluteFrom} from '../../file_system'; import {runInEachFileSystem} from '../../file_system/testing'; -import {AliasingHost, FileToModuleAliasingHost, FileToModuleHost, Reference} from '../../imports'; +import {AliasingHost, Reference, UnifiedModulesAliasingHost} from '../../imports'; import {DtsMetadataReader} from '../../metadata'; import {ClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {makeProgram} from '../../testing'; @@ -19,7 +20,7 @@ import {MetadataDtsModuleScopeResolver} from '../src/dependency'; const MODULE_FROM_NODE_MODULES_PATH = /.*node_modules\/(\w+)\/index\.d\.ts$/; -const testHost: FileToModuleHost = { +const testHost: UnifiedModulesHost = { fileNameToModuleName: function(imported: string): string { const res = MODULE_FROM_NODE_MODULES_PATH.exec(imported) !; return 'root/' + res[1]; @@ -183,7 +184,7 @@ runInEachFileSystem(() => { } `, }, - new FileToModuleAliasingHost(testHost)); + new UnifiedModulesAliasingHost(testHost)); const {ShallowModule} = refs; const scope = resolver.resolve(ShallowModule) !; const [DeepDir, MiddleDir, ShallowDir] = scopeToRefs(scope); @@ -233,7 +234,7 @@ runInEachFileSystem(() => { } `, }, - new FileToModuleAliasingHost(testHost)); + new UnifiedModulesAliasingHost(testHost)); const {ShallowModule} = refs; const scope = resolver.resolve(ShallowModule) !; const [DeepDir, MiddleDir, ShallowDir] = scopeToRefs(scope); @@ -266,7 +267,7 @@ runInEachFileSystem(() => { } `, }, - new FileToModuleAliasingHost(testHost)); + new UnifiedModulesAliasingHost(testHost)); const {DeepExportModule} = refs; const scope = resolver.resolve(DeepExportModule) !; const [DeepDir] = scopeToRefs(scope); diff --git a/packages/compiler-cli/src/ngtsc/shims/index.ts b/packages/compiler-cli/src/ngtsc/shims/index.ts index 7d05c29a8e..84515bd501 100644 --- a/packages/compiler-cli/src/ngtsc/shims/index.ts +++ b/packages/compiler-cli/src/ngtsc/shims/index.ts @@ -8,8 +8,8 @@ /// +export {ShimGenerator} from './src/api'; export {FactoryGenerator, FactoryInfo, generatedFactoryTransform} from './src/factory_generator'; export {FactoryTracker} from './src/factory_tracker'; -export {GeneratedShimsHostWrapper, ShimGenerator} from './src/host'; export {SummaryGenerator} from './src/summary_generator'; export {TypeCheckShimGenerator} from './src/typecheck_shim'; diff --git a/packages/compiler-cli/src/ngtsc/shims/src/api.ts b/packages/compiler-cli/src/ngtsc/shims/src/api.ts new file mode 100644 index 0000000000..33abf9b90d --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/shims/src/api.ts @@ -0,0 +1,27 @@ +/** + * @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 {AbsoluteFsPath} from '../../file_system'; + +export interface ShimGenerator { + /** + * Returns `true` if this generator is intended to handle the given file. + */ + recognize(fileName: AbsoluteFsPath): boolean; + + /** + * Generate a shim's `ts.SourceFile` for the given original file. + * + * `readFile` is a function which allows the generator to look up the contents of existing source + * files. It returns null if the requested file doesn't exist. + * + * If `generate` returns null, then the shim generator declines to generate the file after all. + */ + generate(genFileName: AbsoluteFsPath, readFile: (fileName: string) => ts.SourceFile | null): + ts.SourceFile|null; +} \ No newline at end of file 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 6f68065418..dcbf28a975 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts @@ -11,7 +11,7 @@ import {AbsoluteFsPath, absoluteFrom, basename} from '../../file_system'; import {ImportRewriter} from '../../imports'; import {isNonDeclarationTsPath} from '../../util/src/typescript'; -import {ShimGenerator} from './host'; +import {ShimGenerator} from './api'; import {generatedModuleName} from './util'; const TS_DTS_SUFFIX = /(\.d)?\.ts$/; diff --git a/packages/compiler-cli/src/ngtsc/shims/src/host.ts b/packages/compiler-cli/src/ngtsc/shims/src/host.ts deleted file mode 100644 index 0c5c6cfc7c..0000000000 --- a/packages/compiler-cli/src/ngtsc/shims/src/host.ts +++ /dev/null @@ -1,129 +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 ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom, resolve} from '../../file_system'; - -export interface ShimGenerator { - /** - * Returns `true` if this generator is intended to handle the given file. - */ - recognize(fileName: AbsoluteFsPath): boolean; - - /** - * Generate a shim's `ts.SourceFile` for the given original file. - * - * `readFile` is a function which allows the generator to look up the contents of existing source - * files. It returns null if the requested file doesn't exist. - * - * If `generate` returns null, then the shim generator declines to generate the file after all. - */ - generate(genFileName: AbsoluteFsPath, readFile: (fileName: string) => ts.SourceFile | null): - ts.SourceFile|null; -} - -/** - * A wrapper around a `ts.CompilerHost` which supports generated files. - */ -export class GeneratedShimsHostWrapper implements ts.CompilerHost { - constructor(private delegate: ts.CompilerHost, private shimGenerators: ShimGenerator[]) { - if (delegate.resolveModuleNames !== undefined) { - this.resolveModuleNames = - (moduleNames: string[], containingFile: string, reusedNames: string[], - redirectedReference: ts.ResolvedProjectReference, options?: ts.CompilerOptions) => - // FIXME: Additional parameters are required in TS3.6, but ignored in 3.5. - // Remove the any cast once google3 is fully on TS3.6. - (delegate.resolveModuleNames as any) !( - moduleNames, containingFile, reusedNames, redirectedReference, options); - } - if (delegate.resolveTypeReferenceDirectives) { - // Backward compatibility with TypeScript 2.9 and older since return - // type has changed from (ts.ResolvedTypeReferenceDirective | undefined)[] - // to ts.ResolvedTypeReferenceDirective[] in Typescript 3.0 - type ts3ResolveTypeReferenceDirectives = (names: string[], containingFile: string) => - ts.ResolvedTypeReferenceDirective[]; - this.resolveTypeReferenceDirectives = (names: string[], containingFile: string) => - (delegate.resolveTypeReferenceDirectives as ts3ResolveTypeReferenceDirectives) !( - names, containingFile); - } - if (delegate.directoryExists !== undefined) { - this.directoryExists = (directoryName: string) => delegate.directoryExists !(directoryName); - } - if (delegate.getDirectories !== undefined) { - this.getDirectories = (path: string) => delegate.getDirectories !(path); - } - } - - // FIXME: Additional options param is needed in TS3.6, but not alloowed in 3.5. - // Make the options param non-optional once google3 is fully on TS3.6. - resolveModuleNames?: - (moduleNames: string[], containingFile: string, reusedNames: string[], - redirectedReference: ts.ResolvedProjectReference, - options?: ts.CompilerOptions) => (ts.ResolvedModule | undefined)[]; - - resolveTypeReferenceDirectives?: - (names: string[], containingFile: string) => ts.ResolvedTypeReferenceDirective[]; - - directoryExists?: (directoryName: string) => boolean; - - getSourceFile( - fileName: string, languageVersion: ts.ScriptTarget, - onError?: ((message: string) => void)|undefined, - shouldCreateNewSourceFile?: boolean|undefined): ts.SourceFile|undefined { - for (let i = 0; i < this.shimGenerators.length; i++) { - const generator = this.shimGenerators[i]; - // TypeScript internal paths are guaranteed to be POSIX-like absolute file paths. - const absoluteFsPath = resolve(fileName); - if (generator.recognize(absoluteFsPath)) { - const readFile = (originalFile: string) => { - return this.delegate.getSourceFile( - originalFile, languageVersion, onError, shouldCreateNewSourceFile) || - null; - }; - - return generator.generate(absoluteFsPath, readFile) || undefined; - } - } - return this.delegate.getSourceFile( - fileName, languageVersion, onError, shouldCreateNewSourceFile); - } - - getDefaultLibFileName(options: ts.CompilerOptions): string { - return this.delegate.getDefaultLibFileName(options); - } - - writeFile( - fileName: string, data: string, writeByteOrderMark: boolean, - onError: ((message: string) => void)|undefined, - sourceFiles: ReadonlyArray|undefined): void { - return this.delegate.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles); - } - - getCurrentDirectory(): string { return this.delegate.getCurrentDirectory(); } - - getDirectories?: (path: string) => string[]; - - getCanonicalFileName(fileName: string): string { - return this.delegate.getCanonicalFileName(fileName); - } - - useCaseSensitiveFileNames(): boolean { return this.delegate.useCaseSensitiveFileNames(); } - - getNewLine(): string { return this.delegate.getNewLine(); } - - fileExists(fileName: string): boolean { - // Consider the file as existing whenever - // 1) it really does exist in the delegate host, or - // 2) at least one of the shim generators recognizes it - // Note that we can pass the file name as branded absolute fs path because TypeScript - // internally only passes POSIX-like paths. - return this.delegate.fileExists(fileName) || - this.shimGenerators.some(gen => gen.recognize(absoluteFrom(fileName))); - } - - readFile(fileName: string): string|undefined { return this.delegate.readFile(fileName); } -} 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 6085cb6045..4fde6790c4 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts @@ -11,7 +11,7 @@ import * as ts from 'typescript'; import {AbsoluteFsPath, absoluteFrom} from '../../file_system'; import {isNonDeclarationTsPath} from '../../util/src/typescript'; -import {ShimGenerator} from './host'; +import {ShimGenerator} from './api'; import {generatedModuleName} from './util'; export class SummaryGenerator implements ShimGenerator { diff --git a/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts b/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts index d444132266..8f9d5247db 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {AbsoluteFsPath} from '../../file_system'; -import {ShimGenerator} from './host'; +import {ShimGenerator} from './api'; /** * A `ShimGenerator` which adds a type-checking file to the `ts.Program`. diff --git a/packages/compiler-cli/src/ngtsc/shims/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/shims/test/BUILD.bazel index de435dc818..97fe53bf43 100644 --- a/packages/compiler-cli/src/ngtsc/shims/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/shims/test/BUILD.bazel @@ -17,9 +17,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/shims/test/host_spec.ts b/packages/compiler-cli/src/ngtsc/shims/test/host_spec.ts deleted file mode 100644 index e047855eed..0000000000 --- a/packages/compiler-cli/src/ngtsc/shims/test/host_spec.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 * as ts from 'typescript'; - -import {GeneratedShimsHostWrapper} from '../src/host'; - -describe('shim host', () => { - it('should not have optional methods when delegate does not have them', function() { - const delegate = {} as unknown as ts.CompilerHost; - const shimsHost = new GeneratedShimsHostWrapper(delegate, []); - - expect(shimsHost.resolveModuleNames).not.toBeDefined(); - expect(shimsHost.resolveTypeReferenceDirectives).not.toBeDefined(); - expect(shimsHost.directoryExists).not.toBeDefined(); - expect(shimsHost.getDirectories).not.toBeDefined(); - }); - - it('should delegate optional methods if available', function() { - const delegate = { - resolveModuleNames: () => undefined, - resolveTypeReferenceDirectives: () => undefined, - directoryExists: () => undefined, - getDirectories: () => undefined, - } as unknown as ts.CompilerHost; - const shimsHost = new GeneratedShimsHostWrapper(delegate, []); - - expect(shimsHost.resolveModuleNames).toBeDefined(); - expect(shimsHost.resolveTypeReferenceDirectives).toBeDefined(); - expect(shimsHost.directoryExists).toBeDefined(); - expect(shimsHost.getDirectories).toBeDefined(); - }); -}); diff --git a/packages/compiler-cli/src/ngtsc/testing/src/utils.ts b/packages/compiler-cli/src/ngtsc/testing/src/utils.ts index 27eb587c2d..a71b7d21c3 100644 --- a/packages/compiler-cli/src/ngtsc/testing/src/utils.ts +++ b/packages/compiler-cli/src/ngtsc/testing/src/utils.ts @@ -76,7 +76,9 @@ export function getDeclaration( chosenDecl = decl; } }); - } else if (ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node)) { + } else if ( + ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node) || + ts.isInterfaceDeclaration(node)) { if (node.name !== undefined && node.name.text === name) { chosenDecl = node; } diff --git a/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel b/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel index e3e6309dbc..4a61e72a18 100644 --- a/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/transform/BUILD.bazel @@ -9,6 +9,7 @@ ts_library( ]), deps = [ "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/core:api", "//packages/compiler-cli/src/ngtsc/diagnostics", "//packages/compiler-cli/src/ngtsc/imports", "//packages/compiler-cli/src/ngtsc/incremental:api", diff --git a/packages/compiler-cli/src/ngtsc/transform/index.ts b/packages/compiler-cli/src/ngtsc/transform/index.ts index ca7d7f3167..bc98e8bb76 100644 --- a/packages/compiler-cli/src/ngtsc/transform/index.ts +++ b/packages/compiler-cli/src/ngtsc/transform/index.ts @@ -7,6 +7,8 @@ */ export * from './src/api'; +export {aliasTransformFactory} from './src/alias'; export {ClassRecord, TraitCompiler} from './src/compilation'; export {declarationTransformFactory, DtsTransformRegistry, IvyDeclarationDtsTransform, ReturnTypeTransform} from './src/declaration'; +export {AnalyzedTrait, ErroredTrait, PendingTrait, ResolvedTrait, SkippedTrait, Trait, TraitState} from './src/trait'; export {ivyTransformFactory} from './src/transform'; diff --git a/packages/compiler-cli/src/ngtsc/transform/src/alias.ts b/packages/compiler-cli/src/ngtsc/transform/src/alias.ts index 359d3bf44f..f7698f29e6 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/alias.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/alias.ts @@ -9,9 +9,9 @@ import * as ts from 'typescript'; export function aliasTransformFactory(exportStatements: Map>): - ts.TransformerFactory { + ts.TransformerFactory { return (context: ts.TransformationContext) => { - return (file: ts.SourceFile | ts.Bundle) => { + return (file: ts.SourceFile) => { if (ts.isBundle(file) || !exportStatements.has(file.fileName)) { return file; } diff --git a/packages/compiler-cli/src/ngtsc/transform/src/api.ts b/packages/compiler-cli/src/ngtsc/transform/src/api.ts index 236e24befe..59ba1df358 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/api.ts @@ -153,8 +153,26 @@ export interface DecoratorHandler { constantPool: ConstantPool): CompileResult|CompileResult[]; } +/** + * The output of detecting a trait for a declaration as the result of the first phase of the + * compilation pipeline. + */ export interface DetectResult { + /** + * The node that triggered the match, which is typically a decorator. + */ trigger: ts.Node|null; + + /** + * Refers to the decorator that was recognized for this detection, if any. This can be a concrete + * decorator that is actually present in a file, or a synthetic decorator as inserted + * programmatically. + */ + decorator: Decorator|null; + + /** + * An arbitrary object to carry over from the detection phase into the analysis phase. + */ metadata: Readonly; } diff --git a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts index 84d32fc1d5..e103aadd31 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts @@ -6,22 +6,20 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, Type} from '@angular/compiler'; +import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; -import {ImportRewriter} from '../../imports'; import {IncrementalBuild} from '../../incremental/api'; import {IndexingContext} from '../../indexer'; -import {ModuleWithProvidersScanner} from '../../modulewithproviders'; import {PerfRecorder} from '../../perf'; -import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {ClassDeclaration, Decorator, ReflectionHost} from '../../reflection'; import {TypeCheckContext} from '../../typecheck'; import {getSourceFile, isExported} from '../../util/src/typescript'; -import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence, ResolveResult} from './api'; +import {AnalysisOutput, CompileResult, DecoratorHandler, HandlerFlags, HandlerPrecedence, ResolveResult} from './api'; import {DtsTransformRegistry} from './declaration'; -import {Trait, TraitState} from './trait'; +import {PendingTrait, Trait, TraitState} from './trait'; /** @@ -80,7 +78,7 @@ export class TraitCompiler { * Maps source files to any class declaration(s) within them which have been discovered to contain * Ivy traits. */ - private fileToClasses = new Map>(); + protected fileToClasses = new Map>(); private reexportMap = new Map>(); @@ -103,6 +101,11 @@ export class TraitCompiler { private analyze(sf: ts.SourceFile, preanalyze: false): void; private analyze(sf: ts.SourceFile, preanalyze: true): Promise|undefined; private analyze(sf: ts.SourceFile, preanalyze: boolean): Promise|undefined { + // We shouldn't analyze declaration files. + if (sf.isDeclarationFile) { + return undefined; + } + // analyze() really wants to return `Promise|void`, but TypeScript cannot narrow a return // type of 'void', so `undefined` is used instead. const promises: Promise[] = []; @@ -118,7 +121,7 @@ export class TraitCompiler { } const visit = (node: ts.Node): void => { - if (isNamedClassDeclaration(node)) { + if (this.reflector.isClass(node)) { this.analyzeClass(node, preanalyze ? promises : null); } ts.forEachChild(node, visit); @@ -133,6 +136,14 @@ export class TraitCompiler { } } + recordFor(clazz: ClassDeclaration): ClassRecord|null { + if (this.classes.has(clazz)) { + return this.classes.get(clazz) !; + } else { + return null; + } + } + recordsFor(sf: ts.SourceFile): ClassRecord[]|null { if (!this.fileToClasses.has(sf)) { return null; @@ -187,14 +198,21 @@ export class TraitCompiler { this.fileToClasses.get(sf) !.add(record.node); } - private scanClassForTraits(clazz: ClassDeclaration): ClassRecord|null { + private scanClassForTraits(clazz: ClassDeclaration): + PendingTrait[]|null { if (!this.compileNonExportedClasses && !isExported(clazz)) { return null; } const decorators = this.reflector.getDecoratorsOfDeclaration(clazz); - let record: ClassRecord|null = null; + return this.detectTraits(clazz, decorators); + } + + protected detectTraits(clazz: ClassDeclaration, decorators: Decorator[]|null): + PendingTrait[]|null { + let record: ClassRecord|null = this.recordFor(clazz); + let foundTraits: PendingTrait[] = []; for (const handler of this.handlers) { const result = handler.detect(clazz, decorators); @@ -202,11 +220,12 @@ export class TraitCompiler { continue; } - const isPrimaryHandler = handler.precedence === HandlerPrecedence.PRIMARY; const isWeakHandler = handler.precedence === HandlerPrecedence.WEAK; const trait = Trait.pending(handler, result); + foundTraits.push(trait); + if (record === null) { // This is the first handler to match this class. This path is a fast path through which // most classes will flow. @@ -257,8 +276,8 @@ export class TraitCompiler { length: clazz.getWidth(), messageText: 'Two incompatible decorators on class', }]; - record.traits = []; - return record; + record.traits = foundTraits = []; + break; } // Otherwise, it's safe to accept the multiple decorators here. Update some of the metadata @@ -268,23 +287,34 @@ export class TraitCompiler { } } - return record; + return foundTraits.length > 0 ? foundTraits : null; } - private analyzeClass(clazz: ClassDeclaration, preanalyzeQueue: Promise[]|null): void { - const record = this.scanClassForTraits(clazz); + protected analyzeClass(clazz: ClassDeclaration, preanalyzeQueue: Promise[]|null): void { + const traits = this.scanClassForTraits(clazz); - if (record === null) { + if (traits === null) { // There are no Ivy traits on the class, so it can safely be skipped. return; } - for (const trait of record.traits) { + for (const trait of traits) { const analyze = () => this.analyzeTrait(clazz, trait); let preanalysis: Promise|null = null; if (preanalyzeQueue !== null && trait.handler.preanalyze !== undefined) { - preanalysis = trait.handler.preanalyze(clazz, trait.detected.metadata) || null; + // Attempt to run preanalysis. This could fail with a `FatalDiagnosticError`; catch it if it + // does. + try { + preanalysis = trait.handler.preanalyze(clazz, trait.detected.metadata) || null; + } catch (err) { + if (err instanceof FatalDiagnosticError) { + trait.toErrored([err.toDiagnostic()]); + return; + } else { + throw err; + } + } } if (preanalysis !== null) { preanalyzeQueue !.push(preanalysis.then(analyze)); @@ -294,7 +324,9 @@ export class TraitCompiler { } } - private analyzeTrait(clazz: ClassDeclaration, trait: Trait): void { + protected analyzeTrait( + clazz: ClassDeclaration, trait: Trait, + flags?: HandlerFlags): void { if (trait.state !== TraitState.PENDING) { throw new Error( `Attempt to analyze trait of ${clazz.name.text} in state ${TraitState[trait.state]} (expected DETECTED)`); @@ -303,7 +335,7 @@ export class TraitCompiler { // Attempt analysis. This could fail with a `FatalDiagnosticError`; catch it if it does. let result: AnalysisOutput; try { - result = trait.handler.analyze(clazz, trait.detected.metadata); + result = trait.handler.analyze(clazz, trait.detected.metadata, flags); } catch (err) { if (err instanceof FatalDiagnosticError) { trait = trait.toErrored([err.toDiagnostic()]); @@ -420,7 +452,7 @@ export class TraitCompiler { compile(clazz: ts.Declaration, constantPool: ConstantPool): CompileResult[]|null { const original = ts.getOriginalNode(clazz) as typeof clazz; - if (!isNamedClassDeclaration(clazz) || !isNamedClassDeclaration(original) || + if (!this.reflector.isClass(clazz) || !this.reflector.isClass(original) || !this.classes.has(original)) { return null; } @@ -460,7 +492,7 @@ export class TraitCompiler { decoratorsFor(node: ts.Declaration): ts.Decorator[] { const original = ts.getOriginalNode(node) as typeof node; - if (!isNamedClassDeclaration(original) || !this.classes.has(original)) { + if (!this.reflector.isClass(original) || !this.classes.has(original)) { return []; } diff --git a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts index b8942c89e3..ee4e47b795 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts @@ -67,7 +67,7 @@ export class DtsTransformRegistry { export function declarationTransformFactory( transformRegistry: DtsTransformRegistry, importRewriter: ImportRewriter, - importPrefix?: string): ts.TransformerFactory { + importPrefix?: string): ts.TransformerFactory { return (context: ts.TransformationContext) => { const transformer = new DtsTransformer(context, importRewriter, importPrefix); return (fileOrBundle) => { diff --git a/packages/compiler-cli/src/ngtsc/transform/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/transform/test/BUILD.bazel new file mode 100644 index 0000000000..ca3f71a02e --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/transform/test/BUILD.bazel @@ -0,0 +1,31 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob([ + "**/*.ts", + ]), + deps = [ + "//packages:types", + "//packages/compiler", + "//packages/compiler-cli/src/ngtsc/file_system", + "//packages/compiler-cli/src/ngtsc/file_system/testing", + "//packages/compiler-cli/src/ngtsc/incremental", + "//packages/compiler-cli/src/ngtsc/perf", + "//packages/compiler-cli/src/ngtsc/reflection", + "//packages/compiler-cli/src/ngtsc/testing", + "//packages/compiler-cli/src/ngtsc/transform", + "@npm//typescript", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["//tools/testing:node_no_angular_es5"], + deps = [ + ":test_lib", + ], +) diff --git a/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts b/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts new file mode 100644 index 0000000000..8608e4364f --- /dev/null +++ b/packages/compiler-cli/src/ngtsc/transform/test/compilation_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 {absoluteFrom} from '../../file_system'; +import {runInEachFileSystem} from '../../file_system/testing'; +import {NOOP_INCREMENTAL_BUILD} from '../../incremental'; +import {NOOP_PERF_RECORDER} from '../../perf'; +import {ClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; +import {makeProgram} from '../../testing'; +import {DtsTransformRegistry, TraitCompiler} from '../../transform'; +import {AnalysisOutput, CompileResult, DecoratorHandler, HandlerPrecedence} from '../src/api'; + +runInEachFileSystem(() => { + describe('TraitCompiler', () => { + let _: typeof absoluteFrom; + beforeEach(() => _ = absoluteFrom); + + it('should not run decoration handlers against declaration files', () => { + class FakeDecoratorHandler implements DecoratorHandler<{}|null, unknown, unknown> { + name = 'FakeDecoratorHandler'; + precedence = HandlerPrecedence.PRIMARY; + + detect(): undefined { throw new Error('detect should not have been called'); } + analyze(): AnalysisOutput { + throw new Error('analyze should not have been called'); + } + compile(): CompileResult { throw new Error('compile should not have been called'); } + } + + const {program} = makeProgram([{ + name: _('/lib.d.ts'), + contents: `export declare class SomeDirective {}`, + }]); + const checker = program.getTypeChecker(); + const reflectionHost = new TypeScriptReflectionHost(checker); + const compiler = new TraitCompiler( + [new FakeDecoratorHandler()], reflectionHost, NOOP_PERF_RECORDER, NOOP_INCREMENTAL_BUILD, + true, new DtsTransformRegistry()); + const sourceFile = program.getSourceFile('lib.d.ts') !; + const analysis = compiler.analyzeSync(sourceFile); + + expect(sourceFile.isDeclarationFile).toBe(true); + expect(analysis).toBeFalsy(); + }); + }); +}); diff --git a/packages/compiler-cli/src/ngtsc/typecheck/index.ts b/packages/compiler-cli/src/ngtsc/typecheck/index.ts index 1b9d47c769..49dcc3f660 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/index.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/index.ts @@ -8,5 +8,6 @@ export * from './src/api'; export {TypeCheckContext} from './src/context'; +export {TemplateDiagnostic, isTemplateDiagnostic} from './src/diagnostics'; export {TypeCheckProgramHost} from './src/host'; export {typeCheckFilePath} from './src/type_check_file'; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts index d5ccb7785e..1032c4b2a5 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts @@ -211,6 +211,15 @@ export interface TypeCheckingConfig { * This is currently an unsupported feature. */ checkQueries: false; + + /** + * Whether to use any generic types of the context component. + * + * If this is `true`, then if the context component has generic types, those will be mirrored in + * the template type-checking context. If `false`, any generic type parameters of the context + * component will be set to `any` during type-checking. + */ + useContextGenericType: boolean; } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts index b5b59204b3..b65fa8d818 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts @@ -8,11 +8,20 @@ import {AbsoluteSourceSpan, ParseSourceSpan} from '@angular/compiler'; import * as ts from 'typescript'; -import {ErrorCode, ngErrorCode} from '../../diagnostics'; import {getTokenAtPosition} from '../../util/src/typescript'; import {ExternalTemplateSourceMapping, TemplateId, TemplateSourceMapping} from './api'; +/** + * A `ts.Diagnostic` with additional information about the diagnostic related to template + * type-checking. + */ +export interface TemplateDiagnostic extends ts.Diagnostic { + /** + * The component with the template that resulted in this diagnostic. + */ + componentFile: ts.SourceFile; +} /** * Adapter interface which allows the template type-checking diagnostics code to interpret offsets @@ -136,10 +145,10 @@ export function translateDiagnostic( */ export function makeTemplateDiagnostic( mapping: TemplateSourceMapping, span: ParseSourceSpan, category: ts.DiagnosticCategory, - code: ErrorCode, messageText: string | ts.DiagnosticMessageChain, relatedMessage?: { + code: number, messageText: string | ts.DiagnosticMessageChain, relatedMessage?: { text: string, span: ParseSourceSpan, - }): ts.Diagnostic { + }): TemplateDiagnostic { if (mapping.type === 'direct') { let relatedInformation: ts.DiagnosticRelatedInformation[]|undefined = undefined; if (relatedMessage !== undefined) { @@ -157,8 +166,11 @@ export function makeTemplateDiagnostic( // directly into the bytes of the source file. return { source: 'ngtsc', - code: ngErrorCode(code), category, messageText, + code, + category, + messageText, file: mapping.node.getSourceFile(), + componentFile: mapping.node.getSourceFile(), start: span.start.offset, length: span.end.offset - span.start.offset, relatedInformation, }; @@ -205,8 +217,10 @@ export function makeTemplateDiagnostic( return { source: 'ngtsc', category, - code: ngErrorCode(code), messageText, + code, + messageText, file: sf, + componentFile: componentSf, start: span.start.offset, length: span.end.offset - span.start.offset, // Show a secondary message indicating the component whose template contains the error. @@ -303,3 +317,8 @@ function hasIgnoreMarker(node: ts.Node, sourceFile: ts.SourceFile): boolean { return commentText === IGNORE_MARKER; }) === true; } + +export function isTemplateDiagnostic(diagnostic: ts.Diagnostic): diagnostic is TemplateDiagnostic { + return diagnostic.hasOwnProperty('componentFile') && + ts.isSourceFile((diagnostic as any).componentFile); +} diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts index 48733b5d9e..480577cbdc 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts @@ -9,7 +9,7 @@ import {DomElementSchemaRegistry, ParseSourceSpan, SchemaMetadata, TmplAstElement} from '@angular/compiler'; import * as ts from 'typescript'; -import {ErrorCode} from '../../diagnostics'; +import {ErrorCode, ngErrorCode} from '../../diagnostics'; import {TemplateId} from './api'; import {TemplateSourceResolver, makeTemplateDiagnostic} from './diagnostics'; @@ -92,7 +92,7 @@ export class RegistryDomSchemaChecker implements DomSchemaChecker { const diag = makeTemplateDiagnostic( mapping, element.sourceSpan, ts.DiagnosticCategory.Error, - ErrorCode.SCHEMA_INVALID_ELEMENT, errorMsg); + ngErrorCode(ErrorCode.SCHEMA_INVALID_ELEMENT), errorMsg); this._diagnostics.push(diag); } } @@ -117,7 +117,8 @@ export class RegistryDomSchemaChecker implements DomSchemaChecker { } const diag = makeTemplateDiagnostic( - mapping, span, ts.DiagnosticCategory.Error, ErrorCode.SCHEMA_INVALID_ATTRIBUTE, errorMsg); + mapping, span, ts.DiagnosticCategory.Error, + ngErrorCode(ErrorCode.SCHEMA_INVALID_ATTRIBUTE), errorMsg); this._diagnostics.push(diag); } } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts index 4a5c6dcb41..5f48a9c04b 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts @@ -9,7 +9,7 @@ import {ExpressionType, ExternalExpr, Type, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {NOOP_DEFAULT_IMPORT_RECORDER, Reference, ReferenceEmitter} from '../../imports'; +import {ImportFlags, NOOP_DEFAULT_IMPORT_RECORDER, Reference, ReferenceEmitter} from '../../imports'; import {ClassDeclaration, ReflectionHost} from '../../reflection'; import {ImportManager, translateExpression, translateType} from '../../translator'; @@ -205,7 +205,11 @@ export class Environment { * This may involve importing the node into the file if it's not declared there already. */ reference(ref: Reference>): ts.Expression { - const ngExpr = this.refEmitter.emit(ref, this.contextFile); + // Disable aliasing for imports generated in a template type-checking context, as there is no + // guarantee that any alias re-exports exist in the .d.ts files. It's safe to use direct imports + // in these cases as there is no strict dependency checking during the template type-checking + // pass. + const ngExpr = this.refEmitter.emit(ref, this.contextFile, ImportFlags.NoAliasing); // Use `translateExpression` to convert the `Expression` into a `ts.Expression`. return translateExpression( @@ -218,7 +222,8 @@ export class Environment { * This may involve importing the node into the file if it's not declared there already. */ referenceType(ref: Reference): ts.TypeNode { - const ngExpr = this.refEmitter.emit(ref, this.contextFile); + const ngExpr = this.refEmitter.emit( + ref, this.contextFile, ImportFlags.NoAliasing | ImportFlags.AllowTypeImports); // Create an `ExpressionType` from the `Expression` and translate it via `translateType`. // TODO(alxhub): support references to types with generic arguments in a clean way. diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts index d27f587127..8bbc0edd4c 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts @@ -19,12 +19,18 @@ export class TypeCheckProgramHost implements ts.CompilerHost { */ private sfMap: Map; + readonly resolveModuleNames?: ts.CompilerHost['resolveModuleNames']; + constructor(sfMap: Map, private delegate: ts.CompilerHost) { this.sfMap = sfMap; if (delegate.getDirectories !== undefined) { this.getDirectories = (path: string) => delegate.getDirectories !(path); } + + if (delegate.resolveModuleNames !== undefined) { + this.resolveModuleNames = delegate.resolveModuleNames; + } } getSourceFile( diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts index 6a5404d4c9..58096e4fdb 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts @@ -66,7 +66,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor const errorMsg = `No directive found with exportAs '${value}'.`; this._diagnostics.push(makeTemplateDiagnostic( mapping, ref.valueSpan || ref.sourceSpan, ts.DiagnosticCategory.Error, - ErrorCode.MISSING_REFERENCE_TARGET, errorMsg)); + ngErrorCode(ErrorCode.MISSING_REFERENCE_TARGET), errorMsg)); } missingPipe(templateId: TemplateId, ast: BindingPipe): void { @@ -79,7 +79,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor `Assertion failure: no SourceLocation found for usage of pipe '${ast.name}'.`); } this._diagnostics.push(makeTemplateDiagnostic( - mapping, sourceSpan, ts.DiagnosticCategory.Error, ErrorCode.MISSING_PIPE, errorMsg)); + mapping, sourceSpan, ts.DiagnosticCategory.Error, ngErrorCode(ErrorCode.MISSING_PIPE), + errorMsg)); } illegalAssignmentToTemplateVar( @@ -93,8 +94,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor throw new Error(`Assertion failure: no SourceLocation found for property binding.`); } this._diagnostics.push(makeTemplateDiagnostic( - mapping, sourceSpan, ts.DiagnosticCategory.Error, ErrorCode.WRITE_TO_READ_ONLY_VARIABLE, - errorMsg, { + mapping, sourceSpan, ts.DiagnosticCategory.Error, + ngErrorCode(ErrorCode.WRITE_TO_READ_ONLY_VARIABLE), errorMsg, { text: `The variable ${assignment.name} is declared here.`, span: target.valueSpan || target.sourceSpan, })); diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/ts_util.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/ts_util.ts index 8169a79bdc..a45e491d5c 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/ts_util.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/ts_util.ts @@ -9,7 +9,46 @@ import * as ts from 'typescript'; import {ClassDeclaration} from '../../reflection'; +/** + * A `Set` of `ts.SyntaxKind`s of `ts.Expression` which are safe to wrap in a `ts.AsExpression` + * without needing to be wrapped in parentheses. + * + * For example, `foo.bar()` is a `ts.CallExpression`, and can be safely cast to `any` with + * `foo.bar() as any`. however, `foo !== bar` is a `ts.BinaryExpression`, and attempting to cast + * without the parentheses yields the expression `foo !== bar as any`. This is semantically + * equivalent to `foo !== (bar as any)`, which is not what was intended. Thus, + * `ts.BinaryExpression`s need to be wrapped in parentheses before casting. + */ +// +const SAFE_TO_CAST_WITHOUT_PARENS: Set = new Set([ + // Expressions which are already parenthesized can be cast without further wrapping. + ts.SyntaxKind.ParenthesizedExpression, + + // Expressions which form a single lexical unit leave no room for precedence issues with the cast. + ts.SyntaxKind.Identifier, + ts.SyntaxKind.CallExpression, + ts.SyntaxKind.NonNullExpression, + ts.SyntaxKind.ElementAccessExpression, + ts.SyntaxKind.PropertyAccessExpression, + ts.SyntaxKind.ArrayLiteralExpression, + ts.SyntaxKind.ObjectLiteralExpression, + + // The same goes for various literals. + ts.SyntaxKind.StringLiteral, + ts.SyntaxKind.NumericLiteral, + ts.SyntaxKind.TrueKeyword, + ts.SyntaxKind.FalseKeyword, + ts.SyntaxKind.NullKeyword, + ts.SyntaxKind.UndefinedKeyword, +]); + export function tsCastToAny(expr: ts.Expression): ts.Expression { + // Wrap `expr` in parentheses if needed (see `SAFE_TO_CAST_WITHOUT_PARENS` above). + if (!SAFE_TO_CAST_WITHOUT_PARENS.has(expr.kind)) { + expr = ts.createParen(expr); + } + + // The outer expression is always wrapped in parentheses. return ts.createParen( ts.createAsExpression(expr, ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword))); } 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 a71944c421..b53b739753 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 @@ -57,7 +57,7 @@ export function generateTypeCheckBlock( throw new Error( `Expected TypeReferenceNode when referencing the ctx param for ${ref.debugName}`); } - const paramList = [tcbCtxParam(ref.node, ctxRawType.typeName)]; + const paramList = [tcbCtxParam(ref.node, ctxRawType.typeName, env.config.useContextGenericType)]; const scopeStatements = scope.render(); const innerBody = ts.createBlock([ @@ -73,7 +73,7 @@ export function generateTypeCheckBlock( /* modifiers */ undefined, /* asteriskToken */ undefined, /* name */ name, - /* typeParameters */ ref.node.typeParameters, + /* typeParameters */ env.config.useContextGenericType ? ref.node.typeParameters : undefined, /* parameters */ paramList, /* type */ undefined, /* body */ body); @@ -925,12 +925,18 @@ class Scope { * parameters listed (without their generic bounds). */ function tcbCtxParam( - node: ClassDeclaration, name: ts.EntityName): ts.ParameterDeclaration { + node: ClassDeclaration, name: ts.EntityName, + useGenericType: boolean): ts.ParameterDeclaration { let typeArguments: ts.TypeNode[]|undefined = undefined; // Check if the component is generic, and pass generic type parameters if so. if (node.typeParameters !== undefined) { - typeArguments = - node.typeParameters.map(param => ts.createTypeReferenceNode(param.name, undefined)); + if (useGenericType) { + typeArguments = + node.typeParameters.map(param => ts.createTypeReferenceNode(param.name, undefined)); + } else { + typeArguments = + node.typeParameters.map(() => ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)); + } } const type = ts.createTypeReferenceNode(name, typeArguments); return ts.createParameter( @@ -1174,7 +1180,10 @@ type TcbDirectiveInput = { function tcbGetDirectiveInputs( el: TmplAstElement | TmplAstTemplate, dir: TypeCheckableDirectiveMeta, tcb: Context, scope: Scope): TcbDirectiveInput[] { - const directiveInputs: TcbDirectiveInput[] = []; + // Only the first binding to a property is written. + // TODO(alxhub): produce an error for duplicate bindings to the same property, independently of + // this logic. + const directiveInputs = new Map(); // `dir.inputs` is an object map of field names on the directive class to property names. // This is backwards from what's needed to match bindings - a map of properties to field names // is desired. Invert `dir.inputs` into `propMatch` to create this map. @@ -1185,10 +1194,6 @@ function tcbGetDirectiveInputs( propMatch.set(inputs[key] as string, key); }); - // To determine which of directive's inputs are unset, we keep track of the set of field names - // that have not been seen yet. A field is removed from this set once a binding to it is found. - const unsetFields = new Set(propMatch.values()); - el.inputs.forEach(processAttribute); el.attributes.forEach(processAttribute); if (el instanceof TmplAstTemplate) { @@ -1196,11 +1201,16 @@ function tcbGetDirectiveInputs( } // Add unset directive inputs for each of the remaining unset fields. - for (const field of unsetFields) { - directiveInputs.push({type: 'unset', field}); + // Note: it's actually important here that `propMatch.values()` isn't used, as there can be + // multiple fields which share the same property name and only one of them will be listed as a + // value in `propMatch`. + for (const field of Object.keys(inputs)) { + if (!directiveInputs.has(field)) { + directiveInputs.set(field, {type: 'unset', field}); + } } - return directiveInputs; + return Array.from(directiveInputs.values()); /** * Add a binding expression to the map for each input/template attribute of the directive that has @@ -1223,8 +1233,10 @@ function tcbGetDirectiveInputs( } const field = propMatch.get(attr.name) !; - // Remove the field from the set of unseen fields, now that it's been assigned to. - unsetFields.delete(field); + // Skip the attribute if a previous binding also wrote to it. + if (directiveInputs.has(field)) { + return; + } let expr: ts.Expression; if (attr instanceof TmplAstBoundAttribute) { @@ -1235,7 +1247,7 @@ function tcbGetDirectiveInputs( expr = ts.createStringLiteral(attr.value); } - directiveInputs.push({ + directiveInputs.set(field, { type: 'binding', field: field, expression: expr, diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel index a48813d7ad..8aebe02977 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/BUILD.bazel @@ -24,9 +24,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts index 6c127651d6..aecbb168cc 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts @@ -163,6 +163,7 @@ export const ALL_ENABLED_CONFIG: TypeCheckingConfig = { checkTypeOfNonDomReferences: true, checkTypeOfPipes: true, strictSafeNavigationTypes: true, + useContextGenericType: true, }; // Remove 'ref' from TypeCheckableDirectiveMeta and add a 'selector' instead. @@ -217,6 +218,7 @@ export function tcb( checkTypeOfPipes: true, checkTemplateBodies: true, strictSafeNavigationTypes: true, + useContextGenericType: true, }; options = options || { emitSpans: false, diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts index 6e35fb68f7..2caf51c9ae 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts @@ -51,6 +51,19 @@ describe('type check blocks', () => { expect(tcb(TEMPLATE, DIRECTIVES)).toContain('"inputA": ("value")'); }); + it('should handle multiple bindings to the same property', () => { + const TEMPLATE = `
`; + const DIRECTIVES: TestDeclaration[] = [{ + type: 'directive', + name: 'DirA', + selector: '[dir-a]', + inputs: {inputA: 'inputA'}, + }]; + const block = tcb(TEMPLATE, DIRECTIVES); + expect(block).toContain('"inputA": (1)'); + expect(block).not.toContain('"inputA": (2)'); + }); + it('should handle empty bindings', () => { const TEMPLATE = `
`; const DIRECTIVES: TestDeclaration[] = [{ @@ -313,6 +326,7 @@ describe('type check blocks', () => { checkTypeOfNonDomReferences: true, checkTypeOfPipes: true, strictSafeNavigationTypes: true, + useContextGenericType: true, }; describe('config.applyTemplateContextGuards', () => { @@ -363,20 +377,31 @@ describe('type check blocks', () => { }); describe('config.checkTypeOfBindings', () => { - const TEMPLATE = `
`; it('should check types of bindings when enabled', () => { + const TEMPLATE = `
`; const block = tcb(TEMPLATE, DIRECTIVES); expect(block).toContain('Dir.ngTypeCtor({ "dirInput": ((ctx).a) })'); expect(block).toContain('(ctx).b;'); }); + it('should not check types of bindings when disabled', () => { + const TEMPLATE = `
`; const DISABLED_CONFIG: TypeCheckingConfig = {...BASE_CONFIG, checkTypeOfInputBindings: false}; const block = tcb(TEMPLATE, DIRECTIVES, DISABLED_CONFIG); expect(block).toContain('Dir.ngTypeCtor({ "dirInput": (((ctx).a as any)) })'); expect(block).toContain('((ctx).b as any);'); }); + + it('should wrap the cast to any in parentheses when required', () => { + const TEMPLATE = `
`; + const DISABLED_CONFIG: + TypeCheckingConfig = {...BASE_CONFIG, checkTypeOfInputBindings: false}; + const block = tcb(TEMPLATE, DIRECTIVES, DISABLED_CONFIG); + expect(block).toContain( + 'Dir.ngTypeCtor({ "dirInput": (((((ctx).a) === ((ctx).b)) as any)) })'); + }); }); describe('config.checkTypeOfOutputEvents', () => { @@ -543,5 +568,20 @@ describe('type check blocks', () => { expect(block).toContain('(((ctx).a) != null ? ((ctx).a)!.b : null as any)'); }); }); + + describe('config.strictContextGenerics', () => { + const TEMPLATE = `Test`; + + it('should use the generic type of the context when enabled', () => { + const block = tcb(TEMPLATE); + expect(block).toContain('function Test_TCB(ctx: Test)'); + }); + + it('should use any for the context generic type when disabled', () => { + const DISABLED_CONFIG: TypeCheckingConfig = {...BASE_CONFIG, useContextGenericType: false}; + const block = tcb(TEMPLATE, undefined, DISABLED_CONFIG); + expect(block).toContain('function Test_TCB(ctx: Test)'); + }); + }); }); }); diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts index e8ef2f0193..099573ebb2 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts @@ -162,5 +162,53 @@ runInEachFileSystem(() => { .toThrowError('A type reference to emit must be imported from an absolute module'); }); + it('can emit references to interfaces', () => { + const additionalFiles: TestFile[] = [{ + name: absoluteFrom('/node_modules/types/index.d.ts'), + contents: `export declare interface MyInterface {}`, + }]; + const emitter = createEmitter( + ` + import {MyInterface} from 'types'; + + export class TestClass {}`, + additionalFiles); + + expect(emitter.canEmit()).toBe(true); + expect(emit(emitter)).toEqual(''); + }); + + it('can emit references to enums', () => { + const additionalFiles: TestFile[] = [{ + name: absoluteFrom('/node_modules/types/index.d.ts'), + contents: `export declare enum MyEnum {}`, + }]; + const emitter = createEmitter( + ` + import {MyEnum} from 'types'; + + export class TestClass {}`, + additionalFiles); + + expect(emitter.canEmit()).toBe(true); + expect(emit(emitter)).toEqual(''); + }); + + it('can emit references to type aliases', () => { + const additionalFiles: TestFile[] = [{ + name: absoluteFrom('/node_modules/types/index.d.ts'), + contents: `export declare type MyType = string;`, + }]; + const emitter = createEmitter( + ` + import {MyType} from 'types'; + + export class TestClass {}`, + additionalFiles); + + expect(emitter.canEmit()).toBe(true); + expect(emit(emitter)).toEqual(''); + }); + }); }); diff --git a/packages/compiler-cli/src/ngtsc/util/src/typescript.ts b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts index 09df8fcfc4..68e71b5673 100644 --- a/packages/compiler-cli/src/ngtsc/util/src/typescript.ts +++ b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts @@ -67,9 +67,19 @@ export function identifierOfNode(decl: ts.Node & {name?: ts.Node}): ts.Identifie } export function isDeclaration(node: ts.Node): node is ts.Declaration { - return ts.isEnumDeclaration(node) || ts.isClassDeclaration(node) || - ts.isFunctionDeclaration(node) || ts.isVariableDeclaration(node) || - ts.isTypeAliasDeclaration(node); + return isValueDeclaration(node) || isTypeDeclaration(node); +} + +export function isValueDeclaration(node: ts.Node): node is ts.ClassDeclaration| + ts.FunctionDeclaration|ts.VariableDeclaration { + return ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node) || + ts.isVariableDeclaration(node); +} + +export function isTypeDeclaration(node: ts.Node): node is ts.EnumDeclaration| + ts.TypeAliasDeclaration|ts.InterfaceDeclaration { + return ts.isEnumDeclaration(node) || ts.isTypeAliasDeclaration(node) || + ts.isInterfaceDeclaration(node); } export function isExported(node: ts.Declaration): boolean { diff --git a/packages/compiler-cli/src/ngtsc/util/test/BUILD.bazel b/packages/compiler-cli/src/ngtsc/util/test/BUILD.bazel index a4ca97b5af..58c32aab77 100644 --- a/packages/compiler-cli/src/ngtsc/util/test/BUILD.bazel +++ b/packages/compiler-cli/src/ngtsc/util/test/BUILD.bazel @@ -20,9 +20,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/compiler-cli/src/perform_watch.ts b/packages/compiler-cli/src/perform_watch.ts index c9e802dc37..2d406686ac 100644 --- a/packages/compiler-cli/src/perform_watch.ts +++ b/packages/compiler-cli/src/perform_watch.ts @@ -246,11 +246,13 @@ export function performWatchCompilation(host: PerformWatchHost): } function watchedFileChanged(event: FileChangeEvent, fileName: string) { + const normalizedPath = path.normalize(fileName); + if (cachedOptions && event === FileChangeEvent.Change && // TODO(chuckj): validate that this is sufficient to skip files that were written. // This assumes that the file path we write is the same file path we will receive in the // change notification. - path.normalize(fileName) === path.normalize(cachedOptions.project)) { + normalizedPath === path.normalize(cachedOptions.project)) { // If the configuration file changes, forget everything and start the recompilation timer resetOptions(); } else if ( @@ -263,12 +265,12 @@ export function performWatchCompilation(host: PerformWatchHost): if (event === FileChangeEvent.CreateDeleteDir) { fileCache.clear(); } else { - fileCache.delete(path.normalize(fileName)); + fileCache.delete(normalizedPath); } - if (!ignoreFilesForWatch.has(path.normalize(fileName))) { + if (!ignoreFilesForWatch.has(normalizedPath)) { // Ignore the file if the file is one that was written by the compiler. - startTimerForRecompilation(fileName); + startTimerForRecompilation(normalizedPath); } } diff --git a/packages/compiler-cli/src/transformers/api.ts b/packages/compiler-cli/src/transformers/api.ts index 11eed7c2ad..17da6f47d3 100644 --- a/packages/compiler-cli/src/transformers/api.ts +++ b/packages/compiler-cli/src/transformers/api.ts @@ -9,6 +9,8 @@ import {GeneratedFile, ParseSourceSpan, Position} from '@angular/compiler'; import * as ts from 'typescript'; +import {ExtendedTsCompilerHost, NgCompilerOptions} from '../ngtsc/core/api'; + export const DEFAULT_ERROR_CODE = 100; export const UNKNOWN_ERROR_CODE = 500; export const SOURCE = 'angular' as 'angular'; @@ -37,7 +39,7 @@ export function isNgDiagnostic(diagnostic: any): diagnostic is Diagnostic { return diagnostic != null && diagnostic.source === 'angular'; } -export interface CompilerOptions extends ts.CompilerOptions { +export interface CompilerOptions extends NgCompilerOptions, ts.CompilerOptions { // NOTE: These comments and aio/content/guides/aot-compiler.md should be kept in sync. // Write statistics about compilation (e.g. total time, ...) @@ -62,42 +64,6 @@ export interface CompilerOptions extends ts.CompilerOptions { // Don't produce .ngfactory.js or .ngstyle.js files skipTemplateCodegen?: boolean; - // Always report errors when the type of a parameter supplied whose injection type cannot - // be determined. When this value option is not provided or is `false`, constructor - // parameters of classes marked with `@Injectable` whose type cannot be resolved will - // produce a warning. With this option `true`, they produce an error. When this option is - // not provided is treated as if it were `false`. - strictInjectionParameters?: boolean; - - // Whether to generate a flat module index of the given name and the corresponding - // flat module metadata. This option is intended to be used when creating flat - // modules similar to how `@angular/core` and `@angular/common` are packaged. - // When this option is used the `package.json` for the library should referred to the - // generated flat module index instead of the library index file. When using this - // option only one .metadata.json file is produced that contains all the metadata - // necessary for symbols exported from the library index. - // In the generated .ngfactory.ts files flat module index is used to import symbols - // includes both the public API from the library index as well as shrowded internal - // symbols. - // By default the .ts file supplied in the `files` files field is assumed to be - // library index. If more than one is specified, uses `libraryIndex` to select the - // file to use. If more than on .ts file is supplied and no `libraryIndex` is supplied - // an error is produced. - // A flat module index .d.ts and .js will be created with the given `flatModuleOutFile` - // name in the same location as the library index .d.ts file is emitted. - // For example, if a library uses `public_api.ts` file as the library index of the - // module the `tsconfig.json` `files` field would be `["public_api.ts"]`. The - // `flatModuleOutFile` options could then be set to, for example `"index.js"`, which - // produces `index.d.ts` and `index.metadata.json` files. The library's - // `package.json`'s `module` field would be `"index.js"` and the `typings` field would - // be `"index.d.ts"`. - flatModuleOutFile?: string; - - // Preferred module id to use for importing flat module. References generated by `ngc` - // will use this module name when importing symbols from the flat module. This is only - // meaningful when `flatModuleOutFile` is also supplied. It is otherwise ignored. - flatModuleId?: string; - // A prefix to insert in generated private symbols, e.g. for "my_prefix_" we // would generate private symbols named like `ɵmy_prefix_a`. flatModulePrivateSymbolPrefix?: string; @@ -107,123 +73,6 @@ export interface CompilerOptions extends ts.CompilerOptions { // Default is true. generateCodeForLibraries?: boolean; - /** - * Whether to type check the entire template. - * - * This flag currently controls a couple aspects of template type-checking, including - * whether embedded views are checked. - * - * For maximum type-checking, set this to `true`, and set `strictTemplates` to `true`. - * - * It is an error for this flag to be `false`, while `strictTemplates` is set to `true`. - */ - fullTemplateTypeCheck?: boolean; - - /** - * If `true`, implies all template strictness flags below (unless individually disabled). - * - * Has no effect unless `fullTemplateTypeCheck` is also enabled. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. - */ - strictTemplates?: boolean; - - - /** - * Whether to check the type of a binding to a directive/component input against the type of the - * field on the directive/component. - * - * For example, if this is `false` then the expression `[input]="expr"` will have `expr` type- - * checked, but not the assignment of the resulting type to the `input` property of whichever - * directive or component is receiving the binding. If set to `true`, both sides of the assignment - * are checked. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. - */ - strictInputTypes?: boolean; - - /** - * Whether to use strict null types for input bindings for directives. - * - * If this is `true`, applications that are compiled with TypeScript's `strictNullChecks` enabled - * will produce type errors for bindings which can evaluate to `undefined` or `null` where the - * inputs's type does not include `undefined` or `null` in its type. If set to `false`, all - * binding expressions are wrapped in a non-null assertion operator to effectively disable strict - * null checks. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. Note that if `strictInputTypes` is - * not set, or set to `false`, this flag has no effect. - */ - strictNullInputTypes?: boolean; - - /** - * Whether to check text attributes that happen to be consumed by a directive or component. - * - * For example, in a template containing `` the `disabled` attribute ends - * up being consumed as an input with type `boolean` by the `matInput` directive. At runtime, the - * input will be set to the attribute's string value, which is an empty string for attributes - * without a value, so with this flag set to `true`, an error would be reported. If set to - * `false`, text attributes will never report an error. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. Note that if `strictInputTypes` is - * not set, or set to `false`, this flag has no effect. - */ - strictAttributeTypes?: boolean; - - /** - * Whether to use a strict type for null-safe navigation operations. - * - * If this is `false`, then the return type of `a?.b` or `a?()` will be `any`. If set to `true`, - * then the return type of `a?.b` for example will be the same as the type of the ternary - * expression `a != null ? a.b : a`. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. - */ - strictSafeNavigationTypes?: boolean; - - /** - * Whether to infer the type of local references. - * - * If this is `true`, the type of a `#ref` variable on a DOM node in the template will be - * determined by the type of `document.createElement` for the given DOM node. If set to `false`, - * the type of `ref` for DOM nodes will be `any`. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. - */ - strictDomLocalRefTypes?: boolean; - - /** - * Whether to infer the type of the `$event` variable in event bindings for directive outputs or - * animation events. - * - * If this is `true`, the type of `$event` will be inferred based on the generic type of - * `EventEmitter`/`Subject` of the output. If set to `false`, the `$event` variable will be of - * type `any`. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. - */ - strictOutputEventTypes?: boolean; - - /** - * Whether to infer the type of the `$event` variable in event bindings to DOM events. - * - * If this is `true`, the type of `$event` will be inferred based on TypeScript's - * `HTMLElementEventMap`, with a fallback to the native `Event` type. If set to `false`, the - * `$event` variable will be of type `any`. - * - * Defaults to `false`, even if "fullTemplateTypeCheck" is set. - */ - strictDomEventTypes?: 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; - // Modify how angular annotations are emitted to improve tree-shaking. // Default is static fields. // decorators: Leave the Decorators in-place. This makes compilation faster. @@ -242,9 +91,6 @@ export interface CompilerOptions extends ts.CompilerOptions { // position. disableExpressionLowering?: boolean; - // Disable TypeScript Version Check. - disableTypeScriptVersionCheck?: boolean; - // Locale of the application i18nOutLocale?: string; // Export format (xlf, xlf2 or xmb) @@ -254,33 +100,10 @@ export interface CompilerOptions extends ts.CompilerOptions { // Import format if different from `i18nFormat` i18nInFormat?: string; - // Locale of the imported translations - i18nInLocale?: string; // Path to the translation file i18nInFile?: string; // How to handle missing messages i18nInMissingTranslations?: 'error'|'warning'|'ignore'; - // Whether translation variable name should contain external message id - // (used by Closure Compiler's output of `goog.getMsg` for transition period) - i18nUseExternalIds?: boolean; - - /** - * Render `$localize` messages with legacy format ids. - * - * This is only active if we are building with `enableIvy: true`. - * The default value for now is `true`. - * - * Use this option when use are using the `$localize` based localization messages but - * have not migrated the translation files to use the new `$localize` message id format. - */ - enableI18nLegacyMessageIdFormat?: boolean; - - // Whether to remove blank text nodes from compiled templates. It is `false` by default starting - // from Angular 6. - preserveWhitespaces?: boolean; - - /** generate all possible generated files */ - allowEmptyCodegenFiles?: boolean; /** * Whether to generate .ngsummary.ts files that allow to use AOTed artifacts @@ -298,51 +121,9 @@ export interface CompilerOptions extends ts.CompilerOptions { */ enableResourceInlining?: boolean; - /** - * Controls whether ngtsc will emit `.ngfactory.js` shims for each compiled `.ts` file. - * - * These shims support legacy imports from `ngfactory` files, by exporting a factory shim - * for each component or NgModule in the original `.ts` file. - */ - generateNgFactoryShims?: boolean; - - /** - * Controls whether ngtsc will emit `.ngsummary.js` shims for each compiled `.ts` file. - * - * These shims support legacy imports from `ngsummary` files, by exporting an empty object - * for each NgModule in the original `.ts` file. The only purpose of summaries is to feed them to - * `TestBed`, which is a no-op in Ivy. - */ - generateNgSummaryShims?: boolean; - - /** - * Tells the compiler to generate definitions using the Render3 style code generation. - * This option defaults to `true`. - * - * Acceptable values are as follows: - * - * `false` - run ngc normally - * `true` - run the ngtsc compiler instead of the normal ngc compiler - * `ngtsc` - alias for `true` - * - * @publicApi - */ - enableIvy?: boolean|'ngtsc'; - /** @internal */ collectAllErrors?: boolean; - /** An option to enable ngtsc's internal performance tracing. - * - * This should be a path to a JSON file where trace information will be written. An optional 'ts:' - * prefix will cause the trace to be written via the TS host instead of directly to the filesystem - * (not all hosts support this mode of operation). - * - * This is currently not exposed to users as the trace format is still unstable. - * - * @internal */ - tracePerformance?: string; - /** * 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 @@ -351,72 +132,14 @@ export interface CompilerOptions extends ts.CompilerOptions { * Read more about this here: https://github.com/angular/angular/issues/25644. */ createExternalSymbolFactoryReexports?: boolean; - - /** - * Turn on template type-checking in the Ivy compiler. - * - * This is an internal flag being used to roll out template type-checking in ngtsc. Turning it on - * by default before it's ready might break other users attempting to test the new compiler's - * behavior. - * - * @internal - */ - ivyTemplateTypeCheck?: boolean; - - /** - * Enables the generation of alias re-exports of directives/pipes that are visible from an - * NgModule from that NgModule's file. - * - * This option should be disabled for application builds or for Angular Package Format libraries - * (where NgModules along with their directives/pipes are exported via a single entrypoint). - * - * For other library compilations which are intended to be path-mapped into an application build - * (or another library), enabling this option enables the resulting deep imports to work - * correctly. - * - * A consumer of such a path-mapped library will write an import like: - * - * ```typescript - * import {LibModule} from 'lib/deep/path/to/module'; - * ``` - * - * The compiler will attempt to generate imports of directives/pipes from that same module - * specifier (the compiler does not rewrite the user's given import path, unlike View Engine). - * - * ```typescript - * import {LibDir, LibCmp, LibPipe} from 'lib/deep/path/to/module'; - * ``` - * - * It would be burdensome for users to have to re-export all directives/pipes alongside each - * NgModule to support this import model. Enabling this option tells the compiler to generate - * private re-exports alongside the NgModule of all the directives/pipes it makes available, to - * support these future imports. - */ - generateDeepReexports?: boolean; - - /** - * Whether the compiler should avoid generating code for classes that haven't been exported. - * This is only active when building with `enableIvy: true`. Defaults to `true`. - */ - compileNonExportedClasses?: boolean; } -export interface CompilerHost extends ts.CompilerHost { +export interface CompilerHost extends ts.CompilerHost, ExtendedTsCompilerHost { /** * Converts a module name that is used in an `import` to a file path. * I.e. `path/to/containingFile.ts` containing `import {...} from 'module-name'`. */ moduleNameToFileName?(moduleName: string, containingFile: string): string|null; - /** - * Converts a file path to a module name that can be used as an `import ...` - * I.e. `path/to/importedFile.ts` should be imported by `path/to/containingFile.ts`. - */ - fileNameToModuleName?(importedFilePath: string, containingFilePath: string): string; - /** - * Converts a file path for a resource that is used in a source file or another resource - * into a filepath. - */ - resourceNameToFileName?(resourceName: string, containingFilePath: string): string|null; /** * Converts a file name into a representation that should be stored in a summary file. * This has to include changing the suffix as well. @@ -431,13 +154,6 @@ export interface CompilerHost extends ts.CompilerHost { * given the fileName of the library that is referrig to it. */ fromSummaryFileName?(fileName: string, referringLibFileName: string): string; - /** - * Load a referenced resource either statically or asynchronously. If the host returns a - * `Promise` it is assumed the user of the corresponding `Program` will call - * `loadNgStructureAsync()`. Returning `Promise` outside `loadNgStructureAsync()` will - * cause a diagnostics diagnostic error or an exception to be thrown. - */ - readResource?(fileName: string): Promise|string; /** * Produce an AMD module name for the source file. Used in Bazel. * @@ -445,12 +161,6 @@ export interface CompilerHost extends ts.CompilerHost { * rather than by path. See http://requirejs.org/docs/whyamd.html#namedmodules */ amdModuleName?(sf: ts.SourceFile): string|undefined; - - /** - * Get the absolute paths to the changed files that triggered the current compilation - * or `undefined` if this is not an incremental build. - */ - getModifiedResourceFiles?(): Set|undefined; } export enum EmitFlags { diff --git a/packages/compiler-cli/src/transformers/compiler_host.ts b/packages/compiler-cli/src/transformers/compiler_host.ts index 739cd38e00..353b1884d8 100644 --- a/packages/compiler-cli/src/transformers/compiler_host.ts +++ b/packages/compiler-cli/src/transformers/compiler_host.ts @@ -20,7 +20,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)$/; +const CSS_PREPROCESSOR_EXT = /(\.scss|\.sass|\.less|\.styl)$/; let wrapHostForTest: ((host: ts.CompilerHost) => ts.CompilerHost)|null = null; diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index a3cc752bb4..3855bddf1b 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -860,7 +860,7 @@ export function createProgram({rootNames, options, host, oldProgram}: { host: CompilerHost, oldProgram?: Program }): Program { if (options.enableIvy !== false) { - return new NgtscProgram(rootNames, options, host, oldProgram as NgtscProgram); + return new NgtscProgram(rootNames, options, host, oldProgram as NgtscProgram | undefined); } else { return new AngularCompilerProgram(rootNames, options, host, oldProgram); } diff --git a/packages/compiler-cli/src/typescript_support.ts b/packages/compiler-cli/src/typescript_support.ts index 9a4c430ba5..6e752f3e11 100644 --- a/packages/compiler-cli/src/typescript_support.ts +++ b/packages/compiler-cli/src/typescript_support.ts @@ -19,7 +19,7 @@ const MIN_TS_VERSION = '3.6.4'; * ∀ supported typescript version v, v < MAX_TS_VERSION * MAX_TS_VERSION is not considered as a supported TypeScript version */ -const MAX_TS_VERSION = '3.7.0'; +const MAX_TS_VERSION = '3.8.0'; /** * The currently used version of TypeScript, which can be adjusted for testing purposes using diff --git a/packages/compiler-cli/test/BUILD.bazel b/packages/compiler-cli/test/BUILD.bazel index 3c651e6540..776e7a8684 100644 --- a/packages/compiler-cli/test/BUILD.bazel +++ b/packages/compiler-cli/test/BUILD.bazel @@ -40,7 +40,7 @@ ts_library( jasmine_node_test( name = "extract_i18n", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ "//packages/core:npm_package", ], @@ -53,7 +53,6 @@ jasmine_node_test( ":extract_i18n_lib", "//packages/common:npm_package", "//packages/core", - "//tools/testing:node", "@npm//minimist", ], ) @@ -76,7 +75,7 @@ ts_library( jasmine_node_test( name = "ngc", timeout = "long", # 900 seconds - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ "//packages/common:npm_package", "//packages/core:npm_package", @@ -91,7 +90,6 @@ jasmine_node_test( deps = [ ":ngc_lib", "//packages/core", - "//tools/testing:node", "@npm//minimist", "@npm//rxjs", "@npm//tsickle", @@ -116,14 +114,13 @@ ts_library( jasmine_node_test( name = "perform_watch", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ "//packages/core:npm_package", ], deps = [ ":perform_watch_lib", "//packages/core", - "//tools/testing:node", ], ) @@ -143,13 +140,12 @@ ts_library( jasmine_node_test( name = "perform_compile", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ "//packages/core:npm_package", ], deps = [ ":perform_compile_lib", "//packages/core", - "//tools/testing:node", ], ) diff --git a/packages/compiler-cli/test/compliance/BUILD.bazel b/packages/compiler-cli/test/compliance/BUILD.bazel index ad3a15b865..d238d225a8 100644 --- a/packages/compiler-cli/test/compliance/BUILD.bazel +++ b/packages/compiler-cli/test/compliance/BUILD.bazel @@ -18,7 +18,7 @@ ts_library( jasmine_node_test( name = "compliance", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], data = [ "//packages/compiler-cli/test/ngtsc/fake_core:npm_package", ], @@ -28,6 +28,5 @@ jasmine_node_test( ], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) 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 abb77063b8..6df627e305 100644 --- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts @@ -431,10 +431,8 @@ describe('compiler compliance', () => { const $_c1$ = function (a0, a1) { return { value: a0, params: a1 }; }; const $_c2$ = function (a0, a1) { return { collapsedWidth: a0, expandedWidth: a1 }; }; … - hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(14); - } + hostVars: 14, + hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵupdateSyntheticHostBinding("@expansionHeight", $r3$.ɵɵpureFunction2(5, $_c1$, ctx.getExpandedState(), @@ -479,7 +477,7 @@ describe('compiler compliance', () => { const template = ` MyComponent.ɵcmp = i0.ɵɵdefineComponent({type:MyComponent,selectors:[["my-component"]], decls: 1, - vars: 2, + vars: 4, template: function MyComponent_Template(rf,ctx){ if (rf & 1) { $r3$.ɵɵelement(0, "div"); @@ -3499,10 +3497,8 @@ describe('compiler compliance', () => { // ... BaseClass.ɵdir = $r3$.ɵɵdefineDirective({ type: BaseClass, - hostBindings: function BaseClass_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(1); - } + hostVars: 1, + hostBindings: function BaseClass_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵattribute("tabindex", ctx.tabindex); } @@ -3542,7 +3538,7 @@ describe('compiler compliance', () => { // ... BaseClass.ɵdir = $r3$.ɵɵdefineDirective({ type: BaseClass, - hostBindings: function BaseClass_HostBindings(rf, ctx, elIndex) { + hostBindings: function BaseClass_HostBindings(rf, ctx) { if (rf & 1) { $r3$.ɵɵlistener("mousedown", function BaseClass_mousedown_HostBindingHandler($event) { return ctx.handleMousedown($event); 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 21dc1c2a8a..0f8e6a374d 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 @@ -668,13 +668,11 @@ describe('compiler compliance: bindings', () => { }; const HostBindingDirDeclaration = ` - HostBindingDir.ɵdir = $r3$.ɵɵdefineDirective({ - type: HostBindingDir, - selectors: [["", "hostBindingDir", ""]], - hostBindings: function HostBindingDir_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(1); - } + HostBindingDir.ɵdir = $r3$.ɵɵdefineDirective({ + type: HostBindingDir, + selectors: [["", "hostBindingDir", ""]], + hostVars: 1, + hostBindings: function HostBindingDir_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵhostProperty("id", ctx.dirId); } @@ -717,10 +715,8 @@ describe('compiler compliance: bindings', () => { HostBindingComp.ɵcmp = $r3$.ɵɵdefineComponent({ type: HostBindingComp, selectors: [["host-binding-comp"]], - hostBindings: function HostBindingComp_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(3); - } + hostVars: 3, + hostBindings: function HostBindingComp_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵhostProperty("id", $r3$.ɵɵpureFunction1(1, $ff$, ctx.id)); } @@ -764,10 +760,8 @@ describe('compiler compliance: bindings', () => { HostAttributeDir.ɵdir = $r3$.ɵɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], - hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(1); - } + hostVars: 1, + hostBindings: function HostAttributeDir_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵattribute("required", ctx.required); } @@ -803,16 +797,10 @@ describe('compiler compliance: bindings', () => { }; const HostAttributeDirDeclaration = ` - const $c0$ = ["aria-label", "label"]; - … HostAttributeDir.ɵdir = $r3$.ɵɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], - hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵelementHostAttrs($c0$); - } - } + hostAttrs: ["aria-label", "label"] }); `; @@ -859,32 +847,20 @@ describe('compiler compliance: bindings', () => { }; 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.ɵcmp = $r3$.ɵɵdefineComponent({ type: HostAttributeComp, selectors: [["my-host-attribute-component"]], - hostBindings: function HostAttributeComp_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵelementHostAttrs($c0$); - … - } - … - } + hostAttrs: ["title", "hello there from component", ${AttributeMarker.Styles}, "opacity", "1"], … HostAttributeDir.ɵdir = $r3$.ɵɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], - hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(2); - $r3$.ɵɵelementHostAttrs($c1$); - … - } + hostAttrs: ["title", "hello there from directive", ${AttributeMarker.Classes}, "one", "two", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"], + hostVars: 4, + hostBindings: function HostAttributeDir_HostBindings(rf, ctx) { … } - `; + `; const result = compile(files, angularFiles); const source = result.source; @@ -915,7 +891,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { … if (rf & 2) { $r3$.ɵɵhostProperty("title", ctx.myTitle)("tabindex", 1)("id", ctx.myId); @@ -951,7 +927,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { … if (rf & 2) { $r3$.ɵɵhostProperty("tabindex", 1)("title", ctx.myTitle)("id", ctx.myId); @@ -983,7 +959,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { … if (rf & 2) { $r3$.ɵɵhostProperty("title", "my title")("id", "my-id"); @@ -1019,7 +995,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { … if (rf & 2) { $r3$.ɵɵupdateSyntheticHostBinding("@expand", ctx.expandedState)("@fadeOut", true)("@shrink", ctx.isSmall); @@ -1054,7 +1030,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { … if (rf & 2) { $r3$.ɵɵattribute("title", ctx.myTitle)("tabindex", 1)("id", ctx.myId); @@ -1090,7 +1066,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { … if (rf & 2) { $r3$.ɵɵattribute("tabindex", 1)("title", ctx.myTitle)("id", ctx.myId); @@ -1122,7 +1098,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { … if (rf & 2) { $r3$.ɵɵhostProperty("tabindex", 1); @@ -1160,7 +1136,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyDirective_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyDirective_HostBindings(rf, ctx) { if (rf & 1) { $r3$.ɵɵlistener("mousedown", function MyDirective_mousedown_HostBindingHandler($event) { return ctx.mousedown(); })("mouseup", function MyDirective_mouseup_HostBindingHandler($event) { return ctx.mouseup(); })("click", function MyDirective_click_HostBindingHandler($event) { return ctx.click(); }); } @@ -1193,7 +1169,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 1) { $r3$.ɵɵcomponentHostSyntheticListener("@animation.done", function MyComponent_animation_animation_done_HostBindingHandler($event) { return ctx.done(); })("@animation.start", function MyComponent_animation_animation_start_HostBindingHandler($event) { return ctx.start(); }); } @@ -1231,7 +1207,7 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); const template = ` … - hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { + hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 1) { $r3$.ɵɵcomponentHostSyntheticListener("@animation.done", function MyComponent_animation_animation_done_HostBindingHandler($event) { return ctx.done(); })("@animation.start", function MyComponent_animation_animation_start_HostBindingHandler($event) { return ctx.start(); }); $r3$.ɵɵlistener("mousedown", function MyComponent_mousedown_HostBindingHandler($event) { return ctx.mousedown(); })("mouseup", function MyComponent_mouseup_HostBindingHandler($event) { return ctx.mouseup(); })("click", function MyComponent_click_HostBindingHandler($event) { return ctx.click(); }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts index b69ebbc50d..935d4e447a 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts @@ -99,6 +99,41 @@ describe('compiler compliance: dependency injection', () => { expectEmit(result.source, def, 'Incorrect injectable definition'); }); + it('should create a factory definition for an injectable with an overloaded constructor', () => { + const files = { + app: { + 'spec.ts': ` + import {Injectable, Optional} from '@angular/core'; + + class MyDependency {} + class MyOptionalDependency {} + + @Injectable() + export class MyService { + constructor(dep: MyDependency); + constructor(dep: MyDependency, @Optional() optionalDep?: MyOptionalDependency) {} + } + ` + } + }; + + const factory = ` + MyService.ɵfac = function MyService_Factory(t) { + return new (t || MyService)($r3$.ɵɵinject(MyDependency), $r3$.ɵɵinject(MyOptionalDependency, 8)); + }`; + + const def = ` + MyService.ɵprov = $r3$.ɵɵdefineInjectable({ + token: MyService, + factory: MyService.ɵfac + }); + `; + + const result = compile(files, angularFiles); + expectEmit(result.source, factory, 'Incorrect factory definition'); + expectEmit(result.source, def, 'Incorrect injectable definition'); + }); + it('should create a single factory def if the class has more than one decorator', () => { const files = { app: { 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 46083c897c..2b8b87b877 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 @@ -333,9 +333,9 @@ describe('compiler compliance: styling', () => { const template = ` MyAnimDir.ɵdir = $r3$.ɵɵdefineDirective({ … - hostBindings: function MyAnimDir_HostBindings(rf, ctx, elIndex) { + hostVars: 1, + hostBindings: function MyAnimDir_HostBindings(rf, ctx) { if (rf & 1) { - $r3$.ɵɵallocHostVars(1); $r3$.ɵɵcomponentHostSyntheticListener("@myAnim.start", function MyAnimDir_animation_myAnim_start_HostBindingHandler($event) { return ctx.onStart(); })("@myAnim.done", function MyAnimDir_animation_myAnim_done_HostBindingHandler($event) { return ctx.onDone(); }); } if (rf & 2) { $r3$.ɵɵupdateSyntheticHostBinding("@myAnim", ctx.myAnimState); @@ -377,8 +377,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelement(0, "div"); } if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap($ctx$.myStyleExp); + $r3$.ɵɵstyleMap($ctx$.myStyleExp, $r3$.ɵɵdefaultStyleSanitizer); } } `; @@ -504,15 +503,14 @@ describe('compiler compliance: styling', () => { type: MyComponent, selectors:[["my-component"]], decls: 1, - vars: 5, + vars: 7, consts: [[${AttributeMarker.Styles}, "opacity", "1"]], template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { $r3$.ɵɵelement(0, "div", 0); } if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap($ctx$.myStyleExp); + $r3$.ɵɵstyleMap($ctx$.myStyleExp, $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵstyleProp("width", $ctx$.myWidth)("height", $ctx$.myHeight); $r3$.ɵɵattribute("style", "border-width: 10px", $r3$.ɵɵsanitizeStyle); } @@ -551,14 +549,13 @@ describe('compiler compliance: styling', () => { type: MyComponent, selectors: [["my-component"]], decls: 1, - vars: 1, + vars: 2, template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div"); } if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleProp("background-image", ctx.myImage); + $r3$.ɵɵstyleProp("background-image", ctx.myImage, $r3$.ɵɵdefaultStyleSanitizer); } }, encapsulation: 2 @@ -697,7 +694,7 @@ describe('compiler compliance: styling', () => { type: MyComponent, selectors:[["my-component"]], decls: 1, - vars: 5, + vars: 7, consts: [[${AttributeMarker.Classes}, "grape"]], template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { @@ -816,8 +813,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelement(0, "div"); } if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap($ctx$.myStyleExp); + $r3$.ɵɵstyleMap($ctx$.myStyleExp, $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵclassMap($ctx$.myClassExp); } } @@ -858,8 +854,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap($r3$.ɵɵpipeBind1(1, 4, $ctx$.myStyleExp)); + $r3$.ɵɵstyleMap($r3$.ɵɵpipeBind1(1, 4, $ctx$.myStyleExp), $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵclassMap($r3$.ɵɵpipeBind1(2, 6, $ctx$.myClassExp)); } } @@ -911,11 +906,10 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelementEnd(); } if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap($r3$.ɵɵpipeBind2(1, 8, $ctx$.myStyleExp, 1000)); - $r3$.ɵɵclassMap($r3$.ɵɵpureFunction0(20, _c0)); - $r3$.ɵɵstyleProp("bar", $r3$.ɵɵpipeBind2(2, 11, $ctx$.barExp, 3000))("baz", $r3$.ɵɵpipeBind2(3, 14, $ctx$.bazExp, 4000)); - $r3$.ɵɵclassProp("foo", $r3$.ɵɵpipeBind2(4, 17, $ctx$.fooExp, 2000)); + $r3$.ɵɵstyleMap($r3$.ɵɵpipeBind2(1, 11, $ctx$.myStyleExp, 1000), $r3$.ɵɵdefaultStyleSanitizer); + $r3$.ɵɵclassMap($r3$.ɵɵpureFunction0(23, _c0)); + $r3$.ɵɵstyleProp("bar", $r3$.ɵɵpipeBind2(2, 14, $ctx$.barExp, 3000))("baz", $r3$.ɵɵpipeBind2(3, 17, $ctx$.bazExp, 4000)); + $r3$.ɵɵclassProp("foo", $r3$.ɵɵpipeBind2(4, 20, $ctx$.fooExp, 2000)); $r3$.ɵɵadvance(5); $r3$.ɵɵtextInterpolate1(" ", $ctx$.item, ""); } @@ -1011,14 +1005,11 @@ describe('compiler compliance: styling', () => { }; const template = ` - hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(6); - $r3$.ɵɵelementHostAttrs($e0_attrs$); - } + hostAttrs: [${AttributeMarker.Classes}, "foo", "baz", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"], + hostVars: 8, + hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap(ctx.myStyle); + $r3$.ɵɵstyleMap(ctx.myStyle, $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵclassMap(ctx.myClass); $r3$.ɵɵstyleProp("color", ctx.myColorProp); $r3$.ɵɵclassProp("foo", ctx.myFooClass); @@ -1070,13 +1061,10 @@ describe('compiler compliance: styling', () => { }; const template = ` - hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(8); - } + hostVars: 12, + hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap(ctx.myStyle); + $r3$.ɵɵstyleMap(ctx.myStyle, $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵclassMap(ctx.myClasses); $r3$.ɵɵstyleProp("height", ctx.myHeightProp, "pt")("width", ctx.myWidthProp); $r3$.ɵɵclassProp("bar", ctx.myBarClass)("foo", ctx.myFooClass); @@ -1133,8 +1121,7 @@ describe('compiler compliance: styling', () => { $r3$.ɵɵelement(0, "div"); } if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap(ctx.myStyleExp); + $r3$.ɵɵstyleMap(ctx.myStyleExp, $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵclassMap(ctx.myClassExp); $r3$.ɵɵstyleProp("height", ctx.myHeightExp); $r3$.ɵɵclassProp("bar", ctx.myBarClassExp); @@ -1143,13 +1130,10 @@ describe('compiler compliance: styling', () => { `; const hostBindings = ` - hostBindings: function MyComponent_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(6); - } + hostVars: 8, + hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap(ctx.myStyleExp); + $r3$.ɵɵstyleMap(ctx.myStyleExp, $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵclassMap(ctx.myClassExp); $r3$.ɵɵstyleProp("width", ctx.myWidthExp); $r3$.ɵɵclassProp("foo", ctx.myFooClassExp); @@ -1209,29 +1193,24 @@ describe('compiler compliance: styling', () => { // NOTE: IF YOU ARE CHANGING THIS COMPILER SPEC, YOU MAY NEED TO CHANGE THE DIRECTIVE // DEF THAT'S HARD-CODED IN `ng_class.ts`. const template = ` - function ClassDirective_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(2); - } + … + hostVars: 2, + hostBindings: function ClassDirective_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵclassMap(ctx.myClassMap); } } … - function WidthDirective_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(2); - } + hostVars: 4, + hostBindings: function WidthDirective_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵstyleProp("width", ctx.myWidth); $r3$.ɵɵclassProp("foo", ctx.myFooClass); } } … - function HeightDirective_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(2); - } + hostVars: 4, + hostBindings: function HeightDirective_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵstyleProp("height", ctx.myHeight); $r3$.ɵɵclassProp("bar", ctx.myBarClass); @@ -1424,6 +1403,46 @@ describe('compiler compliance: styling', () => { expectEmit(result.source, template, 'Incorrect handling of interpolated style properties'); }); + it('should generate update instructions for interpolated style properties with a sanitizer', + () => { + const files = { + app: { + 'spec.ts': ` + import {Component} from '@angular/core'; + + @Component({ + template: \` +
+ \` + }) + export class MyComponent { + myUrl1 = '...'; + myUrl2 = '...'; + myBoxX = '0px'; + myBoxY = '0px'; + myBoxWidth = '100px'; + myRepeat = 'no-repeat'; + } + ` + } + }; + + const template = ` + … + if (rf & 2) { + $r3$.ɵɵstylePropInterpolate1("background", "url(", ctx.myUrl1, ")", $r3$.ɵɵdefaultStyleSanitizer); + $r3$.ɵɵstylePropInterpolate2("border-image", "url(", ctx.myUrl2, ") ", ctx.myRepeat, " auto", $r3$.ɵɵdefaultStyleSanitizer); + $r3$.ɵɵstylePropInterpolate3("box-shadow", "", ctx.myBoxX, " ", ctx.myBoxY, " ", ctx.myBoxWidth, " black"); + } + … + `; + const result = compile(files, angularFiles); + + expectEmit(result.source, template, 'Incorrect handling of interpolated style properties'); + }); + it('should generate update instructions for interpolated style properties with !important', () => { const files = { @@ -1785,7 +1804,7 @@ describe('compiler compliance: styling', () => { … MyComponent.ɵcmp = $r3$.ɵɵdefineComponent({ … - hostBindings: function MyComponent_HostBindings(rf, $ctx$, elIndex) { + hostBindings: function MyComponent_HostBindings(rf, $ctx$) { … if (rf & 2) { $r3$.ɵɵstyleProp("color", $ctx$.color)("transition", $ctx$.transition)("border", $ctx$.border); @@ -1840,17 +1859,12 @@ describe('compiler compliance: styling', () => { }; const template = ` - 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) { - $r3$.ɵɵallocHostVars(6); - $r3$.ɵɵelementHostAttrs($_c0$); - } + hostAttrs: ["title", "foo title", ${AttributeMarker.Classes}, "foo", "baz", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"], + hostVars: 6, + hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵhostProperty("id", ctx.id)("title", ctx.title); - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap(ctx.myStyle); + $r3$.ɵɵstyleMap(ctx.myStyle, $r3$.ɵɵdefaultStyleSanitizer); $r3$.ɵɵclassMap(ctx.myClass); } } @@ -1885,10 +1899,8 @@ describe('compiler compliance: styling', () => { }; const template = ` - hostBindings: function WidthDirective_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - $r3$.ɵɵallocHostVars(4); - } + hostVars: 6, + hostBindings: function WidthDirective_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵhostProperty("id", ctx.id)("title", ctx.title); $r3$.ɵɵstyleProp("width", ctx.myWidth); @@ -1926,8 +1938,7 @@ describe('compiler compliance: styling', () => { template: function MyAppComp_Template(rf, ctx) { … if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleProp("background-image", ctx.bgExp); + $r3$.ɵɵstyleProp("background-image", ctx.bgExp, $r3$.ɵɵdefaultStyleSanitizer); } … } @@ -1961,8 +1972,7 @@ describe('compiler compliance: styling', () => { template: function MyAppComp_Template(rf, ctx) { … if (rf & 2) { - $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer); - $r3$.ɵɵstyleMap(ctx.mapExp); + $r3$.ɵɵstyleMap(ctx.mapExp, $r3$.ɵɵdefaultStyleSanitizer); } … } @@ -2051,15 +2061,13 @@ describe('compiler compliance: styling', () => { }; const template = ` - hostBindings: function MyDir_HostBindings(rf, ctx, elIndex) { - … - $r3$.ɵɵallocHostVars(9); - … + hostVars: 10, + hostBindings: function MyDir_HostBindings(rf, ctx) { if (rf & 2) { $r3$.ɵɵhostProperty("title", ctx.title); $r3$.ɵɵupdateSyntheticHostBinding("@anim", - $r3$.ɵɵpureFunction2(6, _c1, ctx._animValue, - $r3$.ɵɵpureFunction2(3, _c0, ctx._animParam1, ctx._animParam2))); + $r3$.ɵɵpureFunction2(7, _c1, ctx._animValue, + $r3$.ɵɵpureFunction2(4, _c0, ctx._animParam1, ctx._animParam2))); $r3$.ɵɵclassProp("foo", ctx.foo); } } diff --git a/packages/compiler-cli/test/diagnostics/BUILD.bazel b/packages/compiler-cli/test/diagnostics/BUILD.bazel index be2cece23f..9c4dab93e3 100644 --- a/packages/compiler-cli/test/diagnostics/BUILD.bazel +++ b/packages/compiler-cli/test/diagnostics/BUILD.bazel @@ -15,7 +15,7 @@ ts_library( jasmine_node_test( name = "check_types", timeout = "long", # 900 seconds - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ "//packages/common:npm_package", "//packages/core:npm_package", @@ -28,7 +28,6 @@ jasmine_node_test( deps = [ ":check_types_lib", "//packages/core", - "//tools/testing:node", ], ) @@ -45,11 +44,8 @@ ts_library( jasmine_node_test( name = "typescript_version", - bootstrap = ["angular/tools/testing/init_node_spec.js"], - data = [ - ], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":typescript_version_lib", - "//tools/testing:node", ], ) diff --git a/packages/compiler-cli/test/metadata/BUILD.bazel b/packages/compiler-cli/test/metadata/BUILD.bazel index 8fe58d3d1e..9217416353 100644 --- a/packages/compiler-cli/test/metadata/BUILD.bazel +++ b/packages/compiler-cli/test/metadata/BUILD.bazel @@ -16,12 +16,11 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ ], deps = [ ":test_lib", "//packages/core", - "//tools/testing:node", ], ) diff --git a/packages/compiler-cli/test/ngtsc/BUILD.bazel b/packages/compiler-cli/test/ngtsc/BUILD.bazel index c9ceca5077..62467c93d9 100644 --- a/packages/compiler-cli/test/ngtsc/BUILD.bazel +++ b/packages/compiler-cli/test/ngtsc/BUILD.bazel @@ -23,14 +23,13 @@ ts_library( jasmine_node_test( name = "ngtsc", timeout = "long", - bootstrap = ["angular/tools/testing/init_node_no_angular_spec.js"], + bootstrap = ["//tools/testing:node_no_angular_es5"], data = [ "//packages/compiler-cli/test/ngtsc/fake_core:npm_package", ], shard_count = 4, deps = [ ":ngtsc_lib", - "//tools/testing:node_no_angular", "@npm//minimist", ], ) diff --git a/packages/compiler-cli/test/ngtsc/env.ts b/packages/compiler-cli/test/ngtsc/env.ts index 66b242fa7e..d8c63fb1fa 100644 --- a/packages/compiler-cli/test/ngtsc/env.ts +++ b/packages/compiler-cli/test/ngtsc/env.ts @@ -248,12 +248,31 @@ class AugmentedCompilerHost extends NgtscCompilerHost { delegate !: ts.CompilerHost; } +const ROOT_PREFIX = 'root/'; + class FileNameToModuleNameHost extends AugmentedCompilerHost { fileNameToModuleName(importedFilePath: string): string { const relativeFilePath = this.fs.relative(this.fs.pwd(), this.fs.resolve(importedFilePath)); const rootedPath = this.fs.join('root', relativeFilePath); return rootedPath.replace(/(\.d)?.ts$/, ''); } + + resolveModuleNames( + moduleNames: string[], containingFile: string, reusedNames: string[]|undefined, + redirectedReference: ts.ResolvedProjectReference|undefined, + options: ts.CompilerOptions): (ts.ResolvedModule|undefined)[] { + return moduleNames.map(moduleName => { + if (moduleName.startsWith(ROOT_PREFIX)) { + // Strip the artificially added root prefix. + moduleName = '/' + moduleName.substr(ROOT_PREFIX.length); + } + + return ts + .resolveModuleName( + moduleName, containingFile, options, this, /* cache */ undefined, redirectedReference) + .resolvedModule; + }); + } } class MultiCompileHostExt extends AugmentedCompilerHost implements Partial { diff --git a/packages/compiler-cli/test/ngtsc/incremental_spec.ts b/packages/compiler-cli/test/ngtsc/incremental_spec.ts index bca5db0dc2..f8842baae6 100644 --- a/packages/compiler-cli/test/ngtsc/incremental_spec.ts +++ b/packages/compiler-cli/test/ngtsc/incremental_spec.ts @@ -251,6 +251,72 @@ runInEachFileSystem(() => { expect(written).toContain('/foo_module.js'); }); + it('should rebuild a component if removed from an NgModule', () => { + // This test consists of a component with a dependency (the directive DepDir) provided via an + // NgModule. Initially this configuration is built, then the component is removed from its + // module (which removes DepDir from the component's scope) and a rebuild is performed. + // The compiler should re-emit the component without DepDir in its scope. + // + // This is a tricky scenario due to the backwards dependency arrow from a component to its + // module. + env.write('dep.ts', ` + import {Directive, NgModule} from '@angular/core'; + + @Directive({selector: '[dep]'}) + export class DepDir {} + + @NgModule({ + declarations: [DepDir], + exports: [DepDir], + }) + export class DepModule {} + `); + + env.write('cmp.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test-cmp', + template: '
', + }) + export class Cmp {} + `); + + env.write('module.ts', ` + import {NgModule} from '@angular/core'; + import {Cmp} from './cmp'; + import {DepModule} from './dep'; + + @NgModule({ + declarations: [Cmp], + imports: [DepModule], + }) + export class Module {} + `); + + env.driveMain(); + env.flushWrittenFileTracking(); + + // Remove the component from the module and recompile. + env.write('module.ts', ` + import {NgModule} from '@angular/core'; + import {DepModule} from './dep'; + + @NgModule({ + declarations: [], + imports: [DepModule], + }) + export class Module {} + `); + + env.driveMain(); + + // After removing the component from the module, it should have been re-emitted without DepDir + // in its scope. + expect(env.getFilesWrittenSinceLastFlush()).toContain('/cmp.js'); + expect(env.getContents('cmp.js')).not.toContain('DepDir'); + }); + it('should rebuild only a Component (but with the correct CompilationScope) and its module if its template has changed', () => { setupFooBarProgram(env); diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 11e8567501..a1f7c99211 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -192,6 +192,32 @@ runInEachFileSystem(os => { expect(jsContents).toContain('inject(Dep, 8)'); }); + it('should compile @Injectable with constructor overloads', () => { + env.write('test.ts', ` + import {Injectable, Optional} from '@angular/core'; + + @Injectable() + class Dep {} + + @Injectable() + class OptionalDep {} + + @Injectable() + class Service { + constructor(dep: Dep); + + constructor(dep: Dep, @Optional() optionalDep?: OptionalDep) {} + } + `); + env.driveMain(); + const jsContents = env.getContents('test.js'); + + expect(jsContents) + .toContain( + `Service.ɵfac = function Service_Factory(t) { ` + + `return new (t || Service)(i0.ɵɵinject(Dep), i0.ɵɵinject(OptionalDep, 8)); };`); + }); + it('should compile Directives without errors', () => { env.write('test.ts', ` import {Directive} from '@angular/core'; @@ -2184,7 +2210,7 @@ runInEachFileSystem(os => { env.driveMain(); const jsContents = env.getContents('test.js'); const hostBindingsFn = ` - hostBindings: function FooCmp_HostBindings(rf, ctx, elIndex) { + hostBindings: function FooCmp_HostBindings(rf, ctx) { if (rf & 1) { i0.ɵɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick(); })("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onDocumentClick($event.target); }, false, i0.ɵɵresolveDocument)("scroll", function FooCmp_scroll_HostBindingHandler($event) { return ctx.onWindowScroll(); }, false, i0.ɵɵresolveWindow); } @@ -2224,30 +2250,68 @@ runInEachFileSystem(os => { } }) 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 bindings', () => { + it('should throw in case pipes are used in host bindings (defined as `value | pipe`)', () => { env.write(`test.ts`, ` - import {Component} from '@angular/core'; + import {Component} from '@angular/core'; - @Component({ - selector: 'test', - template: '...', - host: { - '[id]': 'id | myPipe' - } - }) - class FooCmp {} - `); + @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 throw in case pipes are used in host bindings (defined as `!(value | pipe)`)', + () => { + 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 throw in case pipes are used in host bindings (defined as `(value | pipe) === X`)', + () => { + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '...', + host: { + '[id]': '(id | myPipe) === true' + } + }) + 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.write(`test.ts`, ` import {Component, HostBinding, HostListener, TemplateRef} from '@angular/core'; @@ -2276,9 +2340,9 @@ runInEachFileSystem(os => { env.driveMain(); const jsContents = env.getContents('test.js'); const hostBindingsFn = ` - hostBindings: function FooCmp_HostBindings(rf, ctx, elIndex) { + hostVars: 4, + hostBindings: function FooCmp_HostBindings(rf, ctx) { if (rf & 1) { - i0.ɵɵallocHostVars(3); i0.ɵɵlistener("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onClick($event); })("click", function FooCmp_click_HostBindingHandler($event) { return ctx.onBodyClick($event); }, false, i0.ɵɵresolveBody)("change", function FooCmp_change_HostBindingHandler($event) { return ctx.onChange(ctx.arg1, ctx.arg2, ctx.arg3); }); } if (rf & 2) { @@ -2312,7 +2376,7 @@ runInEachFileSystem(os => { `); env.driveMain(); const jsContents = env.getContents('test.js'); - expect(jsContents).toContain('i0.ɵɵelementHostAttrs(["test", test])'); + expect(jsContents).toContain('hostAttrs: ["test", test]'); }); it('should accept enum values as host bindings', () => { @@ -2355,7 +2419,7 @@ runInEachFileSystem(os => { env.driveMain(); const jsContents = env.getContents('test.js'); const hostBindingsFn = ` - hostBindings: function Dir_HostBindings(rf, ctx, elIndex) { + hostBindings: function Dir_HostBindings(rf, ctx) { if (rf & 1) { i0.ɵɵlistener("change", function Dir_change_HostBindingHandler($event) { return ctx.onChange(ctx.arg); }); } @@ -3488,6 +3552,54 @@ runInEachFileSystem(os => { }); }); + // Run checks that are present in preanalysis phase in both sync and async mode, to make sure + // the error messages are consistently thrown from `analyzeSync` and `analyzeAsync` functions. + ['sync', 'async'].forEach(mode => { + describe(`preanalysis phase checks [${mode}]`, () => { + let driveDiagnostics: () => Promise>; + beforeEach(() => { + if (mode === 'async') { + env.enablePreloading(); + driveDiagnostics = () => env.driveDiagnosticsAsync(); + } else { + driveDiagnostics = () => Promise.resolve(env.driveDiagnostics()); + } + }); + + it('should throw if @Component is missing a template', async() => { + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + }) + export class TestCmp {} + `); + + const diags = await driveDiagnostics(); + expect(diags[0].messageText).toBe('component is missing a template'); + expect(diags[0].file !.fileName).toBe(absoluteFrom('/test.ts')); + }); + + it('should throw if `styleUrls` is defined incorrectly in @Component', async() => { + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '...', + styleUrls: '...' + }) + export class TestCmp {} + `); + + const diags = await driveDiagnostics(); + expect(diags[0].messageText).toBe('styleUrls must be an array of strings'); + expect(diags[0].file !.fileName).toBe(absoluteFrom('/test.ts')); + }); + }); + }); + describe('flat module indices', () => { it('should generate a basic flat module index', () => { env.tsconfig({ @@ -4198,10 +4310,8 @@ runInEachFileSystem(os => { env.driveMain(); const jsContents = env.getContents('test.js'); const hostBindingsFn = ` - hostBindings: function UnsafeAttrsDirective_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - i0.ɵɵallocHostVars(6); - } + hostVars: 6, + hostBindings: function UnsafeAttrsDirective_HostBindings(rf, ctx) { if (rf & 2) { i0.ɵɵattribute("href", ctx.attrHref, i0.ɵɵsanitizeUrlOrResourceUrl)("src", ctx.attrSrc, i0.ɵɵsanitizeUrlOrResourceUrl)("action", ctx.attrAction, i0.ɵɵsanitizeUrl)("profile", ctx.attrProfile, i0.ɵɵsanitizeResourceUrl)("innerHTML", ctx.attrInnerHTML, i0.ɵɵsanitizeHtml)("title", ctx.attrSafeTitle); } @@ -4248,10 +4358,8 @@ runInEachFileSystem(os => { env.driveMain(); const jsContents = env.getContents('test.js'); const hostBindingsFn = ` - hostBindings: function UnsafePropsDirective_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - i0.ɵɵallocHostVars(6); - } + hostVars: 6, + hostBindings: function UnsafePropsDirective_HostBindings(rf, ctx) { if (rf & 2) { i0.ɵɵhostProperty("href", ctx.propHref, i0.ɵɵsanitizeUrlOrResourceUrl)("src", ctx.propSrc, i0.ɵɵsanitizeUrlOrResourceUrl)("action", ctx.propAction, i0.ɵɵsanitizeUrl)("profile", ctx.propProfile, i0.ɵɵsanitizeResourceUrl)("innerHTML", ctx.propInnerHTML, i0.ɵɵsanitizeHtml)("title", ctx.propSafeTitle); } @@ -4283,10 +4391,8 @@ runInEachFileSystem(os => { env.driveMain(); const jsContents = env.getContents('test.js'); const hostBindingsFn = ` - hostBindings: function FooCmp_HostBindings(rf, ctx, elIndex) { - if (rf & 1) { - i0.ɵɵallocHostVars(6); - } + hostVars: 6, + hostBindings: function FooCmp_HostBindings(rf, ctx) { if (rf & 2) { i0.ɵɵhostProperty("src", ctx.srcProp)("href", ctx.hrefProp)("title", ctx.titleProp); i0.ɵɵattribute("src", ctx.srcAttr)("href", ctx.hrefAttr)("title", ctx.titleAttr); diff --git a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts index 543f106218..d97a9ac640 100644 --- a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts @@ -135,6 +135,8 @@ export declare class AnimationEvent { const diags = env.driveDiagnostics(); expect(diags.length).toBe(1); expect(diags[0].messageText).toEqual(`Type 'string' is not assignable to type 'number'.`); + // The reported error code should be in the TS error space, not a -99 "NG" code. + expect(diags[0].code).toBeGreaterThan(0); }); it('should support inputs and outputs with names that are not JavaScript identifiers', () => { @@ -174,6 +176,33 @@ export declare class AnimationEvent { .toEqual(`Argument of type 'string' is not assignable to parameter of type 'number'.`); }); + it('should support one input property mapping to multiple fields', () => { + env.write('test.ts', ` + import {Component, Directive, Input, NgModule} from '@angular/core'; + + @Directive({ + selector: '[dir]', + }) + export class Dir { + + @Input('propertyName') fieldA!: string; + @Input('propertyName') fieldB!: string; + } + + @Component({ + selector: 'test-cmp', + template: '
', + }) + export class Cmp {} + + @NgModule({declarations: [Dir, Cmp]}) + export class Module {} + `); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(0); + }); + it('should check event bindings', () => { env.tsconfig({fullTemplateTypeCheck: true, strictOutputEventTypes: true}); env.write('test.ts', ` @@ -945,7 +974,8 @@ export declare class AnimationEvent { }); it('should constrain types using type parameter bounds', () => { - env.tsconfig({fullTemplateTypeCheck: true, strictInputTypes: true}); + env.tsconfig( + {fullTemplateTypeCheck: true, strictInputTypes: true, strictContextGenerics: true}); env.write('test.ts', ` import {CommonModule} from '@angular/common'; import {Component, Input, NgModule} from '@angular/core'; @@ -1146,6 +1176,71 @@ export declare class AnimationEvent { expect(getSourceCodeForDiagnostic(diags[0])).toEqual('y = !y'); }); + it('should still type-check when fileToModuleName aliasing is enabled, but alias exports are not in the .d.ts file', + () => { + // The template type-checking file imports directives/pipes in order to type-check their + // usage. When `UnifiedModulesHost` aliasing is enabled, these imports would ordinarily use + // aliased values. However, such aliases are not guaranteed to exist in the .d.ts files, + // and so feeding such imports back into TypeScript does not work. + // + // Instead, direct imports should be used within template type-checking code. This test + // verifies that template type-checking is able to cope with such a scenario where + // aliasing is enabled and alias re-exports don't exist in .d.ts files. + env.tsconfig({ + // Setting this private flag turns on aliasing. + '_useHostForImportGeneration': true, + // Because the tsconfig is overridden, template type-checking needs to be turned back on + // explicitly as well. + 'fullTemplateTypeCheck': true, + }); + + // 'alpha' declares the directive which will ultimately be imported. + env.write('alpha.d.ts', ` + import {ɵɵDirectiveDefWithMeta, ɵɵNgModuleDefWithMeta} from '@angular/core'; + + export declare class ExternalDir { + input: string; + static ɵdir: ɵɵDirectiveDefWithMeta; + } + + export declare class AlphaModule { + static ɵmod: ɵɵNgModuleDefWithMeta; + } + `); + + // 'beta' re-exports AlphaModule from alpha. + env.write('beta.d.ts', ` + import {ɵɵNgModuleDefWithMeta} from '@angular/core'; + import {AlphaModule} from './alpha'; + + export declare class BetaModule { + static ɵmod: ɵɵNgModuleDefWithMeta; + } + `); + + // The application imports BetaModule from beta, gaining visibility of ExternalDir from + // alpha. + env.write('test.ts', ` + import {Component, NgModule} from '@angular/core'; + import {BetaModule} from './beta'; + + @Component({ + selector: 'cmp', + template: '
', + }) + export class Cmp {} + + @NgModule({ + declarations: [Cmp], + imports: [BetaModule], + }) + export class Module {} + `); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(0); + }); + describe('input coercion', () => { beforeEach(() => { env.tsconfig({fullTemplateTypeCheck: true, strictInputTypes: true}); diff --git a/packages/compiler-cli/test/perform_watch_spec.ts b/packages/compiler-cli/test/perform_watch_spec.ts index 479a3e388b..1ce31d7ac6 100644 --- a/packages/compiler-cli/test/perform_watch_spec.ts +++ b/packages/compiler-cli/test/perform_watch_spec.ts @@ -64,7 +64,7 @@ describe('perform watch', () => { const watchResult = performWatchCompilation(host); expectNoDiagnostics(config.options, watchResult.firstCompileResult); - const htmlPath = path.posix.join(testSupport.basePath, 'src', 'main.html'); + const htmlPath = path.join(testSupport.basePath, 'src', 'main.html'); const genPath = ivyEnabled ? path.posix.join(outDir, 'src', 'main.js') : path.posix.join(outDir, 'src', 'main.ngfactory.js'); diff --git a/packages/compiler-cli/test/transformers/BUILD.bazel b/packages/compiler-cli/test/transformers/BUILD.bazel index 8c9b603f4f..dd82f46edc 100644 --- a/packages/compiler-cli/test/transformers/BUILD.bazel +++ b/packages/compiler-cli/test/transformers/BUILD.bazel @@ -19,7 +19,7 @@ ts_library( jasmine_node_test( name = "test", timeout = "long", # 900 seconds - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ "//packages/common:npm_package", "//packages/core:npm_package", @@ -33,7 +33,6 @@ jasmine_node_test( deps = [ ":test_lib", "//packages/core", - "//tools/testing:node", "@npm//source-map", ], ) diff --git a/packages/compiler/design/architecture.md b/packages/compiler/design/architecture.md index c21ac1399b..d8427a61c8 100644 --- a/packages/compiler/design/architecture.md +++ b/packages/compiler/design/architecture.md @@ -169,7 +169,7 @@ Angular supports the following class decorators: There are also a list of helper decorators that make the `@Component` and `@Directive` easier to use such as `@Input`, `@Output`, etc.; as well as a set of decorators that help `@Injectable` classes customize the injector such as `@Inject` and `@SkipSelf`. -Each of the class decorators can be thought of as class transformers that take the declared class and transform it, possibly using information from the helper decorators, to produce an Angular class. The JIT compiler performs this transformation at runtime. The AoT compiler performs this transformation at compile time. +Each of the class decorators can be thought of as class transformers that take the declared class and transform it, possibly using information from the helper decorators, to produce an Angular class. The JIT compiler performs this transformation at runtime. The AOT compiler performs this transformation at compile time. Each of the class decorators' class transformer creates a corresponding static member on the class that describes to the runtime how to use the class. For example, the `@Component` decorator creates a `ɵcmp` static member, `@Directive` create a `ɵdir`, etc. Internally, these class transformers are called a "Compiler". Most of the compilers are straight forward translations of the metadata specified in the decorator to the information provided in the corresponding definition and, therefore, do not require anything outside the source file to perform the conversion. However, the component, during production builds and for type checking a template require the module scope of the component which requires information from other files in the program. diff --git a/packages/compiler/src/expression_parser/parser.ts b/packages/compiler/src/expression_parser/parser.ts index 23d804d19b..b34855b825 100644 --- a/packages/compiler/src/expression_parser/parser.ts +++ b/packages/compiler/src/expression_parser/parser.ts @@ -42,6 +42,8 @@ export class Parser { constructor(private _lexer: Lexer) {} + simpleExpressionChecker = SimpleExpressionChecker; + parseAction( input: string, location: any, absoluteOffset: number, interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ASTWithSource { @@ -62,11 +64,17 @@ export class Parser { return new ASTWithSource(ast, input, location, absoluteOffset, this.errors); } + private checkSimpleExpression(ast: AST): string[] { + const checker = new this.simpleExpressionChecker(); + ast.visit(checker); + return checker.errors; + } + parseSimpleBinding( input: string, location: string, absoluteOffset: number, interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ASTWithSource { const ast = this._parseBindingAst(input, location, absoluteOffset, interpolationConfig); - const errors = SimpleExpressionChecker.check(ast); + const errors = this.checkSimpleExpression(ast); if (errors.length > 0) { this._reportError( `Host binding expression cannot contain ${errors.join(' ')}`, input, location); @@ -234,6 +242,10 @@ export class Parser { } } +export class IvyParser extends Parser { + simpleExpressionChecker = IvySimpleExpressionChecker; // +} + export class _ParseAST { private rparensExpected = 0; private rbracketsExpected = 0; @@ -825,12 +837,6 @@ export class _ParseAST { } class SimpleExpressionChecker implements AstVisitor { - static check(ast: AST): string[] { - const s = new SimpleExpressionChecker(); - ast.visit(s); - return s.errors; - } - errors: string[] = []; visitImplicitReceiver(ast: ImplicitReceiver, context: any) {} @@ -875,3 +881,19 @@ class SimpleExpressionChecker implements AstVisitor { visitQuote(ast: Quote, context: any) {} } + +/** + * This class extends SimpleExpressionChecker used in View Engine and performs more strict checks to + * make sure host bindings do not contain pipes. In View Engine, having pipes in host bindings is + * not supported as well, but in some cases (like `!(value | async)`) the error is not triggered at + * compile time. In order to preserve View Engine behavior, more strict checks are introduced for + * Ivy mode only. + */ +class IvySimpleExpressionChecker extends SimpleExpressionChecker { + visitBinary(ast: Binary, context: any) { + ast.left.visit(this); + ast.right.visit(this); + } + + visitPrefixNot(ast: PrefixNot, context: any) { ast.expression.visit(this); } +} \ No newline at end of file diff --git a/packages/compiler/src/output/abstract_emitter.ts b/packages/compiler/src/output/abstract_emitter.ts index ff10e36a4a..3c809fa590 100644 --- a/packages/compiler/src/output/abstract_emitter.ts +++ b/packages/compiler/src/output/abstract_emitter.ts @@ -36,6 +36,10 @@ export class EmitterVisitorContext { constructor(private _indent: number) { this._lines = [new _EmittedLine(_indent)]; } + /** + * @internal strip this from published d.ts files due to + * https://github.com/microsoft/TypeScript/issues/36216 + */ private get _currentLine(): _EmittedLine { return this._lines[this._lines.length - 1]; } println(from?: {sourceSpan: ParseSourceSpan | null}|null, lastPart: string = ''): void { @@ -169,6 +173,10 @@ export class EmitterVisitorContext { return null; } + /** + * @internal strip this from published d.ts files due to + * https://github.com/microsoft/TypeScript/issues/36216 + */ private get sourceLines(): _EmittedLine[] { if (this._lines.length && this._lines[this._lines.length - 1].parts.length === 0) { return this._lines.slice(0, -1); diff --git a/packages/compiler/src/output/source_map.ts b/packages/compiler/src/output/source_map.ts index 595e94221c..359e5fb071 100644 --- a/packages/compiler/src/output/source_map.ts +++ b/packages/compiler/src/output/source_map.ts @@ -74,6 +74,10 @@ export class SourceMapGenerator { return this; } + /** + * @internal strip this from published d.ts files due to + * https://github.com/microsoft/TypeScript/issues/36216 + */ private get currentLine(): Segment[]|null { return this.lines.slice(-1)[0]; } toJSON(): SourceMap|null { diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts index dc43f681a2..c0d70a74cb 100644 --- a/packages/compiler/src/render3/r3_identifiers.ts +++ b/packages/compiler/src/render3/r3_identifiers.ts @@ -113,10 +113,6 @@ export class Identifiers { static stylePropInterpolateV: o.ExternalReference = {name: 'ɵɵstylePropInterpolateV', moduleName: CORE}; - static styleSanitizer: o.ExternalReference = {name: 'ɵɵstyleSanitizer', moduleName: CORE}; - - static elementHostAttrs: o.ExternalReference = {name: 'ɵɵelementHostAttrs', moduleName: CORE}; - static containerCreate: o.ExternalReference = {name: 'ɵɵcontainer', moduleName: CORE}; static nextContext: o.ExternalReference = {name: 'ɵɵnextContext', moduleName: CORE}; @@ -129,8 +125,6 @@ export class Identifiers { static disableBindings: o.ExternalReference = {name: 'ɵɵdisableBindings', moduleName: CORE}; - static allocHostVars: o.ExternalReference = {name: 'ɵɵallocHostVars', moduleName: CORE}; - static getCurrentView: o.ExternalReference = {name: 'ɵɵgetCurrentView', moduleName: CORE}; static textInterpolate: o.ExternalReference = {name: 'ɵɵtextInterpolate', moduleName: CORE}; diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index f0fa0e4944..e105af2d17 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -28,7 +28,7 @@ import {Render3ParseResult} from '../r3_template_transform'; import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util'; import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from './api'; -import {StylingBuilder, StylingInstructionCall} from './styling_builder'; +import {MIN_STYLING_BINDING_SLOTS_REQUIRED, StylingBuilder, StylingInstructionCall} from './styling_builder'; import {BindingScope, TemplateDefinitionBuilder, ValueConverter, makeBindingParser, prepareEventListenerParameters, renderFlagCheckIfStmt, resolveSanitizationFn} from './template'; import {CONTEXT_NAME, DefinitionMap, RENDER_FLAGS, TEMPORARY_NAME, asLiteral, chainedInstruction, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator} from './util'; @@ -63,11 +63,11 @@ function baseDirectiveFields( 'viewQuery', createViewQueriesFunction(meta.viewQueries, constantPool, meta.name)); } - // e.g. `hostBindings: (rf, ctx, elIndex) => { ... } + // e.g. `hostBindings: (rf, ctx) => { ... } definitionMap.set( 'hostBindings', createHostBindingsFunction( meta.host, meta.typeSourceSpan, bindingParser, constantPool, - meta.selector || '', meta.name)); + meta.selector || '', meta.name, definitionMap)); // e.g 'inputs: {a: 'a'}` definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true)); @@ -528,13 +528,10 @@ function createViewQueriesFunction( // Return a host binding function or null if one is not necessary. function createHostBindingsFunction( hostBindingsMetadata: R3HostMetadata, typeSourceSpan: ParseSourceSpan, - bindingParser: BindingParser, constantPool: ConstantPool, selector: string, - name?: string): o.Expression|null { - // Initialize hostVarsCount to number of bound host properties (interpolations illegal) - const hostVarsCount = Object.keys(hostBindingsMetadata.properties).length; - const elVarExp = o.variable('elIndex'); + bindingParser: BindingParser, constantPool: ConstantPool, selector: string, name: string, + definitionMap: DefinitionMap): o.Expression|null { const bindingContext = o.variable(CONTEXT_NAME); - const styleBuilder = new StylingBuilder(elVarExp, bindingContext); + const styleBuilder = new StylingBuilder(bindingContext); const {styleAttr, classAttr} = hostBindingsMetadata.specialAttributes; if (styleAttr !== undefined) { @@ -547,10 +544,38 @@ function createHostBindingsFunction( const createStatements: o.Statement[] = []; const updateStatements: o.Statement[] = []; - let totalHostVarsCount = hostVarsCount; const hostBindingSourceSpan = typeSourceSpan; const directiveSummary = metadataAsSummary(hostBindingsMetadata); + // Calculate host event bindings + const eventBindings = + bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan); + if (eventBindings && eventBindings.length) { + const listeners = createHostListeners(eventBindings, name); + createStatements.push(...listeners); + } + + // Calculate the host property bindings + const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan); + const allOtherBindings: ParsedProperty[] = []; + + // We need to calculate the total amount of binding slots required by + // all the instructions together before any value conversions happen. + // Value conversions may require additional slots for interpolation and + // bindings with pipes. These calculates happen after this block. + let totalHostVarsCount = 0; + bindings && bindings.forEach((binding: ParsedProperty) => { + const name = binding.name; + const stylingInputWasSet = + styleBuilder.registerInputBasedOnName(name, binding.expression, binding.sourceSpan); + if (stylingInputWasSet) { + totalHostVarsCount += MIN_STYLING_BINDING_SLOTS_REQUIRED; + } else { + allOtherBindings.push(binding); + totalHostVarsCount++; + } + }); + let valueConverter: ValueConverter; const getValueConverter = () => { if (!valueConverter) { @@ -568,66 +593,50 @@ function createHostBindingsFunction( return valueConverter; }; - // Calculate host event bindings - const eventBindings = - bindingParser.createDirectiveHostEventAsts(directiveSummary, hostBindingSourceSpan); - if (eventBindings && eventBindings.length) { - const listeners = createHostListeners(eventBindings, name); - createStatements.push(...listeners); - } - - // Calculate the host property bindings - const bindings = bindingParser.createBoundHostProperties(directiveSummary, hostBindingSourceSpan); const propertyBindings: o.Expression[][] = []; const attributeBindings: o.Expression[][] = []; const syntheticHostBindings: o.Expression[][] = []; + allOtherBindings.forEach((binding: ParsedProperty) => { + // resolve literal arrays and literal objects + const value = binding.expression.visit(getValueConverter()); + const bindingExpr = bindingFn(bindingContext, value); - bindings && 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 {bindingName, instruction, isAttribute} = getBindingNameAndInstruction(binding); - const {bindingName, instruction, isAttribute} = getBindingNameAndInstruction(binding); + const securityContexts = + bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute) + .filter(context => context !== core.SecurityContext.NONE); - const securityContexts = - bindingParser.calcPossibleSecurityContexts(selector, bindingName, isAttribute) - .filter(context => context !== core.SecurityContext.NONE); - - 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.literal(bindingName), bindingExpr.currValExpr]; - if (sanitizerFn) { - instructionParams.push(sanitizerFn); - } - - updateStatements.push(...bindingExpr.stmts); - - if (instruction === R3.hostProperty) { - propertyBindings.push(instructionParams); - } else if (instruction === R3.attribute) { - attributeBindings.push(instructionParams); - } else if (instruction === R3.updateSyntheticHostBinding) { - syntheticHostBindings.push(instructionParams); + 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 { - updateStatements.push(o.importExpr(instruction).callFn(instructionParams).toStmt()); + sanitizerFn = resolveSanitizationFn(securityContexts[0], isAttribute); } } + const instructionParams = [o.literal(bindingName), bindingExpr.currValExpr]; + if (sanitizerFn) { + instructionParams.push(sanitizerFn); + } + + updateStatements.push(...bindingExpr.stmts); + + if (instruction === R3.hostProperty) { + propertyBindings.push(instructionParams); + } else if (instruction === R3.attribute) { + attributeBindings.push(instructionParams); + } else if (instruction === R3.updateSyntheticHostBinding) { + syntheticHostBindings.push(instructionParams); + } else { + updateStatements.push(o.importExpr(instruction).callFn(instructionParams).toStmt()); + } }); if (propertyBindings.length > 0) { @@ -651,14 +660,7 @@ function createHostBindingsFunction( // to the host element alongside any of the provided host attributes that were // collected earlier. const hostAttrs = convertAttributesToExpressions(hostBindingsMetadata.attributes); - const hostInstruction = styleBuilder.buildHostAttrsInstruction(null, hostAttrs, constantPool); - if (hostInstruction && hostInstruction.calls.length > 0) { - createStatements.push( - chainedInstruction( - hostInstruction.reference, - hostInstruction.calls.map(call => convertStylingCall(call, bindingContext, bindingFn))) - .toStmt()); - } + styleBuilder.assignHostAttrs(hostAttrs, definitionMap); if (styleBuilder.hasBindings) { // finally each binding that was registered in the statement above will need to be added to @@ -671,7 +673,8 @@ function createHostBindingsFunction( instruction.calls.forEach(call => { // we subtract a value of `1` here because the binding slot was already allocated // at the top of this method when all the input bindings were counted. - totalHostVarsCount += Math.max(call.allocateBindingSlots - 1, 0); + totalHostVarsCount += + Math.max(call.allocateBindingSlots - MIN_STYLING_BINDING_SLOTS_REQUIRED, 0); calls.push(convertStylingCall(call, bindingContext, bindingFn)); }); @@ -681,8 +684,7 @@ function createHostBindingsFunction( } if (totalHostVarsCount) { - createStatements.unshift( - o.importExpr(R3.allocHostVars).callFn([o.literal(totalHostVarsCount)]).toStmt()); + definitionMap.set('hostVars', o.literal(totalHostVarsCount)); } if (createStatements.length > 0 || updateStatements.length > 0) { @@ -695,11 +697,8 @@ function createHostBindingsFunction( statements.push(renderFlagCheckIfStmt(core.RenderFlags.Update, updateStatements)); } return o.fn( - [ - new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null), - new o.FnParam(elVarExp.name !, o.NUMBER_TYPE) - ], - statements, o.INFERRED_TYPE, null, hostBindingsFnName); + [new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null)], statements, + o.INFERRED_TYPE, null, hostBindingsFnName); } return null; diff --git a/packages/compiler/src/render3/view/style_parser.ts b/packages/compiler/src/render3/view/style_parser.ts index 97b3f8c83f..f0de8e362b 100644 --- a/packages/compiler/src/render3/view/style_parser.ts +++ b/packages/compiler/src/render3/view/style_parser.ts @@ -30,7 +30,7 @@ export function parse(value: string): string[] { // we use a string array here instead of a string map // because a string-map is not guaranteed to retain the // order of the entries whereas a string array can be - // construted in a [key, value, key, value] format. + // constructed in a [key, value, key, value] format. const styles: string[] = []; let i = 0; diff --git a/packages/compiler/src/render3/view/styling_builder.ts b/packages/compiler/src/render3/view/styling_builder.ts index 67d546ecab..9ac6d594f1 100644 --- a/packages/compiler/src/render3/view/styling_builder.ts +++ b/packages/compiler/src/render3/view/styling_builder.ts @@ -16,10 +16,60 @@ import {Identifiers as R3} from '../r3_identifiers'; import {hyphenate, parse as parseStyle} from './style_parser'; import {ValueConverter} from './template'; -import {getInterpolationArgsLength} from './util'; +import {DefinitionMap, getInterpolationArgsLength} from './util'; const IMPORTANT_FLAG = '!important'; +/** + * Minimum amount of binding slots required in the runtime for style/class bindings. + * + * Styling in Angular uses up two slots in the runtime LView/TData data structures to + * record binding data, property information and metadata. + * + * When a binding is registered it will place the following information in the `LView`: + * + * slot 1) binding value + * slot 2) cached value (all other values collected before it in string form) + * + * When a binding is registered it will place the following information in the `TData`: + * + * slot 1) prop name + * slot 2) binding index that points to the previous style/class binding (and some extra config + * values) + * + * Let's imagine we have a binding that looks like so: + * + * ``` + *
+ * ``` + * + * Our `LView` and `TData` data-structures look like so: + * + * ```typescript + * LView = [ + * // ... + * x, // value of x + * "width: x", + * + * y, // value of y + * "width: x; height: y", + * // ... + * ]; + * + * TData = [ + * // ... + * "width", // binding slot 20 + * 0, + * + * "height", + * 20, + * // ... + * ]; + * ``` + * + * */ +export const MIN_STYLING_BINDING_SLOTS_REQUIRED = 2; + /** * A styling expression summary that is to be processed by the compiler */ @@ -44,6 +94,7 @@ interface BoundStylingEntry { name: string|null; unit: string|null; sourceSpan: ParseSourceSpan; + sanitize: boolean; value: AST; } @@ -116,11 +167,7 @@ export class StylingBuilder { private _initialStyleValues: string[] = []; private _initialClassValues: string[] = []; - // certain style properties ALWAYS need sanitization - // this is checked each time new styles are encountered - private _useDefaultSanitizer = false; - - constructor(private _elementIndexExpr: o.Expression, private _directiveExpr: o.Expression|null) {} + constructor(private _directiveExpr: o.Expression|null) {} /** * Registers a given input to the styling builder to be later used when producing AOT code. @@ -179,14 +226,13 @@ export class StylingBuilder { const {property, hasOverrideFlag, unit: bindingUnit} = parseProperty(name); const entry: BoundStylingEntry = { name: property, + sanitize: property ? isStyleSanitizable(property) : true, 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; @@ -202,8 +248,8 @@ export class StylingBuilder { return null; } const {property, hasOverrideFlag} = parseProperty(name); - const entry: - BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, unit: null}; + const entry: BoundStylingEntry = + {name: property, value, sourceSpan, sanitize: false, hasOverrideFlag, unit: null}; if (isMapBased) { if (this._classMapInput) { throw new Error( @@ -279,27 +325,11 @@ export class StylingBuilder { * 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. */ - buildHostAttrsInstruction( - sourceSpan: ParseSourceSpan|null, attrs: o.Expression[], - constantPool: ConstantPool): StylingInstruction|null { + assignHostAttrs(attrs: o.Expression[], definitionMap: DefinitionMap): void { if (this._directiveExpr && (attrs.length || this._hasInitialValues)) { - return { - reference: R3.elementHostAttrs, - calls: [{ - sourceSpan, - allocateBindingSlots: 0, - params: () => { - // params => elementHostAttrs(attrs) - this.populateInitialStylingAttrs(attrs); - const attrArray = !attrs.some(attr => attr instanceof o.WrappedNodeExpr) ? - getConstantLiteralFromArray(constantPool, attrs) : - o.literalArr(attrs); - return [attrArray]; - } - }] - }; + this.populateInitialStylingAttrs(attrs); + definitionMap.set('hostAttrs', o.literalArr(attrs)); } - return null; } /** @@ -335,7 +365,7 @@ export class StylingBuilder { // map-based bindings allocate two slots: one for the // previous binding value and another for the previous // className or style attribute value. - let totalBindingSlotsRequired = 2; + let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED; // these values must be outside of the update block so that they can // be evaluated (the AST visit call) during creation time so that any @@ -357,17 +387,23 @@ export class StylingBuilder { allocateBindingSlots: totalBindingSlotsRequired, params: (convertFn: (value: any) => o.Expression | o.Expression[]) => { const convertResult = convertFn(mapValue); - return Array.isArray(convertResult) ? convertResult : [convertResult]; + const params = Array.isArray(convertResult) ? convertResult : [convertResult]; + + // [style] instructions will sanitize all their values. For this reason we + // need to include the sanitizer as a param. + if (!isClassBased) { + params.push(o.importExpr(R3.defaultStyleSanitizer)); + } + return params; } }] }; } private _buildSingleInputs( - reference: o.ExternalReference, inputs: BoundStylingEntry[], mapIndex: Map, - allowUnits: boolean, valueConverter: ValueConverter, - getInterpolationExpressionFn?: (value: Interpolation) => o.ExternalReference): - StylingInstruction[] { + reference: o.ExternalReference, inputs: BoundStylingEntry[], valueConverter: ValueConverter, + getInterpolationExpressionFn: ((value: Interpolation) => o.ExternalReference)|null, + isClassBased: boolean): StylingInstruction[] { const instructions: StylingInstruction[] = []; inputs.forEach(input => { @@ -375,7 +411,14 @@ export class StylingBuilder { instructions[instructions.length - 1]; const value = input.value.visit(valueConverter); let referenceForCall = reference; - let totalBindingSlotsRequired = 1; // each styling binding value is stored in the LView + + // each styling binding value is stored in the LView + // but there are two values stored for each binding: + // 1) the value itself + // 2) an intermediate value (concatenation of style up to this point). + // We need to store the intermediate value so that we don't allocate + // the strings on each CD. + let totalBindingSlotsRequired = MIN_STYLING_BINDING_SLOTS_REQUIRED; if (value instanceof Interpolation) { totalBindingSlotsRequired += value.expressions.length; @@ -390,7 +433,7 @@ export class StylingBuilder { allocateBindingSlots: totalBindingSlotsRequired, supportsInterpolation: !!getInterpolationExpressionFn, params: (convertFn: (value: any) => o.Expression | o.Expression[]) => { - // params => stylingProp(propName, value) + // params => stylingProp(propName, value, suffix|sanitizer) const params: o.Expression[] = []; params.push(o.literal(input.name)); @@ -401,8 +444,16 @@ export class StylingBuilder { params.push(convertResult); } - if (allowUnits && input.unit) { - params.push(o.literal(input.unit)); + // [style.prop] bindings may use suffix values (e.g. px, em, etc...) and they + // can also use a sanitizer. Sanitization occurs for url-based entries. Having + // the suffix value and a sanitizer together into the instruction doesn't make + // any sense (url-based entries cannot be sanitized). + if (!isClassBased) { + if (input.unit) { + params.push(o.literal(input.unit)); + } else if (input.sanitize) { + params.push(o.importExpr(R3.defaultStyleSanitizer)); + } } return params; @@ -427,7 +478,7 @@ export class StylingBuilder { private _buildClassInputs(valueConverter: ValueConverter): StylingInstruction[] { if (this._singleClassInputs) { return this._buildSingleInputs( - R3.classProp, this._singleClassInputs, this._classesIndex, false, valueConverter); + R3.classProp, this._singleClassInputs, valueConverter, null, true); } return []; } @@ -435,23 +486,12 @@ export class StylingBuilder { private _buildStyleInputs(valueConverter: ValueConverter): StylingInstruction[] { if (this._singleStyleInputs) { return this._buildSingleInputs( - R3.styleProp, this._singleStyleInputs, this._stylesIndex, true, valueConverter, - getStylePropInterpolationExpression); + R3.styleProp, this._singleStyleInputs, valueConverter, + getStylePropInterpolationExpression, false); } return []; } - private _buildSanitizerFn(): StylingInstruction { - return { - reference: R3.styleSanitizer, - calls: [{ - sourceSpan: this._firstStylingInput ? this._firstStylingInput.sourceSpan : null, - allocateBindingSlots: 0, - params: () => [o.importExpr(R3.defaultStyleSanitizer)] - }] - }; - } - /** * Constructs all instructions which contain the expressions that will be placed * into the update block of a template function or a directive hostBindings function. @@ -459,9 +499,6 @@ export class StylingBuilder { buildUpdateLevelInstructions(valueConverter: ValueConverter) { const instructions: StylingInstruction[] = []; if (this.hasBindings) { - if (this._useDefaultSanitizer) { - instructions.push(this._buildSanitizerFn()); - } const styleMapInstruction = this.buildStyleMapInstruction(valueConverter); if (styleMapInstruction) { instructions.push(styleMapInstruction); @@ -487,9 +524,10 @@ function isStyleSanitizable(prop: string): boolean { // Note that browsers support both the dash case and // camel case property names when setting through JS. return prop === 'background-image' || prop === 'backgroundImage' || prop === 'background' || - prop === 'border-image' || prop === 'borderImage' || prop === 'filter' || - prop === 'list-style' || prop === 'listStyle' || prop === 'list-style-image' || - prop === 'listStyleImage' || prop === 'clip-path' || prop === 'clipPath'; + prop === 'border-image' || prop === 'borderImage' || prop === 'border-image-source' || + prop === 'borderImageSource' || prop === 'filter' || prop === 'list-style' || + prop === 'listStyle' || prop === 'list-style-image' || prop === 'listStyleImage' || + prop === 'clip-path' || prop === 'clipPath'; } /** diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index d94c65d6dd..990e092220 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -12,7 +12,7 @@ import {ConstantPool} from '../../constant_pool'; import * as core from '../../core'; import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast'; import {Lexer} from '../../expression_parser/lexer'; -import {Parser} from '../../expression_parser/parser'; +import {IvyParser} from '../../expression_parser/parser'; import * as i18n from '../../i18n/i18n_ast'; import * as html from '../../ml_parser/ast'; import {HtmlParser} from '../../ml_parser/html_parser'; @@ -520,7 +520,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver visitElement(element: t.Element) { const elementIndex = this.allocateDataSlot(); - const stylingBuilder = new StylingBuilder(o.literal(elementIndex), null); + const stylingBuilder = new StylingBuilder(null); let isNonBindableMode: boolean = false; const isI18nRootElement: boolean = @@ -684,7 +684,7 @@ export class TemplateDefinitionBuilder implements t.Visitor, LocalResolver // the code here will collect all update-level styling instructions and add them to the // update block of the template function AOT code. Instructions like `styleProp`, - // `styleMap`, `classMap`, `classProp` and `stylingApply` + // `styleMap`, `classMap`, `classProp` // are all generated and assigned in the code below. const stylingInstructions = stylingBuilder.buildUpdateLevelInstructions(this._valueConverter); const limit = stylingInstructions.length - 1; @@ -2004,7 +2004,8 @@ const elementRegistry = new DomElementSchemaRegistry(); */ export function makeBindingParser( interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): BindingParser { - return new BindingParser(new Parser(new Lexer()), interpolationConfig, elementRegistry, null, []); + return new BindingParser( + new IvyParser(new Lexer()), interpolationConfig, elementRegistry, null, []); } export function resolveSanitizationFn(context: core.SecurityContext, isAttribute?: boolean) { diff --git a/packages/compiler/test/BUILD.bazel b/packages/compiler/test/BUILD.bazel index dd3c84969a..ac43c2b336 100644 --- a/packages/compiler/test/BUILD.bazel +++ b/packages/compiler/test/BUILD.bazel @@ -1,4 +1,5 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") # Test that should only be run in node NODE_ONLY = [ @@ -10,6 +11,12 @@ UTILS = [ "aot/test_util.ts", ] +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/compiler/index.js", + deps = ["//packages/compiler"], +) + ts_library( name = "test_utils", testonly = True, @@ -70,7 +77,7 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], data = [ "//packages/animations:npm_package", "//packages/common:npm_package", @@ -83,7 +90,6 @@ jasmine_node_test( deps = [ ":test_lib", ":test_node_only_lib", - "//tools/testing:node", "@npm//base64-js", "@npm//source-map", ], diff --git a/packages/compiler/test/css_parser/BUILD.bazel b/packages/compiler/test/css_parser/BUILD.bazel index b70fa84c8d..13f19b8330 100644 --- a/packages/compiler/test/css_parser/BUILD.bazel +++ b/packages/compiler/test/css_parser/BUILD.bazel @@ -16,10 +16,9 @@ ts_library( jasmine_node_test( name = "css_parser", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":css_parser_lib", - "//tools/testing:node", ], ) diff --git a/packages/compiler/test/expression_parser/BUILD.bazel b/packages/compiler/test/expression_parser/BUILD.bazel index 9ef9fa8704..0fbe4b2e00 100644 --- a/packages/compiler/test/expression_parser/BUILD.bazel +++ b/packages/compiler/test/expression_parser/BUILD.bazel @@ -15,10 +15,9 @@ ts_library( jasmine_node_test( name = "expression_parser", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":expression_parser_lib", - "//tools/testing:node", ], ) diff --git a/packages/compiler/test/ml_parser/BUILD.bazel b/packages/compiler/test/ml_parser/BUILD.bazel index 0569cef2ba..9df32dcf0b 100644 --- a/packages/compiler/test/ml_parser/BUILD.bazel +++ b/packages/compiler/test/ml_parser/BUILD.bazel @@ -13,10 +13,9 @@ ts_library( jasmine_node_test( name = "ml_parser", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":ml_parser_lib", - "//tools/testing:node", ], ) diff --git a/packages/compiler/test/render3/BUILD.bazel b/packages/compiler/test/render3/BUILD.bazel index 25a50c2acb..8288257e9f 100644 --- a/packages/compiler/test/render3/BUILD.bazel +++ b/packages/compiler/test/render3/BUILD.bazel @@ -18,9 +18,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/compiler/test/render3/style_parser_spec.ts b/packages/compiler/test/render3/style_parser_spec.ts index 9fe365bca9..4f44f6aebb 100644 --- a/packages/compiler/test/render3/style_parser_spec.ts +++ b/packages/compiler/test/render3/style_parser_spec.ts @@ -21,6 +21,11 @@ describe('style parsing', () => { expect(result).toEqual(['width', '100px', 'height', '200px', 'opacity', '0']); }); + it('should allow empty values', () => { + const result = parseStyle('width:;height: ;'); + expect(result).toEqual(['width', '', 'height', '']); + }); + it('should trim values and properties', () => { const result = parseStyle('width :333px ; height:666px ; opacity: 0.5;'); expect(result).toEqual(['width', '333px', 'height', '666px', 'opacity', '0.5']); diff --git a/packages/compiler/test/selector/BUILD.bazel b/packages/compiler/test/selector/BUILD.bazel index 7353eb1f3d..c120ec74cc 100644 --- a/packages/compiler/test/selector/BUILD.bazel +++ b/packages/compiler/test/selector/BUILD.bazel @@ -17,10 +17,9 @@ ts_library( jasmine_node_test( name = "selector", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":selector_lib", - "//tools/testing:node", ], ) diff --git a/packages/core/BUILD.bazel b/packages/core/BUILD.bazel index c732e19f78..54fe4f03db 100644 --- a/packages/core/BUILD.bazel +++ b/packages/core/BUILD.bazel @@ -30,7 +30,7 @@ ng_package( "//packages/core/testing:package.json", ], entry_point = ":index.ts", - packages = [ + nested_packages = [ "//packages/core/schematics:npm_package", ], tags = [ diff --git a/packages/core/global/PACKAGE.md b/packages/core/global/PACKAGE.md new file mode 100644 index 0000000000..d278b8586f --- /dev/null +++ b/packages/core/global/PACKAGE.md @@ -0,0 +1,5 @@ +Exposes a set of functions in the global namespace which are useful for debugging the current state +of your application. +These functions are exposed via the global `ng` "namespace" variable automatically when you import +from `@angular/core` and run your application in development mode. These functions are not exposed +when the application runs in a production mode. diff --git a/packages/core/global/index.ts b/packages/core/global/index.ts new file mode 100644 index 0000000000..874b4bde3a --- /dev/null +++ b/packages/core/global/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 + */ + +// The global utilities are re-exported through here so that they get their own separate `global` +// section in the API docs which makes it more visible that they can't be imported directly. +export * from '../src/render3/global_utils_api'; diff --git a/packages/core/schematics/BUILD.bazel b/packages/core/schematics/BUILD.bazel index f393a73a34..3630353908 100644 --- a/packages/core/schematics/BUILD.bazel +++ b/packages/core/schematics/BUILD.bazel @@ -1,11 +1,11 @@ -load("//tools:defaults.bzl", "npm_package") +load("//tools:defaults.bzl", "pkg_npm") exports_files([ "tsconfig.json", "migrations.json", ]) -npm_package( +pkg_npm( name = "npm_package", srcs = ["migrations.json"], visibility = ["//packages/core:__pkg__"], diff --git a/packages/core/src/application_init.ts b/packages/core/src/application_init.ts index 4d85196e66..b9852148c1 100644 --- a/packages/core/src/application_init.ts +++ b/packages/core/src/application_init.ts @@ -12,7 +12,15 @@ import {Inject, Injectable, InjectionToken, Optional} from './di'; /** - * A function that will be executed when an application is initialized. + * An injection token that allows you to provide one or more initialization functions. + * These function are injected at application startup and executed during + * app initialization. If any of these functions returns a Promise, initialization + * does not complete until the Promise is resolved. + * + * You can, for example, create a factory function that loads language data + * or an external configuration, and provide that function to the `APP_INITIALIZER` token. + * That way, the function is executed during the application bootstrap process, + * and the needed data is available on startup. * * @publicApi */ diff --git a/packages/core/src/application_module.ts b/packages/core/src/application_module.ts index 3f71df4468..f59eb86cd3 100644 --- a/packages/core/src/application_module.ts +++ b/packages/core/src/application_module.ts @@ -14,8 +14,8 @@ import {Console} from './console'; import {Injector, StaticProvider} from './di'; import {Inject, Optional, SkipSelf} from './di/metadata'; import {ErrorHandler} from './error_handler'; -import {DEFAULT_LOCALE_ID} from './i18n/localization'; -import {LOCALE_ID} from './i18n/tokens'; +import {DEFAULT_LOCALE_ID, USD_CURRENCY_CODE} from './i18n/localization'; +import {DEFAULT_CURRENCY_CODE, LOCALE_ID} from './i18n/tokens'; import {ivyEnabled} from './ivy_switch'; import {ComponentFactoryResolver} from './linker'; import {Compiler} from './linker/compiler'; @@ -96,6 +96,7 @@ export const APPLICATION_MODULE_PROVIDERS: StaticProvider[] = [ useFactory: _localeFactory, deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]] }, + {provide: DEFAULT_CURRENCY_CODE, useValue: USD_CURRENCY_CODE}, ]; /** diff --git a/packages/core/src/application_ref.ts b/packages/core/src/application_ref.ts index 91e4a40e80..24f173fdf6 100644 --- a/packages/core/src/application_ref.ts +++ b/packages/core/src/application_ref.ts @@ -302,11 +302,6 @@ export class PlatformRef { if (!exceptionHandler) { throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?'); } - // If the `LOCALE_ID` provider is defined at bootstrap we set the value for runtime i18n (ivy) - if (ivyEnabled) { - const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID); - setLocaleId(localeId || DEFAULT_LOCALE_ID); - } moduleRef.onDestroy(() => remove(this._modules, moduleRef)); ngZone !.runOutsideAngular( () => ngZone !.onError.subscribe( @@ -315,6 +310,11 @@ export class PlatformRef { const initStatus: ApplicationInitStatus = moduleRef.injector.get(ApplicationInitStatus); initStatus.runInitializers(); return initStatus.donePromise.then(() => { + if (ivyEnabled) { + // If the `LOCALE_ID` provider is defined at bootstrap then we set the value for ivy + const localeId = moduleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID); + setLocaleId(localeId || DEFAULT_LOCALE_ID); + } this._moduleDoBootstrap(moduleRef); return moduleRef; }); diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 9ac30bca8b..7c2daeedb8 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -26,7 +26,7 @@ export {DebugElement, DebugEventListener, DebugNode, asNativeElements, getDebugN export {GetTestability, Testability, TestabilityRegistry, setTestabilityGetter} from './testability/testability'; export * from './change_detection'; export * from './platform_core_providers'; -export {TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID, MissingTranslationStrategy} from './i18n/tokens'; +export {TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID, DEFAULT_CURRENCY_CODE, MissingTranslationStrategy} from './i18n/tokens'; export {ApplicationModule} from './application_module'; export {AbstractType, Type} from './interface/type'; export {EventEmitter} from './event_emitter'; diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index fab88f1b34..640d7369fb 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -9,13 +9,14 @@ export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS} from './application_ref'; export {APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER} from './application_tokens'; export {defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers} from './change_detection/change_detection'; -export {devModeEqual as ɵdevModeEqual} from './change_detection/change_detection_util'; -export {isListLikeIterable as ɵisListLikeIterable} from './change_detection/change_detection_util'; +export {devModeEqual as ɵdevModeEqual, 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 {getDebugNodeR2 as ɵgetDebugNodeR2} from './debug/debug_node'; export {inject, setCurrentInjector as ɵsetCurrentInjector, ɵɵinject} from './di/injector_compatibility'; export {getInjectableDef as ɵgetInjectableDef, ɵɵInjectableDef, ɵɵInjectorDef} from './di/interface/defs'; export {INJECTOR_SCOPE as ɵINJECTOR_SCOPE} from './di/scope'; +export {CurrencyIndex as ɵCurrencyIndex, ExtraLocaleDataIndex as ɵExtraLocaleDataIndex, LocaleDataIndex as ɵLocaleDataIndex, findLocaleData as ɵfindLocaleData, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, registerLocaleData as ɵregisterLocaleData, unregisterAllLocaleData as ɵunregisterLocaleData} from './i18n/locale_data_api'; export {DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID} from './i18n/localization'; export {ivyEnabled as ɵivyEnabled} from './ivy_switch'; export {ComponentFactory as ɵComponentFactory} from './linker/component_factory'; @@ -23,15 +24,14 @@ export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} fr 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 {BypassType as ɵBypassType, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, getSanitizationBypassType as ɵgetSanitizationBypassType, unwrapSafeValue as ɵunwrapSafeValue} from './sanitization/bypass'; 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} 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 {global as ɵglobal} from './util/global'; export {isObservable as ɵisObservable, isPromise as ɵisPromise} from './util/lang'; +export {stringify as ɵstringify} from './util/stringify'; export {clearOverrides as ɵclearOverrides, initServicesIfNeeded as ɵinitServicesIfNeeded, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider} from './view/index'; export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider'; -export {LocaleDataIndex as ɵLocaleDataIndex, CurrencyIndex as ɵCurrencyIndex, ExtraLocaleDataIndex as ɵExtraLocaleDataIndex, getLocalePluralCase as ɵgetLocalePluralCase, findLocaleData as ɵfindLocaleData, registerLocaleData as ɵregisterLocaleData, unregisterAllLocaleData as ɵunregisterLocaleData} from './i18n/locale_data_api'; -export {allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, getSanitizationBypassType as ɵgetSanitizationBypassType, BypassType as ɵBypassType, unwrapSafeValue as ɵunwrapSafeValue, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue} from './sanitization/bypass'; diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 49beffaba4..056001cf85 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -117,7 +117,6 @@ export { ɵɵreference, ɵɵenableBindings, ɵɵdisableBindings, - ɵɵallocHostVars, ɵɵelementContainerStart, ɵɵelementContainerEnd, ɵɵelementContainer, @@ -144,7 +143,6 @@ export { ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵclassProp, - ɵɵelementHostAttrs, ɵɵselect, ɵɵadvance, diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index 86e3d66b18..3270a568f1 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -7,18 +7,18 @@ */ import {Injector} from '../di'; -import {getViewComponent} from '../render3/global_utils_api'; import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE} from '../render3/interfaces/container'; import {TElementNode, TNode, TNodeFlags, TNodeType} from '../render3/interfaces/node'; import {isComponentHost, isLContainer} from '../render3/interfaces/type_checks'; import {DECLARATION_COMPONENT_VIEW, LView, PARENT, TData, TVIEW, T_HOST} from '../render3/interfaces/view'; -import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, isBrowserEvents, loadLContext} from '../render3/util/discovery_utils'; +import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, getOwningComponent, loadLContext} from '../render3/util/discovery_utils'; import {INTERPOLATION_DELIMITER, renderStringify} from '../render3/util/misc_utils'; import {getComponentLViewByIndex, getNativeByTNodeOrNull} from '../render3/util/view_utils'; import {assertDomNode} from '../util/assert'; import {DebugContext} from '../view/index'; + /** * @publicApi */ @@ -217,14 +217,14 @@ class DebugNode__POST_R3__ implements DebugNode { get componentInstance(): any { const nativeElement = this.nativeNode; return nativeElement && - (getComponent(nativeElement as Element) || getViewComponent(nativeElement)); + (getComponent(nativeElement as Element) || getOwningComponent(nativeElement)); } get context(): any { return getComponent(this.nativeNode as Element) || getContext(this.nativeNode as Element); } get listeners(): DebugEventListener[] { - return getListeners(this.nativeNode as Element).filter(isBrowserEvents); + return getListeners(this.nativeNode as Element).filter(listener => listener.type === 'dom'); } get references(): {[key: string]: any;} { return getLocalRefs(this.nativeNode); } @@ -352,10 +352,14 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme get classes(): {[key: string]: boolean;} { const result: {[key: string]: boolean;} = {}; - const element = this.nativeElement as HTMLElement; - const classNames = element.className.split(' '); + const element = this.nativeElement as HTMLElement | SVGElement; - classNames.forEach((value: string) => result[value] = true); + // SVG elements return an `SVGAnimatedString` instead of a plain string for the `className`. + const className = element.className as string | SVGAnimatedString; + const classes = className && typeof className !== 'string' ? className.baseVal.split(' ') : + className.split(' '); + + classes.forEach((value: string) => result[value] = true); return result; } @@ -406,7 +410,7 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme this.listeners.forEach(listener => { if (listener.name === eventName) { const callback = listener.callback; - callback(eventObj); + callback.call(node, eventObj); invokedListeners.push(callback); } }); @@ -415,11 +419,20 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme // that Zone.js only adds to `EventTarget` in browser environments. if (typeof node.eventListeners === 'function') { // Note that in Ivy we wrap event listeners with a call to `event.preventDefault` in some - // cases. We use `Function` as a special token that gives us access to the actual event + // cases. We use '__ngUnwrap__' as a special token that gives us access to the actual event // listener. node.eventListeners(eventName).forEach((listener: Function) => { - const unwrappedListener = listener(Function); - return invokedListeners.indexOf(unwrappedListener) === -1 && unwrappedListener(eventObj); + // In order to ensure that we can detect the special __ngUnwrap__ token described above, we + // use `toString` on the listener and see if it contains the token. We use this approach to + // ensure that it still worked with compiled code since it cannot remove or rename string + // literals. We also considered using a special function name (i.e. if(listener.name === + // special)) but that was more cumbersome and we were also concerned the compiled code could + // strip the name, turning the condition in to ("" === "") and always returning true. + if (listener.toString().indexOf('__ngUnwrap__') !== -1) { + const unwrappedListener = listener('__ngUnwrap__'); + return invokedListeners.indexOf(unwrappedListener) === -1 && + unwrappedListener.call(node, eventObj); + } }); } } @@ -470,10 +483,16 @@ function _queryAllR3( function _queryAllR3( parentElement: DebugElement, predicate: Predicate| Predicate, matches: DebugElement[] | DebugNode[], elementsOnly: boolean) { - const context = loadLContext(parentElement.nativeNode) !; - const parentTNode = context.lView[TVIEW].data[context.nodeIndex] as TNode; - _queryNodeChildrenR3( - parentTNode, context.lView, predicate, matches, elementsOnly, parentElement.nativeNode); + const context = loadLContext(parentElement.nativeNode, false); + if (context !== null) { + const parentTNode = context.lView[TVIEW].data[context.nodeIndex] as TNode; + _queryNodeChildrenR3( + parentTNode, context.lView, predicate, matches, elementsOnly, parentElement.nativeNode); + } else { + // If the context is null, then `parentElement` was either created with Renderer2 or native DOM + // APIs. + _queryNativeNodeDescendants(parentElement.nativeNode, predicate, matches, elementsOnly); + } } /** @@ -708,6 +727,18 @@ export function getDebugNode__POST_R3__(nativeNode: any): DebugNode|null { */ export const getDebugNode: (nativeNode: any) => DebugNode | null = getDebugNode__PRE_R3__; + +export function getDebugNodeR2__PRE_R3__(nativeNode: any): DebugNode|null { + return getDebugNode__PRE_R3__(nativeNode); +} + +export function getDebugNodeR2__POST_R3__(_nativeNode: any): DebugNode|null { + return null; +} + +export const getDebugNodeR2: (nativeNode: any) => DebugNode | null = getDebugNodeR2__PRE_R3__; + + export function getAllDebugNodes(): DebugNode[] { return Array.from(_nativeNodeToDebugNode.values()); } diff --git a/packages/core/src/di/injectable.ts b/packages/core/src/di/injectable.ts index 72a8685a87..ad046d596c 100644 --- a/packages/core/src/di/injectable.ts +++ b/packages/core/src/di/injectable.ts @@ -9,7 +9,7 @@ import {Type} from '../interface/type'; import {TypeDecorator, makeDecorator} from '../util/decorators'; -import {InjectableType, getInjectableDef, ɵɵInjectableDef, ɵɵdefineInjectable} from './interface/defs'; +import {InjectableType, getInjectableDef, ɵɵdefineInjectable} from './interface/defs'; import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueSansProvider} from './interface/provider'; import {compileInjectable as render3CompileInjectable} from './jit/injectable'; import {convertInjectableProviderToFactory} from './util'; @@ -75,13 +75,13 @@ export interface InjectableDecorator { 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. - * - 'platform' injector, which would be the special singleton platform injector shared by all + * by either associating it with an `@NgModule` or other `InjectorType`, + * or by specifying that this injectable should be provided in one of the following injectors: + * - 'root' : The application-level injector in most apps. + * - 'platform' : A special singleton platform injector shared by all * applications on the page. - * - 'any' injector, which would be the injector which receives the resolution. (Note this only - * works on NgModule Injectors and not on Element Injector) + * - 'any' : The NgModule injector that receives the resolution. + * */ providedIn?: Type|'root'|'platform'|'any'|null; } diff --git a/packages/core/src/di/injector.ts b/packages/core/src/di/injector.ts index 80395cf24a..e88b36d9a4 100644 --- a/packages/core/src/di/injector.ts +++ b/packages/core/src/di/injector.ts @@ -32,12 +32,20 @@ export function INJECTOR_IMPL__POST_R3__( export const INJECTOR_IMPL = INJECTOR_IMPL__PRE_R3__; /** - * Concrete injectors implement this interface. + * Concrete injectors implement this interface. Injectors are configured + * with [providers](guide/glossary#provider) that associate + * dependencies of various types with [injection tokens](guide/glossary#di-token). * - * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). + * @see ["DI Providers"](guide/dependency-injection-providers). + * @see `StaticProvider` * * @usageNotes - * ### Example + * + * The following example creates a service injector instance. + * + * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'} + * + * ### Usage example * * {@example core/di/ts/injector_spec.ts region='Injector'} * @@ -69,16 +77,21 @@ export abstract class Injector { */ static create(providers: StaticProvider[], parent?: Injector): Injector; + /** + * Creates a new injector instance that provides one or more dependencies, + * according to a given type or types of `StaticProvider`. + * + * @param options An object with the following properties: + * * `providers`: An array of providers of the [StaticProvider type](api/core/StaticProvider). + * * `parent`: (optional) A parent injector. + * * `name`: (optional) A developer-defined identifying name for the new injector. + * + * @returns The new injector instance. + * + */ static create(options: {providers: StaticProvider[], parent?: Injector, name?: string}): Injector; - /** - * Create a new Injector which is configure using `StaticProvider`s. - * - * @usageNotes - * ### Example - * - * {@example core/di/ts/provider_spec.ts region='ConstructorProvider'} - */ + static create( options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string}, parent?: Injector): Injector { diff --git a/packages/core/src/di/interface/provider.ts b/packages/core/src/di/interface/provider.ts index 17b3beb3dd..ec8720d089 100644 --- a/packages/core/src/di/interface/provider.ts +++ b/packages/core/src/di/interface/provider.ts @@ -247,8 +247,11 @@ export interface FactoryProvider extends FactorySansProvider { } /** - * Describes how the `Injector` should be configured as static (that is, without reflection). - * @see ["Dependency Injection Guide"](guide/dependency-injection). + * Describes how an `Injector` should be configured as static (that is, without reflection). + * A static provider provides tokens to an injector for various types of dependencies. + * + * @see [Injector.create()](/api/core/Injector#create). + * @see ["Dependency Injection Guide"](guide/dependency-injection-providers). * * @publicApi */ diff --git a/packages/core/src/i18n/locale_data_api.ts b/packages/core/src/i18n/locale_data_api.ts index 4b5895637f..63816bba38 100644 --- a/packages/core/src/i18n/locale_data_api.ts +++ b/packages/core/src/i18n/locale_data_api.ts @@ -63,6 +63,20 @@ export function findLocaleData(locale: string): any { throw new Error(`Missing locale data for the locale "${locale}".`); } +/** + * Retrieves the default currency code for the given locale. + * + * The default is defined as the first currency which is still in use. + * + * @param locale The code of the locale whose currency code we want. + * @returns The code of the default currency for the given locale. + * + */ +export function getLocaleCurrencyCode(locale: string): string|null { + const data = findLocaleData(locale); + return data[LocaleDataIndex.CurrencyCode] || null; +} + /** * Retrieves the plural function used by ICU expressions to determine the plural case to use * for a given locale. @@ -116,6 +130,7 @@ export enum LocaleDataIndex { DateTimeFormat, NumberSymbols, NumberFormats, + CurrencyCode, CurrencySymbol, CurrencyName, Currencies, diff --git a/packages/core/src/i18n/locale_en.ts b/packages/core/src/i18n/locale_en.ts index 785c6d08e7..2e430b5575 100644 --- a/packages/core/src/i18n/locale_en.ts +++ b/packages/core/src/i18n/locale_en.ts @@ -44,6 +44,7 @@ export default [ ['{1}, {0}', u, '{1} \'at\' {0}', u], ['.', ',', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], ['#,##0.###', '#,##0%', '¤#,##0.00', '#E0'], + 'USD', '$', 'US Dollar', {}, diff --git a/packages/core/src/i18n/localization.ts b/packages/core/src/i18n/localization.ts index 27cd62fecf..beeea95c51 100644 --- a/packages/core/src/i18n/localization.ts +++ b/packages/core/src/i18n/localization.ts @@ -34,3 +34,9 @@ export function getPluralCase(value: any, locale: string): string { * The locale id that the application is using by default (for translations and ICU expressions). */ export const DEFAULT_LOCALE_ID = 'en-US'; + +/** + * USD currency code that the application uses by default for CurrencyPipe when no + * DEFAULT_CURRENCY_CODE is provided. + */ +export const USD_CURRENCY_CODE = 'USD'; diff --git a/packages/core/src/i18n/tokens.ts b/packages/core/src/i18n/tokens.ts index 46c7e6d88e..ead8845db1 100644 --- a/packages/core/src/i18n/tokens.ts +++ b/packages/core/src/i18n/tokens.ts @@ -32,6 +32,46 @@ import {InjectionToken} from '../di/injection_token'; */ export const LOCALE_ID = new InjectionToken('LocaleId'); +/** + * Provide this token to set the default currency code your application uses for + * CurrencyPipe when there is no currency code passed into it. This is only used by + * CurrencyPipe and has no relation to locale currency. Defaults to USD if not configured. + * + * See the [i18n guide](guide/i18n#setting-up-locale) for more information. + * + *
+ * + * **Deprecation notice:** + * + * The default currency code is currently always `USD` but this is deprecated from v9. + * + * **In v10 the default currency code will be taken from the current locale.** + * + * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in + * your application `NgModule`: + * + * ```ts + * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'} + * ``` + * + *
+ * + * @usageNotes + * ### Example + * + * ```typescript + * import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + * import { AppModule } from './app/app.module'; + * + * platformBrowserDynamic().bootstrapModule(AppModule, { + * providers: [{provide: DEFAULT_CURRENCY_CODE, useValue: 'EUR' }] + * }); + * ``` + * + * @publicApi + */ +export const DEFAULT_CURRENCY_CODE = new InjectionToken('DefaultCurrencyCode'); + /** * Use this token at bootstrap to provide the content of your translation file (`xtb`, * `xlf` or `xlf2`) when you want to translate your application in another language. diff --git a/packages/core/src/interface/type.ts b/packages/core/src/interface/type.ts index faec83d8a1..e8b0188042 100644 --- a/packages/core/src/interface/type.ts +++ b/packages/core/src/interface/type.ts @@ -37,3 +37,32 @@ export interface Type extends Function { new (...args: any[]): T; } export type Mutable = { [P in K]: T[P]; }; + +/** + * Returns a writable type version of type. + * + * USAGE: + * Given: + * ``` + * interface Person {readonly name: string} + * ``` + * + * We would like to get a read/write version of `Person`. + * ``` + * const WritablePerson = Writable; + * ``` + * + * The result is that you can do: + * + * ``` + * const readonlyPerson: Person = {name: 'Marry'}; + * readonlyPerson.name = 'John'; // TypeError + * (readonlyPerson as WritablePerson).name = 'John'; // OK + * + * // Error: Correctly detects that `Person` did not have `age` property. + * (readonlyPerson as WritablePerson).age = 30; + * ``` + */ +export type Writable = { + -readonly[K in keyof T]: T[K]; +}; diff --git a/packages/core/src/metadata/ng_module.ts b/packages/core/src/metadata/ng_module.ts index e8a9c6f182..bbe0a8c702 100644 --- a/packages/core/src/metadata/ng_module.ts +++ b/packages/core/src/metadata/ng_module.ts @@ -12,7 +12,6 @@ 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 {TypeDecorator, makeDecorator} from '../util/decorators'; diff --git a/packages/core/src/render/api.ts b/packages/core/src/render/api.ts index 9e97b4a0ac..b096fc5fe1 100644 --- a/packages/core/src/render/api.ts +++ b/packages/core/src/render/api.ts @@ -80,6 +80,9 @@ export abstract class RendererFactory2 { * @publicApi */ export enum RendererStyleFlags2 { + // TODO(misko): This needs to be refactored into a separate file so that it can be imported from + // `node_manipulation.ts` Currently doing the import cause resolution order to change and fails + // the tests. The work around is to have hard coded value in `node_manipulation.ts` for now. /** * Marks a style as important. */ diff --git a/packages/core/src/render3/STATUS.md b/packages/core/src/render3/STATUS.md index c2648c11c5..a1e47a0100 100644 --- a/packages/core/src/render3/STATUS.md +++ b/packages/core/src/render3/STATUS.md @@ -52,7 +52,7 @@ A tool which "upgrades" `node_module` compiled with non-ivy `ngc` into ivy compl ## `@angular/core` changes -The goal is for the `@Component` (and friends) to be the compiler of template. Since decorators are functions which execute during parsing of the `.js` file, the decorator can compile the template into Ivy. The AoT compiler's job is to remove the `@Component` and replace it with call to `ɵɵdefineComponent`. +The goal is for the `@Component` (and friends) to be the compiler of template. Since decorators are functions which execute during parsing of the `.js` file, the decorator can compile the template into Ivy. The AOT compiler's job is to remove the `@Component` and replace it with call to `ɵɵdefineComponent`. - ✅ `@angular/compiler` can patch itself onto: - ✅ `@Injectable` diff --git a/packages/core/src/render3/VIEW_DATA.md b/packages/core/src/render3/VIEW_DATA.md index ffaced5fb0..0cb427b515 100644 --- a/packages/core/src/render3/VIEW_DATA.md +++ b/packages/core/src/render3/VIEW_DATA.md @@ -200,14 +200,14 @@ The above will create the following layout: The `EXPANDO` section needs additional information for information stored in `TView.expandoInstructions` -| Index | `TView.expandoInstructions` | Meaning -| ----: | ---------------------------: | ------- -| 0 | -10 | Negative numbers signify pointers to elements. In this case 10 (``) -| 1 | 2 | Injector size. Number of values to skip to get to Host Bindings. -| 2 | Child.ɵcmp.hostBindings | The function to call. (Only when `hostVars` is not `0`) -| 3 | Child.ɵcmp.hostVars | Number of host bindings to process. (Only when `hostVars` is not `0`) -| 4 | Tooltip.ɵdir.hostBindings | The function to call. (Only when `hostVars` is not `0`) -| 5 | Tooltip.ɵdir.hostVars | Number of host bindings to process. (Only when `hostVars` is not `0`) +| Index | `TView.expandoInstructions` | Meaning +| ----: | ---------------------------:| ------- +| 0 | -10 | Negative numbers signify pointers to elements. In this case 10 (``) +| 1 | 2 | Injector size. Number of values to skip to get to Host Bindings. +| 2 | Child.ɵcmp.hostBindings | The function to call. (Only when `hostVars` is not `0`) +| 3 | Child.ɵcmp.hostVars | Number of host bindings to process. (Only when `hostVars` is not `0`) +| 4 | Tooltip.ɵdir.hostBindings | The function to call. (Only when `hostVars` is not `0`) +| 5 | Tooltip.ɵdir.hostVars | Number of host bindings to process. (Only when `hostVars` is not `0`) The reason for this layout is to make the host binding update efficient using this pseudo code: ```typescript @@ -237,16 +237,16 @@ for(var i = 0; i < tView.expandoInstructions.length; i++) { The above code should execute as: -| Instruction | `bindingRootIndex` | `currentDirectiveIndex` | `currentElementIndex` -| ----------: | -----------------: | ----------------------: | --------------------: -| (initial) | `11` | `-1` | `-1` -| `-10` | `19` | `\* new Child() *\ 19` | `\* *\ 10` -| `2` | `21` | `\* new Child() *\ 19` | `\* *\ 10` +| Instruction | `bindingRootIndex` | `currentDirectiveIndex` | `currentElementIndex` +| ----------: | -----------------: | ----------------------: | --------------------: +| (initial) | `11` | `-1` | `-1` +| `-10` | `19` | `\* new Child() *\ 19` | `\* *\ 10` +| `2` | `21` | `\* new Child() *\ 19` | `\* *\ 10` | `Child.ɵcmp.hostBindings` | invoke with => | `\* new Child() *\ 19` | `\* *\ 10` -| | `21` | `\* new Tooltip() *\ 20` | `\* *\ 10` +| | `21` | `\* new Tooltip() *\ 20` | `\* *\ 10` | `Child.ɵcmp.hostVars` | `22` | `\* new Tooltip() *\ 20` | `\* *\ 10` | `Tooltip.ɵdir.hostBindings` | invoke with => | `\* new Tooltip() *\ 20` | `\* *\ 10` -| | `22` | `21` | `\* *\ 10` +| | `22` | `21` | `\* *\ 10` | `Tooltip.ɵdir.hostVars` | `22` | `21` | `\* *\ 10` ## `EXPANDO` and Injection diff --git a/packages/core/src/render3/assert.ts b/packages/core/src/render3/assert.ts index e822917971..d639f88f2f 100644 --- a/packages/core/src/render3/assert.ts +++ b/packages/core/src/render3/assert.ts @@ -73,6 +73,11 @@ export function assertFirstCreatePass(tView: TView, errMessage?: string) { tView.firstCreatePass, true, errMessage || 'Should only be called in first create pass.'); } +export function assertFirstUpdatePass(tView: TView, errMessage?: string) { + assertEqual( + tView.firstUpdatePass, true, errMessage || 'Should only be called in first update pass.'); +} + /** * This is a basic sanity check that an object is probably a directive def. DirectiveDef is * an interface, so we can't do a direct instanceof check. diff --git a/packages/core/src/render3/bindings.ts b/packages/core/src/render3/bindings.ts index bb99394e49..e9e3edefc5 100644 --- a/packages/core/src/render3/bindings.ts +++ b/packages/core/src/render3/bindings.ts @@ -30,7 +30,19 @@ export function getBinding(lView: LView, bindingIndex: number): any { return lView[bindingIndex]; } -/** Updates binding if changed, then returns whether it was updated. */ +/** + * Updates binding if changed, then returns whether it was updated. + * + * This function also checks the `CheckNoChangesMode` and throws if changes are made. + * Some changes (Objects/iterables) during `CheckNoChangesMode` are exempt to comply with VE + * behavior. + * + * @param lView current `LView` + * @param bindingIndex The binding in the `LView` to check + * @param value New value to check against `lView[bindingIndex]` + * @returns `true` if the bindings has changed. (Throws if binding has changed during + * `CheckNoChangesMode`) + */ export function bindingUpdated(lView: LView, bindingIndex: number, value: any): boolean { ngDevMode && assertNotSame(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.'); ngDevMode && @@ -50,6 +62,11 @@ export function bindingUpdated(lView: LView, bindingIndex: number, value: any): throwErrorIfNoChangesMode( oldValue === NO_CHANGE, details.oldValue, details.newValue, details.propName); } + // There was a change, but the `devModeEqual` decided that the change is exempt from an error. + // For this reason we exit as if no change. The early exit is needed to prevent the changed + // value to be written into `LView` (If we would write the new value that we would not see it + // as change on next CD.) + return false; } lView[bindingIndex] = value; return true; diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 2e2825fd26..2895e71664 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -12,18 +12,20 @@ import {Type} from '../core'; import {Injector} from '../di/injector'; import {Sanitizer} from '../sanitization/sanitizer'; import {assertDataInRange} from '../util/assert'; - import {assertComponentType} from './assert'; import {getComponentDef} from './definition'; import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di'; -import {registerPostOrderHooks, registerPreOrderHooks} from './hooks'; -import {CLEAN_PROMISE, addToViewTree, createLView, createTView, getOrCreateTComponentView, getOrCreateTNode, initNodeFlags, instantiateRootComponent, invokeHostBindingsInCreationMode, locateHostElement, markAsComponentHost, refreshView, renderView} from './instructions/shared'; +import {registerPostOrderHooks} from './hooks'; +import {CLEAN_PROMISE, addHostBindingsToExpandoInstructions, addToViewTree, createLView, createTView, getOrCreateTComponentView, getOrCreateTNode, growHostVarsSpace, initTNodeFlags, instantiateRootComponent, invokeHostBindingsInCreationMode, locateHostElement, markAsComponentHost, refreshView, renderView} from './instructions/shared'; import {ComponentDef, ComponentType, RenderFlags} from './interfaces/definition'; import {TElementNode, TNode, TNodeType} from './interfaces/node'; import {PlayerHandler} from './interfaces/player'; -import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; +import {RElement, Renderer3, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; import {CONTEXT, HEADER_OFFSET, LView, LViewFlags, RootContext, RootContextFlags, TVIEW, TViewType} from './interfaces/view'; -import {enterView, getPreviousOrParentTNode, incrementActiveDirectiveId, leaveView, setActiveHostElement} from './state'; +import {writeDirectClass, writeDirectStyle} from './node_manipulation'; +import {enterView, getPreviousOrParentTNode, leaveView, setSelectedIndex} from './state'; +import {computeStaticStyling} from './styling/static_styling'; +import {setUpAttributes} from './util/attrs_utils'; import {publishDefaultGlobalUtils} from './util/global_utils'; import {defaultScheduler, stringifyForError} from './util/misc_utils'; import {getRootContext} from './util/view_traversal_utils'; @@ -114,12 +116,13 @@ export function renderComponent( const rendererFactory = opts.rendererFactory || domRendererFactory3; const sanitizer = opts.sanitizer || null; const componentDef = getComponentDef(componentType) !; - if (componentDef.type != componentType) componentDef.type = componentType; + if (componentDef.type != componentType) (componentDef as{type: Type}).type = componentType; // The first index of the first selector is the tag name. const componentTag = componentDef.selectors ![0] ![0] as string; + const hostRenderer = rendererFactory.createRenderer(null, null); const hostRNode = - locateHostElement(rendererFactory, opts.host || componentTag, componentDef.encapsulation); + locateHostElement(hostRenderer, opts.host || componentTag, componentDef.encapsulation); const rootFlags = componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot : LViewFlags.CheckAlways | LViewFlags.IsRoot; const rootContext = createRootContext(opts.scheduler, opts.playerHandler); @@ -136,14 +139,14 @@ export function renderComponent( try { if (rendererFactory.begin) rendererFactory.begin(); const componentView = createRootComponentView( - hostRNode, componentDef, rootView, rendererFactory, renderer, sanitizer); + hostRNode, componentDef, rootView, rendererFactory, renderer, null, sanitizer); component = createRootComponent( componentView, componentDef, rootView, rootContext, opts.hostFeatures || null); // create mode pass - renderView(rootView, rootTView, null); + renderView(rootTView, rootView, null); // update mode pass - refreshView(rootView, rootTView, null, null); + refreshView(rootTView, rootView, null, null); } finally { leaveView(); @@ -159,27 +162,49 @@ export function renderComponent( * @param rNode Render host element. * @param def ComponentDef * @param rootView The parent view where the host node is stored - * @param renderer The current renderer + * @param hostRenderer The current renderer * @param sanitizer The sanitizer, if provided * * @returns Component view created */ export function createRootComponentView( rNode: RElement | null, def: ComponentDef, rootView: LView, - rendererFactory: RendererFactory3, renderer: Renderer3, sanitizer?: Sanitizer | null): LView { + rendererFactory: RendererFactory3, hostRenderer: Renderer3, addVersion: string | null, + sanitizer: Sanitizer | null): LView { const tView = rootView[TVIEW]; ngDevMode && assertDataInRange(rootView, 0 + HEADER_OFFSET); rootView[0 + HEADER_OFFSET] = rNode; const tNode: TElementNode = getOrCreateTNode(tView, null, 0, TNodeType.Element, null, null); + const mergedAttrs = tNode.mergedAttrs = def.hostAttrs; + if (mergedAttrs !== null) { + computeStaticStyling(tNode, mergedAttrs); + if (rNode !== null) { + setUpAttributes(hostRenderer, rNode, mergedAttrs); + if (tNode.classes !== null) { + writeDirectClass(hostRenderer, rNode, tNode.classes); + } + if (tNode.styles !== null) { + writeDirectStyle(hostRenderer, rNode, tNode.styles); + } + } + } + const viewRenderer = rendererFactory.createRenderer(rNode, def); + if (rNode !== null && addVersion) { + ngDevMode && ngDevMode.rendererSetAttribute++; + isProceduralRenderer(hostRenderer) ? + hostRenderer.setAttribute(rNode, 'ng-version', addVersion) : + rNode.setAttribute('ng-version', addVersion); + } + const componentView = createLView( rootView, getOrCreateTComponentView(def), null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[HEADER_OFFSET], tNode, - rendererFactory, renderer, sanitizer); + rendererFactory, viewRenderer, sanitizer); if (tView.firstCreatePass) { diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, def.type); markAsComponentHost(tView, tNode); - initNodeFlags(tNode, rootView.length, 1); + initTNodeFlags(tNode, rootView.length, 1); } addToViewTree(rootView, componentView); @@ -193,11 +218,11 @@ export function createRootComponentView( * renderComponent() and ViewContainerRef.createComponent(). */ export function createRootComponent( - componentView: LView, componentDef: ComponentDef, rootView: LView, rootContext: RootContext, + componentView: LView, componentDef: ComponentDef, rootLView: LView, rootContext: RootContext, hostFeatures: HostFeature[] | null): any { - const tView = rootView[TVIEW]; + const tView = rootLView[TVIEW]; // Create directive instance with factory() and store at next index in viewData - const component = instantiateRootComponent(tView, rootView, componentDef); + const component = instantiateRootComponent(tView, rootLView, componentDef); rootContext.components.push(component); componentView[CONTEXT] = component; @@ -207,22 +232,21 @@ export function createRootComponent( // We want to generate an empty QueryList for root content queries for backwards // compatibility with ViewEngine. if (componentDef.contentQueries) { - componentDef.contentQueries(RenderFlags.Create, component, rootView.length - 1); + componentDef.contentQueries(RenderFlags.Create, component, rootLView.length - 1); } const rootTNode = getPreviousOrParentTNode(); - if (tView.firstCreatePass && componentDef.hostBindings) { + if (tView.firstCreatePass && + (componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) { const elementIndex = rootTNode.index - HEADER_OFFSET; - setActiveHostElement(elementIndex); - incrementActiveDirectiveId(); + setSelectedIndex(elementIndex); - const expando = tView.expandoInstructions !; - invokeHostBindingsInCreationMode( - componentDef, expando, component, rootTNode, tView.firstCreatePass); + const rootTView = rootLView[TVIEW]; + addHostBindingsToExpandoInstructions(rootTView, componentDef); + growHostVarsSpace(rootTView, rootLView, componentDef.hostVars); - setActiveHostElement(null); + invokeHostBindingsInCreationMode(componentDef, component); } - return component; } diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index a7369f16e8..db73957c4f 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -19,7 +19,6 @@ import {RendererFactory2} from '../render/api'; import {Sanitizer} from '../sanitization/sanitizer'; import {VERSION} from '../version'; 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'; @@ -27,8 +26,9 @@ import {NodeInjector} from './di'; import {assignTViewNodeToLView, createLView, createTView, elementCreate, locateHostElement, renderView} from './instructions/shared'; import {ComponentDef} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode} from './interfaces/node'; -import {RNode, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; +import {RNode, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; import {LView, LViewFlags, TVIEW, TViewType} from './interfaces/view'; +import {stringifyCSSSelectorList} from './node_selector_matcher'; import {enterView, leaveView} from './state'; import {defaultScheduler} from './util/misc_utils'; import {getTNode} from './util/view_utils'; @@ -117,9 +117,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { private componentDef: ComponentDef, private ngModule?: viewEngine_NgModuleRef) { super(); this.componentType = componentDef.type; - - // default to 'div' in case this component has an attribute selector - this.selector = componentDef.selectors[0][0] as string || 'div'; + this.selector = stringifyCSSSelectorList(componentDef.selectors); this.ngContentSelectors = componentDef.ngContentSelectors ? componentDef.ngContentSelectors : []; this.isBoundToModule = !!ngModule; @@ -137,9 +135,15 @@ export class ComponentFactory extends viewEngine_ComponentFactory { rootViewInjector.get(RendererFactory2, domRendererFactory3) as RendererFactory3; const sanitizer = rootViewInjector.get(Sanitizer, null); + const hostRenderer = rendererFactory.createRenderer(null, this.componentDef); const hostRNode = rootSelectorOrNode ? - locateHostElement(rendererFactory, rootSelectorOrNode, this.componentDef.encapsulation) : - elementCreate(this.selector, rendererFactory.createRenderer(null, this.componentDef), null); + locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) : + // Determine a tag name used for creating host elements when this component is created + // dynamically. Default to 'div' if this component did not specify any tag name in its + // selector. + elementCreate( + this.componentDef.selectors[0][0] as string || 'div', + rendererFactory.createRenderer(null, this.componentDef), null); const rootFlags = this.componentDef.onPush ? LViewFlags.Dirty | LViewFlags.IsRoot : LViewFlags.CheckAlways | LViewFlags.IsRoot; @@ -152,20 +156,13 @@ export class ComponentFactory extends viewEngine_ComponentFactory { /^#root-ng-internal-isolated-\d+/.test(rootSelectorOrNode); const rootContext = createRootContext(); - const renderer = rendererFactory.createRenderer(hostRNode, this.componentDef); - - if (rootSelectorOrNode && hostRNode) { - ngDevMode && ngDevMode.rendererSetAttribute++; - isProceduralRenderer(renderer) ? - renderer.setAttribute(hostRNode, 'ng-version', VERSION.full) : - hostRNode.setAttribute('ng-version', VERSION.full); - } // Create the root view. Uses empty TView and ContentTemplate. const rootTView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, null); const rootLView = createLView( - null, rootTView, rootContext, rootFlags, null, null, rendererFactory, renderer, sanitizer, - rootViewInjector); + null, rootTView, rootContext, rootFlags, null, null, rendererFactory, hostRenderer, + sanitizer, rootViewInjector); + const addVersion = rootSelectorOrNode && hostRNode ? VERSION.full : null; // rootView is the parent when bootstrapping // TODO(misko): it looks like we are entering view here but we don't really need to as @@ -179,9 +176,9 @@ export class ComponentFactory extends viewEngine_ComponentFactory { try { const componentView = createRootComponentView( - hostRNode, this.componentDef, rootLView, rendererFactory, renderer); + hostRNode, this.componentDef, rootLView, rendererFactory, hostRenderer, addVersion, null); - tElementNode = getTNode(0, rootLView) as TElementNode; + tElementNode = getTNode(rootLView[TVIEW], 0) as TElementNode; if (projectableNodes) { // projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade @@ -197,7 +194,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { component = createRootComponent( componentView, this.componentDef, rootLView, rootContext, [LifecycleHooksFeature]); - renderView(rootLView, rootTView, null); + renderView(rootTView, rootLView, null); } finally { leaveView(); } diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index a51ff043c0..26ad0dbf0a 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -18,14 +18,17 @@ import {stringify} from '../util/stringify'; import {EMPTY_ARRAY, EMPTY_OBJ} from './empty'; import {NG_COMP_DEF, NG_DIR_DEF, NG_FACTORY_DEF, NG_LOC_ID_DEF, NG_MOD_DEF, NG_PIPE_DEF} from './fields'; import {ComponentDef, ComponentDefFeature, ComponentTemplate, ComponentType, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, DirectiveTypesOrFactory, FactoryFn, HostBindingsFunction, PipeDef, PipeType, PipeTypesOrFactory, ViewQueriesFunction} from './interfaces/definition'; -import {TConstants} from './interfaces/node'; -// while SelectorFlags is unused here, it's required so that types don't get resolved lazily -// see: https://github.com/Microsoft/web-build-tools/issues/1050 +import {AttributeMarker, TAttributes, TConstants} from './interfaces/node'; import {CssSelectorList, SelectorFlags} from './interfaces/projection'; import {NgModuleType} from './ng_module_ref'; let _renderCompCount = 0; +// While these types are unused here, they are required so that types don't +// get resolved lazily. see: https://github.com/Microsoft/web-build-tools/issues/1050 +type _web_build_tools_issue_1050_SelectorFlags = SelectorFlags; +type _web_build_tools_issue_1050_AttributeMarker = AttributeMarker; + /** * Create a component definition object. * @@ -130,6 +133,46 @@ export function ɵɵdefineComponent(componentDefinition: { */ hostBindings?: HostBindingsFunction; + /** + * The number of bindings in this directive `hostBindings` (including pure fn bindings). + * + * Used to calculate the length of the component's LView array, so we + * can pre-fill the array and set the host binding start index. + */ + hostVars?: number; + + /** + * Assign static attribute values to a host element. + * + * This property will assign static attribute values as well as class and style + * values to a host element. Since attribute values can consist of different types of values, the + * `hostAttrs` 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. + */ + hostAttrs?: TAttributes; + /** * Function to create instances of content queries associated with a given directive. */ @@ -263,6 +306,8 @@ export function ɵɵdefineComponent(componentDefinition: { consts: componentDefinition.consts || null, ngContentSelectors: componentDefinition.ngContentSelectors, hostBindings: componentDefinition.hostBindings || null, + hostVars: componentDefinition.hostVars || 0, + hostAttrs: componentDefinition.hostAttrs || null, contentQueries: componentDefinition.contentQueries || null, declaredInputs: declaredInputs, inputs: null !, // assigned in noSideEffects @@ -588,6 +633,46 @@ export const ɵɵdefineDirective = ɵɵdefineComponent as any as(directiveDef */ hostBindings?: HostBindingsFunction; + /** + * The number of bindings in this directive `hostBindings` (including pure fn bindings). + * + * Used to calculate the length of the component's LView array, so we + * can pre-fill the array and set the host binding start index. + */ + hostVars?: number; + + /** + * Assign static attribute values to a host element. + * + * This property will assign static attribute values as well as class and style + * values to a host element. Since attribute values can consist of different types of values, the + * `hostAttrs` 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. + */ + hostAttrs?: TAttributes; + /** * Function to create instances of content queries associated with a given directive. */ diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 57b8cb8058..72dd5d85c8 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -29,7 +29,6 @@ import {enterDI, leaveDI} from './state'; import {isNameOnlyAttributeMarker} from './util/attrs_utils'; import {getParentInjectorIndex, getParentInjectorView, hasParentInjector} from './util/injector_utils'; import {stringifyForError} from './util/misc_utils'; -import {getInitialStylingValue} from './util/styling_utils'; @@ -269,10 +268,10 @@ export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): str tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer); ngDevMode && assertDefined(tNode, 'expecting tNode'); if (attrNameToInject === 'class') { - return getInitialStylingValue(tNode.classes); + return tNode.classes; } if (attrNameToInject === 'style') { - return getInitialStylingValue(tNode.styles); + return tNode.styles; } const attrs = tNode.attrs; diff --git a/packages/core/src/render3/di_setup.ts b/packages/core/src/render3/di_setup.ts index e0815cc58b..1666dbcae5 100644 --- a/packages/core/src/render3/di_setup.ts +++ b/packages/core/src/render3/di_setup.ts @@ -18,7 +18,7 @@ import {NodeInjectorFactory} from './interfaces/injector'; import {TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNodeProviderIndexes} from './interfaces/node'; import {isComponentDef} from './interfaces/type_checks'; import {LView, TData, TVIEW, TView} from './interfaces/view'; -import {getLView, getPreviousOrParentTNode} from './state'; +import {getLView, getPreviousOrParentTNode, getTView} from './state'; @@ -42,8 +42,7 @@ import {getLView, getPreviousOrParentTNode} from './state'; */ export function providersResolver( def: DirectiveDef, providers: Provider[], viewProviders: Provider[]): void { - const lView = getLView(); - const tView: TView = lView[TVIEW]; + const tView = getTView(); if (tView.firstCreatePass) { const isComponent = isComponentDef(def); @@ -71,8 +70,8 @@ function resolveProvider( provider[i], tInjectables, lInjectablesBlueprint, isComponent, isViewProvider); } } else { + const tView = getTView(); const lView = getLView(); - const tView = lView[TVIEW]; let token: any = isTypeProvider(provider) ? provider : resolveForwardRef(provider.provide); let providerFactory: () => any = providerToFactory(provider); diff --git a/packages/core/src/render3/errors.ts b/packages/core/src/render3/errors.ts index d92cb4ebc2..d901bc4089 100644 --- a/packages/core/src/render3/errors.ts +++ b/packages/core/src/render3/errors.ts @@ -55,6 +55,8 @@ export function throwErrorIfNoChangesMode( } // TODO: include debug context, see `viewDebugError` function in // `packages/core/src/view/errors.ts` for reference. + // tslint:disable-next-line + debugger; // Left intentionally for better debugger experience. throw new Error(msg); } diff --git a/packages/core/src/render3/features/inherit_definition_feature.ts b/packages/core/src/render3/features/inherit_definition_feature.ts index 13c21b41e4..e22e4392ca 100644 --- a/packages/core/src/render3/features/inherit_definition_feature.ts +++ b/packages/core/src/render3/features/inherit_definition_feature.ts @@ -6,17 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type} from '../../interface/type'; +import {Type, Writable} from '../../interface/type'; +import {assertEqual} from '../../util/assert'; import {fillProperties} from '../../util/property'; import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty'; import {ComponentDef, ContentQueriesFunction, DirectiveDef, DirectiveDefFeature, HostBindingsFunction, RenderFlags, ViewQueriesFunction} from '../interfaces/definition'; +import {AttributeMarker, TAttributes} from '../interfaces/node'; import {isComponentDef} from '../interfaces/type_checks'; +import {mergeHostAttrs} from '../util/attrs_utils'; export function getSuperType(type: Type): Type& {ɵcmp?: ComponentDef, ɵdir?: DirectiveDef} { return Object.getPrototypeOf(type.prototype).constructor; } +type WritableDef = Writable|ComponentDef>; + /** * Merges the definition from a super class to a sub class. * @param definition The definition that is a SubClass of another directive of component @@ -26,6 +31,7 @@ export function getSuperType(type: Type): Type& export function ɵɵInheritDefinitionFeature(definition: DirectiveDef| ComponentDef): void { let superType = getSuperType(definition.type); let shouldInheritFields = true; + const inheritanceChain: WritableDef[] = [definition]; while (superType) { let superDef: DirectiveDef|ComponentDef|undefined = undefined; @@ -42,9 +48,10 @@ export function ɵɵInheritDefinitionFeature(definition: DirectiveDef| Comp if (superDef) { if (shouldInheritFields) { + inheritanceChain.push(superDef); // Some fields in the definition may be empty, if there were no values to put in them that // would've justified object creation. Unwrap them if necessary. - const writeableDef = definition as any; + const writeableDef = definition as WritableDef; writeableDef.inputs = maybeUnwrapEmpty(definition.inputs); writeableDef.declaredInputs = maybeUnwrapEmpty(definition.declaredInputs); writeableDef.outputs = maybeUnwrapEmpty(definition.outputs); @@ -66,14 +73,14 @@ export function ɵɵInheritDefinitionFeature(definition: DirectiveDef| Comp // Inherit hooks // Assume super class inheritance feature has already run. - definition.afterContentChecked = - definition.afterContentChecked || superDef.afterContentChecked; - definition.afterContentInit = definition.afterContentInit || superDef.afterContentInit; - definition.afterViewChecked = definition.afterViewChecked || superDef.afterViewChecked; - definition.afterViewInit = definition.afterViewInit || superDef.afterViewInit; - definition.doCheck = definition.doCheck || superDef.doCheck; - definition.onDestroy = definition.onDestroy || superDef.onDestroy; - definition.onInit = definition.onInit || superDef.onInit; + writeableDef.afterContentChecked = + writeableDef.afterContentChecked || superDef.afterContentChecked; + writeableDef.afterContentInit = definition.afterContentInit || superDef.afterContentInit; + writeableDef.afterViewChecked = definition.afterViewChecked || superDef.afterViewChecked; + writeableDef.afterViewInit = definition.afterViewInit || superDef.afterViewInit; + writeableDef.doCheck = definition.doCheck || superDef.doCheck; + writeableDef.onDestroy = definition.onDestroy || superDef.onDestroy; + writeableDef.onInit = definition.onInit || superDef.onInit; } // Run parent features @@ -100,6 +107,28 @@ export function ɵɵInheritDefinitionFeature(definition: DirectiveDef| Comp superType = Object.getPrototypeOf(superType); } + mergeHostAttrsAcrossInheritance(inheritanceChain); +} + +/** + * Merge the `hostAttrs` and `hostVars` from the inherited parent to the base class. + * + * @param inheritanceChain A list of `WritableDefs` starting at the top most type and listing + * sub-types in order. For each type take the `hostAttrs` and `hostVars` and merge it with the child + * type. + */ +function mergeHostAttrsAcrossInheritance(inheritanceChain: WritableDef[]) { + let hostVars: number = 0; + let hostAttrs: TAttributes|null = null; + // We process the inheritance order from the base to the leaves here. + for (let i = inheritanceChain.length - 1; i >= 0; i--) { + const def = inheritanceChain[i]; + // For each `hostVars`, we need to add the superclass amount. + def.hostVars = (hostVars += def.hostVars); + // for each `hostAttrs` we need to merge it with superclass. + def.hostAttrs = + mergeHostAttrs(def.hostAttrs, hostAttrs = mergeHostAttrs(hostAttrs, def.hostAttrs)); + } } function maybeUnwrapEmpty(value: T[]): T[]; @@ -114,8 +143,7 @@ function maybeUnwrapEmpty(value: any): any { } } -function inheritViewQuery( - definition: DirectiveDef| ComponentDef, superViewQuery: ViewQueriesFunction) { +function inheritViewQuery(definition: WritableDef, superViewQuery: ViewQueriesFunction) { const prevViewQuery = definition.viewQuery; if (prevViewQuery) { definition.viewQuery = (rf, ctx) => { @@ -128,8 +156,7 @@ function inheritViewQuery( } function inheritContentQueries( - definition: DirectiveDef| ComponentDef, - superContentQueries: ContentQueriesFunction) { + definition: WritableDef, superContentQueries: ContentQueriesFunction) { const prevContentQueries = definition.contentQueries; if (prevContentQueries) { definition.contentQueries = (rf, ctx, directiveIndex) => { @@ -142,13 +169,12 @@ function inheritContentQueries( } function inheritHostBindings( - definition: DirectiveDef| ComponentDef, - superHostBindings: HostBindingsFunction) { + definition: WritableDef, superHostBindings: HostBindingsFunction) { const prevHostBindings = definition.hostBindings; if (prevHostBindings) { - definition.hostBindings = (rf: RenderFlags, ctx: any, elementIndex: number) => { - superHostBindings(rf, ctx, elementIndex); - prevHostBindings(rf, ctx, elementIndex); + definition.hostBindings = (rf: RenderFlags, ctx: any) => { + superHostBindings(rf, ctx); + prevHostBindings(rf, ctx); }; } else { definition.hostBindings = superHostBindings; diff --git a/packages/core/src/render3/features/ng_onchanges_feature.ts b/packages/core/src/render3/features/ng_onchanges_feature.ts index a815609e27..efc69de2ff 100644 --- a/packages/core/src/render3/features/ng_onchanges_feature.ts +++ b/packages/core/src/render3/features/ng_onchanges_feature.ts @@ -51,7 +51,7 @@ export function ɵɵNgOnChangesFeature(): DirectiveDefFeature { function NgOnChangesFeatureImpl(definition: DirectiveDef): void { if (definition.type.prototype.ngOnChanges) { definition.setInput = ngOnChangesSetInput; - definition.onChanges = wrapOnChanges(); + (definition as{onChanges: Function}).onChanges = wrapOnChanges(); } } diff --git a/packages/core/src/render3/global_utils_api.ts b/packages/core/src/render3/global_utils_api.ts index 1884a8e410..330918cf03 100644 --- a/packages/core/src/render3/global_utils_api.ts +++ b/packages/core/src/render3/global_utils_api.ts @@ -15,5 +15,5 @@ * file in the public_api_guard test. */ -export {markDirty} from './instructions/all'; -export {getComponent, getContext, getDebugNode, getDirectives, getHostElement, getInjector, getListeners, getRootComponents, getViewComponent} from './util/discovery_utils'; +export {applyChanges} from './util/change_detection_utils'; +export {Listener, getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getOwningComponent, getRootComponents} from './util/discovery_utils'; diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index e4f4366dba..a679190614 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -13,7 +13,6 @@ import {InertBodyHelper} from '../sanitization/inert_body'; import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer'; import {addAllToArray} from '../util/array_utils'; import {assertDataInRange, assertDefined, assertEqual} from '../util/assert'; - import {bindingUpdated} from './bindings'; import {attachPatchData} from './context_discovery'; import {setDelayProjection} from './instructions/all'; @@ -28,7 +27,7 @@ import {SanitizerFn} from './interfaces/sanitization'; import {isLContainer} from './interfaces/type_checks'; import {HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from './interfaces/view'; import {appendChild, applyProjection, createTextNode, nativeRemoveNode} from './node_manipulation'; -import {getBindingIndex, getIsParent, getLView, getPreviousOrParentTNode, nextBindingIndex, setIsNotParent, setPreviousOrParentTNode} from './state'; +import {getBindingIndex, getIsParent, getLView, getPreviousOrParentTNode, getTView, nextBindingIndex, setIsNotParent, setPreviousOrParentTNode} from './state'; import {renderStringify} from './util/misc_utils'; import {getNativeByIndex, getNativeByTNode, getTNode, load} from './util/view_utils'; @@ -360,14 +359,13 @@ const parentIndexStack: number[] = []; * @codeGenApi */ export function ɵɵi18nStart(index: number, message: string, subTemplateIndex?: number): void { - const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); ngDevMode && assertDefined(tView, `tView should be defined`); i18nIndexStack[++i18nIndexStackPointer] = index; // We need to delay projections until `i18nEnd` setDelayProjection(true); if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) { - i18nStartFirstPass(lView, tView, index, message, subTemplateIndex); + i18nStartFirstPass(getLView(), tView, index, message, subTemplateIndex); } } @@ -471,7 +469,7 @@ function i18nStartFirstPass( } if (i18nVarsCount > 0) { - allocExpando(lView, i18nVarsCount); + allocExpando(tView, lView, i18nVarsCount); } ngDevMode && @@ -490,7 +488,8 @@ function i18nStartFirstPass( } function appendI18nNode( - tNode: TNode, parentTNode: TNode, previousTNode: TNode | null, lView: LView): TNode { + tView: TView, tNode: TNode, parentTNode: TNode, previousTNode: TNode | null, + lView: LView): TNode { ngDevMode && ngDevMode.rendererMoveNode++; const nextNode = tNode.next; if (!previousTNode) { @@ -523,16 +522,16 @@ function appendI18nNode( // If the placeholder to append is a projection, we need to move the projected nodes instead if (tNode.type === TNodeType.Projection) { - applyProjection(lView, tNode as TProjectionNode); + applyProjection(tView, lView, tNode as TProjectionNode); return tNode; } - appendChild(getNativeByTNode(tNode, lView), tNode, lView); + appendChild(tView, lView, getNativeByTNode(tNode, lView), tNode); const slotValue = lView[tNode.index]; if (tNode.type !== TNodeType.Container && isLContainer(slotValue)) { // Nodes that inject ViewContainerRef also have a comment node that should be moved - appendChild(slotValue[NATIVE], tNode, lView); + appendChild(tView, lView, slotValue[NATIVE], tNode); } return tNode; } @@ -657,9 +656,9 @@ export function ɵɵi18nPostprocess( */ export function ɵɵi18nEnd(): void { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); ngDevMode && assertDefined(tView, `tView should be defined`); - i18nEndFirstPass(lView, tView); + i18nEndFirstPass(tView, lView); // Stop delaying projections setDelayProjection(false); } @@ -667,7 +666,7 @@ export function ɵɵi18nEnd(): void { /** * See `i18nEnd` above. */ -function i18nEndFirstPass(lView: LView, tView: TView) { +function i18nEndFirstPass(tView: TView, lView: LView) { ngDevMode && assertEqual( getBindingIndex(), tView.bindingStartIndex, 'i18nEnd should be called before any binding'); @@ -680,16 +679,16 @@ function i18nEndFirstPass(lView: LView, tView: TView) { const lastCreatedNode = getPreviousOrParentTNode(); // Read the instructions to insert/move/remove DOM elements - const visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, lView); + const visitedNodes = readCreateOpCodes(rootIndex, tI18n.create, tView, lView); // Remove deleted nodes let index = rootIndex + 1; while (index <= lastCreatedNode.index - HEADER_OFFSET) { if (visitedNodes.indexOf(index) === -1) { - removeNode(index, lView, /* markAsDetached */ true); + removeNode(tView, lView, index, /* markAsDetached */ true); } // Check if an element has any local refs and skip them - const tNode = getTNode(index, lView); + const tNode = getTNode(tView, index); if (tNode && (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) && tNode.localNames !== null) { // Divide by 2 to get the number of local refs, @@ -705,12 +704,12 @@ function i18nEndFirstPass(lView: LView, tView: TView) { * Creates and stores the dynamic TNode, and unhooks it from the tree for now. */ function createDynamicNodeAtIndex( - lView: LView, index: number, type: TNodeType, native: RElement | RText | null, + tView: TView, lView: LView, index: number, type: TNodeType, native: RElement | RText | null, name: string | null): TElementNode|TIcuContainerNode { const previousOrParentTNode = getPreviousOrParentTNode(); ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); lView[index + HEADER_OFFSET] = native; - const tNode = getOrCreateTNode(lView[TVIEW], lView[T_HOST], index, type as any, name, null); + const tNode = getOrCreateTNode(tView, lView[T_HOST], index, type as any, name, null); // We are creating a dynamic node, the previous tNode might not be pointing at this node. // We will link ourselves into the tree later with `appendI18nNode`. @@ -722,7 +721,7 @@ function createDynamicNodeAtIndex( } function readCreateOpCodes( - index: number, createOpCodes: I18nMutateOpCodes, lView: LView): number[] { + index: number, createOpCodes: I18nMutateOpCodes, tView: TView, lView: LView): number[] { const renderer = lView[RENDERER]; let currentTNode: TNode|null = null; let previousTNode: TNode|null = null; @@ -735,7 +734,7 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateTextNode++; previousTNode = currentTNode; currentTNode = - createDynamicNodeAtIndex(lView, textNodeIndex, TNodeType.Element, textRNode, null); + createDynamicNodeAtIndex(tView, lView, textNodeIndex, TNodeType.Element, textRNode, null); visitedNodes.push(textNodeIndex); setIsNotParent(); } else if (typeof opCode == 'number') { @@ -748,26 +747,27 @@ function readCreateOpCodes( // top-level node and we should use the host node instead destinationTNode = lView[T_HOST] !; } else { - destinationTNode = getTNode(destinationNodeIndex, lView); + destinationTNode = getTNode(tView, destinationNodeIndex); } ngDevMode && assertDefined( currentTNode !, `You need to create or select a node before you can insert it into the DOM`); - previousTNode = appendI18nNode(currentTNode !, destinationTNode, previousTNode, lView); + previousTNode = + appendI18nNode(tView, currentTNode !, destinationTNode, previousTNode, lView); break; case I18nMutateOpCode.Select: const nodeIndex = opCode >>> I18nMutateOpCode.SHIFT_REF; visitedNodes.push(nodeIndex); previousTNode = currentTNode; - currentTNode = getTNode(nodeIndex, lView); + currentTNode = getTNode(tView, nodeIndex); if (currentTNode) { setPreviousOrParentTNode(currentTNode, currentTNode.type === TNodeType.Element); } break; case I18nMutateOpCode.ElementEnd: const elementIndex = opCode >>> I18nMutateOpCode.SHIFT_REF; - previousTNode = currentTNode = getTNode(elementIndex, lView); + previousTNode = currentTNode = getTNode(tView, elementIndex); setPreviousOrParentTNode(currentTNode, false); break; case I18nMutateOpCode.Attr: @@ -776,7 +776,7 @@ function readCreateOpCodes( const attrValue = createOpCodes[++i] as string; // This code is used for ICU expressions only, since we don't support // directives/components in ICUs, we don't need to worry about inputs here - elementAttributeInternal(elementNodeIndex, attrName, attrValue, lView); + elementAttributeInternal(elementNodeIndex, attrName, attrValue, tView, lView); break; default: throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`); @@ -793,7 +793,7 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateComment++; previousTNode = currentTNode; currentTNode = createDynamicNodeAtIndex( - lView, commentNodeIndex, TNodeType.IcuContainer, commentRNode, null); + tView, lView, commentNodeIndex, TNodeType.IcuContainer, commentRNode, null); visitedNodes.push(commentNodeIndex); attachPatchData(commentRNode, lView); (currentTNode as TIcuContainerNode).activeCaseIndex = null; @@ -810,7 +810,7 @@ function readCreateOpCodes( ngDevMode && ngDevMode.rendererCreateElement++; previousTNode = currentTNode; currentTNode = createDynamicNodeAtIndex( - lView, elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue); + tView, lView, elementNodeIndex, TNodeType.Element, elementRNode, tagNameValue); visitedNodes.push(elementNodeIndex); break; default: @@ -826,7 +826,7 @@ function readCreateOpCodes( function readUpdateOpCodes( updateOpCodes: I18nUpdateOpCodes, icus: TIcu[] | null, bindingsStartIndex: number, - changeMask: number, viewData: LView, bypassCheckBit = false) { + changeMask: number, tView: TView, lView: LView, bypassCheckBit = false) { let caseCreated = false; for (let i = 0; i < updateOpCodes.length; i++) { // bit code to check if we should apply the next update @@ -843,7 +843,7 @@ function readUpdateOpCodes( } else if (typeof opCode == 'number') { if (opCode < 0) { // It's a binding index whose value is negative - value += renderStringify(viewData[bindingsStartIndex - opCode]); + value += renderStringify(lView[bindingsStartIndex - opCode]); } else { const nodeIndex = opCode >>> I18nUpdateOpCode.SHIFT_REF; let tIcuIndex: number; @@ -853,15 +853,15 @@ function readUpdateOpCodes( case I18nUpdateOpCode.Attr: const propName = updateOpCodes[++j] as string; const sanitizeFn = updateOpCodes[++j] as SanitizerFn | null; - elementPropertyInternal(viewData, nodeIndex, propName, value, sanitizeFn); + elementPropertyInternal(tView, lView, nodeIndex, propName, value, sanitizeFn); break; case I18nUpdateOpCode.Text: - textBindingInternal(viewData, nodeIndex, value); + textBindingInternal(lView, nodeIndex, value); break; case I18nUpdateOpCode.IcuSwitch: tIcuIndex = updateOpCodes[++j] as number; tIcu = icus ![tIcuIndex]; - icuTNode = getTNode(nodeIndex, viewData) as TIcuContainerNode; + icuTNode = getTNode(tView, nodeIndex) as TIcuContainerNode; // If there is an active case, delete the old nodes if (icuTNode.activeCaseIndex !== null) { const removeCodes = tIcu.remove[icuTNode.activeCaseIndex]; @@ -873,13 +873,13 @@ function readUpdateOpCodes( // Remove DOM element, but do *not* mark TNode as detached, since we are // just switching ICU cases (while keeping the same TNode), so a DOM element // representing a new ICU case will be re-created. - removeNode(nodeIndex, viewData, /* markAsDetached */ false); + removeNode(tView, lView, nodeIndex, /* markAsDetached */ false); break; case I18nMutateOpCode.RemoveNestedIcu: const nestedIcuNodeIndex = removeCodes[k + 1] as number >>> I18nMutateOpCode.SHIFT_REF; const nestedIcuTNode = - getTNode(nestedIcuNodeIndex, viewData) as TIcuContainerNode; + getTNode(tView, nestedIcuNodeIndex) as TIcuContainerNode; const activeIndex = nestedIcuTNode.activeCaseIndex; if (activeIndex !== null) { const nestedIcuTIndex = removeOpCode >>> I18nMutateOpCode.SHIFT_REF; @@ -896,18 +896,18 @@ function readUpdateOpCodes( icuTNode.activeCaseIndex = caseIndex !== -1 ? caseIndex : null; if (caseIndex > -1) { // Add the nodes for the new case - readCreateOpCodes(-1, tIcu.create[caseIndex], viewData); + readCreateOpCodes(-1, tIcu.create[caseIndex], tView, lView); caseCreated = true; } break; case I18nUpdateOpCode.IcuUpdate: tIcuIndex = updateOpCodes[++j] as number; tIcu = icus ![tIcuIndex]; - icuTNode = getTNode(nodeIndex, viewData) as TIcuContainerNode; + icuTNode = getTNode(tView, nodeIndex) as TIcuContainerNode; if (icuTNode.activeCaseIndex !== null) { readUpdateOpCodes( tIcu.update[icuTNode.activeCaseIndex], icus, bindingsStartIndex, changeMask, - viewData, caseCreated); + tView, lView, caseCreated); } break; } @@ -919,18 +919,18 @@ function readUpdateOpCodes( } } -function removeNode(index: number, viewData: LView, markAsDetached: boolean) { - const removedPhTNode = getTNode(index, viewData); - const removedPhRNode = getNativeByIndex(index, viewData); +function removeNode(tView: TView, lView: LView, index: number, markAsDetached: boolean) { + const removedPhTNode = getTNode(tView, index); + const removedPhRNode = getNativeByIndex(index, lView); if (removedPhRNode) { - nativeRemoveNode(viewData[RENDERER], removedPhRNode); + nativeRemoveNode(lView[RENDERER], removedPhRNode); } - const slotValue = load(viewData, index) as RElement | RComment | LContainer; + const slotValue = load(lView, index) as RElement | RComment | LContainer; if (isLContainer(slotValue)) { const lContainer = slotValue as LContainer; if (removedPhTNode.type !== TNodeType.Container) { - nativeRemoveNode(viewData[RENDERER], lContainer[NATIVE]); + nativeRemoveNode(lView[RENDERER], lContainer[NATIVE]); } } @@ -982,7 +982,7 @@ export function ɵɵi18n(index: number, message: string, subTemplateIndex?: numb */ export function ɵɵi18nAttributes(index: number, values: string[]): void { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); ngDevMode && assertDefined(tView, `tView should be defined`); i18nAttributesFirstPass(lView, tView, index, values); } @@ -1014,16 +1014,16 @@ function i18nAttributesFirstPass(lView: LView, tView: TView, index: number, valu generateBindingUpdateOpCodes(value, previousElementIndex, attrName), updateOpCodes); } } else { - const tNode = getTNode(previousElementIndex, lView); + const tNode = getTNode(tView, previousElementIndex); // Set attributes for Elements only, for other types (like ElementContainer), // only set inputs below if (tNode.type === TNodeType.Element) { - elementAttributeInternal(previousElementIndex, attrName, value, lView); + elementAttributeInternal(previousElementIndex, attrName, value, tView, lView); } // Check if that attribute is a directive input const dataValue = tNode.inputs !== null && tNode.inputs[attrName]; if (dataValue) { - setInputsForProperty(lView, dataValue, attrName, value); + setInputsForProperty(tView, lView, dataValue, attrName, value); if (ngDevMode) { const element = getNativeByIndex(previousElementIndex, lView) as RElement | RComment; setNgReflectProperties(lView, element, tNode.type, dataValue, value); @@ -1071,8 +1071,7 @@ export function ɵɵi18nExp(value: T): typeof ɵɵi18nExp { */ export function ɵɵi18nApply(index: number) { if (shiftsCounter) { - const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); ngDevMode && assertDefined(tView, `tView should be defined`); const tI18n = tView.data[index + HEADER_OFFSET]; let updateOpCodes: I18nUpdateOpCodes; @@ -1084,7 +1083,8 @@ export function ɵɵi18nApply(index: number) { icus = (tI18n as TI18n).icus; } const bindingsStartIndex = getBindingIndex() - shiftsCounter - 1; - readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, lView); + const lView = getLView(); + readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, tView, lView); // Reset changeMask & maskBit to default for the next update cycle changeMask = 0b0; diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 7baacc216e..e896ceee85 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -24,8 +24,6 @@ export { store, tick, - ɵɵallocHostVars, - ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, @@ -65,7 +63,6 @@ export { ɵɵelementContainerStart, ɵɵelementEnd, - ɵɵelementHostAttrs, ɵɵelementStart, ɵɵembeddedViewEnd, diff --git a/packages/core/src/render3/instructions/advance.ts b/packages/core/src/render3/instructions/advance.ts index 307d9ece05..551de37caf 100644 --- a/packages/core/src/render3/instructions/advance.ts +++ b/packages/core/src/render3/instructions/advance.ts @@ -7,9 +7,8 @@ */ import {assertDataInRange, assertGreaterThan} from '../../util/assert'; import {executeCheckHooks, executeInitAndCheckHooks} from '../hooks'; -import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, TVIEW} from '../interfaces/view'; -import {ActiveElementFlags, executeElementExitFn, getCheckNoChangesMode, getLView, getSelectedIndex, hasActiveElementFlag, setSelectedIndex} from '../state'; - +import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, TView} from '../interfaces/view'; +import {getCheckNoChangesMode, getLView, getSelectedIndex, getTView, setSelectedIndex} from '../state'; /** @@ -37,7 +36,7 @@ import {ActiveElementFlags, executeElementExitFn, getCheckNoChangesMode, getLVie */ export function ɵɵadvance(delta: number): void { ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward'); - selectIndexInternal(getLView(), getSelectedIndex() + delta, getCheckNoChangesMode()); + selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, getCheckNoChangesMode()); } /** @@ -46,29 +45,27 @@ export function ɵɵadvance(delta: number): void { * @codeGenApi */ export function ɵɵselect(index: number): void { - selectIndexInternal(getLView(), index, getCheckNoChangesMode()); + // TODO(misko): Remove this function as it is no longer being used. + selectIndexInternal(getTView(), getLView(), index, getCheckNoChangesMode()); } -export function selectIndexInternal(lView: LView, index: number, checkNoChangesMode: boolean) { +export function selectIndexInternal( + tView: TView, lView: LView, index: number, checkNoChangesMode: boolean) { ngDevMode && assertGreaterThan(index, -1, 'Invalid index'); ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); - if (hasActiveElementFlag(ActiveElementFlags.RunExitFn)) { - executeElementExitFn(); - } - // Flush the initial hooks for elements in the view that have been added up to this point. // PERF WARNING: do NOT extract this to a separate function without running benchmarks if (!checkNoChangesMode) { const hooksInitPhaseCompleted = (lView[FLAGS] & LViewFlags.InitPhaseStateMask) === InitPhaseState.InitPhaseCompleted; if (hooksInitPhaseCompleted) { - const preOrderCheckHooks = lView[TVIEW].preOrderCheckHooks; + const preOrderCheckHooks = tView.preOrderCheckHooks; if (preOrderCheckHooks !== null) { executeCheckHooks(lView, preOrderCheckHooks, index); } } else { - const preOrderHooks = lView[TVIEW].preOrderHooks; + const preOrderHooks = tView.preOrderHooks; if (preOrderHooks !== null) { executeInitAndCheckHooks(lView, preOrderHooks, InitPhaseState.OnInitHooksToBeRun, index); } diff --git a/packages/core/src/render3/instructions/all.ts b/packages/core/src/render3/instructions/all.ts index daa2da3810..125c077bd4 100644 --- a/packages/core/src/render3/instructions/all.ts +++ b/packages/core/src/render3/instructions/all.ts @@ -25,7 +25,6 @@ * * Jira Issue = FW-1184 */ -export * from './alloc_host_vars'; export * from './attribute'; export * from './attribute_interpolation'; export * from './change_detection'; diff --git a/packages/core/src/render3/instructions/alloc_host_vars.ts b/packages/core/src/render3/instructions/alloc_host_vars.ts deleted file mode 100644 index 1e4c22ccff..0000000000 --- a/packages/core/src/render3/instructions/alloc_host_vars.ts +++ /dev/null @@ -1,65 +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 {assertEqual} from '../../util/assert'; -import {ComponentDef, DirectiveDef} from '../interfaces/definition'; -import {LView, TVIEW, TView} from '../interfaces/view'; -import {getCurrentDirectiveDef, getLView} from '../state'; -import {NO_CHANGE} from '../tokens'; - -/** - * Allocates the necessary amount of slots for host vars. - * - * @param count Amount of vars to be allocated - * - * @codeGenApi - */ -export function ɵɵallocHostVars(count: number): void { - const lView = getLView(); - const tView = lView[TVIEW]; - if (!tView.firstCreatePass) return; - queueHostBindingForCheck(tView, getCurrentDirectiveDef() !, count); - prefillHostVars(tView, lView, count); -} - -/** - * Stores host binding fn and number of host vars so it will be queued for binding refresh during - * CD. - */ -function queueHostBindingForCheck( - tView: TView, def: DirectiveDef| ComponentDef, hostVars: number): void { - ngDevMode && - assertEqual(tView.firstCreatePass, true, 'Should only be called in first create pass.'); - const expando = tView.expandoInstructions !; - const length = expando.length; - // Check whether a given `hostBindings` function already exists in expandoInstructions, - // which can happen in case directive definition was extended from base definition (as a part of - // the `InheritDefinitionFeature` logic). If we found the same `hostBindings` function in the - // list, we just increase the number of host vars associated with that function, but do not add it - // into the list again. - if (length >= 2 && expando[length - 2] === def.hostBindings) { - expando[length - 1] = (expando[length - 1] as number) + hostVars; - } else { - expando.push(def.hostBindings !, hostVars); - } -} - -/** - * On the first template pass, we need to reserve space for host binding values - * after directives are matched (so all directives are saved, then bindings). - * Because we are updating the blueprint, we only need to do this once. - */ -function prefillHostVars(tView: TView, lView: LView, totalHostVars: number): void { - ngDevMode && - assertEqual(tView.firstCreatePass, true, 'Should only be called in first create pass.'); - for (let i = 0; i < totalHostVars; i++) { - lView.push(NO_CHANGE); - tView.blueprint.push(NO_CHANGE); - tView.data.push(null); - } -} diff --git a/packages/core/src/render3/instructions/attribute.ts b/packages/core/src/render3/instructions/attribute.ts index b3d0442f27..13641efd82 100644 --- a/packages/core/src/render3/instructions/attribute.ts +++ b/packages/core/src/render3/instructions/attribute.ts @@ -7,9 +7,7 @@ */ import {bindingUpdated} from '../bindings'; import {SanitizerFn} from '../interfaces/sanitization'; -import {TVIEW} from '../interfaces/view'; -import {getLView, getSelectedIndex, nextBindingIndex} from '../state'; - +import {getLView, getSelectedIndex, getTView, nextBindingIndex} from '../state'; import {elementAttributeInternal, storePropertyBindingMetadata} from './shared'; @@ -34,9 +32,9 @@ export function ɵɵattribute( const bindingIndex = nextBindingIndex(); if (bindingUpdated(lView, bindingIndex, value)) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, name, value, lView, sanitizer, namespace); - ngDevMode && - storePropertyBindingMetadata(lView[TVIEW].data, nodeIndex, 'attr.' + name, bindingIndex); + const tView = getTView(); + elementAttributeInternal(nodeIndex, name, value, tView, lView, sanitizer, namespace); + ngDevMode && storePropertyBindingMetadata(tView.data, nodeIndex, 'attr.' + name, bindingIndex); } return ɵɵattribute; } diff --git a/packages/core/src/render3/instructions/attribute_interpolation.ts b/packages/core/src/render3/instructions/attribute_interpolation.ts index 34ea69f205..1f83b7e817 100644 --- a/packages/core/src/render3/instructions/attribute_interpolation.ts +++ b/packages/core/src/render3/instructions/attribute_interpolation.ts @@ -6,10 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ import {SanitizerFn} from '../interfaces/sanitization'; -import {TVIEW} from '../interfaces/view'; -import {getBindingIndex, getLView, getSelectedIndex} from '../state'; +import {getBindingIndex, getLView, getSelectedIndex, getTView} from '../state'; import {NO_CHANGE} from '../tokens'; - import {interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV} from './interpolation'; import {elementAttributeInternal, storePropertyBindingMetadata} from './shared'; @@ -46,10 +44,12 @@ export function ɵɵattributeInterpolate1( const interpolatedValue = interpolation1(lView, prefix, v0, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 1, - prefix, suffix); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); + ngDevMode && + storePropertyBindingMetadata( + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 1, prefix, suffix); } return ɵɵattributeInterpolate1; } @@ -87,10 +87,12 @@ export function ɵɵattributeInterpolate2( const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 2, - prefix, i0, suffix); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); + ngDevMode && + storePropertyBindingMetadata( + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 2, prefix, i0, suffix); } return ɵɵattributeInterpolate2; } @@ -131,10 +133,12 @@ export function ɵɵattributeInterpolate3( const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 3, - prefix, i0, i1, suffix); + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 3, prefix, i0, + i1, suffix); } return ɵɵattributeInterpolate3; } @@ -178,10 +182,12 @@ export function ɵɵattributeInterpolate4( const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 4, - prefix, i0, i1, i2, suffix); + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 4, prefix, i0, + i1, i2, suffix); } return ɵɵattributeInterpolate4; } @@ -228,10 +234,12 @@ export function ɵɵattributeInterpolate5( interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 5, - prefix, i0, i1, i2, i3, suffix); + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 5, prefix, i0, + i1, i2, i3, suffix); } return ɵɵattributeInterpolate5; } @@ -280,10 +288,12 @@ export function ɵɵattributeInterpolate6( interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 6, - prefix, i0, i1, i2, i3, i4, suffix); + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 6, prefix, i0, + i1, i2, i3, i4, suffix); } return ɵɵattributeInterpolate6; } @@ -334,10 +344,12 @@ export function ɵɵattributeInterpolate7( interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 7, - prefix, i0, i1, i2, i3, i4, i5, suffix); + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 7, prefix, i0, + i1, i2, i3, i4, i5, suffix); } return ɵɵattributeInterpolate7; } @@ -390,10 +402,12 @@ export function ɵɵattributeInterpolate8( lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolatedValue, lView, sanitizer, namespace); + const tView = getTView(); + elementAttributeInternal( + nodeIndex, attrName, interpolatedValue, tView, lView, sanitizer, namespace); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 8, - prefix, i0, i1, i2, i3, i4, i5, i6, suffix); + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - 8, prefix, i0, + i1, i2, i3, i4, i5, i6, suffix); } return ɵɵattributeInterpolate8; } @@ -430,15 +444,16 @@ export function ɵɵattributeInterpolateV( const lView = getLView(); const interpolated = interpolationV(lView, values); if (interpolated !== NO_CHANGE) { + const tView = getTView(); const nodeIndex = getSelectedIndex(); - elementAttributeInternal(nodeIndex, attrName, interpolated, lView, sanitizer, namespace); + elementAttributeInternal(nodeIndex, attrName, interpolated, tView, lView, sanitizer, namespace); if (ngDevMode) { const interpolationInBetween = [values[0]]; // prefix for (let i = 2; i < values.length; i += 2) { interpolationInBetween.push(values[i]); } storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, 'attr.' + attrName, + tView.data, nodeIndex, 'attr.' + attrName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween); } } diff --git a/packages/core/src/render3/instructions/change_detection.ts b/packages/core/src/render3/instructions/change_detection.ts index fc4c9e50d7..3a78623e3c 100644 --- a/packages/core/src/render3/instructions/change_detection.ts +++ b/packages/core/src/render3/instructions/change_detection.ts @@ -8,51 +8,39 @@ import {assertDefined} from '../../util/assert'; import {getComponentViewByInstance} from '../context_discovery'; -import {CONTEXT, RootContext, RootContextFlags} from '../interfaces/view'; +import {CONTEXT, RootContext, RootContextFlags, TVIEW} from '../interfaces/view'; import {getRootView} from '../util/view_traversal_utils'; import {detectChangesInternal, markViewDirty, scheduleTick, tickRootContext} from './shared'; /** * Synchronously perform change detection on a component (and possibly its sub-components). * - * This function triggers change detection in a synchronous way on a component. There should - * be very little reason to call this function directly since a preferred way to do change - * detection is to {@link markDirty} the component and wait for the scheduler to call this method - * at some future point in time. This is because a single user action often results in many - * components being invalidated and calling change detection on each component synchronously - * would be inefficient. It is better to wait until all components are marked as dirty and - * then perform single change detection across all of the components + * This function triggers change detection in a synchronous way on a component. * * @param component The component which the change detection should be performed on. */ -export function detectChanges(component: T): void { +export function detectChanges(component: {}): void { const view = getComponentViewByInstance(component); - detectChangesInternal(view, component); + detectChangesInternal(view[TVIEW], view, component); } /** - * Mark the component as dirty (needing change detection). + * Marks the component as dirty (needing change detection). Marking a component dirty will + * schedule a change detection on it at some point in the future. * - * Marking a component dirty will schedule a change detection on this - * component at some point in the future. Marking an already dirty - * component as dirty is a noop. Only one outstanding change detection - * can be scheduled per component tree. (Two components bootstrapped with - * separate `renderComponent` will have separate schedulers) - * - * When the root component is bootstrapped with `renderComponent`, a scheduler - * can be provided. + * Marking an already dirty component as dirty won't do anything. Only one outstanding change + * detection can be scheduled per component tree. * * @param component Component to mark as dirty. - * - * @publicApi */ -export function markDirty(component: T) { +export function markDirty(component: {}): void { ngDevMode && assertDefined(component, 'component'); const rootView = markViewDirty(getComponentViewByInstance(component)) !; ngDevMode && assertDefined(rootView[CONTEXT], 'rootContext should be defined'); scheduleTick(rootView[CONTEXT] as RootContext, RootContextFlags.DetectChanges); } + /** * Used to perform change detection on the whole application. * diff --git a/packages/core/src/render3/instructions/class_map_interpolation.ts b/packages/core/src/render3/instructions/class_map_interpolation.ts index d1a59cf1b8..e6f4ff3f3b 100644 --- a/packages/core/src/render3/instructions/class_map_interpolation.ts +++ b/packages/core/src/render3/instructions/class_map_interpolation.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {getLView, getSelectedIndex} from '../state'; - +import {keyValueArraySet} from '../../util/array_utils'; +import {getLView} from '../state'; import {interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV} from './interpolation'; -import {classMapInternal} from './styling'; +import {checkStylingMap, classStringParser} from './styling'; @@ -37,7 +37,7 @@ import {classMapInternal} from './styling'; export function ɵɵclassMapInterpolate1(prefix: string, v0: any, suffix: string): void { const lView = getLView(); const interpolatedValue = interpolation1(lView, prefix, v0, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -67,7 +67,7 @@ export function ɵɵclassMapInterpolate2( prefix: string, v0: any, i0: string, v1: any, suffix: string): void { const lView = getLView(); const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -100,7 +100,7 @@ export function ɵɵclassMapInterpolate3( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): void { const lView = getLView(); const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -136,7 +136,7 @@ export function ɵɵclassMapInterpolate4( suffix: string): void { const lView = getLView(); const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -175,7 +175,7 @@ export function ɵɵclassMapInterpolate5( const lView = getLView(); const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -216,7 +216,7 @@ export function ɵɵclassMapInterpolate6( const lView = getLView(); const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -259,7 +259,7 @@ export function ɵɵclassMapInterpolate7( const lView = getLView(); const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -305,7 +305,7 @@ export function ɵɵclassMapInterpolate8( const lView = getLView(); const interpolatedValue = interpolation8( lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } /** @@ -334,5 +334,5 @@ export function ɵɵclassMapInterpolate8( export function ɵɵclassMapInterpolateV(values: any[]): void { const lView = getLView(); const interpolatedValue = interpolationV(lView, values); - classMapInternal(getSelectedIndex(), interpolatedValue); + checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true); } diff --git a/packages/core/src/render3/instructions/container.ts b/packages/core/src/render3/instructions/container.ts index ef5fa7e63f..70c0ce0cd8 100644 --- a/packages/core/src/render3/instructions/container.ts +++ b/packages/core/src/render3/instructions/container.ts @@ -13,12 +13,11 @@ import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/c import {ComponentTemplate} from '../interfaces/definition'; import {LocalRefExtractor, TAttributes, TContainerNode, TNode, TNodeType, TViewNode} from '../interfaces/node'; import {isDirectiveHost} from '../interfaces/type_checks'; -import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, TVIEW, TView, TViewType, T_HOST} from '../interfaces/view'; +import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, TView, TViewType, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild, removeView} from '../node_manipulation'; -import {getBindingIndex, getCheckNoChangesMode, getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode} from '../state'; +import {getBindingIndex, getCheckNoChangesMode, getIsParent, getLView, getPreviousOrParentTNode, getTView, setIsNotParent, setPreviousOrParentTNode} from '../state'; import {getConstant, getLContainerActiveIndex, load} from '../util/view_utils'; - import {addToViewTree, createDirectivesInstances, createLContainer, createTNode, createTView, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData} from './shared'; @@ -36,9 +35,10 @@ import {addToViewTree, createDirectivesInstances, createLContainer, createTNode, */ export function ɵɵcontainer(index: number): void { const lView = getLView(); - const tNode = containerInternal(lView, index, null, null); + const tView = getTView(); + const tNode = containerInternal(tView, lView, index, null, null); - if (lView[TVIEW].firstCreatePass) { + if (tView.firstCreatePass) { tNode.tViews = []; } setIsNotParent(); @@ -98,7 +98,7 @@ export function ɵɵtemplate( tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, localRefExtractor?: LocalRefExtractor) { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); const adjustedIndex = index + HEADER_OFFSET; const tNode = tView.firstCreatePass ? @@ -108,7 +108,7 @@ export function ɵɵtemplate( setPreviousOrParentTNode(tNode, false); const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : ''); - appendChild(comment, tNode, lView); + appendChild(tView, lView, comment, tNode); attachPatchData(comment, lView); addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode)); @@ -131,7 +131,7 @@ export function ɵɵtemplate( */ export function ɵɵcontainerRefreshStart(index: number): void { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); let previousOrParentTNode = load(tView.data, index) as TNode; ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Container); setPreviousOrParentTNode(previousOrParentTNode, true); @@ -188,10 +188,10 @@ export function ɵɵcontainerRefreshEnd(): void { } function containerInternal( - lView: LView, nodeIndex: number, tagName: string | null, + tView: TView, lView: LView, nodeIndex: number, tagName: string | null, attrs: TAttributes | null): TContainerNode { ngDevMode && assertEqual( - getBindingIndex(), lView[TVIEW].bindingStartIndex, + getBindingIndex(), tView.bindingStartIndex, 'container nodes should be created before any bindings'); const adjustedIndex = nodeIndex + HEADER_OFFSET; @@ -200,10 +200,10 @@ function containerInternal( const comment = lView[adjustedIndex] = lView[RENDERER].createComment(ngDevMode ? 'container' : ''); const tNode = - getOrCreateTNode(lView[TVIEW], lView[T_HOST], nodeIndex, TNodeType.Container, tagName, attrs); + getOrCreateTNode(tView, lView[T_HOST], nodeIndex, TNodeType.Container, tagName, attrs); const lContainer = lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode); - appendChild(comment, tNode, lView); + appendChild(tView, lView, comment, tNode); attachPatchData(comment, lView); // Containers are added to the current view tree instead of their embedded views diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index 245769cdd5..52eda6249b 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -7,40 +7,40 @@ */ import {assertDataInRange, assertDefined, assertEqual} from '../../util/assert'; -import {assertHasParent} from '../assert'; +import {assertFirstCreatePass, assertHasParent} from '../assert'; import {attachPatchData} from '../context_discovery'; import {registerPostOrderHooks} from '../hooks'; -import {TAttributes, TElementNode, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; +import {TAttributes, TElementNode, TNode, TNodeType, hasClassInput, hasStyleInput} from '../interfaces/node'; import {RElement} from '../interfaces/renderer'; -import {StylingMapArray, TStylingContext} from '../interfaces/styling'; import {isContentQueryHost, isDirectiveHost} from '../interfaces/type_checks'; import {HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; -import {appendChild} from '../node_manipulation'; -import {decreaseElementDepthCount, getBindingIndex, getElementDepthCount, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, getSelectedIndex, increaseElementDepthCount, setIsNotParent, setPreviousOrParentTNode} from '../state'; +import {appendChild, writeDirectClass, writeDirectStyle} from '../node_manipulation'; +import {decreaseElementDepthCount, getBindingIndex, getElementDepthCount, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, getTView, increaseElementDepthCount, setIsNotParent, setPreviousOrParentTNode} from '../state'; +import {computeStaticStyling} from '../styling/static_styling'; import {setUpAttributes} from '../util/attrs_utils'; -import {getInitialStylingValue, hasClassInput, hasStyleInput, selectClassBasedInputName} from '../util/styling_utils'; -import {getConstant, getNativeByTNode, getTNode} from '../util/view_utils'; +import {getConstant} from '../util/view_utils'; +import {setDirectiveInputsWhichShadowsStyling} from './property'; +import {createDirectivesInstances, elementCreate, executeContentQueries, getOrCreateTNode, matchingSchemas, resolveDirectives, saveResolvedLocalsInData} from './shared'; -import {createDirectivesInstances, elementCreate, executeContentQueries, getOrCreateTNode, matchingSchemas, renderInitialStyling, resolveDirectives, saveResolvedLocalsInData, setInputsForProperty} from './shared'; -import {registerInitialStylingOnTNode} from './styling'; function elementStartFirstCreatePass( index: number, tView: TView, lView: LView, native: RElement, name: string, attrsIndex?: number | null, localRefsIndex?: number): TElementNode { + ngDevMode && assertFirstCreatePass(tView); ngDevMode && ngDevMode.firstCreatePass++; const tViewConsts = tView.consts; const attrs = getConstant(tViewConsts, attrsIndex); const tNode = getOrCreateTNode(tView, lView[T_HOST], index, TNodeType.Element, name, attrs); - if (attrs !== null) { - registerInitialStylingOnTNode(tNode, attrs, 0); - } - const hasDirectives = resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex)); - ngDevMode && warnAboutUnknownElement(lView, native, tNode, hasDirectives); + ngDevMode && warnAboutUnknownElement(tView, lView, native, tNode, hasDirectives); + + if (tNode.mergedAttrs !== null) { + computeStaticStyling(tNode, tNode.mergedAttrs); + } if (tView.queries !== null) { tView.queries.elementStart(tView, tNode); @@ -66,7 +66,7 @@ function elementStartFirstCreatePass( export function ɵɵelementStart( index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); const adjustedIndex = HEADER_OFFSET + index; ngDevMode && assertEqual( @@ -83,15 +83,20 @@ export function ɵɵelementStart( tView.data[adjustedIndex] as TElementNode; setPreviousOrParentTNode(tNode, true); - const attrs = tNode.attrs; - if (attrs != null) { - setUpAttributes(renderer, native, attrs); + const mergedAttrs = tNode.mergedAttrs; + if (mergedAttrs !== null) { + setUpAttributes(renderer, native, mergedAttrs); } - if ((tNode.flags & TNodeFlags.hasInitialStyling) === TNodeFlags.hasInitialStyling) { - renderInitialStyling(renderer, native, tNode, false); + const classes = tNode.classes; + if (classes !== null) { + writeDirectClass(renderer, native, classes); + } + const styles = tNode.styles; + if (styles !== null) { + writeDirectStyle(renderer, native, styles); } - appendChild(native, tNode, lView); + appendChild(tView, lView, native, tNode); // any immediate children of a component or template container must be pre-emptively // monkey-patched with the component view data so that the element can be inspected @@ -106,7 +111,7 @@ export function ɵɵelementStart( createDirectivesInstances(tView, lView, tNode); executeContentQueries(tView, tNode, lView); } - if (localRefsIndex != null) { + if (localRefsIndex !== null) { saveResolvedLocalsInData(lView, tNode); } } @@ -130,11 +135,10 @@ export function ɵɵelementEnd(): void { const tNode = previousOrParentTNode; ngDevMode && assertNodeType(tNode, TNodeType.Element); - const lView = getLView(); - const tView = lView[TVIEW]; decreaseElementDepthCount(); + const tView = getTView(); if (tView.firstCreatePass) { registerPostOrderHooks(tView, previousOrParentTNode); if (isContentQueryHost(previousOrParentTNode)) { @@ -142,17 +146,15 @@ export function ɵɵelementEnd(): void { } } - if (hasClassInput(tNode)) { - const inputName: string = selectClassBasedInputName(tNode.inputs !); - setDirectiveStylingInput(tNode.classes, lView, tNode.inputs ![inputName], inputName); + if (tNode.classes !== null && hasClassInput(tNode)) { + setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.classes, true); } - if (hasStyleInput(tNode)) { - setDirectiveStylingInput(tNode.styles, lView, tNode.inputs !['style'], 'style'); + if (tNode.styles !== null && hasStyleInput(tNode)) { + setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.styles, false); } } - /** * Creates an empty element using {@link elementStart} and {@link elementEnd} * @@ -169,93 +171,9 @@ export function ɵɵelement( ɵɵelementEnd(); } -/** - * 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 of static values (attributes, classes and styles) with the correct marker - * values. - * - * @codeGenApi - */ -export function ɵɵelementHostAttrs(attrs: TAttributes) { - const hostElementIndex = getSelectedIndex(); - const lView = getLView(); - const tView = lView[TVIEW]; - const tNode = getTNode(hostElementIndex, lView); - - // non-element nodes (e.g. ``) are not rendered as actual - // element nodes and adding styles/classes on to them will cause runtime - // errors... - if (tNode.type === TNodeType.Element) { - const native = getNativeByTNode(tNode, lView) as RElement; - const lastAttrIndex = setUpAttributes(lView[RENDERER], native, attrs); - if (tView.firstCreatePass) { - const stylingNeedsToBeRendered = registerInitialStylingOnTNode(tNode, attrs, lastAttrIndex); - - // this is only called during the first template pass in the - // event that this current directive assigned initial style/class - // host attribute values to the element. Because initial styling - // values are applied before directives are first rendered (within - // `createElement`) this means that initial styling for any directives - // still needs to be applied. Note that this will only happen during - // the first template pass and not each time a directive applies its - // attribute values to the element. - if (stylingNeedsToBeRendered) { - const renderer = lView[RENDERER]; - renderInitialStyling(renderer, native, tNode, true); - } - } - } -} - -function setDirectiveStylingInput( - context: TStylingContext | StylingMapArray | null, lView: LView, - stylingInputs: (string | number)[], propName: string) { - // older versions of Angular treat the input as `null` in the - // event that the value does not exist at all. For this reason - // we can't have a styling value be an empty string. - const value = (context && getInitialStylingValue(context)) || null; - - // Ivy does an extra `[class]` write with a falsy value since the value - // is applied during creation mode. This is a deviation from VE and should - // be (Jira Issue = FW-1467). - setInputsForProperty(lView, stylingInputs, propName, value); -} - function warnAboutUnknownElement( - hostView: LView, element: RElement, tNode: TNode, hasDirectives: boolean): void { - const schemas = hostView[TVIEW].schemas; + tView: TView, lView: LView, element: RElement, tNode: TNode, hasDirectives: boolean): void { + const schemas = tView.schemas; // If `schemas` is set to `null`, that's an indication that this Component was compiled in AOT // mode where this check happens at compile time. In JIT mode, `schemas` is always present and @@ -278,7 +196,7 @@ function warnAboutUnknownElement( (typeof customElements !== 'undefined' && tagName.indexOf('-') > -1 && !customElements.get(tagName)); - if (isUnknown && !matchingSchemas(hostView, tagName)) { + if (isUnknown && !matchingSchemas(tView, lView, tagName)) { let warning = `'${tagName}' is not a known element:\n`; warning += `1. If '${tagName}' is an Angular component, then verify that it is part of this module.\n`; diff --git a/packages/core/src/render3/instructions/element_container.ts b/packages/core/src/render3/instructions/element_container.ts index 8456ad1ff9..54f1cd9dd3 100644 --- a/packages/core/src/render3/instructions/element_container.ts +++ b/packages/core/src/render3/instructions/element_container.ts @@ -11,14 +11,14 @@ import {attachPatchData} from '../context_discovery'; import {registerPostOrderHooks} from '../hooks'; import {TAttributes, TElementContainerNode, TNodeType} from '../interfaces/node'; import {isContentQueryHost, isDirectiveHost} from '../interfaces/type_checks'; -import {HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from '../interfaces/view'; +import {HEADER_OFFSET, LView, RENDERER, TView, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild} from '../node_manipulation'; -import {getBindingIndex, getIsParent, getLView, getPreviousOrParentTNode, setIsNotParent, setPreviousOrParentTNode} from '../state'; +import {getBindingIndex, getIsParent, getLView, getPreviousOrParentTNode, getTView, setIsNotParent, setPreviousOrParentTNode} from '../state'; +import {computeStaticStyling} from '../styling/static_styling'; import {getConstant} from '../util/view_utils'; import {createDirectivesInstances, executeContentQueries, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData} from './shared'; -import {registerInitialStylingOnTNode} from './styling'; function elementContainerStartFirstCreatePass( index: number, tView: TView, lView: LView, attrsIndex?: number | null, @@ -33,7 +33,7 @@ function elementContainerStartFirstCreatePass( // While ng-container doesn't necessarily support styling, we use the style context to identify // and execute directives on the ng-container. if (attrs !== null) { - registerInitialStylingOnTNode(tNode, attrs, 0); + computeStaticStyling(tNode, attrs); } const localRefs = getConstant(tViewConsts, localRefsIndex); @@ -63,7 +63,7 @@ function elementContainerStartFirstCreatePass( export function ɵɵelementContainerStart( index: number, attrsIndex?: number | null, localRefsIndex?: number): void { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); const adjustedIndex = index + HEADER_OFFSET; ngDevMode && assertDataInRange(lView, adjustedIndex); @@ -79,7 +79,7 @@ export function ɵɵelementContainerStart( ngDevMode && ngDevMode.rendererCreateComment++; const native = lView[adjustedIndex] = lView[RENDERER].createComment(ngDevMode ? 'ng-container' : ''); - appendChild(native, tNode, lView); + appendChild(tView, lView, native, tNode); attachPatchData(native, lView); if (isDirectiveHost(tNode)) { @@ -99,8 +99,7 @@ export function ɵɵelementContainerStart( */ export function ɵɵelementContainerEnd(): void { let previousOrParentTNode = getPreviousOrParentTNode(); - const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); if (getIsParent()) { setIsNotParent(); } else { diff --git a/packages/core/src/render3/instructions/embedded_view.ts b/packages/core/src/render3/instructions/embedded_view.ts index f6ff3b550f..777d22911b 100644 --- a/packages/core/src/render3/instructions/embedded_view.ts +++ b/packages/core/src/render3/instructions/embedded_view.ts @@ -14,7 +14,7 @@ import {TContainerNode, TNodeType} from '../interfaces/node'; import {CONTEXT, LView, LViewFlags, PARENT, TVIEW, TView, TViewType, T_HOST} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {insertView, removeView} from '../node_manipulation'; -import {enterView, getIsParent, getLView, getPreviousOrParentTNode, leaveViewProcessExit, setIsParent, setPreviousOrParentTNode} from '../state'; +import {enterView, getIsParent, getLView, getPreviousOrParentTNode, getTView, leaveView, setIsParent, setPreviousOrParentTNode} from '../state'; import {getLContainerActiveIndex, isCreationMode} from '../util/view_utils'; import {assignTViewNodeToLView, createLView, createTView, refreshView, renderView} from './shared'; @@ -58,7 +58,8 @@ export function ɵɵembeddedViewStart(viewBlockId: number, decls: number, vars: if (lContainer) { if (isCreationMode(viewToRender)) { // it is a new view, insert it into collection of views for a given container - insertView(viewToRender, lContainer, getLContainerActiveIndex(lContainer)); + insertView( + viewToRender[TVIEW], viewToRender, lContainer, getLContainerActiveIndex(lContainer)); } lContainer[ACTIVE_INDEX] += ActiveIndexFlag.INCREMENT; } @@ -128,17 +129,17 @@ function scanForView(lContainer: LContainer, startIdx: number, viewBlockId: numb */ export function ɵɵembeddedViewEnd(): void { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); const viewHost = lView[T_HOST]; const context = lView[CONTEXT]; if (isCreationMode(lView)) { - renderView(lView, tView, context); // creation mode pass + renderView(tView, lView, context); // creation mode pass } - refreshView(lView, tView, tView.template, context); // update mode pass + refreshView(tView, lView, tView.template, context); // update mode pass const lContainer = lView[PARENT] as LContainer; ngDevMode && assertLContainerOrUndefined(lContainer); - leaveViewProcessExit(); + leaveView(); setPreviousOrParentTNode(viewHost !, false); } diff --git a/packages/core/src/render3/instructions/host_property.ts b/packages/core/src/render3/instructions/host_property.ts index 460f45caec..3201c3ab0c 100644 --- a/packages/core/src/render3/instructions/host_property.ts +++ b/packages/core/src/render3/instructions/host_property.ts @@ -7,10 +7,8 @@ */ import {bindingUpdated} from '../bindings'; import {SanitizerFn} from '../interfaces/sanitization'; -import {TVIEW} from '../interfaces/view'; -import {getLView, getSelectedIndex, nextBindingIndex} from '../state'; +import {getLView, getSelectedIndex, getTView, nextBindingIndex} from '../state'; import {NO_CHANGE} from '../tokens'; - import {elementPropertyInternal, loadComponentRenderer, storePropertyBindingMetadata} from './shared'; /** @@ -33,8 +31,9 @@ export function ɵɵhostProperty( const bindingIndex = nextBindingIndex(); if (bindingUpdated(lView, bindingIndex, value)) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, value, sanitizer, true); - ngDevMode && storePropertyBindingMetadata(lView[TVIEW].data, nodeIndex, propName, bindingIndex); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, value, sanitizer, true); + ngDevMode && storePropertyBindingMetadata(tView.data, nodeIndex, propName, bindingIndex); } return ɵɵhostProperty; } @@ -68,9 +67,10 @@ export function ɵɵupdateSyntheticHostBinding( const bindingIndex = nextBindingIndex(); if (bindingUpdated(lView, bindingIndex, value)) { const nodeIndex = getSelectedIndex(); + const tView = getTView(); elementPropertyInternal( - lView, nodeIndex, propName, value, sanitizer, true, loadComponentRenderer); - ngDevMode && storePropertyBindingMetadata(lView[TVIEW].data, nodeIndex, propName, bindingIndex); + tView, lView, nodeIndex, propName, value, sanitizer, true, loadComponentRenderer); + ngDevMode && storePropertyBindingMetadata(tView.data, nodeIndex, propName, bindingIndex); } return ɵɵupdateSyntheticHostBinding; } diff --git a/packages/core/src/render3/instructions/listener.ts b/packages/core/src/render3/instructions/listener.ts index 07faa7eefd..981924a988 100644 --- a/packages/core/src/render3/instructions/listener.ts +++ b/packages/core/src/render3/instructions/listener.ts @@ -13,12 +13,11 @@ import {EMPTY_OBJ} from '../empty'; import {PropertyAliasValue, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; import {GlobalTargetResolver, RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer'; import {isDirectiveHost} from '../interfaces/type_checks'; -import {CLEANUP, FLAGS, LView, LViewFlags, RENDERER, TVIEW} from '../interfaces/view'; +import {CLEANUP, FLAGS, LView, LViewFlags, RENDERER, TView} from '../interfaces/view'; import {assertNodeOfPossibleTypes} from '../node_assert'; -import {getLView, getPreviousOrParentTNode} from '../state'; +import {getLView, getPreviousOrParentTNode, getTView} from '../state'; import {getComponentLViewByIndex, getNativeByTNode, unwrapRNode} from '../util/view_utils'; - -import {getCleanup, handleError, loadComponentRenderer, markViewDirty} from './shared'; +import {getLCleanup, handleError, loadComponentRenderer, markViewDirty} from './shared'; @@ -40,9 +39,10 @@ export function ɵɵlistener( eventName: string, listenerFn: (e?: any) => any, useCapture = false, eventTargetResolver?: GlobalTargetResolver): typeof ɵɵlistener { const lView = getLView(); + const tView = getTView(); const tNode = getPreviousOrParentTNode(); listenerInternal( - lView, lView[RENDERER], tNode, eventName, listenerFn, useCapture, eventTargetResolver); + tView, lView, lView[RENDERER], tNode, eventName, listenerFn, useCapture, eventTargetResolver); return ɵɵlistener; } @@ -70,10 +70,12 @@ export function ɵɵlistener( export function ɵɵcomponentHostSyntheticListener( eventName: string, listenerFn: (e?: any) => any, useCapture = false, eventTargetResolver?: GlobalTargetResolver): typeof ɵɵcomponentHostSyntheticListener { - const lView = getLView(); const tNode = getPreviousOrParentTNode(); + const lView = getLView(); const renderer = loadComponentRenderer(tNode, lView); - listenerInternal(lView, renderer, tNode, eventName, listenerFn, useCapture, eventTargetResolver); + const tView = getTView(); + listenerInternal( + tView, lView, renderer, tNode, eventName, listenerFn, useCapture, eventTargetResolver); return ɵɵcomponentHostSyntheticListener; } @@ -83,8 +85,7 @@ export function ɵɵcomponentHostSyntheticListener( * are registered for a given element. */ function findExistingListener( - lView: LView, eventName: string, tNodeIdx: number): ((e?: any) => any)|null { - const tView = lView[TVIEW]; + tView: TView, lView: LView, eventName: string, tNodeIdx: number): ((e?: any) => any)|null { const tCleanup = tView.cleanup; if (tCleanup != null) { for (let i = 0; i < tCleanup.length - 1; i += 2) { @@ -111,10 +112,9 @@ function findExistingListener( } function listenerInternal( - lView: LView, renderer: Renderer3, tNode: TNode, eventName: string, + tView: TView, lView: LView, renderer: Renderer3, tNode: TNode, eventName: string, listenerFn: (e?: any) => any, useCapture = false, eventTargetResolver?: GlobalTargetResolver): void { - const tView = lView[TVIEW]; const isTNodeDirectiveHost = isDirectiveHost(tNode); const firstCreatePass = tView.firstCreatePass; const tCleanup: false|any[] = firstCreatePass && (tView.cleanup || (tView.cleanup = [])); @@ -122,7 +122,7 @@ function listenerInternal( // When the ɵɵlistener instruction was generated and is executed we know that there is either a // native listener or a directive output on this element. As such we we know that we will have to // register a listener and store its cleanup function on LView. - const lCleanup = getCleanup(lView); + const lCleanup = getLCleanup(lView); ngDevMode && assertNodeOfPossibleTypes( tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); @@ -160,7 +160,7 @@ function listenerInternal( // matching on a given node as we can't register multiple event handlers for the same event in // a template (this would mean having duplicate attributes). if (!eventTargetResolver && isTNodeDirectiveHost) { - existingListener = findExistingListener(lView, eventName, tNode.index); + existingListener = findExistingListener(tView, lView, eventName, tNode.index); } if (existingListener !== null) { // Attach a new listener to coalesced listeners list, maintaining the order in which diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index 6490db105e..a801bbe5e2 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -8,21 +8,20 @@ import {AttributeMarker, ComponentTemplate} from '..'; import {SchemaMetadata} from '../../core'; +import {KeyValueArray} from '../../util/array_utils'; import {assertDefined} from '../../util/assert'; import {createNamedArrayType} from '../../util/named_array_type'; import {initNgDevMode} from '../../util/ng_dev_mode'; import {ACTIVE_INDEX, ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS, NATIVE} from '../interfaces/container'; import {DirectiveDefList, PipeDefList, ViewQueriesFunction} from '../interfaces/definition'; import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, TIcu} from '../interfaces/i18n'; -import {PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TViewNode} from '../interfaces/node'; +import {PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TViewNode} from '../interfaces/node'; import {SelectorFlags} from '../interfaces/projection'; import {TQueries} from '../interfaces/query'; import {RComment, RElement, RNode} from '../interfaces/renderer'; -import {TStylingContext} from '../interfaces/styling'; +import {TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate} from '../interfaces/styling'; import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, HookData, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TData, TVIEW, TView as ITView, TView, TViewType, T_HOST} from '../interfaces/view'; -import {DebugNodeStyling, NodeStylingDebug} from '../styling/styling_debug'; import {attachDebugObject} from '../util/debug_utils'; -import {isStylingContext} from '../util/styling_utils'; import {getLContainerActiveIndex, getTNode, unwrapRNode} from '../util/view_utils'; const NG_DEV_MODE = ((typeof ngDevMode === 'undefined' || !!ngDevMode) && initNgDevMode()); @@ -140,7 +139,7 @@ export const TViewConstructor = class TView implements ITView { public components: number[]|null, // public directiveRegistry: DirectiveDefList|null, // public pipeRegistry: PipeDefList|null, // - public firstChild: TNode|null, // + public firstChild: ITNode|null, // public schemas: SchemaMetadata[]|null, // public consts: TConstants|null, // ) {} @@ -152,31 +151,37 @@ export const TViewConstructor = class TView implements ITView { } }; -export const TNodeConstructor = class TNode implements ITNode { +class TNode implements ITNode { constructor( - public tView_: TView, // - public type: TNodeType, // - public index: number, // - public injectorIndex: number, // - public directiveStart: number, // - public directiveEnd: number, // - public propertyBindings: number[]|null, // - public flags: TNodeFlags, // - public providerIndexes: TNodeProviderIndexes, // - public tagName: string|null, // - public attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null, // - public localNames: (string|number)[]|null, // - public initialInputs: (string[]|null)[]|null|undefined, // - public inputs: PropertyAliases|null, // - public outputs: PropertyAliases|null, // - public tViews: ITView|ITView[]|null, // - public next: ITNode|null, // - public projectionNext: ITNode|null, // - public child: ITNode|null, // - public parent: TElementNode|TContainerNode|null, // - public projection: number|(ITNode|RNode[])[]|null, // - public styles: TStylingContext|null, // - public classes: TStylingContext|null, // + public tView_: TView, // + public type: TNodeType, // + public index: number, // + public injectorIndex: number, // + public directiveStart: number, // + public directiveEnd: number, // + public directiveStylingLast: number, // + public propertyBindings: number[]|null, // + public flags: TNodeFlags, // + public providerIndexes: TNodeProviderIndexes, // + public tagName: string|null, // + public attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null, // + public mergedAttrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null, // + public localNames: (string|number)[]|null, // + public initialInputs: (string[]|null)[]|null|undefined, // + public inputs: PropertyAliases|null, // + public outputs: PropertyAliases|null, // + public tViews: ITView|ITView[]|null, // + public next: ITNode|null, // + public projectionNext: ITNode|null, // + public child: ITNode|null, // + public parent: TElementNode|TContainerNode|null, // + public projection: number|(ITNode|RNode[])[]|null, // + public styles: string|null, // + public residualStyles: KeyValueArray|undefined|null, // + public classes: string|null, // + public residualClasses: KeyValueArray|undefined|null, // + public classBindings: TStylingRange, // + public styleBindings: TStylingRange, // ) {} get type_(): string { @@ -203,7 +208,6 @@ export const TNodeConstructor = class TNode implements ITNode { if (this.flags & TNodeFlags.hasClassInput) flags.push('TNodeFlags.hasClassInput'); if (this.flags & TNodeFlags.hasContentQuery) flags.push('TNodeFlags.hasContentQuery'); if (this.flags & TNodeFlags.hasStyleInput) flags.push('TNodeFlags.hasStyleInput'); - if (this.flags & TNodeFlags.hasInitialStyling) flags.push('TNodeFlags.hasInitialStyling'); if (this.flags & TNodeFlags.hasHostBindings) flags.push('TNodeFlags.hasHostBindings'); if (this.flags & TNodeFlags.isComponentHost) flags.push('TNodeFlags.isComponentHost'); if (this.flags & TNodeFlags.isDirectiveHost) flags.push('TNodeFlags.isDirectiveHost'); @@ -230,9 +234,53 @@ export const TNodeConstructor = class TNode implements ITNode { buf.push(''); return buf.join(''); } -}; -function processTNodeChildren(tNode: TNode | null, buf: string[]) { + get styleBindings_(): DebugStyleBindings { return toDebugStyleBinding(this, false); } + get classBindings_(): DebugStyleBindings { return toDebugStyleBinding(this, true); } +} +export const TNodeDebug = TNode; +export type TNodeDebug = TNode; + +export interface DebugStyleBindings extends + Array|DebugStyleBinding|string|null> {} +export interface DebugStyleBinding { + key: TStylingKey; + index: number; + isTemplate: boolean; + prevDuplicate: boolean; + nextDuplicate: boolean; + prevIndex: number; + nextIndex: number; +} + +function toDebugStyleBinding(tNode: TNode, isClassBased: boolean): DebugStyleBindings { + const tData = tNode.tView_.data; + const bindings: DebugStyleBindings = [] as any; + const range = isClassBased ? tNode.classBindings : tNode.styleBindings; + const prev = getTStylingRangePrev(range); + const next = getTStylingRangeNext(range); + let isTemplate = next !== 0; + let cursor = isTemplate ? next : prev; + while (cursor !== 0) { + const itemKey = tData[cursor] as TStylingKey; + const itemRange = tData[cursor + 1] as TStylingRange; + bindings.unshift({ + key: itemKey, + index: cursor, + isTemplate: isTemplate, + prevDuplicate: getTStylingRangePrevDuplicate(itemRange), + nextDuplicate: getTStylingRangeNextDuplicate(itemRange), + nextIndex: getTStylingRangeNext(itemRange), + prevIndex: getTStylingRangePrev(itemRange), + }); + if (cursor === prev) isTemplate = false; + cursor = getTStylingRangePrev(itemRange); + } + bindings.push((isClassBased ? tNode.residualClasses : tNode.residualStyles) || null); + return bindings; +} + +function processTNodeChildren(tNode: ITNode | null, buf: string[]) { while (tNode) { buf.push((tNode as any as{template_: string}).template_); tNode = tNode.next; @@ -386,8 +434,6 @@ export class LViewDebug { export interface DebugNode { html: string|null; native: Node; - styles: DebugNodeStyling|null; - classes: DebugNodeStyling|null; nodes: DebugNode[]|null; component: LViewDebug|null; } @@ -398,10 +444,10 @@ export interface DebugNode { * @param tNode * @param lView */ -export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|null { +export function toDebugNodes(tNode: ITNode | null, lView: LView): DebugNode[]|null { if (tNode) { const debugNodes: DebugNode[] = []; - let tNodeCursor: TNode|null = tNode; + let tNodeCursor: ITNode|null = tNode; while (tNodeCursor) { debugNodes.push(buildDebugNode(tNodeCursor, lView, tNodeCursor.index)); tNodeCursor = tNodeCursor.next; @@ -412,19 +458,13 @@ export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|nul } } -export function buildDebugNode(tNode: TNode, lView: LView, nodeIndex: number): DebugNode { +export function buildDebugNode(tNode: ITNode, lView: LView, nodeIndex: number): DebugNode { const rawValue = lView[nodeIndex]; const native = unwrapRNode(rawValue); const componentLViewDebug = toDebug(readLViewValue(rawValue)); - const styles = isStylingContext(tNode.styles) ? - new NodeStylingDebug(tNode.styles as any as TStylingContext, tNode, lView, false) : - null; - const classes = isStylingContext(tNode.classes) ? - new NodeStylingDebug(tNode.classes as any as TStylingContext, tNode, lView, true) : - null; return { html: toHtml(native), - native: native as any, styles, classes, + native: native as any, nodes: toDebugNodes(tNode.child, lView), component: componentLViewDebug, }; @@ -467,7 +507,7 @@ export function readLViewValue(value: any): LView|null { export class I18NDebugItem { [key: string]: any; - get tNode() { return getTNode(this.nodeIndex, this._lView); } + get tNode() { return getTNode(this._lView[TVIEW], this.nodeIndex); } constructor( public __raw_opCode: any, private _lView: LView, public nodeIndex: number, diff --git a/packages/core/src/render3/instructions/projection.ts b/packages/core/src/render3/instructions/projection.ts index 730a071a8e..b432a37d64 100644 --- a/packages/core/src/render3/instructions/projection.ts +++ b/packages/core/src/render3/instructions/projection.ts @@ -8,10 +8,10 @@ import {newArray} from '../../util/array_utils'; import {TAttributes, TElementNode, TNode, TNodeType} from '../interfaces/node'; import {ProjectionSlots} from '../interfaces/projection'; -import {DECLARATION_COMPONENT_VIEW, TVIEW, T_HOST} from '../interfaces/view'; +import {DECLARATION_COMPONENT_VIEW, T_HOST} from '../interfaces/view'; import {applyProjection} from '../node_manipulation'; import {getProjectAsAttrValue, isNodeMatchingSelectorList, isSelectorInSelectorList} from '../node_selector_matcher'; -import {getLView, setIsNotParent} from '../state'; +import {getLView, getTView, setIsNotParent} from '../state'; import {getOrCreateTNode} from './shared'; @@ -123,8 +123,9 @@ export function setDelayProjection(value: boolean) { export function ɵɵprojection( nodeIndex: number, selectorIndex: number = 0, attrs?: TAttributes): void { const lView = getLView(); - const tProjectionNode = getOrCreateTNode( - lView[TVIEW], lView[T_HOST], nodeIndex, TNodeType.Projection, null, attrs || null); + const tView = getTView(); + const tProjectionNode = + getOrCreateTNode(tView, lView[T_HOST], nodeIndex, TNodeType.Projection, null, attrs || null); // We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views. if (tProjectionNode.projection === null) tProjectionNode.projection = selectorIndex; @@ -135,6 +136,6 @@ export function ɵɵprojection( // We might need to delay the projection of nodes if they are in the middle of an i18n block if (!delayProjection) { // re-distribution of projectable nodes is stored on a component's view level - applyProjection(lView, tProjectionNode); + applyProjection(tView, lView, tProjectionNode); } } diff --git a/packages/core/src/render3/instructions/property.ts b/packages/core/src/render3/instructions/property.ts index 524fb644fa..dda96ec053 100644 --- a/packages/core/src/render3/instructions/property.ts +++ b/packages/core/src/render3/instructions/property.ts @@ -6,11 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ import {bindingUpdated} from '../bindings'; +import {TNode} from '../interfaces/node'; import {SanitizerFn} from '../interfaces/sanitization'; -import {TVIEW} from '../interfaces/view'; -import {getLView, getSelectedIndex, nextBindingIndex} from '../state'; - -import {elementPropertyInternal, storePropertyBindingMetadata} from './shared'; +import {LView, TView} from '../interfaces/view'; +import {getLView, getSelectedIndex, getTView, nextBindingIndex} from '../state'; +import {elementPropertyInternal, setInputsForProperty, storePropertyBindingMetadata} from './shared'; /** @@ -37,8 +37,22 @@ export function ɵɵproperty( const bindingIndex = nextBindingIndex(); if (bindingUpdated(lView, bindingIndex, value)) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, value, sanitizer); - ngDevMode && storePropertyBindingMetadata(lView[TVIEW].data, nodeIndex, propName, bindingIndex); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, value, sanitizer); + ngDevMode && storePropertyBindingMetadata(tView.data, nodeIndex, propName, bindingIndex); } return ɵɵproperty; } + +/** + * Given `
` and `MyDir` with `@Input('style')` we need to write to + * directive input. + */ +export function setDirectiveInputsWhichShadowsStyling( + tView: TView, tNode: TNode, lView: LView, value: any, isClassBased: boolean) { + const inputs = tNode.inputs !; + const property = isClassBased ? 'class' : 'style'; + // We support both 'class' and `className` hence the fallback. + const stylingInputs = inputs[property] || (isClassBased && inputs['className']); + setInputsForProperty(tView, lView, stylingInputs, property, value); +} diff --git a/packages/core/src/render3/instructions/property_interpolation.ts b/packages/core/src/render3/instructions/property_interpolation.ts index 213d320e44..1ac64eefd7 100644 --- a/packages/core/src/render3/instructions/property_interpolation.ts +++ b/packages/core/src/render3/instructions/property_interpolation.ts @@ -6,15 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ import {SanitizerFn} from '../interfaces/sanitization'; -import {TVIEW} from '../interfaces/view'; -import {getBindingIndex, getLView, getSelectedIndex} from '../state'; +import {getBindingIndex, getLView, getSelectedIndex, getTView} from '../state'; import {NO_CHANGE} from '../tokens'; - import {interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV} from './interpolation'; import {elementPropertyInternal, storePropertyBindingMetadata} from './shared'; - /** * * Update an interpolated property on an element with a lone bound value @@ -86,9 +83,10 @@ export function ɵɵpropertyInterpolate1( const interpolatedValue = interpolation1(lView, prefix, v0, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 1, prefix, suffix); + tView.data, nodeIndex, propName, getBindingIndex() - 1, prefix, suffix); } return ɵɵpropertyInterpolate1; } @@ -130,10 +128,10 @@ export function ɵɵpropertyInterpolate2( const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); - ngDevMode && - storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 2, prefix, i0, suffix); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); + ngDevMode && storePropertyBindingMetadata( + tView.data, nodeIndex, propName, getBindingIndex() - 2, prefix, i0, suffix); } return ɵɵpropertyInterpolate2; } @@ -178,10 +176,11 @@ export function ɵɵpropertyInterpolate3( const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 3, prefix, i0, i1, suffix); + tView.data, nodeIndex, propName, getBindingIndex() - 3, prefix, i0, i1, suffix); } return ɵɵpropertyInterpolate3; } @@ -228,10 +227,11 @@ export function ɵɵpropertyInterpolate4( const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); - ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 4, prefix, i0, i1, - i2, suffix); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); + ngDevMode && + storePropertyBindingMetadata( + tView.data, nodeIndex, propName, getBindingIndex() - 4, prefix, i0, i1, i2, suffix); } return ɵɵpropertyInterpolate4; } @@ -282,10 +282,11 @@ export function ɵɵpropertyInterpolate5( interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); - ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 5, prefix, i0, i1, - i2, i3, suffix); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); + ngDevMode && + storePropertyBindingMetadata( + tView.data, nodeIndex, propName, getBindingIndex() - 5, prefix, i0, i1, i2, i3, suffix); } return ɵɵpropertyInterpolate5; } @@ -338,10 +339,11 @@ export function ɵɵpropertyInterpolate6( interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 6, prefix, i0, i1, - i2, i3, i4, suffix); + tView.data, nodeIndex, propName, getBindingIndex() - 6, prefix, i0, i1, i2, i3, + i4, suffix); } return ɵɵpropertyInterpolate6; } @@ -396,10 +398,11 @@ export function ɵɵpropertyInterpolate7( interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 7, prefix, i0, i1, - i2, i3, i4, i5, suffix); + tView.data, nodeIndex, propName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, + i4, i5, suffix); } return ɵɵpropertyInterpolate7; } @@ -456,10 +459,11 @@ export function ɵɵpropertyInterpolate8( lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); ngDevMode && storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, getBindingIndex() - 8, prefix, i0, i1, - i2, i3, i4, i5, i6, suffix); + tView.data, nodeIndex, propName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, + i4, i5, i6, suffix); } return ɵɵpropertyInterpolate8; } @@ -500,15 +504,16 @@ export function ɵɵpropertyInterpolateV( const interpolatedValue = interpolationV(lView, values); if (interpolatedValue !== NO_CHANGE) { const nodeIndex = getSelectedIndex(); - elementPropertyInternal(lView, nodeIndex, propName, interpolatedValue, sanitizer); + const tView = getTView(); + elementPropertyInternal(tView, lView, nodeIndex, propName, interpolatedValue, sanitizer); if (ngDevMode) { const interpolationInBetween = [values[0]]; // prefix for (let i = 2; i < values.length; i += 2) { interpolationInBetween.push(values[i]); } storePropertyBindingMetadata( - lView[TVIEW].data, nodeIndex, propName, - getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween); + tView.data, nodeIndex, propName, getBindingIndex() - interpolationInBetween.length + 1, + ...interpolationInBetween); } } return ɵɵpropertyInterpolateV; diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index d5d7149930..58509c4517 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -11,7 +11,7 @@ import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../me import {ViewEncapsulation} from '../../metadata/view'; import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization'; import {Sanitizer} from '../../sanitization/sanitizer'; -import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertNotEqual, assertNotSame} from '../../util/assert'; +import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertNotEqual, assertNotSame, assertSame} from '../../util/assert'; import {createNamedArrayType} from '../../util/named_array_type'; import {initNgDevMode} from '../../util/ng_dev_mode'; import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect'; @@ -20,7 +20,7 @@ import {attachPatchData} from '../context_discovery'; import {getFactoryDef} from '../definition'; import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} from '../di'; import {throwMultipleComponentError} from '../errors'; -import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags, registerPreOrderHooks} from '../hooks'; +import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags} from '../hooks'; import {ACTIVE_INDEX, ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS} from '../interfaces/container'; import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from '../interfaces/definition'; import {INJECTOR_BLOOM_PARENT_SIZE, NodeInjectorFactory} from '../interfaces/injector'; @@ -28,20 +28,18 @@ import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, Pro import {RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from '../interfaces/renderer'; import {SanitizerFn} from '../interfaces/sanitization'; import {isComponentDef, isComponentHost, isContentQueryHost, isLContainer, isRootView} from '../interfaces/type_checks'; -import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, INJECTOR, InitPhaseState, LView, LViewFlags, NEXT, PARENT, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TData, TVIEW, TView, TViewType, T_HOST} from '../interfaces/view'; +import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, INJECTOR, InitPhaseState, LView, LViewFlags, NEXT, PARENT, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TData, TVIEW, TView, TViewType, T_HOST} from '../interfaces/view'; import {assertNodeOfPossibleTypes} from '../node_assert'; import {isNodeMatchingSelectorList} from '../node_selector_matcher'; -import {ActiveElementFlags, enterView, executeElementExitFn, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getPreviousOrParentTNode, getSelectedIndex, hasActiveElementFlag, incrementActiveDirectiveId, leaveView, leaveViewProcessExit, setActiveHostElement, setBindingIndex, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setPreviousOrParentTNode, setSelectedIndex} from '../state'; -import {renderStylingMap, writeStylingValueDirectly} from '../styling/bindings'; +import {enterView, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getPreviousOrParentTNode, getSelectedIndex, getTView, leaveView, setBindingIndex, setBindingRootForHostBindings, setCheckNoChangesMode, setCurrentQueryIndex, setPreviousOrParentTNode, setSelectedIndex} from '../state'; import {NO_CHANGE} from '../tokens'; -import {isAnimationProp} from '../util/attrs_utils'; +import {isAnimationProp, mergeHostAttrs} from '../util/attrs_utils'; import {INTERPOLATION_DELIMITER, renderStringify, stringifyForError} from '../util/misc_utils'; -import {getInitialStylingValue} from '../util/styling_utils'; import {getLViewParent} from '../util/view_traversal_utils'; -import {getComponentLViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isCreationMode, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_utils'; +import {getComponentLViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isCreationMode, readPatchedLView, resetPreOrderHookFlags, viewAttachedToChangeDetector} from '../util/view_utils'; import {selectIndexInternal} from './advance'; -import {LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeConstructor, TNodeInitialInputs, TNodeLocalNames, TViewComponents, TViewConstructor, attachLContainerDebug, attachLViewDebug, cloneToLViewFromTViewBlueprint, cloneToTViewData} from './lview_debug'; +import {LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeDebug, TNodeInitialInputs, TNodeLocalNames, TViewComponents, TViewConstructor, attachLContainerDebug, attachLViewDebug, cloneToLViewFromTViewBlueprint, cloneToTViewData} from './lview_debug'; @@ -51,24 +49,40 @@ import {LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeConstructor, TNod */ const _CLEAN_PROMISE = (() => Promise.resolve(null))(); -/** Sets the host bindings for the current view. */ -export function setHostBindings(tView: TView, lView: LView): void { - const selectedIndex = getSelectedIndex(); +/** + * Process the `TView.expandoInstructions`. (Execute the `hostBindings`.) + * + * @param tView `TView` containing the `expandoInstructions` + * @param lView `LView` associated with the `TView` + */ +export function setHostBindingsByExecutingExpandoInstructions(tView: TView, lView: LView): void { + ngDevMode && assertSame(tView, lView[TVIEW], '`LView` is not associated with the `TView`!'); try { const expandoInstructions = tView.expandoInstructions; if (expandoInstructions !== null) { - let bindingRootIndex = setBindingIndex(tView.expandoStartIndex); - setBindingRoot(bindingRootIndex); + let bindingRootIndex = tView.expandoStartIndex; let currentDirectiveIndex = -1; let currentElementIndex = -1; + // TODO(misko): PERF It is possible to get here with `TView.expandoInstructions` containing no + // functions to execute. This is wasteful as there is no work to be done, but we still need + // to iterate over the instructions. + // In example of this is in this test: `host_binding_spec.ts` + // `fit('should not cause problems if detectChanges is called when a property updates', ...` + // In the above test we get here with expando [0, 0, 1] which requires a lot of processing but + // there is no function to execute. for (let i = 0; i < expandoInstructions.length; i++) { const instruction = expandoInstructions[i]; if (typeof instruction === 'number') { if (instruction <= 0) { // Negative numbers mean that we are starting new EXPANDO block and need to update // the current element and directive index. - currentElementIndex = -instruction; - setActiveHostElement(currentElementIndex); + // Important: In JS `-x` and `0-x` is not the same! If `x===0` then `-x` will produce + // `-0` which requires non standard math arithmetic and it can prevent VM optimizations. + // `0-0` will always produce `0` and will not cause a potential deoptimization in VM. + // TODO(misko): PERF This should be refactored to use `~instruction` as that does not + // suffer from `-0` and it is faster/more compact. + currentElementIndex = 0 - instruction; + setSelectedIndex(currentElementIndex); // Injector block and providers are taken into account. const providerCount = (expandoInstructions[++i] as number); @@ -81,29 +95,25 @@ export function setHostBindings(tView: TView, lView: LView): void { // (to get to the next set of host bindings on this node). bindingRootIndex += instruction; } - setBindingRoot(bindingRootIndex); } else { // If it's not a number, it's a host binding function that needs to be executed. if (instruction !== null) { - // Each directive gets a uniqueId value that is the same for both - // create and update calls when the hostBindings function is called. The - // directive uniqueId is not set anywhere--it is just incremented between - // each hostBindings call and is useful for helping instruction code - // uniquely determine which directive is currently active when executed. - // It is important that this be called first before the actual instructions - // are run because this way the first directive ID value is not zero. - incrementActiveDirectiveId(); - - setBindingIndex(bindingRootIndex); - const hostCtx = unwrapRNode(lView[currentDirectiveIndex]); - instruction(RenderFlags.Update, hostCtx, currentElementIndex); + setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex); + const hostCtx = lView[currentDirectiveIndex]; + instruction(RenderFlags.Update, hostCtx); } + // TODO(misko): PERF Relying on incrementing the `currentDirectiveIndex` here is + // sub-optimal. The implications are that if we have a lot of directives but none of them + // have host bindings we nevertheless need to iterate over the expando instructions to + // update the counter. It would be much better if we could encode the + // `currentDirectiveIndex` into the `expandoInstruction` array so that we only need to + // iterate over those directives which actually have `hostBindings`. currentDirectiveIndex++; } } } } finally { - setActiveHostElement(selectedIndex); + setSelectedIndex(-1); } } @@ -279,19 +289,19 @@ export function assignTViewNodeToLView( * i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future * template passes. * - * @param view The LView containing the blueprint to adjust + * @param tView `TView` associated with `LView` + * @param view The `LView` containing the blueprint to adjust * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0 */ -export function allocExpando(view: LView, numSlotsToAlloc: number) { +export function allocExpando(tView: TView, lView: LView, numSlotsToAlloc: number) { ngDevMode && assertGreaterThan( numSlotsToAlloc, 0, 'The number of slots to alloc should be greater than 0'); if (numSlotsToAlloc > 0) { - const tView = view[TVIEW]; if (tView.firstCreatePass) { for (let i = 0; i < numSlotsToAlloc; i++) { tView.blueprint.push(null); tView.data.push(null); - view.push(null); + lView.push(null); } // We should only increment the expando start index if there aren't already directives @@ -319,7 +329,7 @@ export function allocExpando(view: LView, numSlotsToAlloc: number) { * - updating static queries (if any); * - creating child components defined in a given view. */ -export function renderView(lView: LView, tView: TView, context: T): void { +export function renderView(tView: TView, lView: LView, context: T): void { ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode'); enterView(lView, lView[T_HOST]); try { @@ -332,7 +342,7 @@ export function renderView(lView: LView, tView: TView, context: T): void { // defined for the root component views. const templateFn = tView.template; if (templateFn !== null) { - executeTemplate(lView, templateFn, RenderFlags.Create, context); + executeTemplate(tView, lView, templateFn, RenderFlags.Create, context); } // This needs to be set before children are processed to support recursive components. @@ -379,24 +389,24 @@ export function renderView(lView: LView, tView: TView, context: T): void { * - refreshing child (embedded and component) views. */ export function refreshView( - lView: LView, tView: TView, templateFn: ComponentTemplate<{}>| null, context: T) { + tView: TView, lView: LView, templateFn: ComponentTemplate<{}>| null, context: T) { ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode'); const flags = lView[FLAGS]; if ((flags & LViewFlags.Destroyed) === LViewFlags.Destroyed) return; enterView(lView, lView[T_HOST]); + const checkNoChangesMode = getCheckNoChangesMode(); try { resetPreOrderHookFlags(lView); setBindingIndex(tView.bindingStartIndex); if (templateFn !== null) { - executeTemplate(lView, templateFn, RenderFlags.Update, context); + executeTemplate(tView, lView, templateFn, RenderFlags.Update, context); } - const checkNoChangesMode = getCheckNoChangesMode(); const hooksInitPhaseCompleted = (flags & LViewFlags.InitPhaseStateMask) === InitPhaseState.InitPhaseCompleted; - // execute pre-order hooks (OnInit, OnChanges, DoChanges) + // execute pre-order hooks (OnInit, OnChanges, DoCheck) // PERF WARNING: do NOT extract this to a separate function without running benchmarks if (!checkNoChangesMode) { if (hooksInitPhaseCompleted) { @@ -438,7 +448,7 @@ export function refreshView( } } - setHostBindings(tView, lView); + setHostBindingsByExecutingExpandoInstructions(tView, lView); // Refresh child component views. const components = tView.components; @@ -470,30 +480,43 @@ export function refreshView( incrementInitPhaseFlags(lView, InitPhaseState.AfterViewInitHooksToBeRun); } } - - } finally { if (tView.firstUpdatePass === true) { + // We need to make sure that we only flip the flag on successful `refreshView` only + // Don't do this in `finally` block. + // If we did this in `finally` block then an exception could block the execution of styling + // instructions which in turn would be unable to insert themselves into the styling linked + // list. The result of this would be that if the exception would not be throw on subsequent CD + // the styling would be unable to process it data and reflect to the DOM. tView.firstUpdatePass = false; } - lView[FLAGS] &= ~(LViewFlags.Dirty | LViewFlags.FirstLViewPass); - leaveViewProcessExit(); + + // Do not reset the dirty state when running in check no changes mode. We don't want components + // to behave differently depending on whether check no changes is enabled or not. For example: + // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to + // refresh a `NgClass` binding should work. If we would reset the dirty state in the check + // no changes cycle, the component would be not be dirty for the next update pass. This would + // be different in production mode where the component dirty state is not reset. + if (!checkNoChangesMode) { + lView[FLAGS] &= ~(LViewFlags.Dirty | LViewFlags.FirstLViewPass); + } + } finally { + leaveView(); } } export function renderComponentOrTemplate( - hostView: LView, templateFn: ComponentTemplate<{}>| null, context: T) { - const rendererFactory = hostView[RENDERER_FACTORY]; + tView: TView, lView: LView, templateFn: ComponentTemplate<{}>| null, context: T) { + const rendererFactory = lView[RENDERER_FACTORY]; const normalExecutionPath = !getCheckNoChangesMode(); - const creationModeIsActive = isCreationMode(hostView); + const creationModeIsActive = isCreationMode(lView); try { if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) { rendererFactory.begin(); } - const tView = hostView[TVIEW]; if (creationModeIsActive) { - renderView(hostView, tView, context); + renderView(tView, lView, context); } - refreshView(hostView, tView, templateFn, context); + refreshView(tView, lView, templateFn, context); } finally { if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) { rendererFactory.end(); @@ -502,20 +525,17 @@ export function renderComponentOrTemplate( } function executeTemplate( - lView: LView, templateFn: ComponentTemplate, rf: RenderFlags, context: T) { + tView: TView, lView: LView, templateFn: ComponentTemplate, rf: RenderFlags, context: T) { const prevSelectedIndex = getSelectedIndex(); try { - setActiveHostElement(null); + setSelectedIndex(-1); if (rf & RenderFlags.Update && lView.length > HEADER_OFFSET) { // When we're updating, inherently select 0 so we don't // have to generate that instruction for most update blocks. - selectIndexInternal(lView, 0, getCheckNoChangesMode()); + selectIndexInternal(tView, lView, 0, getCheckNoChangesMode()); } templateFn(rf, context); } finally { - if (hasActiveElementFlag(ActiveElementFlags.RunExitFn)) { - executeElementExitFn(); - } setSelectedIndex(prevSelectedIndex); } } @@ -709,10 +729,8 @@ function assertHostNodeExists(rElement: RElement, elementOrSelector: RElement | * @param encapsulation View Encapsulation defined for component that requests host element. */ export function locateHostElement( - rendererFactory: RendererFactory3, elementOrSelector: RElement | string, + renderer: Renderer3, elementOrSelector: RElement | string, encapsulation: ViewEncapsulation): RElement { - const renderer = rendererFactory.createRenderer(null, null); - if (isProceduralRenderer(renderer)) { // When using native Shadow DOM, do not clear host element to allow native slot projection const preserveContent = encapsulation === ViewEncapsulation.ShadowDom; @@ -740,12 +758,13 @@ export function locateHostElement( * - Cleanup function * - Index of context we just saved in LView.cleanupInstances */ -export function storeCleanupWithContext(lView: LView, context: any, cleanupFn: Function): void { - const lCleanup = getCleanup(lView); +export function storeCleanupWithContext( + tView: TView, lView: LView, context: any, cleanupFn: Function): void { + const lCleanup = getLCleanup(lView); lCleanup.push(context); - if (lView[TVIEW].firstCreatePass) { - getTViewCleanup(lView).push(cleanupFn, lCleanup.length - 1); + if (tView.firstCreatePass) { + getTViewCleanup(tView).push(cleanupFn, lCleanup.length - 1); } } @@ -757,11 +776,11 @@ export function storeCleanupWithContext(lView: LView, context: any, cleanupFn: F * * On the first template pass, the index of the cleanup function is saved in TView. */ -export function storeCleanupFn(view: LView, cleanupFn: Function): void { - getCleanup(view).push(cleanupFn); +export function storeCleanupFn(tView: TView, lView: LView, cleanupFn: Function): void { + getLCleanup(lView).push(cleanupFn); - if (view[TVIEW].firstCreatePass) { - getTViewCleanup(view).push(view[CLEANUP] !.length - 1, null); + if (tView.firstCreatePass) { + getTViewCleanup(tView).push(lView[CLEANUP] !.length - 1, null); } } @@ -781,18 +800,20 @@ export function createTNode( adjustedIndex: number, tagName: string | null, attrs: TAttributes | null): TNode { ngDevMode && ngDevMode.tNode++; let injectorIndex = tParent ? tParent.injectorIndex : -1; - return ngDevMode ? new TNodeConstructor( + return ngDevMode ? new TNodeDebug( tView, // tView_: TView type, // type: TNodeType adjustedIndex, // index: number injectorIndex, // injectorIndex: number -1, // directiveStart: number -1, // directiveEnd: number + -1, // directiveStylingLast: number null, // propertyBindings: number[]|null 0, // flags: TNodeFlags 0, // providerIndexes: TNodeProviderIndexes tagName, // tagName: string|null attrs, // attrs: (string|AttributeMarker|(string|SelectorFlags)[])[]|null + null, // mergedAttrs null, // localNames: (string|number)[]|null undefined, // initialInputs: (string[]|null)[]|null|undefined null, // inputs: PropertyAliases|null @@ -803,8 +824,12 @@ export function createTNode( null, // child: ITNode|null tParent, // parent: TElementNode|TContainerNode|null null, // projection: number|(ITNode|RNode[])[]|null - null, // styles: TStylingContext|null - null, // classes: TStylingContext|null + null, // styles: string|null + undefined, // residualStyles: string|null + null, // classes: string|null + undefined, // residualClasses: string|null + 0 as any, // classBindings: TStylingRange; + 0 as any, // styleBindings: TStylingRange; ) : { type: type, @@ -812,11 +837,13 @@ export function createTNode( injectorIndex: injectorIndex, directiveStart: -1, directiveEnd: -1, + directiveStylingLast: -1, propertyBindings: null, flags: 0, providerIndexes: 0, tagName: tagName, attrs: attrs, + mergedAttrs: null, localNames: null, initialInputs: undefined, inputs: null, @@ -828,7 +855,11 @@ export function createTNode( parent: tParent, projection: null, styles: null, + residualStyles: undefined, classes: null, + residualClasses: undefined, + classBindings: 0 as any, + styleBindings: 0 as any, }; } @@ -910,16 +941,16 @@ function mapPropName(name: string): string { } export function elementPropertyInternal( - lView: LView, index: number, propName: string, value: T, sanitizer?: SanitizerFn | null, - nativeOnly?: boolean, + tView: TView, lView: LView, index: number, propName: string, value: T, + sanitizer?: SanitizerFn | null, nativeOnly?: boolean, loadRendererFn?: ((tNode: TNode, lView: LView) => Renderer3) | null): void { ngDevMode && assertNotSame(value, NO_CHANGE as any, 'Incoming value should never be NO_CHANGE.'); const element = getNativeByIndex(index, lView) as RElement | RComment; - const tNode = getTNode(index, lView); + const tNode = getTNode(tView, index); let inputData = tNode.inputs; let dataValue: PropertyAliasValue|undefined; if (!nativeOnly && inputData != null && (dataValue = inputData[propName])) { - setInputsForProperty(lView, dataValue, propName, value); + setInputsForProperty(tView, lView, dataValue, propName, value); if (isComponentHost(tNode)) markDirtyIfOnPush(lView, index + HEADER_OFFSET); if (ngDevMode) { setNgReflectProperties(lView, element, tNode.type, dataValue, value); @@ -929,7 +960,7 @@ export function elementPropertyInternal( if (ngDevMode) { validateAgainstEventProperties(propName); - if (!validateProperty(lView, element, propName, tNode)) { + if (!validateProperty(tView, lView, element, propName, tNode)) { // Return here since we only log warnings for unknown properties. warnAboutUnknownProperty(propName, tNode); return; @@ -950,7 +981,7 @@ export function elementPropertyInternal( } else if (tNode.type === TNodeType.Container) { // If the node is a container and the property didn't // match any of the inputs or schemas we should throw. - if (ngDevMode && !matchingSchemas(lView, tNode.tagName)) { + if (ngDevMode && !matchingSchemas(tView, lView, tNode.tagName)) { warnAboutUnknownProperty(propName, tNode); } } @@ -1008,10 +1039,11 @@ export function setNgReflectProperties( } function validateProperty( - hostView: LView, element: RElement | RComment, propName: string, tNode: TNode): boolean { + tView: TView, lView: LView, element: RElement | RComment, propName: string, + tNode: TNode): boolean { // The property is considered valid if the element matches the schema, it exists on the element // or it is synthetic, and we are in a browser context (web worker nodes should be skipped). - if (matchingSchemas(hostView, tNode.tagName) || propName in element || + if (matchingSchemas(tView, lView, tNode.tagName) || propName in element || isAnimationProp(propName)) { return true; } @@ -1021,8 +1053,8 @@ function validateProperty( return typeof Node === 'undefined' || Node === null || !(element instanceof Node); } -export function matchingSchemas(hostView: LView, tagName: string | null): boolean { - const schemas = hostView[TVIEW].schemas; +export function matchingSchemas(tView: TView, lView: LView, tagName: string | null): boolean { + const schemas = tView.schemas; if (schemas !== null) { for (let i = 0; i < schemas.length; i++) { @@ -1076,61 +1108,118 @@ export function resolveDirectives( // tsickle. ngDevMode && assertFirstCreatePass(tView); - if (!getBindingsEnabled()) return false; - - const directives: DirectiveDef[]|null = findDirectiveMatches(tView, lView, tNode); - const exportsMap: ({[key: string]: number} | null) = localRefs === null ? null : {'': -1}; let hasDirectives = false; + if (getBindingsEnabled()) { + const directiveDefs: DirectiveDef[]|null = findDirectiveDefMatches(tView, lView, tNode); + const exportsMap: ({[key: string]: number} | null) = localRefs === null ? null : {'': -1}; - if (directives !== null) { - hasDirectives = true; - initNodeFlags(tNode, tView.data.length, directives.length); - // When the same token is provided by several directives on the same node, some rules apply in - // the viewEngine: - // - viewProviders have priority over providers - // - the last directive in NgModule.declarations has priority over the previous one - // So to match these rules, the order in which providers are added in the arrays is very - // important. - for (let i = 0; i < directives.length; i++) { - const def = directives[i] as DirectiveDef; - if (def.providersResolver) def.providersResolver(def); - } - generateExpandoInstructionBlock(tView, tNode, directives.length); - let preOrderHooksFound = false; - let preOrderCheckHooksFound = false; - for (let i = 0; i < directives.length; i++) { - const def = directives[i] as DirectiveDef; + if (directiveDefs !== null) { + let totalDirectiveHostVars = 0; + hasDirectives = true; + initTNodeFlags(tNode, tView.data.length, directiveDefs.length); + // When the same token is provided by several directives on the same node, some rules apply in + // the viewEngine: + // - viewProviders have priority over providers + // - the last directive in NgModule.declarations has priority over the previous one + // So to match these rules, the order in which providers are added in the arrays is very + // important. + for (let i = 0; i < directiveDefs.length; i++) { + const def = directiveDefs[i]; + if (def.providersResolver) def.providersResolver(def); + } + generateExpandoInstructionBlock(tView, tNode, directiveDefs.length); + let preOrderHooksFound = false; + let preOrderCheckHooksFound = false; + for (let i = 0; i < directiveDefs.length; i++) { + const def = directiveDefs[i]; + // Merge the attrs in the order of matches. This assumes that the first directive is the + // component itself, so that the component has the least priority. + tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, def.hostAttrs); - baseResolveDirective(tView, lView, def); + baseResolveDirective(tView, lView, def); - saveNameToExportMap(tView.data !.length - 1, def, exportsMap); + saveNameToExportMap(tView.data !.length - 1, def, exportsMap); - if (def.contentQueries !== null) tNode.flags |= TNodeFlags.hasContentQuery; - if (def.hostBindings !== null) tNode.flags |= TNodeFlags.hasHostBindings; + if (def.contentQueries !== null) tNode.flags |= TNodeFlags.hasContentQuery; + if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0) + tNode.flags |= TNodeFlags.hasHostBindings; - // Only push a node index into the preOrderHooks array if this is the first - // pre-order hook found on this node. - if (!preOrderHooksFound && (def.onChanges || def.onInit || def.doCheck)) { - // We will push the actual hook function into this array later during dir instantiation. - // We cannot do it now because we must ensure hooks are registered in the same - // order that directives are created (i.e. injection order). - (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index - HEADER_OFFSET); - preOrderHooksFound = true; + // Only push a node index into the preOrderHooks array if this is the first + // pre-order hook found on this node. + if (!preOrderHooksFound && (def.onChanges || def.onInit || def.doCheck)) { + // We will push the actual hook function into this array later during dir instantiation. + // We cannot do it now because we must ensure hooks are registered in the same + // order that directives are created (i.e. injection order). + (tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index - HEADER_OFFSET); + preOrderHooksFound = true; + } + + if (!preOrderCheckHooksFound && (def.onChanges || def.doCheck)) { + (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [ + ])).push(tNode.index - HEADER_OFFSET); + preOrderCheckHooksFound = true; + } + + addHostBindingsToExpandoInstructions(tView, def); + totalDirectiveHostVars += def.hostVars; } - if (!preOrderCheckHooksFound && (def.onChanges || def.doCheck)) { - (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [ - ])).push(tNode.index - HEADER_OFFSET); - preOrderCheckHooksFound = true; - } + initializeInputAndOutputAliases(tView, tNode); + growHostVarsSpace(tView, lView, totalDirectiveHostVars); } - - initializeInputAndOutputAliases(tView, tNode); + if (exportsMap) cacheMatchingLocalNames(tNode, localRefs, exportsMap); } - if (exportsMap) cacheMatchingLocalNames(tNode, localRefs, exportsMap); + // Merge the template attrs last so that they have the highest priority. + tNode.mergedAttrs = mergeHostAttrs(tNode.mergedAttrs, tNode.attrs); return hasDirectives; } +/** + * Add `hostBindings` to the `TView.expandoInstructions`. + * + * @param tView `TView` to which the `hostBindings` should be added. + * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add. + */ +export function addHostBindingsToExpandoInstructions( + tView: TView, def: ComponentDef| DirectiveDef): void { + ngDevMode && assertFirstCreatePass(tView); + const expando = tView.expandoInstructions !; + // TODO(misko): PERF we are adding `hostBindings` even if there is nothing to add! This is + // suboptimal for performance. `def.hostBindings` may be null, + // but we still need to push null to the array as a placeholder + // to ensure the directive counter is incremented (so host + // binding functions always line up with the corrective directive). + // This is suboptimal for performance. See `currentDirectiveIndex` + // comment in `setHostBindingsByExecutingExpandoInstructions` for more + // details. expando.push(def.hostBindings); + expando.push(def.hostBindings); + const hostVars = def.hostVars; + if (hostVars !== 0) { + expando.push(def.hostVars); + } +} + +/** + * Grow the `LView`, blueprint and `TView.data` to accommodate the `hostBindings`. + * + * To support locality we don't know ahead of time how many `hostVars` of the containing directives + * we need to allocate. For this reason we allow growing these data structures as we discover more + * directives to accommodate them. + * + * @param tView `TView` which needs to be grown. + * @param lView `LView` which needs to be grown. + * @param count Size by which we need to grow the data structures. + */ +export function growHostVarsSpace(tView: TView, lView: LView, count: number) { + ngDevMode && assertFirstCreatePass(tView); + ngDevMode && assertSame(tView, lView[TVIEW], '`LView` must be associated with `TView`!'); + for (let i = 0; i < count; i++) { + lView.push(NO_CHANGE); + tView.blueprint.push(NO_CHANGE); + tView.data.push(null); + } +} + /** * Instantiate all the directives that were previously resolved on the current node. */ @@ -1168,55 +1257,46 @@ function instantiateAllDirectives( } } -function invokeDirectivesHostBindings(tView: TView, viewData: LView, tNode: TNode) { +function invokeDirectivesHostBindings(tView: TView, lView: LView, tNode: TNode) { const start = tNode.directiveStart; const end = tNode.directiveEnd; const expando = tView.expandoInstructions !; const firstCreatePass = tView.firstCreatePass; const elementIndex = tNode.index - HEADER_OFFSET; try { - setActiveHostElement(elementIndex); - + setSelectedIndex(elementIndex); for (let i = start; i < end; i++) { const def = tView.data[i] as DirectiveDef; - const directive = viewData[i]; - if (def.hostBindings) { - // It is important that this be called first before the actual instructions - // are run because this way the first directive ID value is not zero. - incrementActiveDirectiveId(); - invokeHostBindingsInCreationMode(def, expando, directive, tNode, firstCreatePass); + const directive = lView[i]; + if (def.hostBindings !== null || def.hostVars !== 0 || def.hostAttrs !== null) { + invokeHostBindingsInCreationMode(def, directive); } else if (firstCreatePass) { expando.push(null); } } } finally { - setActiveHostElement(null); - } -} - -export function invokeHostBindingsInCreationMode( - def: DirectiveDef, expando: ExpandoInstructions, directive: any, tNode: TNode, - firstCreatePass: boolean) { - const previousExpandoLength = expando.length; - setCurrentDirectiveDef(def); - const elementIndex = tNode.index - HEADER_OFFSET; - def.hostBindings !(RenderFlags.Create, directive, elementIndex); - 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 && firstCreatePass) { - expando.push(def.hostBindings); + setSelectedIndex(-1); } } /** -* Generates a new block in TView.expandoInstructions for this node. -* -* Each expando block starts with the element index (turned negative so we can distinguish -* it from the hostVar count) and the directive count. See more in VIEW_DATA.md. -*/ + * Invoke the host bindings in creation mode. + * + * @param def `DirectiveDef` which may contain the `hostBindings` function. + * @param directive Instance of directive. + */ +export function invokeHostBindingsInCreationMode(def: DirectiveDef, directive: any) { + if (def.hostBindings !== null) { + def.hostBindings !(RenderFlags.Create, directive); + } +} + +/** + * Generates a new block in TView.expandoInstructions for this node. + * + * Each expando block starts with the element index (turned negative so we can distinguish + * it from the hostVar count) and the directive count. See more in VIEW_DATA.md. + */ export function generateExpandoInstructionBlock( tView: TView, tNode: TNode, directiveCount: number): void { ngDevMode && assertEqual( @@ -1237,7 +1317,7 @@ export function generateExpandoInstructionBlock( * Matches the current node against all available selectors. * If a component is matched (at most one), it is returned in first position in the array. */ -function findDirectiveMatches( +function findDirectiveDefMatches( tView: TView, viewData: LView, tNode: TElementNode | TContainerNode | TElementContainerNode): DirectiveDef[]|null { ngDevMode && assertFirstCreatePass(tView); @@ -1319,7 +1399,7 @@ function saveNameToExportMap( * the directive count to 0, and adding the isComponent flag. * @param index the initial index */ -export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: number) { +export function initTNodeFlags(tNode: TNode, index: number, numberOfDirectives: number) { ngDevMode && assertNotEqual( numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, 'Reached the max number of directives'); @@ -1332,7 +1412,8 @@ export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: n function baseResolveDirective(tView: TView, viewData: LView, def: DirectiveDef) { tView.data.push(def); - const directiveFactory = def.factory || (def.factory = getFactoryDef(def.type, true)); + const directiveFactory = + def.factory || ((def as{factory: Function}).factory = getFactoryDef(def.type, true)); const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null); tView.blueprint.push(nodeInjectorFactory); viewData.push(nodeInjectorFactory); @@ -1357,8 +1438,8 @@ function addComponentLogic(lView: LView, hostTNode: TElementNode, def: Compon } export function elementAttributeInternal( - index: number, name: string, value: any, lView: LView, sanitizer?: SanitizerFn | null, - namespace?: string) { + index: number, name: string, value: any, tView: TView, lView: LView, + sanitizer?: SanitizerFn | null, namespace?: string) { ngDevMode && assertNotSame(value, NO_CHANGE as any, 'Incoming value should never be NO_CHANGE.'); ngDevMode && validateAgainstEventAttributes(name); const element = getNativeByIndex(index, lView) as RElement; @@ -1369,7 +1450,7 @@ export function elementAttributeInternal( element.removeAttribute(name); } else { ngDevMode && ngDevMode.rendererSetAttribute++; - const tNode = getTNode(index, lView); + const tNode = getTNode(tView, index); const strValue = sanitizer == null ? renderStringify(value) : sanitizer(value, tNode.tagName || '', name); @@ -1512,10 +1593,13 @@ function refreshDynamicEmbeddedViews(lView: LView) { (activeIndexFlag = viewOrContainer[ACTIVE_INDEX]) >> ActiveIndexFlag.SHIFT === ActiveIndexFlag.DYNAMIC_EMBEDDED_VIEWS_ONLY) { for (let i = CONTAINER_HEADER_OFFSET; i < viewOrContainer.length; i++) { - const embeddedLView = viewOrContainer[i]; + const embeddedLView = viewOrContainer[i] as LView; const embeddedTView = embeddedLView[TVIEW]; ngDevMode && assertDefined(embeddedTView, 'TView must be allocated'); - refreshView(embeddedLView, embeddedTView, embeddedTView.template, embeddedLView[CONTEXT] !); + if (viewAttachedToChangeDetector(embeddedLView)) { + refreshView( + embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT] !); + } } if ((activeIndexFlag & ActiveIndexFlag.HAS_TRANSPLANTED_VIEWS) !== 0) { // We should only CD moved views if the component where they were inserted does not match @@ -1563,7 +1647,7 @@ function refreshTransplantedViews(lContainer: LContainer, declaredComponentLView // point. const movedTView = movedLView[TVIEW]; ngDevMode && assertDefined(movedTView, 'TView must be allocated'); - refreshView(movedLView, movedTView, movedTView.template, movedLView[CONTEXT] !); + refreshView(movedTView, movedLView, movedTView.template, movedLView[CONTEXT] !); } } } @@ -1582,16 +1666,17 @@ function refreshComponent(hostLView: LView, componentHostIdx: number): void { // Only attached components that are CheckAlways or OnPush and dirty should be refreshed if (viewAttachedToChangeDetector(componentView) && componentView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) { - const tView = componentView[TVIEW]; - refreshView(componentView, tView, tView.template, componentView[CONTEXT]); + const componentTView = componentView[TVIEW]; + refreshView(componentTView, componentView, componentTView.template, componentView[CONTEXT]); } } function renderComponent(hostLView: LView, componentHostIdx: number) { ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode'); const componentView = getComponentLViewByIndex(componentHostIdx, hostLView); - syncViewWithBlueprint(componentView); - renderView(componentView, componentView[TVIEW], componentView[CONTEXT]); + const componentTView = componentView[TVIEW]; + syncViewWithBlueprint(componentTView, componentView); + renderView(componentTView, componentView, componentView[CONTEXT]); } /** @@ -1618,12 +1703,12 @@ function renderComponent(hostLView: LView, componentHostIdx: number) { * Note that embedded views inside ngFor loops will never be out of sync because these views * are processed as soon as they are created. * - * @param componentView The view to sync + * @param tView The `TView` that contains the blueprint for syncing + * @param lView The view to sync */ -function syncViewWithBlueprint(componentView: LView) { - const componentTView = componentView[TVIEW]; - for (let i = componentView.length; i < componentTView.blueprint.length; i++) { - componentView.push(componentTView.blueprint[i]); +function syncViewWithBlueprint(tView: TView, lView: LView) { + for (let i = lView.length; i < tView.blueprint.length; i++) { + lView.push(tView.blueprint[i]); } } @@ -1640,12 +1725,9 @@ function syncViewWithBlueprint(componentView: LView) { */ export function addToViewTree(lView: LView, lViewOrLContainer: T): T { // TODO(benlesh/misko): This implementation is incorrect, because it always adds the LContainer - // to - // the end of the queue, which means if the developer retrieves the LContainers from RNodes out - // of - // order, the change detection will run out of order, as the act of retrieving the the - // LContainer - // from the RNode is what adds it to the queue. + // to the end of the queue, which means if the developer retrieves the LContainers from RNodes out + // of order, the change detection will run out of order, as the act of retrieving the the + // LContainer from the RNode is what adds it to the queue. if (lView[CHILD_HEAD]) { lView[CHILD_TAIL] ![NEXT] = lViewOrLContainer; } else { @@ -1729,18 +1811,17 @@ export function tickRootContext(rootContext: RootContext) { const rootComponent = rootContext.components[i]; const lView = readPatchedLView(rootComponent) !; const tView = lView[TVIEW]; - renderComponentOrTemplate(lView, tView.template, rootComponent); + renderComponentOrTemplate(tView, lView, tView.template, rootComponent); } } -export function detectChangesInternal(view: LView, context: T) { - const rendererFactory = view[RENDERER_FACTORY]; +export function detectChangesInternal(tView: TView, lView: LView, context: T) { + const rendererFactory = lView[RENDERER_FACTORY]; if (rendererFactory.begin) rendererFactory.begin(); try { - const tView = view[TVIEW]; - refreshView(view, tView, tView.template, context); + refreshView(tView, lView, tView.template, context); } catch (error) { - handleError(view, error); + handleError(lView, error); throw error; } finally { if (rendererFactory.end) rendererFactory.end(); @@ -1756,10 +1837,10 @@ export function detectChangesInRootView(lView: LView): void { tickRootContext(lView[CONTEXT] as RootContext); } -export function checkNoChangesInternal(view: LView, context: T) { +export function checkNoChangesInternal(tView: TView, view: LView, context: T) { setCheckNoChangesMode(true); try { - detectChangesInternal(view, context); + detectChangesInternal(tView, view, context); } finally { setCheckNoChangesMode(false); } @@ -1839,13 +1920,13 @@ export function storePropertyBindingMetadata( export const CLEAN_PROMISE = _CLEAN_PROMISE; -export function getCleanup(view: LView): any[] { +export function getLCleanup(view: LView): any[] { // top level variables should not be exported for performance reasons (PERF_NOTES.md) return view[CLEANUP] || (view[CLEANUP] = ngDevMode ? new LCleanup() : []); } -function getTViewCleanup(view: LView): any[] { - return view[TVIEW].cleanup || (view[TVIEW].cleanup = ngDevMode ? new TCleanup() : []); +function getTViewCleanup(tView: TView): any[] { + return tView.cleanup || (tView.cleanup = ngDevMode ? new TCleanup() : []); } /** @@ -1867,14 +1948,14 @@ export function handleError(lView: LView, error: any): void { /** * Set the inputs of directives at the current node to corresponding value. * + * @param tView The current TView * @param lView the `LView` which contains the directives. * @param inputs mapping between the public "input" name and privately-known, - * possibly minified, property names to write to. + * possibly minified, property names to write to. * @param value Value to set. */ export function setInputsForProperty( - lView: LView, inputs: PropertyAliasValue, publicName: string, value: any): void { - const tView = lView[TVIEW]; + tView: TView, lView: LView, inputs: PropertyAliasValue, publicName: string, value: any): void { for (let i = 0; i < inputs.length;) { const index = inputs[i++] as number; const privateName = inputs[i++] as string; @@ -1901,32 +1982,3 @@ export function textBindingInternal(lView: LView, index: number, value: string): const renderer = lView[RENDERER]; isProceduralRenderer(renderer) ? renderer.setValue(element, value) : element.textContent = value; } - -/** - * Renders all initial styling (class and style values) on to the element from the tNode. - * - * All initial styling data (i.e. any values extracted from the `style` or `class` attributes - * on an element) are collected into the `tNode.styles` and `tNode.classes` data structures. - * These values are populated during the creation phase of an element and are then later - * applied once the element is instantiated. This function applies each of the static - * style and class entries to the element. - */ -export function renderInitialStyling( - renderer: Renderer3, native: RElement, tNode: TNode, append: boolean) { - if (tNode.classes !== null) { - if (append) { - renderStylingMap(renderer, native, tNode.classes, true); - } else { - const classes = getInitialStylingValue(tNode.classes); - writeStylingValueDirectly(renderer, native, classes, true, null); - } - } - if (tNode.styles !== null) { - if (append) { - renderStylingMap(renderer, native, tNode.styles, false); - } else { - const styles = getInitialStylingValue(tNode.styles); - writeStylingValueDirectly(renderer, native, styles, false, null); - } - } -} diff --git a/packages/core/src/render3/instructions/storage.ts b/packages/core/src/render3/instructions/storage.ts index 3af4c123f8..c373e912cc 100644 --- a/packages/core/src/render3/instructions/storage.ts +++ b/packages/core/src/render3/instructions/storage.ts @@ -5,14 +5,13 @@ * 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 {HEADER_OFFSET, TVIEW} from '../interfaces/view'; -import {getContextLView, getLView} from '../state'; +import {HEADER_OFFSET, LView, TView} from '../interfaces/view'; +import {getContextLView} from '../state'; import {load} from '../util/view_utils'; + /** Store a value in the `data` at a given `index`. */ -export function store(index: number, value: T): void { - const lView = getLView(); - const tView = lView[TVIEW]; +export function store(tView: TView, lView: LView, index: number, value: T): void { // We don't store any static data for local variables, so the first time // we see the template, we should store as null to avoid a sparse array const adjustedIndex = index + HEADER_OFFSET; diff --git a/packages/core/src/render3/instructions/style_prop_interpolation.ts b/packages/core/src/render3/instructions/style_prop_interpolation.ts index 0bdadb76e1..a5d3ca7580 100644 --- a/packages/core/src/render3/instructions/style_prop_interpolation.ts +++ b/packages/core/src/render3/instructions/style_prop_interpolation.ts @@ -5,11 +5,10 @@ * 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 {getLView, getSelectedIndex} from '../state'; +import {getLView,} from '../state'; import {interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV} from './interpolation'; -import {stylePropInternal} from './styling'; - +import {checkStylingProperty} from './styling'; /** @@ -43,7 +42,7 @@ export function ɵɵstylePropInterpolate1( valueSuffix?: string | null): typeof ɵɵstylePropInterpolate1 { const lView = getLView(); const interpolatedValue = interpolation1(lView, prefix, v0, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate1; } @@ -80,7 +79,7 @@ export function ɵɵstylePropInterpolate2( valueSuffix?: string | null): typeof ɵɵstylePropInterpolate2 { const lView = getLView(); const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate2; } @@ -119,7 +118,7 @@ export function ɵɵstylePropInterpolate3( valueSuffix?: string | null): typeof ɵɵstylePropInterpolate3 { const lView = getLView(); const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate3; } @@ -160,7 +159,7 @@ export function ɵɵstylePropInterpolate4( v3: any, suffix: string, valueSuffix?: string | null): typeof ɵɵstylePropInterpolate4 { const lView = getLView(); const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate4; } @@ -205,7 +204,7 @@ export function ɵɵstylePropInterpolate5( const lView = getLView(); const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate5; } @@ -252,7 +251,7 @@ export function ɵɵstylePropInterpolate6( const lView = getLView(); const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate6; } @@ -302,7 +301,7 @@ export function ɵɵstylePropInterpolate7( const lView = getLView(); const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate7; } @@ -354,7 +353,7 @@ export function ɵɵstylePropInterpolate8( const lView = getLView(); const interpolatedValue = interpolation8( lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolate8; } @@ -392,6 +391,6 @@ export function ɵɵstylePropInterpolateV( prop: string, values: any[], valueSuffix?: string | null): typeof ɵɵstylePropInterpolateV { const lView = getLView(); const interpolatedValue = interpolationV(lView, values); - stylePropInternal(getSelectedIndex(), prop, interpolatedValue as string, valueSuffix); + checkStylingProperty(prop, interpolatedValue, valueSuffix, false); return ɵɵstylePropInterpolateV; } diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts index 68c108bdcf..0fe940e6ca 100644 --- a/packages/core/src/render3/instructions/styling.ts +++ b/packages/core/src/render3/instructions/styling.ts @@ -5,36 +5,31 @@ * 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 {SafeValue} from '../../sanitization/bypass'; + +import {SafeValue, unwrapSafeValue} from '../../sanitization/bypass'; +import {stylePropNeedsSanitization, ɵɵsanitizeStyle} from '../../sanitization/sanitization'; import {StyleSanitizeFn} from '../../sanitization/style_sanitizer'; -import {throwErrorIfNoChangesMode} from '../errors'; -import {setInputsForProperty} from '../instructions/shared'; +import {KeyValueArray, keyValueArrayGet, keyValueArraySet} from '../../util/array_utils'; +import {assertDefined, assertEqual, assertLessThan, assertNotEqual, throwError} from '../../util/assert'; +import {EMPTY_ARRAY} from '../../util/empty'; +import {concatStringsWithSpace, stringify} from '../../util/stringify'; +import {assertFirstUpdatePass} from '../assert'; +import {bindingUpdated} from '../bindings'; +import {DirectiveDef} from '../interfaces/definition'; import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; -import {RElement} from '../interfaces/renderer'; -import {StylingMapArray, StylingMapArrayIndex, TStylingContext} from '../interfaces/styling'; -import {isDirectiveHost} from '../interfaces/type_checks'; -import {LView, RENDERER, TVIEW} from '../interfaces/view'; -import {getActiveDirectiveId, getCheckNoChangesMode, getCurrentStyleSanitizer, getLView, getSelectedIndex, incrementBindingIndex, nextBindingIndex, resetCurrentStyleSanitizer, setCurrentStyleSanitizer, setElementExitFn} from '../state'; -import {applyStylingMapDirectly, applyStylingValueDirectly, flushStyling, setClass, setStyle, updateClassViaContext, updateStyleViaContext} from '../styling/bindings'; -import {activateStylingMapFeature} from '../styling/map_based_bindings'; -import {attachStylingDebugObject} from '../styling/styling_debug'; +import {RElement, Renderer3} from '../interfaces/renderer'; +import {SanitizerFn} from '../interfaces/sanitization'; +import {TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate} from '../interfaces/styling'; +import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view'; +import {applyStyling} from '../node_manipulation'; +import {getCurrentDirectiveIndex, getCurrentStyleSanitizer, getLView, getSelectedIndex, getTView, incrementBindingIndex, setCurrentStyleSanitizer} from '../state'; +import {insertTStylingBinding} from '../styling/style_binding_list'; +import {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser'; import {NO_CHANGE} from '../tokens'; -import {renderStringify} from '../util/misc_utils'; -import {addItemToStylingMap, allocStylingMapArray, allocTStylingContext, allowDirectStyling, concatString, forceClassesAsString, forceStylesAsString, getInitialStylingValue, getStylingMapArray, getValue, hasClassInput, hasStyleInput, hasValueChanged, hasValueChangedUnwrapSafeValue, isHostStylingActive, isStylingContext, isStylingMapArray, isStylingValueDefined, normalizeIntoStylingMap, patchConfig, selectClassBasedInputName, setValue, stylingMapToString} from '../util/styling_utils'; -import {getNativeByTNode, getTNode} from '../util/view_utils'; +import {getNativeByIndex} from '../util/view_utils'; +import {setDirectiveInputsWhichShadowsStyling} from './property'; - -/** - * -------- - * - * This file contains the core logic for how styling instructions are processed in Angular. - * - * To learn more about the algorithm see `TStylingContext`. - * - * -------- - */ - /** * Sets the current style sanitizer function which will then be used * within all follow-up prop and map-based style binding instructions @@ -77,49 +72,12 @@ export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): void { * @codeGenApi */ export function ɵɵstyleProp( - prop: string, value: string | number | SafeValue | null, + prop: string, value: string | number | SafeValue | undefined | null, suffix?: string | null): typeof ɵɵstyleProp { - stylePropInternal(getSelectedIndex(), prop, value, suffix); + checkStylingProperty(prop, value, suffix, false); return ɵɵstyleProp; } -/** - * Internal function for applying a single style to an element. - * - * The reason why this function has been separated from `ɵɵstyleProp` is because - * it is also called from `ɵɵstylePropInterpolate`. - */ -export function stylePropInternal( - elementIndex: number, prop: string, value: string | number | SafeValue | null, - suffix?: string | null | undefined): void { - // if a value is interpolated then it may render a `NO_CHANGE` value. - // in this case we do not need to do anything, but the binding index - // still needs to be incremented because all styling binding values - // are stored inside of the lView. - const bindingIndex = nextBindingIndex(); - const lView = getLView(); - const tNode = getTNode(elementIndex, lView); - const firstUpdatePass = lView[TVIEW].firstUpdatePass; - - // we check for this in the instruction code so that the context can be notified - // about prop or map bindings so that the direct apply check can decide earlier - // if it allows for context resolution to be bypassed. - if (firstUpdatePass) { - patchConfig(tNode, TNodeFlags.hasStylePropBindings); - patchHostStylingFlag(tNode, isHostStyling(), false); - } - - const updated = stylingProp( - tNode, firstUpdatePass, lView, bindingIndex, prop, resolveStylePropValue(value, suffix), - false); - if (ngDevMode) { - ngDevMode.styleProp++; - if (updated) { - ngDevMode.stylePropCacheMiss++; - } - } -} - /** * Update a class binding on an element with the provided value. * @@ -135,102 +93,12 @@ export function stylePropInternal( * * @codeGenApi */ -export function ɵɵclassProp(className: string, value: boolean | null): typeof ɵɵclassProp { - // if a value is interpolated then it may render a `NO_CHANGE` value. - // in this case we do not need to do anything, but the binding index - // still needs to be incremented because all styling binding values - // are stored inside of the lView. - const bindingIndex = nextBindingIndex(); - const lView = getLView(); - const elementIndex = getSelectedIndex(); - const tNode = getTNode(elementIndex, lView); - const firstUpdatePass = lView[TVIEW].firstUpdatePass; - - // we check for this in the instruction code so that the context can be notified - // about prop or map bindings so that the direct apply check can decide earlier - // if it allows for context resolution to be bypassed. - if (firstUpdatePass) { - patchConfig(tNode, TNodeFlags.hasClassPropBindings); - patchHostStylingFlag(tNode, isHostStyling(), true); - } - - const updated = stylingProp(tNode, firstUpdatePass, lView, bindingIndex, className, value, true); - if (ngDevMode) { - ngDevMode.classProp++; - if (updated) { - ngDevMode.classPropCacheMiss++; - } - } +export function ɵɵclassProp( + className: string, value: boolean | undefined | null): typeof ɵɵclassProp { + checkStylingProperty(className, value, null, true); return ɵɵclassProp; } -/** - * Shared function used to update a prop-based styling binding for an element. - * - * Depending on the state of the `tNode.styles` styles context, the style/prop - * value may be applied directly to the element instead of being processed - * through the context. The reason why this occurs is for performance and fully - * depends on the state of the context (i.e. whether or not there are duplicate - * bindings or whether or not there are map-based bindings and property bindings - * present together). - */ -function stylingProp( - tNode: TNode, firstUpdatePass: boolean, lView: LView, bindingIndex: number, prop: string, - value: boolean | number | SafeValue | string | null | undefined | NO_CHANGE, - isClassBased: boolean): boolean { - let updated = false; - - const native = getNativeByTNode(tNode, lView) as RElement; - const context = isClassBased ? getClassesContext(tNode) : getStylesContext(tNode); - const sanitizer = isClassBased ? null : getCurrentStyleSanitizer(); - - // [style.prop] and [class.name] bindings do not use `bind()` and will - // therefore manage accessing and updating the new value in the lView directly. - // For this reason, the checkNoChanges situation must also be handled here - // as well. - if (ngDevMode && getCheckNoChangesMode()) { - const oldValue = getValue(lView, bindingIndex); - if (hasValueChangedUnwrapSafeValue(oldValue, value)) { - const field = isClassBased ? `class.${prop}` : `style.${prop}`; - throwErrorIfNoChangesMode(false, oldValue, value, field); - } - } - - // Direct Apply Case: bypass context resolution and apply the - // style/class value directly to the element - if (allowDirectStyling(tNode, isClassBased, firstUpdatePass)) { - const sanitizerToUse = isClassBased ? null : sanitizer; - const renderer = getRenderer(tNode, lView); - updated = applyStylingValueDirectly( - renderer, context, tNode, native, lView, bindingIndex, prop, value, isClassBased, - sanitizerToUse); - - if (sanitizerToUse) { - // it's important we remove the current style sanitizer once the - // element exits, otherwise it will be used by the next styling - // instructions for the next element. - setElementExitFn(stylingApply); - } - } else { - // Context Resolution (or first update) Case: save the value - // and defer to the context to flush and apply the style/class binding - // value to the element. - const directiveIndex = getActiveDirectiveId(); - if (isClassBased) { - updated = updateClassViaContext( - context, tNode, lView, native, directiveIndex, prop, bindingIndex, - value as string | boolean | null, false, firstUpdatePass); - } else { - updated = updateStyleViaContext( - context, tNode, lView, native, directiveIndex, prop, bindingIndex, - value as string | SafeValue | null, sanitizer, false, firstUpdatePass); - } - - setElementExitFn(stylingApply); - } - - return updated; -} /** * Update style bindings using an object literal on an element. @@ -251,41 +119,29 @@ function stylingProp( * * @codeGenApi */ -export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | null): void { - const index = getSelectedIndex(); - const lView = getLView(); - const tNode = getTNode(index, lView); - const firstUpdatePass = lView[TVIEW].firstUpdatePass; - const context = getStylesContext(tNode); - const hasDirectiveInput = hasStyleInput(tNode); - - // if a value is interpolated then it may render a `NO_CHANGE` value. - // in this case we do not need to do anything, but the binding index - // still needs to be incremented because all styling binding values - // are stored inside of the lView. - const bindingIndex = incrementBindingIndex(2); - const hostBindingsMode = isHostStyling(); - - // 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 (!hostBindingsMode && hasDirectiveInput && styles !== NO_CHANGE) { - updateDirectiveInputValue(context, lView, tNode, bindingIndex, styles, false, firstUpdatePass); - styles = NO_CHANGE; - } - - // we check for this in the instruction code so that the context can be notified - // about prop or map bindings so that the direct apply check can decide earlier - // if it allows for context resolution to be bypassed. - if (firstUpdatePass) { - patchConfig(tNode, TNodeFlags.hasStyleMapBindings); - patchHostStylingFlag(tNode, isHostStyling(), false); - } - - stylingMap( - context, tNode, firstUpdatePass, lView, bindingIndex, styles, false, hasDirectiveInput); +export function ɵɵstyleMap( + styles: {[styleName: string]: any} | Map| string | + undefined | null): void { + checkStylingMap(styleKeyValueArraySet, styleStringParser, styles, false); } + +/** + * Parse text as style and add values to KeyValueArray. + * + * This code is pulled out to a separate function so that it can be tree shaken away if it is not + * needed. It is only referenced from `ɵɵstyleMap`. + * + * @param keyValueArray KeyValueArray to add parsed values to. + * @param text text to parse. + */ +export function styleStringParser(keyValueArray: KeyValueArray, text: string): void { + for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i)) { + styleKeyValueArraySet(keyValueArray, getLastParsedKey(text), getLastParsedValue(text)); + } +} + + /** * Update class bindings using an object literal or class-string on an element. * @@ -304,322 +160,762 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu * * @codeGenApi */ -export function ɵɵclassMap(classes: {[className: string]: any} | NO_CHANGE | string | null): void { - classMapInternal(getSelectedIndex(), classes); +export function ɵɵclassMap( + classes: {[className: string]: boolean | undefined | null} | + Map| Set| string[] | string | undefined | null): void { + checkStylingMap(keyValueArraySet, classStringParser, classes, true); } /** - * Internal function for applying a class string or key/value map of classes to an element. + * Parse text as class and add values to KeyValueArray. * - * The reason why this function has been separated from `ɵɵclassMap` is because - * it is also called from `ɵɵclassMapInterpolate`. + * This code is pulled out to a separate function so that it can be tree shaken away if it is not + * needed. It is only referenced from `ɵɵclassMap`. + * + * @param keyValueArray KeyValueArray to add parsed values to. + * @param text text to parse. */ -export function classMapInternal( - elementIndex: number, classes: {[className: string]: any} | NO_CHANGE | string | null): void { +export function classStringParser(keyValueArray: KeyValueArray, text: string): void { + for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) { + keyValueArraySet(keyValueArray, getLastParsedKey(text), true); + } +} + +/** + * Common code between `ɵɵclassProp` and `ɵɵstyleProp`. + * + * @param prop property name. + * @param value binding value. + * @param suffixOrSanitizer suffix or sanitization function + * @param isClassBased `true` if `class` change (`false` if `style`) + */ +export function checkStylingProperty( + prop: string, value: any | NO_CHANGE, + suffixOrSanitizer: SanitizerFn | string | undefined | null, isClassBased: boolean): void { const lView = getLView(); - const tNode = getTNode(elementIndex, lView); - const firstUpdatePass = lView[TVIEW].firstUpdatePass; - const context = getClassesContext(tNode); - const hasDirectiveInput = hasClassInput(tNode); - - // if a value is interpolated then it may render a `NO_CHANGE` value. - // in this case we do not need to do anything, but the binding index - // still needs to be incremented because all styling binding values - // are stored inside of the lView. + const tView = getTView(); + // Styling instructions use 2 slots per binding. + // 1. one for the value / TStylingKey + // 2. one for the intermittent-value / TStylingRange const bindingIndex = incrementBindingIndex(2); - const hostBindingsMode = isHostStyling(); - - // 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 (!hostBindingsMode && hasDirectiveInput && classes !== NO_CHANGE) { - updateDirectiveInputValue(context, lView, tNode, bindingIndex, classes, true, firstUpdatePass); - classes = NO_CHANGE; + if (tView.firstUpdatePass) { + stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased); } - - // we check for this in the instruction code so that the context can be notified - // about prop or map bindings so that the direct apply check can decide earlier - // if it allows for context resolution to be bypassed. - if (firstUpdatePass) { - patchConfig(tNode, TNodeFlags.hasClassMapBindings); - patchHostStylingFlag(tNode, isHostStyling(), true); + if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) { + // This is a work around. Once PR#34480 lands the sanitizer is passed explicitly and this line + // can be removed. + let styleSanitizer: StyleSanitizeFn|null; + if (suffixOrSanitizer == null) { + if (styleSanitizer = getCurrentStyleSanitizer()) { + suffixOrSanitizer = styleSanitizer as any; + } + } + const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode; + updateStyling( + tView, tNode, lView, lView[RENDERER], prop, + lView[bindingIndex + 1] = normalizeAndApplySuffixOrSanitizer(value, suffixOrSanitizer), + isClassBased, bindingIndex); } - - stylingMap( - context, tNode, firstUpdatePass, lView, bindingIndex, classes, true, hasDirectiveInput); } /** - * Shared function used to update a map-based styling binding for an element. + * Common code between `ɵɵclassMap` and `ɵɵstyleMap`. * - * When this function is called it will activate support for `[style]` and - * `[class]` bindings in Angular. + * @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a + * function so that + * `style` can pass in version which does sanitization. This is done for tree shaking + * purposes. + * @param stringParser Parser used to parse `value` if `string`. (Passed in as `style` and `class` + * have different parsers.) + * @param value bound value from application + * @param isClassBased `true` if `class` change (`false` if `style`) */ -function stylingMap( - context: TStylingContext, tNode: TNode, firstUpdatePass: boolean, lView: LView, - bindingIndex: number, value: {[key: string]: any} | string | null, isClassBased: boolean, - hasDirectiveInput: boolean): void { - const directiveIndex = getActiveDirectiveId(); - const native = getNativeByTNode(tNode, lView) as RElement; - const oldValue = getValue(lView, bindingIndex); - const sanitizer = getCurrentStyleSanitizer(); - const valueHasChanged = hasValueChanged(oldValue, value); - - // [style] and [class] bindings do not use `bind()` and will therefore - // manage accessing and updating the new value in the lView directly. - // For this reason, the checkNoChanges situation must also be handled here - // as well. - if (ngDevMode && valueHasChanged && getCheckNoChangesMode()) { - // check if the value is a StylingMapArray, in which case take the first value (which stores raw - // value) from the array - const previousValue = - isStylingMapArray(oldValue) ? oldValue[StylingMapArrayIndex.RawValuePosition] : oldValue; - throwErrorIfNoChangesMode(false, previousValue, value); +export function checkStylingMap( + keyValueArraySet: (keyValueArray: KeyValueArray, key: string, value: any) => void, + stringParser: (styleKeyValueArray: KeyValueArray, text: string) => void, + value: any|NO_CHANGE, isClassBased: boolean): void { + const tView = getTView(); + const bindingIndex = incrementBindingIndex(2); + if (tView.firstUpdatePass) { + stylingFirstUpdatePass(tView, null, bindingIndex, isClassBased); } + const lView = getLView(); + if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) { + // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the + // if so as not to read unnecessarily. + const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode; + if (hasStylingInputShadow(tNode, isClassBased) && !isInHostBindings(tView, bindingIndex)) { + if (ngDevMode) { + // verify that if we are shadowing then `TData` is appropriately marked so that we skip + // processing this binding in styling resolution. + const tStylingKey = tView.data[bindingIndex]; + assertEqual( + Array.isArray(tStylingKey) ? tStylingKey[1] : tStylingKey, false, + 'Styling linked list shadow input should be marked as \'false\''); + } + // VE does not concatenate the static portion like we are doing here. + // Instead VE just ignores the static completely if dynamic binding is present. + // Because of locality we have already set the static portion because we don't know if there + // is a dynamic portion until later. If we would ignore the static portion it would look like + // the binding has removed it. This would confuse `[ngStyle]`/`[ngClass]` to do the wrong + // thing as it would think that the static portion was removed. For this reason we + // concatenate it so that `[ngStyle]`/`[ngClass]` can continue to work on changed. + let staticPrefix = isClassBased ? tNode.classes : tNode.styles; + ngDevMode && isClassBased === false && staticPrefix !== null && + assertEqual( + staticPrefix.endsWith(';'), true, 'Expecting static portion to end with \';\''); + if (typeof value === 'string') { + value = concatStringsWithSpace(staticPrefix, value as string); + } + // Given `
` such that `my-dir` has `@Input('style')`. + // This takes over the `[style]` binding. (Same for `[class]`) + setDirectiveInputsWhichShadowsStyling(tView, tNode, lView, value, isClassBased); + } else { + updateStylingMap( + tView, tNode, lView, lView[RENDERER], lView[bindingIndex + 1], + lView[bindingIndex + 1] = toStylingKeyValueArray(keyValueArraySet, stringParser, value), + isClassBased, bindingIndex); + } + } +} - // Direct Apply Case: bypass context resolution and apply the - // style/class map values directly to the element - if (allowDirectStyling(tNode, isClassBased, firstUpdatePass)) { - const sanitizerToUse = isClassBased ? null : sanitizer; - const renderer = getRenderer(tNode, lView); - applyStylingMapDirectly( - renderer, context, tNode, native, lView, bindingIndex, value, isClassBased, sanitizerToUse, - valueHasChanged, hasDirectiveInput); - if (sanitizerToUse) { - // it's important we remove the current style sanitizer once the - // element exits, otherwise it will be used by the next styling - // instructions for the next element. - setElementExitFn(stylingApply); +/** + * Determines when the binding is in `hostBindings` section + * + * @param tView Current `TView` + * @param bindingIndex index of binding which we would like if it is in `hostBindings` + */ +function isInHostBindings(tView: TView, bindingIndex: number): boolean { + // All host bindings are placed after the expando section. + return bindingIndex >= tView.expandoStartIndex; +} + +/** +* Collects the necessary information to insert the binding into a linked list of style bindings +* using `insertTStylingBinding`. +* +* @param tView `TView` where the binding linked list will be stored. +* @param tStylingKey Property/key of the binding. +* @param bindingIndex Index of binding associated with the `prop` +* @param isClassBased `true` if `class` change (`false` if `style`) +*/ +function stylingFirstUpdatePass( + tView: TView, tStylingKey: TStylingKey, bindingIndex: number, isClassBased: boolean): void { + ngDevMode && assertFirstUpdatePass(tView); + const tData = tView.data; + if (tData[bindingIndex + 1] === null) { + // The above check is necessary because we don't clear first update pass until first successful + // (no exception) template execution. This prevents the styling instruction from double adding + // itself to the list. + // `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the + // if so as not to read unnecessarily. + const tNode = tData[getSelectedIndex() + HEADER_OFFSET] as TNode; + const isHostBindings = isInHostBindings(tView, bindingIndex); + if (hasStylingInputShadow(tNode, isClassBased) && tStylingKey === null && !isHostBindings) { + // `tStylingKey === null` implies that we are either `[style]` or `[class]` binding. + // If there is a directive which uses `@Input('style')` or `@Input('class')` than + // we need to neutralize this binding since that directive is shadowing it. + // We turn this into a noop by setting the key to `false` + tStylingKey = false; + } + tStylingKey = wrapInStaticStylingKey(tData, tNode, tStylingKey, isClassBased); + insertTStylingBinding(tData, tNode, tStylingKey, bindingIndex, isHostBindings, isClassBased); + } +} + +/** + * Adds static styling information to the binding if applicable. + * + * The linked list of styles not only stores the list and keys, but also stores static styling + * information on some of the keys. This function determines if the key should contain the styling + * information and computes it. + * + * See `TStylingStatic` for more details. + * + * @param tData `TData` where the linked list is stored. + * @param tNode `TNode` for which the styling is being computed. + * @param stylingKey `TStylingKeyPrimitive` which may need to be wrapped into `TStylingKey` + * @param isClassBased `true` if `class` (`false` if `style`) + */ +export function wrapInStaticStylingKey( + tData: TData, tNode: TNode, stylingKey: TStylingKey, isClassBased: boolean): TStylingKey { + const hostDirectiveDef = getHostDirectiveDef(tData); + let residual = isClassBased ? tNode.residualClasses : tNode.residualStyles; + if (hostDirectiveDef === null) { + // We are in template node. + // If template node already had styling instruction then it has already collected the static + // styling and there is no need to collect them again. We know that we are the first styling + // instruction because the `TNode.*Bindings` points to 0 (nothing has been inserted yet). + const isFirstStylingInstructionInTemplate = + (isClassBased ? tNode.classBindings : tNode.styleBindings) as any as number === 0; + if (isFirstStylingInstructionInTemplate) { + // It would be nice to be able to get the statics from `mergeAttrs`, however, at this point + // they are already merged and it would not be possible to figure which property belongs where + // in the priority. + stylingKey = collectStylingFromDirectives(null, tData, tNode, stylingKey, isClassBased); + stylingKey = collectStylingFromTAttrs(stylingKey, tNode.attrs, isClassBased); + // We know that if we have styling binding in template we can't have residual. + residual = null; } } else { - const stylingMapArr = - value === NO_CHANGE ? NO_CHANGE : normalizeIntoStylingMap(oldValue, value, !isClassBased); - - activateStylingMapFeature(); - - // Context Resolution (or first update) Case: save the map value - // and defer to the context to flush and apply the style/class binding - // value to the element. - if (isClassBased) { - updateClassViaContext( - context, tNode, lView, native, directiveIndex, null, bindingIndex, stylingMapArr, - valueHasChanged, firstUpdatePass); - } else { - updateStyleViaContext( - context, tNode, lView, native, directiveIndex, null, bindingIndex, stylingMapArr, - sanitizer, valueHasChanged, firstUpdatePass); + // We are in host binding node and there was no binding instruction in template node. + // This means that we need to compute the residual. + const directiveStylingLast = tNode.directiveStylingLast; + const isFirstStylingInstructionInHostBinding = + directiveStylingLast === -1 || tData[directiveStylingLast] !== hostDirectiveDef; + if (isFirstStylingInstructionInHostBinding) { + stylingKey = + collectStylingFromDirectives(hostDirectiveDef, tData, tNode, stylingKey, isClassBased); + if (residual === null) { + // - If `null` than either: + // - Template styling instruction already ran and it has consumed the static + // styling into its `TStylingKey` and so there is no need to update residual. Instead + // we need to update the `TStylingKey` associated with the first template node + // instruction. OR + // - Some other styling instruction ran and determined that there are no residuals + let templateStylingKey = getTemplateHeadTStylingKey(tData, tNode, isClassBased); + if (templateStylingKey !== undefined && Array.isArray(templateStylingKey)) { + // Only recompute if `templateStylingKey` had static values. (If no static value found + // then there is nothing to do since this operation can only produce less static keys, not + // more.) + templateStylingKey = collectStylingFromDirectives( + null, tData, tNode, templateStylingKey[1] /* unwrap previous statics */, + isClassBased); + templateStylingKey = + collectStylingFromTAttrs(templateStylingKey, tNode.attrs, isClassBased); + setTemplateHeadTStylingKey(tData, tNode, isClassBased, templateStylingKey); + } + } else { + // We only need to recompute residual if it is not `null`. + // - If existing residual (implies there was no template styling). This means that some of + // the statics may have moved from the residual to the `stylingKey` and so we have to + // recompute. + // - If `undefined` this is the first time we are running. + residual = collectResidual(tData, tNode, isClassBased); + } } - - setElementExitFn(stylingApply); } + if (residual !== undefined) { + isClassBased ? (tNode.residualClasses = residual) : (tNode.residualStyles = residual); + } + return stylingKey; +} - if (ngDevMode) { - isClassBased ? ngDevMode.classMap : ngDevMode.styleMap++; - if (valueHasChanged) { - isClassBased ? ngDevMode.classMapCacheMiss : ngDevMode.styleMapCacheMiss++; +/** + * Retrieve the `TStylingKey` for the template styling instruction. + * + * This is needed since `hostBinding` styling instructions are inserted after the template + * instruction. While the template instruction needs to update the residual in `TNode` the + * `hostBinding` instructions need to update the `TStylingKey` of the template instruction because + * the template instruction is downstream from the `hostBindings` instructions. + * + * @param tData `TData` where the linked list is stored. + * @param tNode `TNode` for which the styling is being computed. + * @param isClassBased `true` if `class` (`false` if `style`) + * @return `TStylingKey` if found or `undefined` if not found. + */ +function getTemplateHeadTStylingKey(tData: TData, tNode: TNode, isClassBased: boolean): TStylingKey| + undefined { + const bindings = isClassBased ? tNode.classBindings : tNode.styleBindings; + if (getTStylingRangeNext(bindings) === 0) { + // There does not seem to be a styling instruction in the `template`. + return undefined; + } + return tData[getTStylingRangePrev(bindings)] as TStylingKey; +} + +/** + * Update the `TStylingKey` of the first template instruction in `TNode`. + * + * Logically `hostBindings` styling instructions are of lower priority than that of the template. + * However, they execute after the template styling instructions. This means that they get inserted + * in front of the template styling instructions. + * + * If we have a template styling instruction and a new `hostBindings` styling instruction is + * executed it means that it may need to steal static fields from the template instruction. This + * method allows us to update the first template instruction `TStylingKey` with a new value. + * + * Assume: + * ``` + *
+ * + * @Directive({ + * host: { + * 'style': 'width: 100px', + * '[style.color]': 'dirExp', + * } + * }) + * class MyDir {} + * ``` + * + * when `[style.color]="tmplExp"` executes it creates this data structure. + * ``` + * ['', 'color', 'color', 'red', 'width', '100px'], + * ``` + * + * The reason for this is that the template instruction does not know if there are styling + * instructions and must assume that there are none and must collect all of the static styling. + * (both + * `color' and 'width`) + * + * When `'[style.color]': 'dirExp',` executes we need to insert a new data into the linked list. + * ``` + * ['', 'color', 'width', '100px'], // newly inserted + * ['', 'color', 'color', 'red', 'width', '100px'], // this is wrong + * ``` + * + * Notice that the template statics is now wrong as it incorrectly contains `width` so we need to + * update it like so: + * ``` + * ['', 'color', 'width', '100px'], + * ['', 'color', 'color', 'red'], // UPDATE + * ``` + * + * @param tData `TData` where the linked list is stored. + * @param tNode `TNode` for which the styling is being computed. + * @param isClassBased `true` if `class` (`false` if `style`) + * @param tStylingKey New `TStylingKey` which is replacing the old one. + */ +function setTemplateHeadTStylingKey( + tData: TData, tNode: TNode, isClassBased: boolean, tStylingKey: TStylingKey): void { + const bindings = isClassBased ? tNode.classBindings : tNode.styleBindings; + ngDevMode && assertNotEqual( + getTStylingRangeNext(bindings), 0, + 'Expecting to have at least one template styling binding.'); + tData[getTStylingRangePrev(bindings)] = tStylingKey; +} + +/** + * Collect all static values after the current `TNode.directiveStylingLast` index. + * + * Collect the remaining styling information which has not yet been collected by an existing + * styling instruction. + * + * @param tData `TData` where the `DirectiveDefs` are stored. + * @param tNode `TNode` which contains the directive range. + * @param isClassBased `true` if `class` (`false` if `style`) + */ +function collectResidual(tData: TData, tNode: TNode, isClassBased: boolean): KeyValueArray| + null { + let residual: KeyValueArray|null|undefined = undefined; + const directiveEnd = tNode.directiveEnd; + ngDevMode && + assertNotEqual( + tNode.directiveStylingLast, -1, + 'By the time this function gets called at least one hostBindings-node styling instruction must have executed.'); + // We add `1 + tNode.directiveStart` because we need to skip the current directive (as we are + // collecting things after the last `hostBindings` directive which had a styling instruction.) + for (let i = 1 + tNode.directiveStylingLast; i < directiveEnd; i++) { + const attrs = (tData[i] as DirectiveDef).hostAttrs; + residual = collectStylingFromTAttrs(residual, attrs, isClassBased) as KeyValueArray| null; + } + return collectStylingFromTAttrs(residual, tNode.attrs, isClassBased) as KeyValueArray| null; +} + +/** + * Collect the static styling information with lower priority than `hostDirectiveDef`. + * + * (This is opposite of residual styling.) + * + * @param hostDirectiveDef `DirectiveDef` for which we want to collect lower priority static + * styling. (Or `null` if template styling) + * @param tData `TData` where the linked list is stored. + * @param tNode `TNode` for which the styling is being computed. + * @param stylingKey Existing `TStylingKey` to update or wrap. + * @param isClassBased `true` if `class` (`false` if `style`) + */ +function collectStylingFromDirectives( + hostDirectiveDef: DirectiveDef| null, tData: TData, tNode: TNode, stylingKey: TStylingKey, + isClassBased: boolean): TStylingKey { + // We need to loop because there can be directives which have `hostAttrs` but don't have + // `hostBindings` so this loop catches up to the current directive.. + let currentDirective: DirectiveDef|null = null; + const directiveEnd = tNode.directiveEnd; + let directiveStylingLast = tNode.directiveStylingLast; + if (directiveStylingLast === -1) { + directiveStylingLast = tNode.directiveStart; + } else { + directiveStylingLast++; + } + while (directiveStylingLast < directiveEnd) { + currentDirective = tData[directiveStylingLast] as DirectiveDef; + ngDevMode && assertDefined(currentDirective, 'expected to be defined'); + stylingKey = collectStylingFromTAttrs(stylingKey, currentDirective.hostAttrs, isClassBased); + if (currentDirective === hostDirectiveDef) break; + directiveStylingLast++; + } + if (hostDirectiveDef !== null) { + // we only advance the styling cursor if we are collecting data from host bindings. + // Template executes before host bindings and so if we would update the index, + // host bindings would not get their statics. + tNode.directiveStylingLast = directiveStylingLast; + } + return stylingKey; +} + +/** + * Convert `TAttrs` into `TStylingStatic`. + * + * @param stylingKey existing `TStylingKey` to update or wrap. + * @param attrs `TAttributes` to process. + * @param isClassBased `true` if `class` (`false` if `style`) + */ +function collectStylingFromTAttrs( + stylingKey: TStylingKey | undefined, attrs: TAttributes | null, + isClassBased: boolean): TStylingKey { + const desiredMarker = isClassBased ? AttributeMarker.Classes : AttributeMarker.Styles; + let currentMarker = AttributeMarker.ImplicitAttributes; + if (attrs !== null) { + for (let i = 0; i < attrs.length; i++) { + const item = attrs[i] as number | string; + if (typeof item === 'number') { + currentMarker = item; + } else { + if (currentMarker === desiredMarker) { + if (!Array.isArray(stylingKey)) { + stylingKey = stylingKey === undefined ? [] : ['', stylingKey] as any; + } + keyValueArraySet( + stylingKey as KeyValueArray, item, isClassBased ? true : attrs[++i]); + } + } } } + return stylingKey === undefined ? null : stylingKey; +} + +/** + * Retrieve the current `DirectiveDef` which is active when `hostBindings` style instruction is + * being executed (or `null` if we are in `template`.) + * + * @param tData Current `TData` where the `DirectiveDef` will be looked up at. + */ +export function getHostDirectiveDef(tData: TData): DirectiveDef|null { + const currentDirectiveIndex = getCurrentDirectiveIndex(); + return currentDirectiveIndex === -1 ? null : tData[currentDirectiveIndex] as DirectiveDef; +} + +/** + * Convert user input to `KeyValueArray`. + * + * This function takes user input which could be `string`, Object literal, or iterable and converts + * it into a consistent representation. The output of this is `KeyValueArray` (which is an array + * where + * even indexes contain keys and odd indexes contain values for those keys). + * + * The advantage of converting to `KeyValueArray` is that we can perform diff in an input + * independent + * way. + * (ie we can compare `foo bar` to `['bar', 'baz'] and determine a set of changes which need to be + * applied) + * + * The fact that `KeyValueArray` is sorted is very important because it allows us to compute the + * difference in linear fashion without the need to allocate any additional data. + * + * For example if we kept this as a `Map` we would have to iterate over previous `Map` to determine + * which values need to be deleted, over the new `Map` to determine additions, and we would have to + * keep additional `Map` to keep track of duplicates or items which have not yet been visited. + * + * @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a + * function so that + * `style` can pass in version which does sanitization. This is done for tree shaking + * purposes. + * @param stringParser The parser is passed in so that it will be tree shakable. See + * `styleStringParser` and `classStringParser` + * @param value The value to parse/convert to `KeyValueArray` + */ +export function toStylingKeyValueArray( + keyValueArraySet: (keyValueArray: KeyValueArray, key: string, value: any) => void, + stringParser: (styleKeyValueArray: KeyValueArray, text: string) => void, value: string| + string[]|{[key: string]: any}|Map|Set|null|undefined): KeyValueArray { + if (value == null /*|| value === undefined */ || value === '') return EMPTY_ARRAY as any; + const styleKeyValueArray: KeyValueArray = [] as any; + if (Array.isArray(value)) { + for (let i = 0; i < value.length; i++) { + keyValueArraySet(styleKeyValueArray, value[i], true); + } + } else if (typeof value === 'object') { + if (value instanceof Map) { + value.forEach((v, k) => keyValueArraySet(styleKeyValueArray, k, v)); + } else if (value instanceof Set) { + value.forEach((k) => keyValueArraySet(styleKeyValueArray, k, true)); + } else { + for (const key in value) { + if (value.hasOwnProperty(key)) { + keyValueArraySet(styleKeyValueArray, key, value[key]); + } + } + } + } else if (typeof value === 'string') { + stringParser(styleKeyValueArray, value); + } else { + ngDevMode && throwError('Unsupported styling type ' + typeof value + ': ' + value); + } + return styleKeyValueArray; +} + +/** + * Set a `value` for a `key` taking style sanitization into account. + * + * See: `keyValueArraySet` for details + * + * @param keyValueArray KeyValueArray to add to. + * @param key Style key to add. (This key will be checked if it needs sanitization) + * @param value The value to set (If key needs sanitization it will be sanitized) + */ +function styleKeyValueArraySet(keyValueArray: KeyValueArray, key: string, value: any) { + if (stylePropNeedsSanitization(key)) { + value = ɵɵsanitizeStyle(value); + } + keyValueArraySet(keyValueArray, key, value); +} + +/** + * Update map based styling. + * + * Map based styling could be anything which contains more than one binding. For example `string`, + * `Map`, `Set` or object literal. Dealing with all of these types would complicate the logic so + * instead this function expects that the complex input is first converted into normalized + * `KeyValueArray`. The advantage of normalization is that we get the values sorted, which makes it + * very + * cheap to compute deltas between the previous and current value. + * + * @param tView Associated `TView.data` contains the linked list of binding priorities. + * @param tNode `TNode` where the binding is located. + * @param lView `LView` contains the values associated with other styling binding at this `TNode`. + * @param renderer Renderer to use if any updates. + * @param oldKeyValueArray Previous value represented as `KeyValueArray` + * @param newKeyValueArray Current value represented as `KeyValueArray` + * @param isClassBased `true` if `class` (`false` if `style`) + * @param bindingIndex Binding index of the binding. + */ +function updateStylingMap( + tView: TView, tNode: TNode, lView: LView, renderer: Renderer3, + oldKeyValueArray: KeyValueArray, newKeyValueArray: KeyValueArray, + isClassBased: boolean, bindingIndex: number) { + if (oldKeyValueArray as KeyValueArray| NO_CHANGE === NO_CHANGE) { + // On first execution the oldKeyValueArray is NO_CHANGE => treat it as empty KeyValueArray. + oldKeyValueArray = EMPTY_ARRAY as any; + } + let oldIndex = 0; + let newIndex = 0; + let oldKey: string|null = 0 < oldKeyValueArray.length ? oldKeyValueArray[0] : null; + let newKey: string|null = 0 < newKeyValueArray.length ? newKeyValueArray[0] : null; + while (oldKey !== null || newKey !== null) { + ngDevMode && assertLessThan(oldIndex, 999, 'Are we stuck in infinite loop?'); + ngDevMode && assertLessThan(newIndex, 999, 'Are we stuck in infinite loop?'); + const oldValue = + oldIndex < oldKeyValueArray.length ? oldKeyValueArray[oldIndex + 1] : undefined; + const newValue = + newIndex < newKeyValueArray.length ? newKeyValueArray[newIndex + 1] : undefined; + let setKey: string|null = null; + let setValue: any = undefined; + if (oldKey === newKey) { + // UPDATE: Keys are equal => new value is overwriting old value. + oldIndex += 2; + newIndex += 2; + if (oldValue !== newValue) { + setKey = newKey; + setValue = newValue; + } + } else if (newKey === null || oldKey !== null && oldKey < newKey !) { + // DELETE: oldKey key is missing or we did not find the oldKey in the newValue + // (because the keyValueArray is sorted and `newKey` is found later alphabetically). + // `"background" < "color"` so we need to delete `"background"` because it is not found in the + // new array. + oldIndex += 2; + setKey = oldKey; + } else { + // CREATE: newKey's is earlier alphabetically than oldKey's (or no oldKey) => we have new key. + // `"color" > "background"` so we need to add `color` because it is in new array but not in + // old array. + ngDevMode && assertDefined(newKey, 'Expecting to have a valid key'); + newIndex += 2; + setKey = newKey; + setValue = newValue; + } + if (setKey !== null) { + updateStyling(tView, tNode, lView, renderer, setKey, setValue, isClassBased, bindingIndex); + } + oldKey = oldIndex < oldKeyValueArray.length ? oldKeyValueArray[oldIndex] : null; + newKey = newIndex < newKeyValueArray.length ? newKeyValueArray[newIndex] : null; + } } /** - * Writes a value to a directive's `style` or `class` input binding (if it has changed). + * Update a simple (property name) styling. * - * If a directive has a `@Input` binding that is set on `style` or `class` then that value - * will take priority over the underlying style/class styling bindings. This value will - * be updated for the binding each time during change detection. + * This function takes `prop` and updates the DOM to that value. The function takes the binding + * value as well as binding priority into consideration to determine which value should be written + * to DOM. (For example it may be determined that there is a higher priority overwrite which blocks + * the DOM write, or if the value goes to `undefined` a lower priority overwrite may be consulted.) * - * When this occurs this function will attempt to write the value to the input binding - * depending on the following situations: - * - * - If `oldValue !== newValue` - * - If `newValue` is `null` (but this is skipped if it is during the first update pass) + * @param tView Associated `TView.data` contains the linked list of binding priorities. + * @param tNode `TNode` where the binding is located. + * @param lView `LView` contains the values associated with other styling binding at this `TNode`. + * @param renderer Renderer to use if any updates. + * @param prop Either style property name or a class name. + * @param value Either style value for `prop` or `true`/`false` if `prop` is class. + * @param isClassBased `true` if `class` (`false` if `style`) + * @param bindingIndex Binding index of the binding. */ -function updateDirectiveInputValue( - context: TStylingContext, lView: LView, tNode: TNode, bindingIndex: number, newValue: any, - isClassBased: boolean, firstUpdatePass: boolean): void { - const oldValue = getValue(lView, bindingIndex); - if (hasValueChanged(oldValue, newValue)) { - // even if the value has changed we may not want to emit it to the - // directive input(s) in the event that it is falsy during the - // first update pass. - if (isStylingValueDefined(newValue) || !firstUpdatePass) { - const inputName: string = isClassBased ? selectClassBasedInputName(tNode.inputs !) : 'style'; - const inputs = tNode.inputs ![inputName] !; - const initialValue = getInitialStylingValue(context); - const value = normalizeStylingDirectiveInputValue(initialValue, newValue, isClassBased); - setInputsForProperty(lView, inputs, inputName, value); - setElementExitFn(stylingApply); +function updateStyling( + tView: TView, tNode: TNode, lView: LView, renderer: Renderer3, prop: string, + value: string | undefined | null | boolean, isClassBased: boolean, bindingIndex: number) { + if (tNode.type !== TNodeType.Element) { + // It is possible to have styling on non-elements (such as ng-container). + // This is rare, but it does happen. In such a case, just ignore the binding. + return; + } + const tData = tView.data; + const tRange = tData[bindingIndex + 1] as TStylingRange; + const higherPriorityValue = getTStylingRangeNextDuplicate(tRange) ? + findStylingValue(tData, tNode, lView, prop, getTStylingRangeNext(tRange), isClassBased) : + undefined; + if (!isStylingValuePresent(higherPriorityValue)) { + // We don't have a next duplicate, or we did not find a duplicate value. + if (!isStylingValuePresent(value)) { + // We should delete current value or restore to lower priority value. + if (getTStylingRangePrevDuplicate(tRange)) { + // We have a possible prev duplicate, let's retrieve it. + value = findStylingValue(tData, null, lView, prop, bindingIndex, isClassBased); + } } - setValue(lView, bindingIndex, newValue); + const rNode = getNativeByIndex(getSelectedIndex(), lView) as RElement; + applyStyling(renderer, isClassBased, rNode, prop, value); } } /** - * Returns the appropriate directive input value for `style` or `class`. + * Search for styling value with higher priority which is overwriting current value, or a + * value of lower priority to which we should fall back if the value is `undefined`. * - * Earlier versions of Angular expect a binding value to be passed into directive code - * exactly as it is unless there is a static value present (in which case both values - * will be stringified and concatenated). + * When value is being applied at a location, related values need to be consulted. + * - If there is a higher priority binding, we should be using that one instead. + * For example `
` change to `exp1` + * requires that we check `exp2` to see if it is set to value other than `undefined`. + * - If there is a lower priority binding and we are changing to `undefined` + * For example `
` change to `exp2` to + * `undefined` requires that we check `exp1` (and static values) and use that as new value. + * + * NOTE: The styling stores two values. + * 1. The raw value which came from the application is stored at `index + 0` location. (This value + * is used for dirty checking). + * 2. The normalized value (converted to `KeyValueArray` if map and sanitized) is stored at `index + + * 1`. + * The advantage of storing the sanitized value is that once the value is written we don't need + * to worry about sanitizing it later or keeping track of the sanitizer. + * + * @param tData `TData` used for traversing the priority. + * @param tNode `TNode` to use for resolving static styling. Also controls search direction. + * - `TNode` search next and quit as soon as `isStylingValuePresent(value)` is true. + * If no value found consult `tNode.residualStyle`/`tNode.residualClass` for default value. + * - `null` search prev and go all the way to end. Return last value where + * `isStylingValuePresent(value)` is true. + * @param lView `LView` used for retrieving the actual values. + * @param prop Property which we are interested in. + * @param index Starting index in the linked list of styling bindings where the search should start. + * @param isClassBased `true` if `class` (`false` if `style`) */ -function normalizeStylingDirectiveInputValue( - initialValue: string, bindingValue: string | {[key: string]: any} | null, - isClassBased: boolean) { - let value = bindingValue; - - // we only concat values if there is an initial value, otherwise we return the value as is. - // Note that this is to satisfy backwards-compatibility in Angular. - if (initialValue.length) { - if (isClassBased) { - value = concatString(initialValue, forceClassesAsString(bindingValue)); - } else { - value = concatString(initialValue, forceStylesAsString(bindingValue, true), ';'); +function findStylingValue( + tData: TData, tNode: TNode | null, lView: LView, prop: string, index: number, + isClassBased: boolean): any { + // `TNode` to use for resolving static styling. Also controls search direction. + // - `TNode` search next and quit as soon as `isStylingValuePresent(value)` is true. + // If no value found consult `tNode.residualStyle`/`tNode.residualClass` for default value. + // - `null` search prev and go all the way to end. Return last value where + // `isStylingValuePresent(value)` is true. + const isPrevDirection = tNode === null; + let value: any = undefined; + while (index > 0) { + const rawKey = tData[index] as TStylingKey; + const containsStatics = Array.isArray(rawKey); + // Unwrap the key if we contain static values. + const key = containsStatics ? (rawKey as string[])[1] : rawKey; + const isStylingMap = key === null; + let valueAtLViewIndex = lView[index + 1]; + if (valueAtLViewIndex === NO_CHANGE) { + // In firstUpdatePass the styling instructions create a linked list of styling. + // On subsequent passes it is possible for a styling instruction to try to read a binding + // which + // has not yet executed. In that case we will find `NO_CHANGE` and we should assume that + // we have `undefined` (or empty array in case of styling-map instruction) instead. This + // allows the resolution to apply the value (which may later be overwritten when the + // binding actually executes.) + valueAtLViewIndex = isStylingMap ? EMPTY_ARRAY : undefined; + } + let currentValue = isStylingMap ? keyValueArrayGet(valueAtLViewIndex, prop) : + key === prop ? valueAtLViewIndex : undefined; + if (containsStatics && !isStylingValuePresent(currentValue)) { + currentValue = keyValueArrayGet(rawKey as KeyValueArray, prop); + } + if (isStylingValuePresent(currentValue)) { + value = currentValue; + if (isPrevDirection) { + return value; + } + } + const tRange = tData[index + 1] as TStylingRange; + index = isPrevDirection ? getTStylingRangePrev(tRange) : getTStylingRangeNext(tRange); + } + if (tNode !== null) { + // in case where we are going in next direction AND we did not find anything, we need to + // consult residual styling + let residual = isClassBased ? tNode.residualClasses : tNode.residualStyles; + if (residual != null /** OR residual !=== undefined */) { + value = keyValueArrayGet(residual !, prop); } } return value; } /** - * Flushes all styling code to the element. + * Determines if the binding value should be used (or if the value is 'undefined' and hence priority + * resolution should be used.) * - * This function is designed to be scheduled from any of the four styling instructions - * in this file. When called it will flush all style and class bindings to the element - * via the context resolution algorithm. + * @param value Binding style value. */ -function stylingApply(): void { - const lView = getLView(); - const tView = lView[TVIEW]; - const elementIndex = getSelectedIndex(); - const tNode = getTNode(elementIndex, lView); - const native = getNativeByTNode(tNode, lView) as RElement; - const directiveIndex = getActiveDirectiveId(); - const renderer = getRenderer(tNode, lView); - const sanitizer = getCurrentStyleSanitizer(); - const classesContext = isStylingContext(tNode.classes) ? tNode.classes as TStylingContext : null; - const stylesContext = isStylingContext(tNode.styles) ? tNode.styles as TStylingContext : null; - flushStyling( - renderer, lView, tNode, classesContext, stylesContext, native, directiveIndex, sanitizer, - tView.firstUpdatePass); - resetCurrentStyleSanitizer(); -} - -function getRenderer(tNode: TNode, lView: LView) { - return tNode.type === TNodeType.Element ? lView[RENDERER] : null; +function isStylingValuePresent(value: any): boolean { + // Currently only `undefined` value is considered non-binding. That is `undefined` says I don't + // have an opinion as to what this binding should be and you should consult other bindings by + // priority to determine the valid value. + // This is extracted into a single function so that we have a single place to control this. + return value !== undefined; } /** - * Searches and assigns provided all static style/class entries (found in the `attrs` value) - * and registers them in their respective styling contexts. + * Sanitizes or adds suffix to the value. + * + * If value is `null`/`undefined` no suffix is added + * @param value + * @param suffixOrSanitizer */ -export function registerInitialStylingOnTNode( - tNode: TNode, attrs: TAttributes, startIndex: number): boolean { - let hasAdditionalInitialStyling = false; - let styles = getStylingMapArray(tNode.styles); - let classes = getStylingMapArray(tNode.classes); - let mode = -1; - for (let i = startIndex; i < attrs.length; i++) { - const attr = attrs[i] as string; - if (typeof attr == 'number') { - mode = attr; - } else if (mode == AttributeMarker.Classes) { - classes = classes || allocStylingMapArray(null); - addItemToStylingMap(classes, attr, true); - hasAdditionalInitialStyling = true; - } else if (mode == AttributeMarker.Styles) { - const value = attrs[++i] as string | null; - styles = styles || allocStylingMapArray(null); - addItemToStylingMap(styles, attr, value); - hasAdditionalInitialStyling = true; - } +function normalizeAndApplySuffixOrSanitizer( + value: any, suffixOrSanitizer: SanitizerFn | string | undefined | null): string|null|undefined| + boolean { + if (value == null /** || value === undefined */) { + // do nothing + } else if (typeof suffixOrSanitizer === 'function') { + // sanitize the value. + value = suffixOrSanitizer(value); + } else if (typeof suffixOrSanitizer === 'string') { + value = value + suffixOrSanitizer; + } else if (typeof value === 'object') { + value = stringify(unwrapSafeValue(value)); } - - if (classes && classes.length > StylingMapArrayIndex.ValuesStartPosition) { - if (!tNode.classes) { - tNode.classes = classes; - } - updateRawValueOnContext(tNode.classes, stylingMapToString(classes, true)); - } - - if (styles && styles.length > StylingMapArrayIndex.ValuesStartPosition) { - if (!tNode.styles) { - tNode.styles = styles; - } - updateRawValueOnContext(tNode.styles, stylingMapToString(styles, false)); - } - - if (hasAdditionalInitialStyling) { - tNode.flags |= TNodeFlags.hasInitialStyling; - } - - return hasAdditionalInitialStyling; + return value; } -function updateRawValueOnContext(context: TStylingContext | StylingMapArray, value: string) { - const stylingMapArr = getStylingMapArray(context) !; - stylingMapArr[StylingMapArrayIndex.RawValuePosition] = value; -} - -function getStylesContext(tNode: TNode): TStylingContext { - return getContext(tNode, false); -} - -function getClassesContext(tNode: TNode): TStylingContext { - return getContext(tNode, true); -} /** - * Returns/instantiates a styling context from/to a `tNode` instance. + * Tests if the `TNode` has input shadow. + * + * An input shadow is when a directive steals (shadows) the input by using `@Input('style')` or + * `@Input('class')` as input. + * + * @param tNode `TNode` which we would like to see if it has shadow. + * @param isClassBased `true` if `class` (`false` if `style`) */ -function getContext(tNode: TNode, isClassBased: boolean): TStylingContext { - let context = isClassBased ? tNode.classes : tNode.styles; - if (!isStylingContext(context)) { - const hasDirectives = isDirectiveHost(tNode); - context = allocTStylingContext(context as StylingMapArray | null, hasDirectives); - if (ngDevMode) { - attachStylingDebugObject(context as TStylingContext, tNode, isClassBased); - } - - if (isClassBased) { - tNode.classes = context; - } else { - tNode.styles = context; - } - } - return context as TStylingContext; -} - -function resolveStylePropValue( - value: string | number | SafeValue | null | NO_CHANGE, - suffix: string | null | undefined): string|SafeValue|null|undefined|NO_CHANGE { - if (value === NO_CHANGE) return value; - - let resolvedValue: string|null = null; - if (isStylingValueDefined(value)) { - if (suffix) { - // when a suffix is applied then it will bypass - // sanitization entirely (b/c a new string is created) - resolvedValue = renderStringify(value) + suffix; - } else { - // sanitization happens by dealing with a string value - // this means that the string value will be passed through - // into the style rendering later (which is where the value - // will be sanitized before it is applied) - resolvedValue = value as any as string; - } - } - return resolvedValue; -} - -/** - * Whether or not the style/class binding being applied was executed within a host bindings - * function. - */ -function isHostStyling(): boolean { - return isHostStylingActive(getActiveDirectiveId()); -} - -function patchHostStylingFlag(tNode: TNode, hostBindingsMode: boolean, isClassBased: boolean) { - const flag = hostBindingsMode ? - isClassBased ? TNodeFlags.hasHostClassBindings : TNodeFlags.hasHostStyleBindings : - isClassBased ? TNodeFlags.hasTemplateClassBindings : TNodeFlags.hasTemplateStyleBindings; - patchConfig(tNode, flag); +export function hasStylingInputShadow(tNode: TNode, isClassBased: boolean) { + return (tNode.flags & (isClassBased ? TNodeFlags.hasClassInput : TNodeFlags.hasStyleInput)) !== 0; } diff --git a/packages/core/src/render3/instructions/text.ts b/packages/core/src/render3/instructions/text.ts index 7f97e05c16..b7b1c90906 100644 --- a/packages/core/src/render3/instructions/text.ts +++ b/packages/core/src/render3/instructions/text.ts @@ -7,10 +7,9 @@ */ import {assertDataInRange, assertEqual} from '../../util/assert'; import {TElementNode, TNodeType} from '../interfaces/node'; -import {HEADER_OFFSET, RENDERER, TVIEW, T_HOST} from '../interfaces/view'; +import {HEADER_OFFSET, RENDERER, T_HOST} from '../interfaces/view'; import {appendChild, createTextNode} from '../node_manipulation'; -import {getBindingIndex, getLView, setPreviousOrParentTNode} from '../state'; - +import {getBindingIndex, getLView, getTView, setPreviousOrParentTNode} from '../state'; import {getOrCreateTNode} from './shared'; @@ -25,7 +24,7 @@ import {getOrCreateTNode} from './shared'; */ export function ɵɵtext(index: number, value: string = ''): void { const lView = getLView(); - const tView = lView[TVIEW]; + const tView = getTView(); const adjustedIndex = index + HEADER_OFFSET; ngDevMode && assertEqual( @@ -38,7 +37,7 @@ export function ɵɵtext(index: number, value: string = ''): void { tView.data[adjustedIndex] as TElementNode; const textNative = lView[adjustedIndex] = createTextNode(value, lView[RENDERER]); - appendChild(textNative, tNode, lView); + appendChild(tView, lView, textNative, tNode); // Text nodes are self closing. setPreviousOrParentTNode(tNode, false); diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index 6b49420f87..34f5538cb8 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -10,7 +10,7 @@ import {SchemaMetadata, ViewEncapsulation} from '../../core'; import {ProcessProvidersFunction} from '../../di/interface/provider'; import {Type} from '../../interface/type'; -import {TConstants} from './node'; +import {TAttributes, TConstants} from './node'; import {CssSelectorList} from './projection'; import {TView} from './view'; @@ -146,10 +146,50 @@ export interface DirectiveDef { /** * Refreshes host bindings on the associated directive. */ - hostBindings: HostBindingsFunction|null; + readonly hostBindings: HostBindingsFunction|null; + + /** + * The number of bindings in this directive `hostBindings` (including pure fn bindings). + * + * Used to calculate the length of the component's LView array, so we + * can pre-fill the array and set the host binding start index. + */ + readonly hostVars: number; + + /** + * Assign static attribute values to a host element. + * + * This property will assign static attribute values as well as class and style + * values to a host element. Since attribute values can consist of different types of values, the + * `hostAttrs` 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. + */ + readonly hostAttrs: TAttributes|null; /** Token representing the directive. Used by DI. */ - type: Type; + readonly type: Type; /** Function that resolves providers and publishes them into the DI system. */ providersResolver: @@ -168,17 +208,17 @@ export interface DirectiveDef { * Factory function used to create a new directive instance. Will be null initially. * Populated when the factory is first requested by directive instantiation logic. */ - factory: FactoryFn|null; + readonly factory: FactoryFn|null; /* The following are lifecycle hooks for this component */ - onChanges: (() => void)|null; - onInit: (() => void)|null; - doCheck: (() => void)|null; - afterContentInit: (() => void)|null; - afterContentChecked: (() => void)|null; - afterViewInit: (() => void)|null; - afterViewChecked: (() => void)|null; - onDestroy: (() => void)|null; + readonly onChanges: (() => void)|null; + readonly onInit: (() => void)|null; + readonly doCheck: (() => void)|null; + readonly afterContentInit: (() => void)|null; + readonly afterContentChecked: (() => void)|null; + readonly afterViewInit: (() => void)|null; + readonly afterViewChecked: (() => void)|null; + readonly onDestroy: (() => void)|null; /** * The features applied to this directive @@ -403,8 +443,7 @@ export type DirectiveTypeList = (DirectiveType| ComponentType| Type/* Type as workaround for: Microsoft/TypeScript/issues/4881 */)[]; -export type HostBindingsFunction = - (rf: RenderFlags, ctx: U, elementIndex: number) => void; +export type HostBindingsFunction = (rf: RenderFlags, ctx: U) => void; /** * Type used for PipeDefs on component definition. diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index bf52d5a1ec..e2d662f517 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -5,12 +5,16 @@ * 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 {StylingMapArray, TStylingContext} from '../interfaces/styling'; +import {KeyValueArray} from '../../util/array_utils'; +import {TStylingRange} from '../interfaces/styling'; + +import {DirectiveDef} from './definition'; import {CssSelector} from './projection'; import {RNode} from './renderer'; import {LView, TView} from './view'; + /** * TNodeType corresponds to the {@link TNode} `type` property. */ @@ -77,111 +81,6 @@ export const enum TNodeFlags { * that actually have directives with host bindings. */ hasHostBindings = 0x80, - - /** Bit #9 - This bit is set if the node has initial styling */ - hasInitialStyling = 0x100, - - /** - * Bit #10 - Whether or not there are class-based map bindings present. - * - * Examples include: - * 1. `
` - * 2. `@HostBinding('class') x` - */ - hasClassMapBindings = 0x200, - - /** - * Bit #11 - Whether or not there are any class-based prop bindings present. - * - * Examples include: - * 1. `
` - * 2. `@HostBinding('class.name') x` - */ - hasClassPropBindings = 0x400, - - /** - * Bit #12 - whether or not there are any active [class] and [class.name] bindings - */ - hasClassPropAndMapBindings = hasClassMapBindings | hasClassPropBindings, - - /** - * Bit #13 - Whether or not the context contains one or more class-based template bindings. - * - * Examples include: - * 1. `
` - * 2. `
` - */ - hasTemplateClassBindings = 0x800, - - /** - * Bit #14 - Whether or not the context contains one or more class-based host bindings. - * - * Examples include: - * 1. `@HostBinding('class') x` - * 2. `@HostBinding('class.name') x` - */ - hasHostClassBindings = 0x1000, - - /** - * Bit #15 - Whether or not there are two or more sources for a class property in the context. - * - * Examples include: - * 1. prop + prop: `
` - * 2. map + prop: `
` - * 3. map + map: `
` - */ - hasDuplicateClassBindings = 0x2000, - - /** - * Bit #16 - Whether or not there are style-based map bindings present. - * - * Examples include: - * 1. `
` - * 2. `@HostBinding('style') x` - */ - hasStyleMapBindings = 0x4000, - - /** - * Bit #17 - Whether or not there are any style-based prop bindings present. - * - * Examples include: - * 1. `
` - * 2. `@HostBinding('style.prop') x` - */ - hasStylePropBindings = 0x8000, - - /** - * Bit #18 - whether or not there are any active [style] and [style.prop] bindings - */ - hasStylePropAndMapBindings = hasStyleMapBindings | hasStylePropBindings, - - /** - * Bit #19 - Whether or not the context contains one or more style-based template bindings. - * - * Examples include: - * 1. `
` - * 2. `
` - */ - hasTemplateStyleBindings = 0x10000, - - /** - * Bit #20 - Whether or not the context contains one or more style-based host bindings. - * - * Examples include: - * 1. `@HostBinding('style') x` - * 2. `@HostBinding('style.prop') x` - */ - hasHostStyleBindings = 0x20000, - - /** - * Bit #21 - Whether or not there are two or more sources for a style property in the context. - * - * Examples include: - * 1. prop + prop: `
` - * 2. map + prop: `
` - * 3. map + map: `
` - */ - hasDuplicateStyleBindings = 0x40000, } /** @@ -201,6 +100,15 @@ export const enum TNodeProviderIndexes { * items are not regular attributes and the processing should be adapted accordingly. */ export const enum AttributeMarker { + /** + * An implicit marker which indicates that the value in the array are of `attributeKey`, + * `attributeValue` format. + * + * NOTE: This is implicit as it is the type when no marker is present in array. We indicate that + * it should not be present at runtime by the negative number. + */ + ImplicitAttributes = -1, + /** * Marker indicates that the following 3 values in the attributes array are: * namespaceUri, attributeName, attributeValue @@ -386,6 +294,24 @@ export interface TNode { */ directiveEnd: number; + /** + * Stores the last directive which had a styling instruction. + * + * Initial value of this is `-1` which means that no `hostBindings` styling instruction has + * executed. As `hostBindings` instructions execute they set the value to the index of the + * `DirectiveDef` which contained the last `hostBindings` styling instruction. + * + * Valid values are: + * - `-1` No `hostBindings` instruction has executed. + * - `directiveStart <= directiveStylingLast < directiveEnd`: Points to the `DirectiveDef` of the + * last styling instruction which executed in the `hostBindings`. + * + * This data is needed so that styling instructions know which static styling data needs to be + * collected from the `DirectiveDef.hostAttrs`. A styling instruction needs to collect all data + * since last styling instruction. + */ + directiveStylingLast: number; + /** * Stores indexes of property bindings. This field is only set in the ngDevMode and holds indexes * of property bindings so TestBed can get bound property metadata for a given node. @@ -425,6 +351,19 @@ export interface TNode { */ attrs: TAttributes|null; + /** + * Same as `TNode.attrs` but contains merged data across all directive host bindings. + * + * We need to keep `attrs` as unmerged so that it can be used for attribute selectors. + * We merge attrs here so that it can be used in a performant way for initial rendering. + * + * The `attrs` are merged in first pass in following order: + * - Component's `hostAttrs` + * - Directives' `hostAttrs` + * - Template `TNode.attrs` associated with the current `TNode`. + */ + mergedAttrs: TAttributes|null; + /** * A set of local names under which a given element is exported in a template and * visible to queries. An entry in this array can be created for different reasons: @@ -561,44 +500,92 @@ export interface TNode { projection: (TNode|RNode[])[]|number|null; /** - * A collection of all style bindings and/or static style values for an element. + * A collection of all style static values for an element. * * This field will be populated if and when: * * - There are one or more initial styles on an element (e.g. `
`) - * - There are one or more style bindings on an element (e.g. `
`) - * - * If and when there are only initial styles (no bindings) then an instance of `StylingMapArray` - * will be used here. Otherwise an instance of `TStylingContext` will be created when there - * are one or more style bindings on an element. - * - * During element creation this value is likely to be populated with an instance of - * `StylingMapArray` and only when the bindings are evaluated (which happens during - * update mode) then it will be converted to a `TStylingContext` if any style bindings - * are encountered. If and when this happens then the existing `StylingMapArray` value - * will be placed into the initial styling slot in the newly created `TStylingContext`. */ - styles: StylingMapArray|TStylingContext|null; + styles: string|null; /** - * A collection of all class bindings and/or static class values for an element. + * A `KeyValueArray` version of residual `styles`. + * + * When there are styling instructions than each instruction stores the static styling + * which is of lower priority than itself. This means that there may be a higher priority styling + * than the instruction. + * + * Imagine: + * ``` + *
+ * + * @Directive({ + * host: { + * style: 'color: lowest; ', + * '[styles.color]': 'exp' // ɵɵstyleProp('color', ctx.exp); + * } + * }) + * ``` + * + * In the above case: + * - `color: lowest` is stored with `ɵɵstyleProp('color', ctx.exp);` instruction + * - `color: highest` is the residual and is stored here. + * + * - `undefined': not initialized. + * - `null`: initialized but `styles` is `null` + * - `KeyValueArray`: parsed version of `styles`. + */ + residualStyles: KeyValueArray|undefined|null; + + /** + * A collection of all class static values for an element. * * This field will be populated if and when: * * - There are one or more initial classes on an element (e.g. `
`) - * - There are one or more class bindings on an element (e.g. `
`) - * - * If and when there are only initial classes (no bindings) then an instance of `StylingMapArray` - * will be used here. Otherwise an instance of `TStylingContext` will be created when there - * are one or more class bindings on an element. - * - * During element creation this value is likely to be populated with an instance of - * `StylingMapArray` and only when the bindings are evaluated (which happens during - * update mode) then it will be converted to a `TStylingContext` if any class bindings - * are encountered. If and when this happens then the existing `StylingMapArray` value - * will be placed into the initial styling slot in the newly created `TStylingContext`. */ - classes: StylingMapArray|TStylingContext|null; + classes: string|null; + + /** + * A `KeyValueArray` version of residual `classes`. + * + * Same as `TNode.residualStyles` but for classes. + * + * - `undefined': not initialized. + * - `null`: initialized but `classes` is `null` + * - `KeyValueArray`: parsed version of `classes`. + */ + residualClasses: KeyValueArray|undefined|null; + + /** + * Stores the head/tail index of the class bindings. + * + * - If no bindings, the head and tail will both be 0. + * - If there are template bindings, stores the head/tail of the class bindings in the template. + * - If no template bindings but there are host bindings, the head value will point to the last + * host binding for "class" (not the head of the linked list), tail will be 0. + * + * See: `style_binding_list.ts` for details. + * + * This is used by `insertTStylingBinding` to know where the next styling binding should be + * inserted so that they can be sorted in priority order. + */ + classBindings: TStylingRange; + + /** + * Stores the head/tail index of the class bindings. + * + * - If no bindings, the head and tail will both be 0. + * - If there are template bindings, stores the head/tail of the style bindings in the template. + * - If no template bindings but there are host bindings, the head value will point to the last + * host binding for "style" (not the head of the linked list), tail will be 0. + * + * See: `style_binding_list.ts` for details. + * + * This is used by `insertTStylingBinding` to know where the next styling binding should be + * inserted so that they can be sorted in priority order. + */ + styleBindings: TStylingRange; } /** Static data for an element */ @@ -788,3 +775,53 @@ export type TNodeWithLocalRefs = TContainerNode | TElementNode | TElementContain * - `` - `tplRef` should point to the `TemplateRef` instance; */ export type LocalRefExtractor = (tNode: TNodeWithLocalRefs, currentView: LView) => any; + +/** + * Returns `true` if the `TNode` has a directive which has `@Input()` for `class` binding. + * + * ``` + *
+ * ``` + * and + * ``` + * @Directive({ + * }) + * class MyDirective { + * @Input() + * class: string; + * } + * ``` + * + * In the above case it is necessary to write the reconciled styling information into the + * directive's input. + * + * @param tNode + */ +export function hasClassInput(tNode: TNode) { + return (tNode.flags & TNodeFlags.hasClassInput) !== 0; +} + +/** + * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding. + * + * ``` + *
+ * ``` + * and + * ``` + * @Directive({ + * }) + * class MyDirective { + * @Input() + * class: string; + * } + * ``` + * + * In the above case it is necessary to write the reconciled styling information into the + * directive's input. + * + * @param tNode + */ +export function hasStyleInput(tNode: TNode) { + return (tNode.flags & TNodeFlags.hasStyleInput) !== 0; +} diff --git a/packages/core/src/render3/interfaces/styling.ts b/packages/core/src/render3/interfaces/styling.ts index 04a88399ed..e80ed1fbae 100644 --- a/packages/core/src/render3/interfaces/styling.ts +++ b/packages/core/src/render3/interfaces/styling.ts @@ -5,469 +5,214 @@ * 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 {StyleSanitizeFn} from '../../sanitization/style_sanitizer'; - -import {TNodeFlags} from './node'; -import {ProceduralRenderer3, RElement, Renderer3} from './renderer'; -import {LView} from './view'; +import {KeyValueArray} from '../../util/array_utils'; +import {assertNumber, assertNumberInRange} from '../../util/assert'; /** - * -------- + * Value stored in the `TData` which is needed to re-concatenate the styling. * - * This file contains the core interfaces for styling in Angular. - * - * To learn more about the algorithm see `TStylingContext`. - * - * -------- + * See: `TStylingKeyPrimitive` and `TStylingStatic` */ +export type TStylingKey = TStylingKeyPrimitive | TStylingStatic; + /** - * A static-level representation of all style or class bindings/values - * associated with a `TNode`. + * The primitive portion (`TStylingStatic` removed) of the value stored in the `TData` which is + * needed to re-concatenate the styling. * - * The `TStylingContext` unites all template styling bindings (i.e. - * `[class]` and `[style]` bindings) as well as all host-level - * styling bindings (for components and directives) together into - * a single manifest + * - `string`: Stores the property name. Used with `ɵɵstyleProp`/`ɵɵclassProp` instruction. + * - `null`: Represents map, so there is no name. Used with `ɵɵstyleMap`/`ɵɵclassMap`. + * - `false`: Represents an ignore case. This happens when `ɵɵstyleProp`/`ɵɵclassProp` instruction + * is combined with directive which shadows its input `@Input('class')`. That way the binding + * should not participate in the styling resolution. + */ +export type TStylingKeyPrimitive = string | null | false; + +/** + * Store the static values for the styling binding. * - * The styling context is stored on a `TNode` on and there are - * two instances of it: one for classes and another for styles. + * The `TStylingStatic` is just `KeyValueArray` where key `""` (stored at location 0) contains the + * `TStylingKey` (stored at location 1). In other words this wraps the `TStylingKey` such that the + * `""` contains the wrapped value. * - * ```typescript - * tNode.styles = [ ... a context only for styles ... ]; - * tNode.classes = [ ... a context only for classes ... ]; - * ``` + * When instructions are resolving styling they may need to look forward or backwards in the linked + * list to resolve the value. For this reason we have to make sure that he linked list also contains + * the static values. However the list only has space for one item per styling instruction. For this + * reason we store the static values here as part of the `TStylingKey`. This means that the + * resolution function when looking for a value needs to first look at the binding value, and than + * at `TStylingKey` (if it exists). * - * The styling context is created each time there are one or more - * styling bindings (style or class bindings) present for an element, - * but is only created once per `TNode`. - * - * `tNode.styles` and `tNode.classes` can be an instance of the following: - * - * ```typescript - * tNode.styles = null; // no static styling or styling bindings active - * tNode.styles = StylingMapArray; // only static values present (e.g. `
`) - * tNode.styles = TStylingContext; // one or more styling bindings present (e.g. `
`) - * ``` - * - * Both `tNode.styles` and `tNode.classes` are instantiated when anything - * styling-related is active on an element. They are first created from - * from the any of the element-level instructions (e.g. `element`, - * `elementStart`, `elementHostAttrs`). When any static style/class - * values are encountered they are registered on the `tNode.styles` - * and `tNode.classes` data-structures. By default (when any static - * values are encountered) the `tNode.styles` or `tNode.classes` values - * are instances of a `StylingMapArray`. Only when style/class bindings - * are detected then that styling map is converted into an instance of - * `TStylingContext`. - * - * Due to the fact the the `TStylingContext` is stored on a `TNode` - * this means that all data within the context is static. Instead of - * storing actual styling binding values, the lView binding index values - * are stored within the context. (static nature means it is more compact.) - * - * The code below shows a breakdown of two instances of `TStylingContext` - * (one for `tNode.styles` and another for `tNode.classes`): - * - * ```typescript - * //
// lView binding index = 22 - * // ... - * //
- * tNode.styles = [ - * 1, // the total amount of sources present (only `1` b/c there are only template - * bindings) - * [null], // initial values array (an instance of `StylingMapArray`) - * - * 0, // config entry for the property (see `TStylingContextPropConfigFlags`) - * 0b010, // template guard mask for height - * 0, // host bindings guard mask for height - * 'height', // the property name - * 22, // the binding location for the "y" binding in the lView - * null, // the default value for height - * - * 0, // config entry for the property (see `TStylingContextPropConfigFlags`) - * 0b001, // template guard mask for width - * 0, // host bindings guard mask for width - * 'width', // the property name - * 21, // the binding location for the "x" binding in the lView - * null, // the default value for width - * ]; - * - * tNode.classes = [ - * 0, // the context config value (see `TStylingContextConfig`) - * 1, // the total amount of sources present (only `1` b/c there are only template - * bindings) - * [null], // initial values array (an instance of `StylingMapArray`) - * - * 0, // config entry for the property (see `TStylingContextPropConfigFlags`) - * 0b001, // template guard mask for width - * 0, // host bindings guard mask for width - * 'active', // the property name - * 20, // the binding location for the "c" binding in the lView - * null, // the default value for the `active` class - * ]; - * ``` - * - * Entry value present in an entry (called a tuple) within the - * styling context is as follows: - * - * ```typescript - * context = [ - * //... - * configValue, - * templateGuardMask, - * hostBindingsGuardMask, - * propName, - * ...bindingIndices..., - * defaultValue - * //... - * ]; - * ``` - * - * Below is a breakdown of each value: - * - * - **configValue**: - * Property-specific configuration values. The only config setting - * that is implemented right now is whether or not to sanitize the - * value. - * - * - **templateGuardMask**: - * A numeric value where each bit represents a binding index - * location. Each binding index location is assigned based on - * a local counter value that increments each time an instruction - * is called: + * Imagine we have: * * ``` - *
// binding index = 22 (counter index = 1) - * ``` + *
* - * In the example code above, if the `width` value where to change - * then the first bit in the local bit mask value would be flipped - * (and the second bit for when `height`). - * - * If and when there are more than 32 binding sources in the context - * (more than 32 `[style/class]` bindings) then the bit masking will - * overflow and we are left with a situation where a `-1` value will - * represent the bit mask. Due to the way that JavaScript handles - * negative values, when the bit mask is `-1` then all bits within - * that value will be automatically flipped (this is a quick and - * efficient way to flip all bits on the mask when a special kind - * of caching scenario occurs or when there are more than 32 bindings). - * - * - **hostBindingsGuardMask**: - * Another instance of a guard mask that is specific to host bindings. - * This behaves exactly the same way as does the `templateGuardMask`, - * but will not contain any binding information processed in the template. - * The reason why there are two instances of guard masks (one for the - * template and another for host bindings) is because the template bindings - * are processed before host bindings and the state information is not - * carried over into the host bindings code. As soon as host bindings are - * processed for an element the counter and state-based bit mask values are - * set to `0`. - * - * ``` - *
// binding index = 31 (counter index = 1) - * ``` - * - * - **propName**: - * The CSS property name or class name (e.g `width` or `active`). - * - * - **bindingIndices...**: - * A series of numeric binding values that reflect where in the - * lView to find the style/class values associated with the property. - * Each value is in order in terms of priority (templates are first, - * then directives and then components). When the context is flushed - * and the style/class values are applied to the element (this happens - * inside of the `stylingApply` instruction) then the flushing code - * will keep checking each binding index against the associated lView - * to find the first style/class value that is non-null. - * - * - **defaultValue**: - * This is the default that will always be applied to the element if - * and when all other binding sources return a result that is null. - * Usually this value is `null` but it can also be a static value that - * is intercepted when the tNode is first constructured (e.g. - * `
` has a default value of `200px` for - * the `width` property). - * - * Each time a new binding is encountered it is registered into the - * context. The context then is continually updated until the first - * styling apply call has been called (which is automatically scheduled - * to be called once an element exits during change detection). Note that - * each entry in the context is stored in alphabetical order. - * - * Once styling has been flushed for the first time for an element the - * context will set as locked (this prevents bindings from being added - * to the context later on). - * - * # How Styles/Classes are Rendered - * Each time a styling instruction (e.g. `[class.name]`, `[style.prop]`, - * etc...) is executed, the associated `lView` for the view is updated - * at the current binding location. Also, when this happens, a local - * counter value is incremented. If the binding value has changed then - * a local `bitMask` variable is updated with the specific bit based - * on the counter value. - * - * Below is a lightweight example of what happens when a single style - * property is updated (i.e. `
`): - * - * ```typescript - * function updateStyleProp(prop: string, value: string) { - * const lView = getLView(); - * const bindingIndex = BINDING_INDEX++; - * - * // update the local counter value - * const indexForStyle = stylingState.stylesCount++; - * if (lView[bindingIndex] !== value) { - * lView[bindingIndex] = value; - * - * // tell the local state that we have updated a style value - * // by updating the bit mask - * stylingState.bitMaskForStyles |= 1 << indexForStyle; + * @Directive({ + * host: { + * class: 'DIR', + * '[class.dynamic]': 'exp' // ɵɵclassProp('dynamic', ctx.exp); * } - * } + * }) * ``` * - * Once all the bindings have updated a `bitMask` value will be populated. - * This `bitMask` value is used in the apply algorithm (which is called - * context resolution). + * In the above case the linked list will contain one item: * - * ## The Apply Algorithm (Context Resolution) - * As explained above, each time a binding updates its value, the resulting - * value is stored in the `lView` array. These styling values have yet to - * be flushed to the element. + * ``` + * // assume binding location: 10 for `ɵɵclassProp('dynamic', ctx.exp);` + * tData[10] = [ + * '': 'dynamic', // This is the wrapped value of `TStylingKey` + * 'DIR': true, // This is the default static value of directive binding. + * ]; + * tData[10 + 1] = 0; // We don't have prev/next. * - * Once all the styling instructions have been evaluated, then the styling - * context(s) are flushed to the element. When this happens, the context will - * be iterated over (property by property) and each binding source will be - * examined and the first non-null value will be applied to the element. - * - * Let's say that we the following template code: - * - * ```html - *
+ * lView[10] = undefined; // assume `ctx.exp` is `undefined` + * lView[10 + 1] = undefined; // Just normalized `lView[10]` * ``` * - * There are two styling bindings in the code above and they both write - * to the `width` property. When styling is flushed on the element, the - * algorithm will try and figure out which one of these values to write - * to the element. + * So when the function is resolving styling value, it first needs to look into the linked list + * (there is none) and than into the static `TStylingStatic` too see if there is a default value for + * `dynamic` (there is not). Therefore it is safe to remove it. * - * In order to figure out which value to apply, the following - * binding prioritization is adhered to: + * If setting `true` case: + * ``` + * lView[10] = true; // assume `ctx.exp` is `true` + * lView[10 + 1] = true; // Just normalized `lView[10]` + * ``` + * So when the function is resolving styling value, it first needs to look into the linked list + * (there is none) and than into `TNode.residualClass` (TNode.residualStyle) which contains + * ``` + * tNode.residualClass = [ + * 'TEMPLATE': true, + * ]; + * ``` * - * 1. First template-level styling bindings are applied (if present). - * This includes things like `[style.width]` and `[class.active]`. - * - * 2. Second are styling-level host bindings present in directives. - * (if there are sub/super directives present then the sub directives - * are applied first). - * - * 3. Third are styling-level host bindings present in components. - * (if there are sub/super components present then the sub directives - * are applied first). - * - * This means that in the code above the styling binding present in the - * template is applied first and, only if its falsy, then the directive - * styling binding for width will be applied. - * - * ### What about map-based styling bindings? - * Map-based styling bindings are activated when there are one or more - * `[style]` and/or `[class]` bindings present on an element. When this - * code is activated, the apply algorithm will iterate over each map - * entry and apply each styling value to the element with the same - * prioritization rules as above. - * - * For the algorithm to apply styling values efficiently, the - * styling map entries must be applied in sync (property by property) - * with prop-based bindings. (The map-based algorithm is described - * more inside of the `render3/styling/map_based_bindings.ts` file.) - * - * ## Sanitization - * Sanitization is used to prevent invalid style values from being applied to - * the element. - * - * It is enabled in two cases: - * - * 1. The `styleSanitizer(sanitizerFn)` instruction was called (just before any other - * styling instructions are run). - * - * 2. The component/directive `LView` instance has a sanitizer object attached to it - * (this happens when `renderComponent` is executed with a `sanitizer` value or - * if the ngModule contains a sanitizer provider attached to it). - * - * If and when sanitization is active then all property/value entries will be evaluated - * through the active sanitizer before they are applied to the element (or the styling - * debug handler). - * - * If a `Sanitizer` object is used (via the `LView[SANITIZER]` value) then that object - * will be used for every property. - * - * If a `StyleSanitizerFn` function is used (via the `styleSanitizer`) then it will be - * called in two ways: - * - * 1. property validation mode: this will be called early to mark whether a property - * should be sanitized or not at during the flushing stage. - * - * 2. value sanitization mode: this will be called during the flushing stage and will - * run the sanitizer function against the value before applying it to the element. - * - * If sanitization returns an empty value then that empty value will be applied - * to the element. + * This means that it is safe to add class. */ -export interface TStylingContext extends - Array { - /** The total amount of sources present in the context */ - [TStylingContextIndex.TotalSourcesPosition]: number; - - /** Initial value position for static styles */ - [TStylingContextIndex.InitialStylingValuePosition]: StylingMapArray; -} +export interface TStylingStatic extends KeyValueArray {} /** - * An index of position and offset values used to navigate the `TStylingContext`. - */ -export const enum TStylingContextIndex { - TotalSourcesPosition = 0, - InitialStylingValuePosition = 1, - ValuesStartPosition = 2, - - // each tuple entry in the context - // (config, templateBitGuard, hostBindingBitGuard, prop, ...bindings||default-value) - ConfigOffset = 0, - TemplateBitGuardOffset = 1, - HostBindingsBitGuardOffset = 2, - PropOffset = 3, - BindingsStartOffset = 4 -} - -/** - * A series of flags used for each property entry within the `TStylingContext`. - */ -export const enum TStylingContextPropConfigFlags { - Default = 0b0, - SanitizationRequired = 0b1, - TotalBits = 1, - Mask = 0b1, -} - -/** - * A function used to apply or remove styling from an element for a given property. - */ -export interface ApplyStylingFn { - (renderer: Renderer3|ProceduralRenderer3|null, element: RElement, prop: string, value: any, - bindingIndex?: number|null): void; -} - -/** - * Runtime data type that is used to store binding data referenced from the `TStylingContext`. + * This is a branded number which contains previous and next index. * - * Because `LView` is just an array with data, there is no reason to - * special case `LView` everywhere in the styling algorithm. By allowing - * this data type to be an array that contains various scalar data types, - * an instance of `LView` doesn't need to be constructed for tests. + * When we come across styling instructions we need to store the `TStylingKey` in the correct + * order so that we can re-concatenate the styling value in the desired priority. + * + * The insertion can happen either at the: + * - end of template as in the case of coming across additional styling instruction in the template + * - in front of the template in the case of coming across additional instruction in the + * `hostBindings`. + * + * We use `TStylingRange` to store the previous and next index into the `TData` where the template + * bindings can be found. + * + * - bit 0 is used to mark that the previous index has a duplicate for current value. + * - bit 1 is used to mark that the next index has a duplicate for the current value. + * - bits 2-16 are used to encode the next/tail of the template. + * - bits 17-32 are used to encode the previous/head of template. + * + * NODE: *duplicate* false implies that it is statically known that this binding will not collide + * with other bindings and therefore there is no need to check other bindings. For example the + * bindings in `
` will never collide and will have + * their bits set accordingly. Previous duplicate means that we may need to check previous if the + * current binding is `null`. Next duplicate means that we may need to check next bindings if the + * current binding is not `null`. + * + * NOTE: `0` has special significance and represents `null` as in no additional pointer. */ -export type LStylingData = LView | (string | number | boolean | null)[]; +export interface TStylingRange { __brand__: 'TStylingRange'; } /** - * Array-based representation of a key/value array. - * - * The format of the array is "property", "value", "property2", - * "value2", etc... - * - * The first value in the array is reserved to store the instance - * of the key/value array that was used to populate the property/ - * value entries that take place in the remainder of the array. + * Shift and masks constants for encoding two numbers into and duplicate info into a single number. */ -export interface StylingMapArray extends Array<{}|string|number|null|undefined> { +export const enum StylingRange { + /// Number of bits to shift for the previous pointer + PREV_SHIFT = 17, + /// Previous pointer mask. + PREV_MASK = 0xFFFE0000, + + /// Number of bits to shift for the next pointer + NEXT_SHIFT = 2, + /// Next pointer mask. + NEXT_MASK = 0x001FFFC, + + // Mask to remove nagative bit. (interpret number as positive) + UNSIGNED_MASK = 0x7FFF, + /** - * The last raw value used to generate the entries in the map. + * This bit is set if the previous bindings contains a binding which could possibly cause a + * duplicate. For example: `
`, the `width` binding will + * have previous duplicate set. The implication is that if `width` binding becomes `null`, it is + * necessary to defer the value to `map.width`. (Because `width` overwrites `map.width`.) */ - [StylingMapArrayIndex.RawValuePosition]: {}|string|number|null|undefined; + PREV_DUPLICATE = 0x02, + + /** + * This bit is set to if the next binding contains a binding which could possibly cause a + * duplicate. For example: `
`, the `map` binding will + * have next duplicate set. The implication is that if `map.width` binding becomes not `null`, it + * is necessary to defer the value to `width`. (Because `width` overwrites `map.width`.) + */ + NEXT_DUPLICATE = 0x01, } -/** - * An index of position and offset points for any data stored within a `StylingMapArray` instance. - */ -export const enum StylingMapArrayIndex { - /** Where the values start in the array */ - ValuesStartPosition = 1, - /** The location of the raw key/value map instance used last to populate the array entries */ - RawValuePosition = 0, - - /** The size of each property/value entry */ - TupleSize = 2, - - /** The offset for the property entry in the tuple */ - PropOffset = 0, - - /** The offset for the value entry in the tuple */ - ValueOffset = 1, +export function toTStylingRange(prev: number, next: number): TStylingRange { + ngDevMode && assertNumberInRange(prev, 0, StylingRange.UNSIGNED_MASK); + ngDevMode && assertNumberInRange(next, 0, StylingRange.UNSIGNED_MASK); + return (prev << StylingRange.PREV_SHIFT | next << StylingRange.NEXT_SHIFT) as any; } -/** - * Used to apply/traverse across all map-based styling entries up to the provided `targetProp` - * value. - * - * When called, each of the map-based `StylingMapArray` entries (which are stored in - * the provided `LStylingData` array) will be iterated over. Depending on the provided - * `mode` value, each prop/value entry may be applied or skipped over. - * - * If `targetProp` value is provided the iteration code will stop once it reaches - * the property (if found). Otherwise if the target property is not encountered then - * it will stop once it reaches the next value that appears alphabetically after it. - * - * If a `defaultValue` is provided then it will be applied to the element only if the - * `targetProp` property value is encountered and the value associated with the target - * property is `null`. The reason why the `defaultValue` is needed is to avoid having the - * algorithm apply a `null` value and then apply a default value afterwards (this would - * end up being two style property writes). - * - * @returns whether or not the target property was reached and its value was - * applied to the element. - */ -export interface SyncStylingMapsFn { - (context: TStylingContext, renderer: Renderer3|ProceduralRenderer3|null, element: RElement, - data: LStylingData, sourceIndex: number, applyStylingFn: ApplyStylingFn, - sanitizer: StyleSanitizeFn|null, mode: StylingMapsSyncMode, targetProp?: string|null, - defaultValue?: boolean|string|null): boolean; +export function getTStylingRangePrev(tStylingRange: TStylingRange): number { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + return ((tStylingRange as any as number) >> StylingRange.PREV_SHIFT) & StylingRange.UNSIGNED_MASK; } -/** - * Used to direct how map-based values are applied/traversed when styling is flushed. - */ -export const enum StylingMapsSyncMode { - /** Only traverse values (no prop/value styling entries get applied) */ - TraverseValues = 0b000, - - /** Apply every prop/value styling entry to the element */ - ApplyAllValues = 0b001, - - /** Only apply the target prop/value entry */ - ApplyTargetProp = 0b010, - - /** Skip applying the target prop/value entry */ - SkipTargetProp = 0b100, - - /** Iterate over inner maps map values in the context */ - RecurseInnerMaps = 0b1000, - - /** Only check to see if a value was set somewhere in each map */ - CheckValuesOnly = 0b10000, +export function getTStylingRangePrevDuplicate(tStylingRange: TStylingRange): boolean { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + return ((tStylingRange as any as number) & StylingRange.PREV_DUPLICATE) == + StylingRange.PREV_DUPLICATE; } -/** - * Simplified `TNode` interface for styling-related code. - * - * The styling algorithm code only needs access to `flags`. - */ -export interface TStylingNode { flags: TNodeFlags; } +export function setTStylingRangePrev( + tStylingRange: TStylingRange, previous: number): TStylingRange { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + ngDevMode && assertNumberInRange(previous, 0, StylingRange.UNSIGNED_MASK); + return ( + ((tStylingRange as any as number) & ~StylingRange.PREV_MASK) | + (previous << StylingRange.PREV_SHIFT)) as any; +} + +export function setTStylingRangePrevDuplicate(tStylingRange: TStylingRange): TStylingRange { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + return ((tStylingRange as any as number) | StylingRange.PREV_DUPLICATE) as any; +} + +export function getTStylingRangeNext(tStylingRange: TStylingRange): number { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + return ((tStylingRange as any as number) & StylingRange.NEXT_MASK) >> StylingRange.NEXT_SHIFT; +} + +export function setTStylingRangeNext(tStylingRange: TStylingRange, next: number): TStylingRange { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + ngDevMode && assertNumberInRange(next, 0, StylingRange.UNSIGNED_MASK); + return ( + ((tStylingRange as any as number) & ~StylingRange.NEXT_MASK) | // + next << StylingRange.NEXT_SHIFT) as any; +} + +export function getTStylingRangeNextDuplicate(tStylingRange: TStylingRange): boolean { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + return ((tStylingRange as any as number) & StylingRange.NEXT_DUPLICATE) === + StylingRange.NEXT_DUPLICATE; +} + +export function setTStylingRangeNextDuplicate(tStylingRange: TStylingRange): TStylingRange { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + return ((tStylingRange as any as number) | StylingRange.NEXT_DUPLICATE) as any; +} + +export function getTStylingRangeTail(tStylingRange: TStylingRange): number { + ngDevMode && assertNumber(tStylingRange, 'expected number'); + const next = getTStylingRangeNext(tStylingRange); + return next === 0 ? getTStylingRangePrev(tStylingRange) : next; +} \ No newline at end of file diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index c7468a3c5f..9a7e4ee0f8 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -15,10 +15,11 @@ import {Sanitizer} from '../../sanitization/sanitizer'; import {LContainer} from './container'; import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, HostBindingsFunction, PipeDef, PipeDefList, ViewQueriesFunction} from './definition'; import {I18nUpdateOpCodes, TI18n} from './i18n'; -import {TAttributes, TConstants, TElementNode, TNode, TViewNode} from './node'; +import {TConstants, TElementNode, TNode, TViewNode} from './node'; import {PlayerHandler} from './player'; import {LQueries, TQueries} from './query'; import {RElement, Renderer3, RendererFactory3} from './renderer'; +import {TStylingKey, TStylingRange} from './styling'; @@ -470,7 +471,17 @@ export interface TView { /** Whether or not this template has been processed in creation mode. */ firstCreatePass: boolean; - /** Whether or not the first update for this template has been processed. */ + /** + * Whether or not this template has been processed in update mode (e.g. change detected) + * + * `firstUpdatePass` is used by styling to set up `TData` to contain metadata about the styling + * instructions. (Mainly to build up a linked list of styling priority order.) + * + * Typically this function gets cleared after first execution. If exception is thrown then this + * flag can remain turned un until there is first successful (no exception) pass. This means that + * individual styling instructions keep track of if they have already been added to the linked + * list to prevent double adding. + */ firstUpdatePass: boolean; /** Static data equivalent of LView.data[]. Contains TNodes, PipeDefInternal or TI18n. */ @@ -524,6 +535,8 @@ export interface TView { * * See VIEW_DATA.md for more information. */ + // TODO(misko): `expandoInstructions` should be renamed to `hostBindingsInstructions` since they + // keep track of `hostBindings` which need to be executed. expandoInstructions: ExpandoInstructions|null; /** @@ -751,8 +764,8 @@ export type HookData = (number | (() => void))[]; * Injector bloom filters are also stored here. */ export type TData = - (TNode | PipeDef| DirectiveDef| ComponentDef| number | Type| - InjectionToken| TI18n | I18nUpdateOpCodes | null | string)[]; + (TNode | PipeDef| DirectiveDef| ComponentDef| number | TStylingRange | + TStylingKey | Type| 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/environment.ts b/packages/core/src/render3/jit/environment.ts index 5e4612edb2..444869543a 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -58,7 +58,6 @@ export const angularCoreEnv: {[name: string]: Function} = 'ɵɵnamespaceSVG': r3.ɵɵnamespaceSVG, 'ɵɵenableBindings': r3.ɵɵenableBindings, 'ɵɵdisableBindings': r3.ɵɵdisableBindings, - 'ɵɵallocHostVars': r3.ɵɵallocHostVars, 'ɵɵelementStart': r3.ɵɵelementStart, 'ɵɵelementEnd': r3.ɵɵelementEnd, 'ɵɵelement': r3.ɵɵelement, @@ -107,7 +106,6 @@ export const angularCoreEnv: {[name: string]: Function} = 'ɵɵloadQuery': r3.ɵɵloadQuery, 'ɵɵcontentQuery': r3.ɵɵcontentQuery, 'ɵɵreference': r3.ɵɵreference, - 'ɵɵelementHostAttrs': r3.ɵɵelementHostAttrs, 'ɵɵclassMap': r3.ɵɵclassMap, 'ɵɵclassMapInterpolate1': r3.ɵɵclassMapInterpolate1, 'ɵɵclassMapInterpolate2': r3.ɵɵclassMapInterpolate2, diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 1f22e6da4f..50c33997e4 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ +import {Renderer2} from '../core'; import {ViewEncapsulation} from '../metadata/view'; import {addToArray, removeFromArray} from '../util/array_utils'; -import {assertDefined, assertDomNode, assertEqual} from '../util/assert'; +import {assertDefined, assertDomNode, assertEqual, assertString} from '../util/assert'; import {assertLContainer, assertLView, assertTNodeForLView} from './assert'; import {attachPatchData} from './context_discovery'; import {ACTIVE_INDEX, ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS, NATIVE, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; @@ -18,7 +19,7 @@ import {TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode, import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; import {ProceduralRenderer3, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; import {isLContainer, isLView} from './interfaces/type_checks'; -import {CHILD_HEAD, CLEANUP, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, FLAGS, HOST, HookData, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, T_HOST, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; +import {CHILD_HEAD, CLEANUP, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, FLAGS, HOST, HookData, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, TView, T_HOST, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; import {getLViewParent} from './util/view_traversal_utils'; import {getNativeByTNode, unwrapRNode} from './util/view_utils'; @@ -129,31 +130,34 @@ export function createTextNode(value: string, renderer: Renderer3): RText { * to propagate deeply into the nested containers to remove all elements in the * views beneath it. * + * @param tView The `TView' of the `LView` from which elements should be added or removed * @param lView The view from which elements should be added or removed * @param insertMode Whether or not elements should be added (if false, removing) * @param beforeNode The node before which elements should be added, if insert mode */ export function addRemoveViewFromContainer( - lView: LView, insertMode: true, beforeNode: RNode | null): void; -export function addRemoveViewFromContainer(lView: LView, insertMode: false, beforeNode: null): void; + tView: TView, lView: LView, insertMode: true, beforeNode: RNode | null): void; export function addRemoveViewFromContainer( - lView: LView, insertMode: boolean, beforeNode: RNode | null): void { - const renderParent = getContainerRenderParent(lView[TVIEW].node as TViewNode, lView); - ngDevMode && assertNodeType(lView[TVIEW].node as TNode, TNodeType.View); + tView: TView, lView: LView, insertMode: false, beforeNode: null): void; +export function addRemoveViewFromContainer( + tView: TView, lView: LView, insertMode: boolean, beforeNode: RNode | null): void { + const renderParent = getContainerRenderParent(tView.node as TViewNode, lView); + ngDevMode && assertNodeType(tView.node as TNode, TNodeType.View); if (renderParent) { const renderer = lView[RENDERER]; const action = insertMode ? WalkTNodeTreeAction.Insert : WalkTNodeTreeAction.Detach; - applyView(renderer, action, lView, renderParent, beforeNode); + applyView(tView, lView, renderer, action, renderParent, beforeNode); } } /** * Detach a `LView` from the DOM by detaching its nodes. * + * @param tView The `TView' of the `LView` to be detached * @param lView the `LView` to be detached. */ -export function renderDetachView(lView: LView) { - applyView(lView[RENDERER], WalkTNodeTreeAction.Detach, lView, null, null); +export function renderDetachView(tView: TView, lView: LView) { + applyView(tView, lView, lView[RENDERER], WalkTNodeTreeAction.Detach, null, null); } /** @@ -173,7 +177,7 @@ export function destroyViewTree(rootView: LView): void { // If the view has no children, we can clean it up and return early. let lViewOrLContainer = rootView[CHILD_HEAD]; if (!lViewOrLContainer) { - return cleanUpView(rootView); + return cleanUpView(rootView[TVIEW], rootView); } while (lViewOrLContainer) { @@ -193,10 +197,11 @@ export function destroyViewTree(rootView: LView): void { // Only clean up view when moving to the side or up, as destroy hooks // should be called in order from the bottom up. while (lViewOrLContainer && !lViewOrLContainer ![NEXT] && lViewOrLContainer !== rootView) { - cleanUpView(lViewOrLContainer); + isLView(lViewOrLContainer) && cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer); lViewOrLContainer = getParentState(lViewOrLContainer, rootView); } - cleanUpView(lViewOrLContainer || rootView); + if (lViewOrLContainer === null) lViewOrLContainer = rootView; + isLView(lViewOrLContainer) && cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer); next = lViewOrLContainer && lViewOrLContainer ![NEXT]; } lViewOrLContainer = next; @@ -211,11 +216,12 @@ export function destroyViewTree(rootView: LView): void { * root node of another view (in that case, the view's elements will be added when * the container's parent view is added later). * + * @param tView The `TView' of the `LView` to insert * @param lView The view to insert * @param lContainer The container into which the view should be inserted * @param index Which index in the container to insert the child view into */ -export function insertView(lView: LView, lContainer: LContainer, index: number) { +export function insertView(tView: TView, lView: LView, lContainer: LContainer, index: number) { ngDevMode && assertLView(lView); ngDevMode && assertLContainer(lContainer); const indexInContainer = CONTAINER_HEADER_OFFSET + index; @@ -244,7 +250,7 @@ export function insertView(lView: LView, lContainer: LContainer, index: number) // notify query that a new view has been added const lQueries = lView[QUERIES]; if (lQueries !== null) { - lQueries.insertView(lView[TVIEW]); + lQueries.insertView(tView); } // Sets the attached flag @@ -320,7 +326,7 @@ export function detachView(lContainer: LContainer, removeIndex: number): LView|u lContainer[indexInContainer - 1][NEXT] = viewToDetach[NEXT] as LView; } const removedLView = removeFromArray(lContainer, CONTAINER_HEADER_OFFSET + removeIndex); - addRemoveViewFromContainer(viewToDetach, false, null); + addRemoveViewFromContainer(viewToDetach[TVIEW], viewToDetach, false, null); // notify query that a view has been removed const lQueries = removedLView[QUERIES]; @@ -344,20 +350,21 @@ export function detachView(lContainer: LContainer, removeIndex: number): LView|u */ export function removeView(lContainer: LContainer, removeIndex: number) { const detachedView = detachView(lContainer, removeIndex); - detachedView && destroyLView(detachedView); + detachedView && destroyLView(detachedView[TVIEW], detachedView); } /** * A standalone function which destroys an LView, - * conducting cleanup (e.g. removing listeners, calling onDestroys). + * conducting clean up (e.g. removing listeners, calling onDestroys). * + * @param tView The `TView' of the `LView` to be destroyed * @param lView The view to be destroyed. */ -export function destroyLView(lView: LView) { +export function destroyLView(tView: TView, lView: LView) { if (!(lView[FLAGS] & LViewFlags.Destroyed)) { const renderer = lView[RENDERER]; if (isProceduralRenderer(renderer) && renderer.destroyNode) { - applyView(renderer, WalkTNodeTreeAction.Destroy, lView, null, null); + applyView(tView, lView, renderer, WalkTNodeTreeAction.Destroy, null, null); } destroyViewTree(lView); @@ -395,50 +402,52 @@ export function getParentState(lViewOrLContainer: LView | LContainer, rootView: * listeners. Listeners are removed as the last step so events delivered in the onDestroys hooks * can be propagated to @Output listeners. * - * @param view The LView to clean up + * @param tView `TView` for the `LView` to clean up. + * @param lView The LView to clean up */ -function cleanUpView(view: LView | LContainer): void { - if (isLView(view) && !(view[FLAGS] & LViewFlags.Destroyed)) { +function cleanUpView(tView: TView, lView: LView): void { + if (!(lView[FLAGS] & LViewFlags.Destroyed)) { // Usually the Attached flag is removed when the view is detached from its parent, however // if it's a root view, the flag won't be unset hence why we're also removing on destroy. - view[FLAGS] &= ~LViewFlags.Attached; + lView[FLAGS] &= ~LViewFlags.Attached; // 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; + lView[FLAGS] |= LViewFlags.Destroyed; - executeOnDestroys(view); - removeListeners(view); - const hostTNode = view[T_HOST]; + executeOnDestroys(tView, lView); + removeListeners(tView, lView); + const hostTNode = lView[T_HOST]; // For component views only, the local renderer is destroyed as clean up time. - if (hostTNode && hostTNode.type === TNodeType.Element && isProceduralRenderer(view[RENDERER])) { + if (hostTNode && hostTNode.type === TNodeType.Element && + isProceduralRenderer(lView[RENDERER])) { ngDevMode && ngDevMode.rendererDestroy++; - (view[RENDERER] as ProceduralRenderer3).destroy(); + (lView[RENDERER] as ProceduralRenderer3).destroy(); } - const declarationContainer = view[DECLARATION_LCONTAINER]; + const declarationContainer = lView[DECLARATION_LCONTAINER]; // we are dealing with an embedded view that is still inserted into a container - if (declarationContainer !== null && isLContainer(view[PARENT])) { + if (declarationContainer !== null && isLContainer(lView[PARENT])) { // and this is a projected view - if (declarationContainer !== view[PARENT]) { - detachMovedView(declarationContainer, view); + if (declarationContainer !== lView[PARENT]) { + detachMovedView(declarationContainer, lView); } // For embedded views still attached to a container: remove query result from this view. - const lQueries = view[QUERIES]; + const lQueries = lView[QUERIES]; if (lQueries !== null) { - lQueries.detachView(view[TVIEW]); + lQueries.detachView(tView); } } } } /** Removes listeners and unsubscribes from output subscriptions */ -function removeListeners(lView: LView): void { - const tCleanup = lView[TVIEW].cleanup; +function removeListeners(tView: TView, lView: LView): void { + const tCleanup = tView.cleanup; if (tCleanup !== null) { const lCleanup = lView[CLEANUP] !; for (let i = 0; i < tCleanup.length - 1; i += 2) { @@ -474,13 +483,12 @@ function removeListeners(lView: LView): void { } /** Calls onDestroy hooks for this view */ -function executeOnDestroys(view: LView): void { - const tView = view[TVIEW]; +function executeOnDestroys(tView: TView, lView: LView): void { let destroyHooks: HookData|null; if (tView != null && (destroyHooks = tView.destroyHooks) != null) { for (let i = 0; i < destroyHooks.length; i += 2) { - const context = view[destroyHooks[i] as number]; + const context = lView[destroyHooks[i] as number]; // Only call the destroy hook if the context has been requested. if (!(context instanceof NodeInjectorFactory)) { @@ -502,7 +510,7 @@ function executeOnDestroys(view: LView): void { * of a View which has not be inserted or is made for projection but has not been inserted * into destination. */ -function getRenderParent(tNode: TNode, currentView: LView): RElement|null { +function getRenderParent(tView: TView, tNode: TNode, currentView: LView): RElement|null { // Skip over element and ICU containers as those are represented by a comment node and // can't be used as a render parent. let parentTNode = tNode.parent; @@ -541,7 +549,7 @@ function getRenderParent(tNode: TNode, currentView: LView): RElement|null { ngDevMode && assertNodeType(parentTNode, TNodeType.Element); if (parentTNode.flags & TNodeFlags.isComponentHost) { - const tData = currentView[TVIEW].data; + const tData = tView.data; const tNode = tData[parentTNode.index] as TNode; const encapsulation = (tData[tNode.directiveStart] as ComponentDef).encapsulation; @@ -644,17 +652,19 @@ function getNativeAnchorNode(parentTNode: TNode, lView: LView): RNode|null { * * The element insertion might be delayed {@link canInsertNativeNode}. * + * @param tView The `TView' to be appended + * @param lView The current LView * @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 | RNode[], childTNode: TNode, currentView: LView): void { - const renderParent = getRenderParent(childTNode, currentView); +export function appendChild( + tView: TView, lView: LView, childEl: RNode | RNode[], childTNode: TNode): void { + const renderParent = getRenderParent(tView, childTNode, lView); if (renderParent != null) { - const renderer = currentView[RENDERER]; - const parentTNode: TNode = childTNode.parent || currentView[T_HOST] !; - const anchorNode = getNativeAnchorNode(parentTNode, currentView); + const renderer = lView[RENDERER]; + const parentTNode: TNode = childTNode.parent || lView[T_HOST] !; + const anchorNode = getNativeAnchorNode(parentTNode, lView); if (Array.isArray(childEl)) { for (let i = 0; i < childEl.length; i++) { nativeAppendOrInsertBefore(renderer, renderParent, childEl[i], anchorNode); @@ -795,16 +805,16 @@ function applyNodes( * As you can see this is a very recursive problem. Yes recursion is not most efficient but the * code is complicated enough that trying to implemented with recursion becomes unmaintainable. * + * @param tView The `TView' which needs to be inserted, detached, destroyed + * @param lView The LView which needs to be inserted, detached, destroyed. * @param renderer Renderer to use * @param action action to perform (insert, detach, destroy) - * @param lView The LView which needs to be inserted, detached, destroyed. * @param renderParent parent DOM element for insertion/removal. * @param beforeNode Before which node the insertions should happen. */ function applyView( - renderer: Renderer3, action: WalkTNodeTreeAction, lView: LView, renderParent: RElement | null, - beforeNode: RNode | null) { - const tView = lView[TVIEW]; + tView: TView, lView: LView, renderer: Renderer3, action: WalkTNodeTreeAction, + renderParent: RElement | null, beforeNode: RNode | null) { ngDevMode && assertNodeType(tView.node !, TNodeType.View); const viewRootTNode: TNode|null = tView.node !.child; applyNodes(renderer, action, viewRootTNode, lView, renderParent, beforeNode, false); @@ -816,12 +826,13 @@ function applyView( * Inserting a projection requires us to locate the projected nodes from the parent component. The * complication is that those nodes themselves could be re-projected from their parent component. * - * @param lView The LView which needs to be inserted, detached, destroyed. + * @param tView The `TView` of `LView` which needs to be inserted, detached, destroyed + * @param lView The `LView` which needs to be inserted, detached, destroyed. * @param tProjectionNode node to project */ -export function applyProjection(lView: LView, tProjectionNode: TProjectionNode) { +export function applyProjection(tView: TView, lView: LView, tProjectionNode: TProjectionNode) { const renderer = lView[RENDERER]; - const renderParent = getRenderParent(tProjectionNode, lView); + const renderParent = getRenderParent(tView, tProjectionNode, lView); const parentTNode = tProjectionNode.parent || lView[T_HOST] !; let beforeNode = getNativeAnchorNode(parentTNode, lView); applyProjectionRecursive( @@ -903,6 +914,106 @@ function applyContainer( } for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) { const lView = lContainer[i] as LView; - applyView(renderer, action, lView, renderParent, anchor); + applyView(lView[TVIEW], lView, renderer, action, renderParent, anchor); } } + +/** + * Writes class/style to element. + * + * @param renderer Renderer to use. + * @param isClassBased `true` if it should be written to `class` (`false` to write to `style`) + * @param rNode The Node to write to. + * @param prop Property to write to. This would be the class/style name. + * @param value Value to write. If `null`/`undefined`/`false` this is considered a remove (set/add + * otherwise). + */ +export function applyStyling( + renderer: Renderer3, isClassBased: boolean, rNode: RElement, prop: string, value: any) { + const isProcedural = isProceduralRenderer(renderer); + if (isClassBased) { + // We actually want JS true/false here because any truthy value should add the class + if (!value) { + ngDevMode && ngDevMode.rendererRemoveClass++; + if (isProcedural) { + (renderer as Renderer2).removeClass(rNode, prop); + } else { + (rNode as HTMLElement).classList.remove(prop); + } + } else { + ngDevMode && ngDevMode.rendererAddClass++; + if (isProcedural) { + (renderer as Renderer2).addClass(rNode, prop); + } else { + ngDevMode && assertDefined((rNode as HTMLElement).classList, 'HTMLElement expected'); + (rNode as HTMLElement).classList.add(prop); + } + } + } else { + // TODO(misko): Can't import RendererStyleFlags2.DashCase as it causes imports to be resolved in + // different order which causes failures. Using direct constant as workaround for now. + const flags = prop.indexOf('-') == -1 ? undefined : 2 /* RendererStyleFlags2.DashCase */; + if (value == null /** || value === undefined */) { + ngDevMode && ngDevMode.rendererRemoveStyle++; + if (isProcedural) { + (renderer as Renderer2).removeStyle(rNode, prop, flags); + } else { + (rNode as HTMLElement).style.removeProperty(prop); + } + } else { + ngDevMode && ngDevMode.rendererSetStyle++; + if (isProcedural) { + (renderer as Renderer2).setStyle(rNode, prop, value, flags); + } else { + ngDevMode && assertDefined((rNode as HTMLElement).style, 'HTMLElement expected'); + (rNode as HTMLElement).style.setProperty(prop, value); + } + } + } +} + + +/** + * Write `cssText` to `RElement`. + * + * This function does direct write without any reconciliation. Used for writing initial values, so + * that static styling values do not pull in the style parser. + * + * @param renderer Renderer to use + * @param element The element which needs to be updated. + * @param newValue The new class list to write. + */ +export function writeDirectStyle(renderer: Renderer3, element: RElement, newValue: string) { + ngDevMode && assertString(newValue, '\'newValue\' should be a string'); + if (isProceduralRenderer(renderer)) { + renderer.setAttribute(element, 'style', newValue); + } else { + (element as HTMLElement).style.cssText = newValue; + } + ngDevMode && ngDevMode.rendererSetStyle++; +} + +/** + * Write `className` to `RElement`. + * + * This function does direct write without any reconciliation. Used for writing initial values, so + * that static styling values do not pull in the style parser. + * + * @param renderer Renderer to use + * @param element The element which needs to be updated. + * @param newValue The new class list to write. + */ +export function writeDirectClass(renderer: Renderer3, element: RElement, newValue: string) { + ngDevMode && assertString(newValue, '\'newValue\' should be a string'); + if (isProceduralRenderer(renderer)) { + if (newValue === '') { + // There are tests in `google3` which expect `element.getAttribute('class')` to be `null`. + renderer.removeAttribute(element, 'class'); + } else { + renderer.setAttribute(element, 'class', newValue); + } + } else { + element.className = newValue; + } + ngDevMode && ngDevMode.rendererSetClassName++; +} \ No newline at end of file diff --git a/packages/core/src/render3/node_selector_matcher.ts b/packages/core/src/render3/node_selector_matcher.ts index a943f12ce8..6eaf8bca7d 100644 --- a/packages/core/src/render3/node_selector_matcher.ts +++ b/packages/core/src/render3/node_selector_matcher.ts @@ -8,32 +8,52 @@ import '../util/ng_dev_mode'; -import {assertDefined, assertNotEqual} from '../util/assert'; +import {assertDefined, assertEqual, assertNotEqual} from '../util/assert'; import {AttributeMarker, TAttributes, TNode, TNodeType, unusedValueExportToPlacateAjd as unused1} from './interfaces/node'; import {CssSelector, CssSelectorList, SelectorFlags, unusedValueExportToPlacateAjd as unused2} from './interfaces/projection'; +import {classIndexOf} from './styling/class_differ'; import {isNameOnlyAttributeMarker} from './util/attrs_utils'; -import {getInitialStylingValue} from './util/styling_utils'; const unusedValueToPlacateAjd = unused1 + unused2; const NG_TEMPLATE_SELECTOR = 'ng-template'; -function isCssClassMatching(nodeClassAttrVal: string, cssClassToMatch: string): boolean { - const nodeClassesLen = nodeClassAttrVal.length; - // we lowercase the class attribute value to be able to match - // selectors without case-sensitivity - // (selectors are already in lowercase when generated) - const matchIndex = nodeClassAttrVal.toLowerCase().indexOf(cssClassToMatch); - const matchEndIdx = matchIndex + cssClassToMatch.length; - if (matchIndex === -1 // no match - || (matchIndex > 0 && nodeClassAttrVal ![matchIndex - 1] !== ' ') // no space before - || - (matchEndIdx < nodeClassesLen && nodeClassAttrVal ![matchEndIdx] !== ' ')) // no space after - { - return false; +/** + * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive) + * + * @param attrs `TAttributes` to search through. + * @param cssClassToMatch class to match (lowercase) + * @param isProjectionMode Whether or not class matching should look into the attribute `class` in + * addition to the `AttributeMarker.Classes`. + */ +function isCssClassMatching( + attrs: TAttributes, cssClassToMatch: string, isProjectionMode: boolean): boolean { + // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect. + // It is strange to me that sometimes the class information comes in form of `class` attribute + // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine + // if that is the right behavior. + ngDevMode && + assertEqual( + cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.'); + let i = 0; + while (i < attrs.length) { + let item = attrs[i++]; + if (isProjectionMode && item === 'class') { + item = attrs[i] as string; + if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) { + return true; + } + } else if (item === AttributeMarker.Classes) { + // We found the classes section. Start searching for the class. + while (i < attrs.length && typeof(item = attrs[i++]) == 'string') { + // while we have strings + if (item.toLowerCase() === cssClassToMatch) return true; + } + return false; + } } - return true; + return false; } /** @@ -106,9 +126,8 @@ export function isNodeMatchingSelector( // 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.classes) { - if (!isCssClassMatching( - getInitialStylingValue(tNode.classes), selectorAttrValue as string)) { + if ((mode & SelectorFlags.CLASS) && tNode.attrs !== null) { + if (!isCssClassMatching(tNode.attrs, selectorAttrValue as string, isProjectionMode)) { if (isPositive(mode)) return false; skipToNextSelector = true; } @@ -143,7 +162,7 @@ export function isNodeMatchingSelector( const compareAgainstClassName = mode & SelectorFlags.CLASS ? nodeAttrValue : null; if (compareAgainstClassName && - !isCssClassMatching(compareAgainstClassName, selectorAttrValue as string) || + classIndexOf(compareAgainstClassName, selectorAttrValue as string, 0) !== -1 || mode & SelectorFlags.ATTRIBUTE && selectorAttrValue !== nodeAttrValue) { if (isPositive(mode)) return false; skipToNextSelector = true; @@ -297,3 +316,76 @@ export function isSelectorInSelectorList(selector: CssSelector, list: CssSelecto } return false; } + +function maybeWrapInNotSelector(isNegativeMode: boolean, chunk: string): string { + return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk; +} + +function stringifyCSSSelector(selector: CssSelector): string { + let result = selector[0] as string; + let i = 1; + let mode = SelectorFlags.ATTRIBUTE; + let currentChunk = ''; + let isNegativeMode = false; + while (i < selector.length) { + let valueOrMarker = selector[i]; + if (typeof valueOrMarker === 'string') { + if (mode & SelectorFlags.ATTRIBUTE) { + const attrValue = selector[++i] as string; + currentChunk += + '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']'; + } else if (mode & SelectorFlags.CLASS) { + currentChunk += '.' + valueOrMarker; + } else if (mode & SelectorFlags.ELEMENT) { + currentChunk += ' ' + valueOrMarker; + } + } else { + // + // Append current chunk to the final result in case we come across SelectorFlag, which + // indicates that the previous section of a selector is over. We need to accumulate content + // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g. + // ``` + // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC'] + // ``` + // should be transformed to `.classA :not(.classB .classC)`. + // + // Note: for negative selector part, we accumulate content between flags until we find the + // next negative flag. This is needed to support a case where `:not()` rule contains more than + // one chunk, e.g. the following selector: + // ``` + // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar'] + // ``` + // should be stringified to `:not(p.foo) :not(.bar)` + // + if (currentChunk !== '' && !isPositive(valueOrMarker)) { + result += maybeWrapInNotSelector(isNegativeMode, currentChunk); + currentChunk = ''; + } + mode = valueOrMarker; + // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative + // mode is maintained for remaining chunks of a selector. + isNegativeMode = isNegativeMode || !isPositive(mode); + } + i++; + } + if (currentChunk !== '') { + result += maybeWrapInNotSelector(isNegativeMode, currentChunk); + } + return result; +} + +/** + * Generates string representation of CSS selector in parsed form. + * + * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing + * additional parsing at runtime (for example, for directive matching). However in some cases (for + * example, while bootstrapping a component), a string version of the selector is required to query + * for the host element on the page. This function takes the parsed form of a selector and returns + * its string representation. + * + * @param selectorList selector in parsed form + * @returns string representation of a given selector + */ +export function stringifyCSSSelectorList(selectorList: CssSelectorList): string { + return selectorList.map(stringifyCSSSelector).join(','); +} \ No newline at end of file diff --git a/packages/core/src/render3/node_util.ts b/packages/core/src/render3/node_util.ts index 1640aade65..8f750ea399 100644 --- a/packages/core/src/render3/node_util.ts +++ b/packages/core/src/render3/node_util.ts @@ -12,8 +12,10 @@ import {DECLARATION_VIEW, LView, T_HOST} from './interfaces/view'; import {getParentInjectorViewOffset} from './util/injector_utils'; /** - * Unwraps a parent injector location number to find the view offset from the current injector, - * then walks up the declaration view tree until the TNode of the parent injector is found. + * If `startTNode.parent` exists and has an injector, returns TNode for that injector. + * Otherwise, unwraps a parent injector location number to find the view offset from the current + * injector, then walks up the declaration view tree until the TNode of the parent injector is + * found. * * @param location The location of the parent injector, which contains the view offset * @param startView The LView instance from which to start walking up the view tree @@ -23,14 +25,17 @@ import {getParentInjectorViewOffset} from './util/injector_utils'; export function getParentInjectorTNode( location: RelativeInjectorLocation, startView: LView, startTNode: TNode): TElementNode| TContainerNode|null { + // If there is an injector on the parent TNode, retrieve the TNode for that injector. if (startTNode.parent && startTNode.parent.injectorIndex !== -1) { // view offset is 0 const injectorIndex = startTNode.parent.injectorIndex; - let parentTNode = startTNode.parent; - while (parentTNode.parent != null && injectorIndex == parentTNode.injectorIndex) { - parentTNode = parentTNode.parent; + let tNode = startTNode.parent; + // If tNode.injectorIndex === tNode.parent.injectorIndex, then the index belongs to a parent + // injector. + while (tNode.parent != null && injectorIndex == tNode.parent.injectorIndex) { + tNode = tNode.parent; } - return parentTNode; + return tNode; } let viewOffset = getParentInjectorViewOffset(location); // view offset is 1 diff --git a/packages/core/src/render3/pipe.ts b/packages/core/src/render3/pipe.ts index 30ba298e53..a7b1452b91 100644 --- a/packages/core/src/render3/pipe.ts +++ b/packages/core/src/render3/pipe.ts @@ -14,7 +14,7 @@ import {store} from './instructions/all'; import {PipeDef, PipeDefList} from './interfaces/definition'; import {HEADER_OFFSET, LView, TVIEW} from './interfaces/view'; import {pureFunction1Internal, pureFunction2Internal, pureFunction3Internal, pureFunction4Internal, pureFunctionVInternal} from './pure_function'; -import {getBindingIndex, getBindingRoot, getLView} from './state'; +import {getBindingIndex, getBindingRoot, getLView, getTView} from './state'; import {NO_CHANGE} from './tokens'; import {load} from './util/view_utils'; @@ -30,7 +30,7 @@ import {load} from './util/view_utils'; * @codeGenApi */ export function ɵɵpipe(index: number, pipeName: string): any { - const tView = getLView()[TVIEW]; + const tView = getTView(); let pipeDef: PipeDef; const adjustedIndex = index + HEADER_OFFSET; @@ -46,7 +46,7 @@ export function ɵɵpipe(index: number, pipeName: string): any { const pipeFactory = pipeDef.factory || (pipeDef.factory = getFactoryDef(pipeDef.type, true)); const pipeInstance = pipeFactory(); - store(index, pipeInstance); + store(tView, getLView(), index, pipeInstance); return pipeInstance; } @@ -57,8 +57,6 @@ export function ɵɵpipe(index: number, pipeName: string): any { * @param name Name of pipe to resolve * @param registry Full list of available pipes * @returns Matching PipeDef - * - * @publicApi */ function getPipeDef(name: string, registry: PipeDefList | null): PipeDef { if (registry) { diff --git a/packages/core/src/render3/query.ts b/packages/core/src/render3/query.ts index 0717eeae84..ebbef19a4a 100644 --- a/packages/core/src/render3/query.ts +++ b/packages/core/src/render3/query.ts @@ -27,7 +27,7 @@ import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, u import {LQueries, LQuery, TQueries, TQuery, TQueryMetadata, unusedValueExportToPlacateAjd as unused4} from './interfaces/query'; import {DECLARATION_LCONTAINER, LView, PARENT, QUERIES, TVIEW, TView} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; -import {getCurrentQueryIndex, getLView, getPreviousOrParentTNode, setCurrentQueryIndex} from './state'; +import {getCurrentQueryIndex, getLView, getPreviousOrParentTNode, getTView, setCurrentQueryIndex} from './state'; import {isCreationMode} from './util/view_utils'; import {createContainerRef, createElementRef, createTemplateRef} from './view_engine_compatibility'; @@ -308,10 +308,11 @@ function createSpecialToken(lView: LView, tNode: TNode, read: any): any { * processing once and only once for a given view instance (a set of results for a given view * doesn't change). */ -function materializeViewResults(lView: LView, tQuery: TQuery, queryIndex: number): (T | null)[] { +function materializeViewResults( + tView: TView, lView: LView, tQuery: TQuery, queryIndex: number): (T | null)[] { const lQuery = lView[QUERIES] !.queries ![queryIndex]; if (lQuery.matches === null) { - const tViewData = lView[TVIEW].data; + const tViewData = tView.data; const tQueryMatches = tQuery.matches !; const result: T|null[] = []; for (let i = 0; i < tQueryMatches.length; i += 2) { @@ -337,11 +338,11 @@ function materializeViewResults(lView: LView, tQuery: TQuery, queryIndex: num * A helper function that collects (already materialized) query results from a tree of views, * starting with a provided LView. */ -function collectQueryResults(lView: LView, queryIndex: number, result: T[]): T[] { - const tQuery = lView[TVIEW].queries !.getByIndex(queryIndex); +function collectQueryResults(tView: TView, lView: LView, queryIndex: number, result: T[]): T[] { + const tQuery = tView.queries !.getByIndex(queryIndex); const tQueryMatches = tQuery.matches; if (tQueryMatches !== null) { - const lViewResults = materializeViewResults(lView, tQuery, queryIndex); + const lViewResults = materializeViewResults(tView, lView, tQuery, queryIndex); for (let i = 0; i < tQueryMatches.length; i += 2) { const tNodeIdx = tQueryMatches[i]; @@ -359,7 +360,7 @@ function collectQueryResults(lView: LView, queryIndex: number, result: T[]): for (let i = CONTAINER_HEADER_OFFSET; i < declarationLContainer.length; i++) { const embeddedLView = declarationLContainer[i]; if (embeddedLView[DECLARATION_LCONTAINER] === embeddedLView[PARENT]) { - collectQueryResults(embeddedLView, childQueryIndex, result); + collectQueryResults(embeddedLView[TVIEW], embeddedLView, childQueryIndex, result); } } @@ -368,7 +369,8 @@ function collectQueryResults(lView: LView, queryIndex: number, result: T[]): if (declarationLContainer[MOVED_VIEWS] !== null) { const embeddedLViews = declarationLContainer[MOVED_VIEWS] !; for (let i = 0; i < embeddedLViews.length; i++) { - collectQueryResults(embeddedLViews[i], childQueryIndex, result); + const embeddedLView = embeddedLViews[i]; + collectQueryResults(embeddedLView[TVIEW], embeddedLView, childQueryIndex, result); } } } @@ -388,17 +390,19 @@ function collectQueryResults(lView: LView, queryIndex: number, result: T[]): */ export function ɵɵqueryRefresh(queryList: QueryList): boolean { const lView = getLView(); + const tView = getTView(); const queryIndex = getCurrentQueryIndex(); setCurrentQueryIndex(queryIndex + 1); - const tQuery = getTQuery(lView[TVIEW], queryIndex); + const tQuery = getTQuery(tView, queryIndex); if (queryList.dirty && (isCreationMode(lView) === tQuery.metadata.isStatic)) { if (tQuery.matches === null) { queryList.reset([]); } else { - const result = tQuery.crossesNgTemplate ? collectQueryResults(lView, queryIndex, []) : - materializeViewResults(lView, tQuery, queryIndex); + const result = tQuery.crossesNgTemplate ? + collectQueryResults(tView, lView, queryIndex, []) : + materializeViewResults(tView, lView, tQuery, queryIndex); queryList.reset(result); queryList.notifyOnChanges(); } @@ -419,7 +423,7 @@ export function ɵɵqueryRefresh(queryList: QueryList): boolean { */ export function ɵɵstaticViewQuery( predicate: Type| string[], descend: boolean, read?: any): void { - viewQueryInternal(getLView(), predicate, descend, read, true); + viewQueryInternal(getTView(), getLView(), predicate, descend, read, true); } /** @@ -432,20 +436,19 @@ export function ɵɵstaticViewQuery( * @codeGenApi */ export function ɵɵviewQuery(predicate: Type| string[], descend: boolean, read?: any): void { - viewQueryInternal(getLView(), predicate, descend, read, false); + viewQueryInternal(getTView(), getLView(), predicate, descend, read, false); } function viewQueryInternal( - lView: LView, predicate: Type| string[], descend: boolean, read: any, + tView: TView, lView: LView, predicate: Type| string[], descend: boolean, read: any, isStatic: boolean): void { - const tView = lView[TVIEW]; if (tView.firstCreatePass) { createTQuery(tView, new TQueryMetadata_(predicate, descend, isStatic, read), -1); if (isStatic) { tView.staticViewQueries = true; } } - createLQuery(lView); + createLQuery(tView, lView); } /** @@ -463,7 +466,8 @@ function viewQueryInternal( export function ɵɵcontentQuery( directiveIndex: number, predicate: Type| string[], descend: boolean, read?: any): void { contentQueryInternal( - getLView(), predicate, descend, read, false, getPreviousOrParentTNode(), directiveIndex); + getTView(), getLView(), predicate, descend, read, false, getPreviousOrParentTNode(), + directiveIndex); } /** @@ -481,13 +485,13 @@ export function ɵɵcontentQuery( export function ɵɵstaticContentQuery( directiveIndex: number, predicate: Type| string[], descend: boolean, read?: any): void { contentQueryInternal( - getLView(), predicate, descend, read, true, getPreviousOrParentTNode(), directiveIndex); + getTView(), getLView(), predicate, descend, read, true, getPreviousOrParentTNode(), + directiveIndex); } function contentQueryInternal( - lView: LView, predicate: Type| string[], descend: boolean, read: any, isStatic: boolean, - tNode: TNode, directiveIndex: number): void { - const tView = lView[TVIEW]; + tView: TView, lView: LView, predicate: Type| string[], descend: boolean, read: any, + isStatic: boolean, tNode: TNode, directiveIndex: number): void { if (tView.firstCreatePass) { createTQuery(tView, new TQueryMetadata_(predicate, descend, isStatic, read), tNode.index); saveContentQueryAndDirectiveIndex(tView, directiveIndex); @@ -496,7 +500,7 @@ function contentQueryInternal( } } - createLQuery(lView); + createLQuery(tView, lView); } /** @@ -515,9 +519,9 @@ function loadQueryInternal(lView: LView, queryIndex: number): QueryList { return lView[QUERIES] !.queries[queryIndex].queryList; } -function createLQuery(lView: LView) { +function createLQuery(tView: TView, lView: LView) { const queryList = new QueryList(); - storeCleanupWithContext(lView, queryList, queryList.destroy); + storeCleanupWithContext(tView, lView, queryList, queryList.destroy); if (lView[QUERIES] === null) lView[QUERIES] = new LQueries_(); lView[QUERIES] !.queries.push(new LQuery_(queryList)); diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index 3746c90c6c..63816da418 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -7,12 +7,10 @@ */ import {StyleSanitizeFn} from '../sanitization/style_sanitizer'; -import {assertDefined, assertEqual} from '../util/assert'; - +import {assertDefined} from '../util/assert'; import {assertLViewOrUndefined} from './assert'; -import {ComponentDef, DirectiveDef} from './interfaces/definition'; import {TNode} from './interfaces/node'; -import {CONTEXT, DECLARATION_VIEW, LView, OpaqueViewState, TVIEW} from './interfaces/view'; +import {CONTEXT, DECLARATION_VIEW, LView, OpaqueViewState, TVIEW, TView} from './interfaces/view'; /** @@ -41,10 +39,18 @@ interface LFrame { */ lView: LView; + /** + * Current `TView` associated with the `LFrame.lView`. + * + * One can get `TView` from `lFrame[TVIEW]` however because it is so common it makes sense to + * store it in `LFrame` for perf reasons. + */ + tView: TView; + /** * Used to set the parent property when nodes are created and track query results. * - * This is used in conjection with `isParent`. + * This is used in conjunction with `isParent`. */ previousOrParentTNode: TNode; @@ -94,20 +100,6 @@ interface LFrame { currentSanitizer: StyleSanitizeFn|null; - /** - * Used when processing host bindings. - */ - currentDirectiveDef: DirectiveDef|ComponentDef|null; - - /** - * Used as the starting directive id value. - * - * All subsequent directives are incremented from this value onwards. - * The reason why this value is `1` instead of `0` is because the `0` - * value is reserved for the template. - */ - activeDirectiveId: number; - /** * The root index from which pure function instructions should calculate their binding * indices. In component views, this is TView.bindingStartIndex. In a host binding @@ -120,6 +112,13 @@ interface LFrame { * We iterate over the list of Queries and increment current query index at every step. */ currentQueryIndex: number; + + /** + * When host binding is executing this points to the directive index. + * `TView.data[currentDirectiveIndex]` is `DirectiveDef` + * `LView[currentDirectiveIndex]` is directive instance. + */ + currentDirectiveIndex: number; } /** @@ -165,19 +164,11 @@ interface InstructionState { * Necessary to support ChangeDetectorRef.checkNoChanges(). */ checkNoChangesMode: boolean; - - /** - * Function to be called when the element is exited. - * - * NOTE: The function is here for tree shakable purposes since it is only needed by styling. - */ - elementExitFn: (() => void)|null; } export const instructionState: InstructionState = { lFrame: createLFrame(null), bindingsEnabled: true, - elementExitFn: null, checkNoChangesMode: false, }; @@ -194,14 +185,6 @@ export function decreaseElementDepthCount() { instructionState.lFrame.elementDepthCount--; } -export function getCurrentDirectiveDef(): DirectiveDef|ComponentDef|null { - return instructionState.lFrame.currentDirectiveDef; -} - -export function setCurrentDirectiveDef(def: DirectiveDef| ComponentDef| null): void { - instructionState.lFrame.currentDirectiveDef = def; -} - export function getBindingsEnabled(): boolean { return instructionState.bindingsEnabled; } @@ -254,135 +237,17 @@ export function ɵɵdisableBindings(): void { } /** - * Return the current LView. - * - * The return value can be `null` if the method is called outside of template. This can happen if - * directive is instantiated by module injector (rather than by node injector.) + * Return the current `LView`. */ export function getLView(): LView { - // TODO(misko): the return value should be `LView|null` but doing so breaks a lot of code. - const lFrame = instructionState.lFrame; - return lFrame === null ? null ! : lFrame.lView; + return instructionState.lFrame.lView; } /** - * Flags used for an active element during change detection. - * - * These flags are used within other instructions to inform cleanup or - * exit operations to run when an element is being processed. - * - * Note that these flags are reset each time an element changes (whether it - * happens when `advance()` is run or when change detection exits out of a template - * function or when all host bindings are processed for an element). + * Return the current `TView`. */ -export const enum ActiveElementFlags { - Initial = 0b00, - RunExitFn = 0b01, - Size = 1, -} - -/** - * Determines whether or not a flag is currently set for the active element. - */ -export function hasActiveElementFlag(flag: ActiveElementFlags) { - return (instructionState.lFrame.selectedIndex & flag) === flag; -} - -/** - * Sets a flag is for the active element. - */ -function setActiveElementFlag(flag: ActiveElementFlags) { - instructionState.lFrame.selectedIndex |= flag; -} - -/** - * Sets the active directive host element and resets the directive id value - * (when the provided elementIndex value has changed). - * - * @param elementIndex the element index value for the host element where - * the directive/component instance lives - */ -export function setActiveHostElement(elementIndex: number | null) { - if (hasActiveElementFlag(ActiveElementFlags.RunExitFn)) { - executeElementExitFn(); - } - setSelectedIndex(elementIndex === null ? -1 : elementIndex); - instructionState.lFrame.activeDirectiveId = 0; -} - -export function executeElementExitFn() { - instructionState.elementExitFn !(); - instructionState.lFrame.selectedIndex &= ~ActiveElementFlags.RunExitFn; -} - -/** - * Queues a function to be run once the element is "exited" in CD. - * - * Change detection will focus on an element either when the `advance()` - * instruction is called or when the template or host bindings instruction - * code is invoked. The element is then "exited" when the next element is - * selected or when change detection for the template or host bindings is - * complete. When this occurs (the element change operation) then an exit - * function will be invoked if it has been set. This function can be used - * to assign that exit function. - * - * @param fn - */ -export function setElementExitFn(fn: () => void): void { - setActiveElementFlag(ActiveElementFlags.RunExitFn); - if (instructionState.elementExitFn === null) { - instructionState.elementExitFn = fn; - } - ngDevMode && - assertEqual(instructionState.elementExitFn, fn, 'Expecting to always get the same function'); -} - -/** - * Returns the current id value of the current directive. - * - * For example we have an element that has two directives on it: - *
- * - * dirOne->hostBindings() (id == 1) - * dirTwo->hostBindings() (id == 2) - * - * Note that this is only active when `hostBinding` functions are being processed. - * - * Note that directive id values are specific to an element (this means that - * the same id value could be present on another element with a completely - * different set of directives). - */ -export function getActiveDirectiveId() { - return instructionState.lFrame.activeDirectiveId; -} - -/** - * Increments the current directive id value. - * - * For example we have an element that has two directives on it: - *
- * - * dirOne->hostBindings() (index = 1) - * // increment - * dirTwo->hostBindings() (index = 2) - * - * Depending on whether or not a previous directive had any inherited - * directives present, that value will be incremented in addition - * to the id jumping up by one. - * - * Note that this is only active when `hostBinding` functions are being processed. - * - * Note that directive id values are specific to an element (this means that - * the same id value could be present on another element with a completely - * different set of directives). - */ -export function incrementActiveDirectiveId() { - // Each directive gets a uniqueId value that is the same for both - // create and update calls when the hostBindings function is called. The - // directive uniqueId is not set anywhere--it is just incremented between - // each hostBindings call and is useful for helping instruction code - // uniquely determine which directive is currently active when executed. - instructionState.lFrame.activeDirectiveId += 1; +export function getTView(): TView { + return instructionState.lFrame.tView; } /** @@ -425,6 +290,7 @@ export function getContextLView(): LView { } export function getCheckNoChangesMode(): boolean { + // TODO(misko): remove this from the LView since it is ngDevMode=true mode only. return instructionState.checkNoChangesMode; } @@ -437,8 +303,7 @@ export function getBindingRoot() { const lFrame = instructionState.lFrame; let index = lFrame.bindingRootIndex; if (index === -1) { - const lView = lFrame.lView; - index = lFrame.bindingRootIndex = lView[TVIEW].bindingStartIndex; + index = lFrame.bindingRootIndex = lFrame.tView.bindingStartIndex; } return index; } @@ -468,10 +333,25 @@ export function incrementBindingIndex(count: number): number { * Bindings inside the host template are 0 index. But because we don't know ahead of time * how many host bindings we have we can't pre-compute them. For this reason they are all * 0 index and we just shift the root so that they match next available location in the LView. - * @param value + * + * @param bindingRootIndex Root index for `hostBindings` + * @param currentDirectiveIndex `TData[currentDirectiveIndex]` will point to the current directive + * whose `hostBindings` are being processed. */ -export function setBindingRoot(value: number) { - instructionState.lFrame.bindingRootIndex = value; +export function setBindingRootForHostBindings( + bindingRootIndex: number, currentDirectiveIndex: number) { + const lFrame = instructionState.lFrame; + lFrame.bindingIndex = lFrame.bindingRootIndex = bindingRootIndex; + lFrame.currentDirectiveIndex = currentDirectiveIndex; +} + +/** + * When host binding is executing this points to the directive index. + * `TView.data[getCurrentDirectiveIndex()]` is `DirectiveDef` + * `LView[getCurrentDirectiveIndex()]` is directive instance. + */ +export function getCurrentDirectiveIndex(): number { + return instructionState.lFrame.currentDirectiveIndex; } export function getCurrentQueryIndex(): number { @@ -501,8 +381,6 @@ export function enterDI(newView: LView, tNode: TNode) { newLFrame.elementDepthCount = DEV_MODE_VALUE; newLFrame.currentNamespace = DEV_MODE_VALUE; newLFrame.currentSanitizer = DEV_MODE_VALUE; - newLFrame.currentDirectiveDef = DEV_MODE_VALUE; - newLFrame.activeDirectiveId = DEV_MODE_VALUE; newLFrame.bindingRootIndex = DEV_MODE_VALUE; newLFrame.currentQueryIndex = DEV_MODE_VALUE; } @@ -533,19 +411,20 @@ export const leaveDI = leaveView; export function enterView(newView: LView, tNode: TNode | null): void { ngDevMode && assertLViewOrUndefined(newView); const newLFrame = allocLFrame(); + const tView = newView[TVIEW]; instructionState.lFrame = newLFrame; newLFrame.previousOrParentTNode = tNode !; newLFrame.isParent = true; newLFrame.lView = newView; + newLFrame.tView = tView; newLFrame.selectedIndex = 0; newLFrame.contextLView = newView !; newLFrame.elementDepthCount = 0; + newLFrame.currentDirectiveIndex = -1; newLFrame.currentNamespace = null; newLFrame.currentSanitizer = null; - newLFrame.currentDirectiveDef = null; - newLFrame.activeDirectiveId = 0; newLFrame.bindingRootIndex = -1; - newLFrame.bindingIndex = newView === null ? -1 : newView[TVIEW].bindingStartIndex; + newLFrame.bindingIndex = tView.bindingStartIndex; newLFrame.currentQueryIndex = 0; } @@ -564,13 +443,13 @@ function createLFrame(parent: LFrame | null): LFrame { previousOrParentTNode: null !, // isParent: true, // lView: null !, // + tView: null !, // selectedIndex: 0, // contextLView: null !, // elementDepthCount: 0, // currentNamespace: null, // currentSanitizer: null, // - currentDirectiveDef: null, // - activeDirectiveId: 0, // + currentDirectiveIndex: -1, // bindingRootIndex: -1, // bindingIndex: -1, // currentQueryIndex: 0, // @@ -581,13 +460,6 @@ function createLFrame(parent: LFrame | null): LFrame { return lFrame; } -export function leaveViewProcessExit() { - if (hasActiveElementFlag(ActiveElementFlags.RunExitFn)) { - executeElementExitFn(); - } - leaveView(); -} - export function leaveView() { instructionState.lFrame = instructionState.lFrame.parent; } @@ -610,13 +482,13 @@ function walkUpViews(nestingLevel: number, currentView: LView): LView { } /** - * Gets the most recent index passed to {@link select} + * Gets the currently selected element index. * * Used with {@link property} instruction (and more in the future) to identify the index in the * current `LView` to act on. */ export function getSelectedIndex() { - return instructionState.lFrame.selectedIndex >> ActiveElementFlags.Size; + return instructionState.lFrame.selectedIndex; } /** @@ -629,7 +501,7 @@ export function getSelectedIndex() { * run if and when the provided `index` value is different from the current selected index value.) */ export function setSelectedIndex(index: number) { - instructionState.lFrame.selectedIndex = index << ActiveElementFlags.Size; + instructionState.lFrame.selectedIndex = index; } diff --git a/packages/core/src/render3/styling/bindings.ts b/packages/core/src/render3/styling/bindings.ts deleted file mode 100644 index 176f03f050..0000000000 --- a/packages/core/src/render3/styling/bindings.ts +++ /dev/null @@ -1,1108 +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 {SafeValue, unwrapSafeValue} from '../../sanitization/bypass'; -import {StyleSanitizeFn, StyleSanitizeMode} from '../../sanitization/style_sanitizer'; -import {global} from '../../util/global'; -import {TNodeFlags} from '../interfaces/node'; -import {ProceduralRenderer3, RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer'; -import {ApplyStylingFn, LStylingData, StylingMapArray, StylingMapArrayIndex, StylingMapsSyncMode, SyncStylingMapsFn, TStylingContext, TStylingContextIndex, TStylingContextPropConfigFlags, TStylingNode} from '../interfaces/styling'; -import {NO_CHANGE} from '../tokens'; -import {DEFAULT_BINDING_INDEX, DEFAULT_BINDING_VALUE, DEFAULT_GUARD_MASK_VALUE, MAP_BASED_ENTRY_PROP_NAME, TEMPLATE_DIRECTIVE_INDEX, concatString, forceStylesAsString, getBindingValue, getDefaultValue, getGuardMask, getInitialStylingValue, getMapProp, getMapValue, getProp, getPropValuesStartPosition, getStylingMapArray, getTotalSources, getValue, getValuesCount, hasConfig, hasValueChanged, isHostStylingActive, isSanitizationRequired, isStylingMapArray, isStylingValueDefined, normalizeIntoStylingMap, patchConfig, setDefaultValue, setGuardMask, setMapAsDirty, setValue} from '../util/styling_utils'; - -import {getStylingState, resetStylingState} from './state'; - -const VALUE_IS_EXTERNALLY_MODIFIED = {}; - -/** - * -------- - * - * This file contains the core logic for styling in Angular. - * - * All styling bindings (i.e. `[style]`, `[style.prop]`, `[class]` and `[class.name]`) - * will have their values be applied through the logic in this file. - * - * When a binding is encountered (e.g. `
`) then - * the binding data will be populated into a `TStylingContext` data-structure. - * There is only one `TStylingContext` per `TStylingNode` and each element instance - * will update its style/class binding values in concert with the styling - * context. - * - * To learn more about the algorithm see `TStylingContext`. - * - * -------- - */ - -/** - * The guard/update mask bit index location for map-based bindings. - * - * All map-based bindings (i.e. `[style]` and `[class]` ) - */ -const STYLING_INDEX_FOR_MAP_BINDING = 0; - -/** - * Visits a class-based binding and updates the new value (if changed). - * - * This function is called each time a class-based styling instruction - * is executed. It's important that it's always called (even if the value - * has not changed) so that the inner counter index value is incremented. - * This way, each instruction is always guaranteed to get the same counter - * state each time it's called (which then allows the `TStylingContext` - * and the bit mask values to be in sync). - */ -export function updateClassViaContext( - context: TStylingContext, tNode: TStylingNode, data: LStylingData, element: RElement, - directiveIndex: number, prop: string | null, bindingIndex: number, - value: boolean | string | null | undefined | StylingMapArray | NO_CHANGE, forceUpdate: boolean, - firstUpdatePass: boolean): boolean { - const isMapBased = !prop; - const state = getStylingState(element, directiveIndex); - const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.classesIndex++; - - // even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngClass]) - // then we still need to register the binding within the context so that the context - // is aware of the binding even if things change after the first update pass. - if (firstUpdatePass || value !== NO_CHANGE) { - const updated = updateBindingData( - context, tNode, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate, - false, firstUpdatePass, true); - if (updated || forceUpdate) { - // We flip the bit in the bitMask to reflect that the binding - // at the `index` slot has changed. This identifies to the flushing - // phase that the bindings for this particular CSS class need to be - // applied again because on or more of the bindings for the CSS - // class have changed. - state.classesBitMask |= 1 << countIndex; - return true; - } - } - return false; -} - -/** - * Visits a style-based binding and updates the new value (if changed). - * - * This function is called each time a style-based styling instruction - * is executed. It's important that it's always called (even if the value - * has not changed) so that the inner counter index value is incremented. - * This way, each instruction is always guaranteed to get the same counter - * state each time it's called (which then allows the `TStylingContext` - * and the bit mask values to be in sync). - */ -export function updateStyleViaContext( - context: TStylingContext, tNode: TStylingNode, data: LStylingData, element: RElement, - directiveIndex: number, prop: string | null, bindingIndex: number, - value: string | number | SafeValue | null | undefined | StylingMapArray | NO_CHANGE, - sanitizer: StyleSanitizeFn | null, forceUpdate: boolean, firstUpdatePass: boolean): boolean { - const isMapBased = !prop; - const state = getStylingState(element, directiveIndex); - const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.stylesIndex++; - - // even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngStyle]) - // then we still need to register the binding within the context so that the context - // is aware of the binding even if things change after the first update pass. - if (firstUpdatePass || value !== NO_CHANGE) { - const sanitizationRequired = isMapBased ? - true : - (sanitizer ? sanitizer(prop !, null, StyleSanitizeMode.ValidateProperty) : false); - const updated = updateBindingData( - context, tNode, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate, - sanitizationRequired, firstUpdatePass, false); - if (updated || forceUpdate) { - // We flip the bit in the bitMask to reflect that the binding - // at the `index` slot has changed. This identifies to the flushing - // phase that the bindings for this particular property need to be - // applied again because on or more of the bindings for the CSS - // property have changed. - state.stylesBitMask |= 1 << countIndex; - return true; - } - } - return false; -} - -/** - * Called each time a binding value has changed within the provided `TStylingContext`. - * - * This function is designed to be called from `updateStyleBinding` and `updateClassBinding`. - * If called during the first update pass, the binding will be registered in the context. - * - * This function will also update binding slot in the provided `LStylingData` with the - * new binding entry (if it has changed). - * - * @returns whether or not the binding value was updated in the `LStylingData`. - */ -function updateBindingData( - context: TStylingContext, tNode: TStylingNode, data: LStylingData, counterIndex: number, - sourceIndex: number, prop: string | null, bindingIndex: number, - value: string | SafeValue | number | boolean | null | undefined | StylingMapArray, - forceUpdate: boolean, sanitizationRequired: boolean, firstUpdatePass: boolean, - isClassBased: boolean): boolean { - const hostBindingsMode = isHostStylingActive(sourceIndex); - const hostBindingsFlag = - isClassBased ? TNodeFlags.hasHostClassBindings : TNodeFlags.hasHostStyleBindings; - if (firstUpdatePass) { - // this will only happen during the first update pass of the - // context. The reason why we can't use `tView.firstCreatePass` - // here is because its not guaranteed to be true when the first - // update pass is executed (remember that all styling instructions - // are run in the update phase, and, as a result, are no more - // styling instructions that are run in the creation phase). - registerBinding( - context, tNode, counterIndex, sourceIndex, prop, bindingIndex, sanitizationRequired, - isClassBased); - } - - const changed = forceUpdate || hasValueChanged(data[bindingIndex], value); - if (changed) { - setValue(data, bindingIndex, value); - const doSetValuesAsStale = - hasConfig(tNode, hostBindingsFlag) && !hostBindingsMode && (prop ? !value : true); - if (doSetValuesAsStale) { - renderHostBindingsAsStale(context, tNode, data, prop, isClassBased); - } - } - return changed; -} - -/** - * Iterates over all host-binding values for the given `prop` value in the context and sets their - * corresponding binding values to `null`. - * - * Whenever a template binding changes its value to `null`, all host-binding values should be - * re-applied - * to the element when the host bindings are evaluated. This may not always happen in the event - * that none of the bindings changed within the host bindings code. For this reason this function - * is expected to be called each time a template binding becomes falsy or when a map-based template - * binding changes. - */ -function renderHostBindingsAsStale( - context: TStylingContext, tNode: TStylingNode, data: LStylingData, prop: string | null, - isClassBased: boolean): void { - const valuesCount = getValuesCount(context); - - const hostBindingsFlag = - isClassBased ? TNodeFlags.hasHostClassBindings : TNodeFlags.hasHostStyleBindings; - if (prop !== null && hasConfig(tNode, hostBindingsFlag)) { - const itemsPerRow = TStylingContextIndex.BindingsStartOffset + valuesCount; - - let i = TStylingContextIndex.ValuesStartPosition; - let found = false; - while (i < context.length) { - if (getProp(context, i) === prop) { - found = true; - break; - } - i += itemsPerRow; - } - - if (found) { - const bindingsStart = i + TStylingContextIndex.BindingsStartOffset; - const valuesStart = bindingsStart + 1; // the first column is template bindings - const valuesEnd = bindingsStart + valuesCount - 1; - - for (let i = valuesStart; i < valuesEnd; i++) { - const bindingIndex = context[i] as number; - if (bindingIndex !== 0) { - setValue(data, bindingIndex, null); - } - } - } - } - - const mapBindingsFlag = - isClassBased ? TNodeFlags.hasClassMapBindings : TNodeFlags.hasStyleMapBindings; - if (hasConfig(tNode, mapBindingsFlag)) { - const bindingsStart = - TStylingContextIndex.ValuesStartPosition + TStylingContextIndex.BindingsStartOffset; - const valuesStart = bindingsStart + 1; // the first column is template bindings - const valuesEnd = bindingsStart + valuesCount - 1; - for (let i = valuesStart; i < valuesEnd; i++) { - const stylingMap = getValue(data, context[i] as number); - if (stylingMap) { - setMapAsDirty(stylingMap); - } - } - } -} - -/** - * Registers the provided binding (prop + bindingIndex) into the context. - * - * It is needed because it will either update or insert a styling property - * into the context at the correct spot. - * - * When called, one of two things will happen: - * - * 1) If the property already exists in the context then it will just add - * the provided `bindingValue` to the end of the binding sources region - * for that particular property. - * - * - If the binding value is a number then it will be added as a new - * binding index source next to the other binding sources for the property. - * - * - Otherwise, if the binding value is a string/boolean/null type then it will - * replace the default value for the property if the default value is `null`. - * - * 2) If the property does not exist then it will be inserted into the context. - * The styling context relies on all properties being stored in alphabetical - * order, so it knows exactly where to store it. - * - * When inserted, a default `null` value is created for the property which exists - * as the default value for the binding. If the bindingValue property is inserted - * and it is either a string, number or null value then that will replace the default - * value. - * - * Note that this function is also used for map-based styling bindings. They are treated - * much the same as prop-based bindings, but, their property name value is set as `[MAP]`. - */ -export function registerBinding( - context: TStylingContext, tNode: TStylingNode, countId: number, sourceIndex: number, - prop: string | null, bindingValue: number | null | string | boolean, - sanitizationRequired: boolean, isClassBased: boolean): void { - let found = false; - prop = prop || MAP_BASED_ENTRY_PROP_NAME; - - let totalSources = getTotalSources(context); - - // if a new source is detected then a new column needs to be allocated into - // the styling context. The column is basically a new allocation of binding - // sources that will be available to each property. - while (totalSources <= sourceIndex) { - addNewSourceColumn(context); - totalSources++; - } - - const collisionFlag = - isClassBased ? TNodeFlags.hasDuplicateClassBindings : TNodeFlags.hasDuplicateStyleBindings; - const isBindingIndexValue = typeof bindingValue === 'number'; - const entriesPerRow = TStylingContextIndex.BindingsStartOffset + getValuesCount(context); - let i = TStylingContextIndex.ValuesStartPosition; - - // all style/class bindings are sorted by property name - while (i < context.length) { - const p = getProp(context, i); - if (prop <= p) { - if (prop < p) { - allocateNewContextEntry(context, i, prop, sanitizationRequired); - } else if (isBindingIndexValue) { - patchConfig(tNode, collisionFlag); - } - addBindingIntoContext(context, i, bindingValue, countId, sourceIndex); - found = true; - break; - } - i += entriesPerRow; - } - - if (!found) { - allocateNewContextEntry(context, context.length, prop, sanitizationRequired); - addBindingIntoContext(context, i, bindingValue, countId, sourceIndex); - } -} - -/** - * Inserts a new row into the provided `TStylingContext` and assigns the provided `prop` value as - * the property entry. - */ -function allocateNewContextEntry( - context: TStylingContext, index: number, prop: string, sanitizationRequired?: boolean): void { - const config = sanitizationRequired ? TStylingContextPropConfigFlags.SanitizationRequired : - TStylingContextPropConfigFlags.Default; - context.splice( - index, 0, - config, // 1) config value - DEFAULT_GUARD_MASK_VALUE, // 2) template bit mask - DEFAULT_GUARD_MASK_VALUE, // 3) host bindings bit mask - prop, // 4) prop value (e.g. `width`, `myClass`, etc...) - ); - - index += 4; // the 4 values above - - // 5...) default binding index for the template value - // depending on how many sources already exist in the context, - // multiple default index entries may need to be inserted for - // the new value in the context. - const totalBindingsPerEntry = getTotalSources(context); - for (let i = 0; i < totalBindingsPerEntry; i++) { - context.splice(index, 0, DEFAULT_BINDING_INDEX); - index++; - } - - // 6) default binding value for the new entry - context.splice(index, 0, DEFAULT_BINDING_VALUE); -} - -/** - * Inserts a new binding value into a styling property tuple in the `TStylingContext`. - * - * A bindingValue is inserted into a context during the first update pass - * of a template or host bindings function. When this occurs, two things - * happen: - * - * - If the bindingValue value is a number then it is treated as a bindingIndex - * value (a index in the `LView`) and it will be inserted next to the other - * binding index entries. - * - * - Otherwise the binding value will update the default value for the property - * and this will only happen if the default value is `null`. - */ -function addBindingIntoContext( - context: TStylingContext, index: number, bindingValue: number | string | boolean | null, - bitIndex: number, sourceIndex: number) { - if (typeof bindingValue === 'number') { - const hostBindingsMode = isHostStylingActive(sourceIndex); - const cellIndex = index + TStylingContextIndex.BindingsStartOffset + sourceIndex; - context[cellIndex] = bindingValue; - const updatedBitMask = getGuardMask(context, index, hostBindingsMode) | (1 << bitIndex); - setGuardMask(context, index, updatedBitMask, hostBindingsMode); - } else if (bindingValue !== null && getDefaultValue(context, index) === null) { - setDefaultValue(context, index, bindingValue); - } -} - -/** - * Registers a new column into the provided `TStylingContext`. - * - * If and when a new source is detected then a new column needs to - * be allocated into the styling context. The column is basically - * a new allocation of binding sources that will be available to each - * property. - * - * Each column that exists in the styling context resembles a styling - * source. A styling source an either be the template or one or more - * components or directives all containing styling host bindings. - */ -function addNewSourceColumn(context: TStylingContext): void { - // we use -1 here because we want to insert right before the last value (the default value) - const insertOffset = TStylingContextIndex.BindingsStartOffset + getValuesCount(context) - 1; - - let index = TStylingContextIndex.ValuesStartPosition; - while (index < context.length) { - index += insertOffset; - context.splice(index++, 0, DEFAULT_BINDING_INDEX); - - // the value was inserted just before the default value, but the - // next entry in the context starts just after it. Therefore++. - index++; - } - context[TStylingContextIndex.TotalSourcesPosition]++; -} - -/** - * Applies all pending style and class bindings to the provided element. - * - * This function will attempt to flush styling via the provided `classesContext` - * and `stylesContext` context values. This function is designed to be run from - * the internal `stylingApply` function (which is scheduled to run at the very - * end of change detection for an element if one or more style/class bindings - * were processed) and will rely on any state values that are set from when - * any of the styling bindings executed. - * - * This function is designed to be called twice: one when change detection has - * processed an element within the template bindings (i.e. just as `advance()` - * is called) and when host bindings have been processed. In both cases the - * styles and classes in both contexts will be applied to the element, but the - * algorithm will selectively decide which bindings to run depending on the - * columns in the context. The provided `directiveIndex` value will help the - * algorithm determine which bindings to apply: either the template bindings or - * the host bindings (see `applyStylingToElement` for more information). - * - * Note that once this function is called all temporary styling state data - * (i.e. the `bitMask` and `counter` values for styles and classes will be cleared). - */ -export function flushStyling( - renderer: Renderer3 | ProceduralRenderer3 | null, data: LStylingData, tNode: TStylingNode, - classesContext: TStylingContext | null, stylesContext: TStylingContext | null, - element: RElement, directiveIndex: number, styleSanitizer: StyleSanitizeFn | null, - firstUpdatePass: boolean): void { - ngDevMode && ngDevMode.flushStyling++; - - const state = getStylingState(element, directiveIndex); - const hostBindingsMode = isHostStylingActive(state.sourceIndex); - - if (stylesContext) { - firstUpdatePass && syncContextInitialStyling(stylesContext, tNode, false); - - if (state.stylesBitMask !== 0) { - applyStylingViaContext( - stylesContext, tNode, renderer, element, data, state.stylesBitMask, setStyle, - styleSanitizer, hostBindingsMode, false); - } - } - - if (classesContext) { - firstUpdatePass && syncContextInitialStyling(classesContext, tNode, true); - - if (state.classesBitMask !== 0) { - applyStylingViaContext( - classesContext, tNode, renderer, element, data, state.classesBitMask, setClass, null, - hostBindingsMode, true); - } - } - - resetStylingState(); -} - -/** - * Registers all static styling values into the context as default values. - * - * Static styles are stored on the `tNode.styles` and `tNode.classes` - * properties as instances of `StylingMapArray`. When an instance of - * `TStylingContext` is assigned to `tNode.styles` and `tNode.classes` - * then the existing initial styling values are copied into the the - * `InitialStylingValuePosition` slot. - * - * Because all static styles/classes are collected and registered on - * the initial styling array each time a directive is instantiated, - * the context may not yet know about the static values. When this - * function is called it will copy over all the static style/class - * values from the initial styling array into the context as default - * values for each of the matching entries in the context. - * - * Let's imagine the following example: - * - * ```html - *
- * ... - *
- * ``` - * - * When the code above is processed, the underlying element/styling - * instructions will create an instance of `TStylingContext` for - * the `tNode.styles` property. Here's what that looks like: - * - * ```typescript - * tNode.styles = [ - * // ... - * // initial styles - * ['color:red; height:200px', 'color', 'red', 'height', '200px'], - * - * 0, 0b1, 0b0, 'color', 20, null, // [style.color] binding - * ] - * ``` - * - * After this function is called it will balance out the context with - * the static `color` and `height` values and set them as defaults within - * the context: - * - * ```typescript - * tNode.styles = [ - * // ... - * // initial styles - * ['color:red; height:200px', 'color', 'red', 'height', '200px'], - * - * 0, 0b1, 0b0, 'color', 20, 'red', - * 0, 0b0, 0b0, 'height', 0, '200px', - * ] - * ``` - */ -function syncContextInitialStyling( - context: TStylingContext, tNode: TStylingNode, isClassBased: boolean): void { - // the TStylingContext always has initial style/class values which are - // stored in styling array format. - updateInitialStylingOnContext(context, tNode, getStylingMapArray(context) !, isClassBased); -} - -/** - * Registers all initial styling entries into the provided context. - * - * This function will iterate over all entries in the provided `initialStyling` ar}ray and register - * them as default (initial) values in the provided context. Initial styling values in a context are - * the default values that are to be applied unless overwritten by a binding. - * - * The reason why this function exists and isn't a part of the context construction is because - * host binding is evaluated at a later stage after the element is created. This means that - * if a directive or component contains any initial styling code (i.e. `
`) - * then that initial styling data can only be applied once the styling for that element - * is first applied (at the end of the update phase). Once that happens then the context will - * update itself with the complete initial styling for the element. - */ -function updateInitialStylingOnContext( - context: TStylingContext, tNode: TStylingNode, initialStyling: StylingMapArray, - isClassBased: boolean): void { - // `-1` is used here because all initial styling data is not a apart - // of a binding (since it's static) - const COUNT_ID_FOR_STYLING = -1; - - let hasInitialStyling = false; - for (let i = StylingMapArrayIndex.ValuesStartPosition; i < initialStyling.length; - i += StylingMapArrayIndex.TupleSize) { - const value = getMapValue(initialStyling, i); - if (value) { - const prop = getMapProp(initialStyling, i); - registerBinding(context, tNode, COUNT_ID_FOR_STYLING, 0, prop, value, false, isClassBased); - hasInitialStyling = true; - } - } - - if (hasInitialStyling) { - patchConfig(tNode, TNodeFlags.hasInitialStyling); - } -} - -/** - * Runs through the provided styling context and applies each value to - * the provided element (via the renderer) if one or more values are present. - * - * This function will iterate over all entries present in the provided - * `TStylingContext` array (both prop-based and map-based bindings).- - * - * Each entry, within the `TStylingContext` array, is stored alphabetically - * and this means that each prop/value entry will be applied in order - * (so long as it is marked dirty in the provided `bitMask` value). - * - * If there are any map-based entries present (which are applied to the - * element via the `[style]` and `[class]` bindings) then those entries - * will be applied as well. However, the code for that is not a part of - * this function. Instead, each time a property is visited, then the - * code below will call an external function called `stylingMapsSyncFn` - * and, if present, it will keep the application of styling values in - * map-based bindings up to sync with the application of prop-based - * bindings. - * - * Visit `styling/map_based_bindings.ts` to learn more about how the - * algorithm works for map-based styling bindings. - * - * Note that this function is not designed to be called in isolation (use - * the `flushStyling` function so that it can call this function for both - * the styles and classes contexts). - */ -export function applyStylingViaContext( - context: TStylingContext, tNode: TStylingNode, renderer: Renderer3 | ProceduralRenderer3 | null, - element: RElement, bindingData: LStylingData, bitMaskValue: number | boolean, - applyStylingFn: ApplyStylingFn, sanitizer: StyleSanitizeFn | null, hostBindingsMode: boolean, - isClassBased: boolean): void { - const bitMask = normalizeBitMaskValue(bitMaskValue); - - let stylingMapsSyncFn: SyncStylingMapsFn|null = null; - let applyAllValues = false; - const mapBindingsFlag = - isClassBased ? TNodeFlags.hasClassMapBindings : TNodeFlags.hasStyleMapBindings; - if (hasConfig(tNode, mapBindingsFlag)) { - stylingMapsSyncFn = getStylingMapsSyncFn(); - const mapsGuardMask = - getGuardMask(context, TStylingContextIndex.ValuesStartPosition, hostBindingsMode); - applyAllValues = (bitMask & mapsGuardMask) !== 0; - } - - const valuesCount = getValuesCount(context); - let totalBindingsToVisit = 1; - let mapsMode = - applyAllValues ? StylingMapsSyncMode.ApplyAllValues : StylingMapsSyncMode.TraverseValues; - if (hostBindingsMode) { - mapsMode |= StylingMapsSyncMode.RecurseInnerMaps; - totalBindingsToVisit = valuesCount - 1; - } - - let i = getPropValuesStartPosition(context, tNode, isClassBased); - while (i < context.length) { - const guardMask = getGuardMask(context, i, hostBindingsMode); - if (bitMask & guardMask) { - let valueApplied = false; - const prop = getProp(context, i); - const defaultValue = getDefaultValue(context, i); - - // Part 1: Visit the `[styling.prop]` value - for (let j = 0; j < totalBindingsToVisit; j++) { - const bindingIndex = getBindingValue(context, i, j) as number; - if (!valueApplied && bindingIndex !== 0) { - const value = getValue(bindingData, bindingIndex); - if (isStylingValueDefined(value)) { - const checkValueOnly = hostBindingsMode && j === 0; - if (!checkValueOnly) { - const finalValue = sanitizer && isSanitizationRequired(context, i) ? - sanitizer(prop, value, StyleSanitizeMode.SanitizeOnly) : - unwrapSafeValue(value); - applyStylingFn(renderer, element, prop, finalValue, bindingIndex); - } - valueApplied = true; - } - } - - // Part 2: Visit the `[style]` or `[class]` map-based value - if (stylingMapsSyncFn) { - // determine whether or not to apply the target property or to skip it - let mode = mapsMode | (valueApplied ? StylingMapsSyncMode.SkipTargetProp : - StylingMapsSyncMode.ApplyTargetProp); - - // the first column in the context (when `j == 0`) is special-cased for - // template bindings. If and when host bindings are being processed then - // the first column will still be iterated over, but the values will only - // be checked against (not applied). If and when this happens we need to - // notify the map-based syncing code to know not to apply the values it - // comes across in the very first map-based binding (which is also located - // in column zero). - if (hostBindingsMode && j === 0) { - mode |= StylingMapsSyncMode.CheckValuesOnly; - } - - const valueAppliedWithinMap = stylingMapsSyncFn( - context, renderer, element, bindingData, j, applyStylingFn, sanitizer, mode, prop, - defaultValue); - valueApplied = valueApplied || valueAppliedWithinMap; - } - } - - // Part 3: apply the default value (e.g. `
` => `200px` gets applied) - // if the value has not yet been applied then a truthy value does not exist in the - // prop-based or map-based bindings code. If and when this happens, just apply the - // default value (even if the default value is `null`). - if (!valueApplied) { - applyStylingFn(renderer, element, prop, defaultValue); - } - } - - i += TStylingContextIndex.BindingsStartOffset + valuesCount; - } - - // the map-based styling entries may have not applied all their - // values. For this reason, one more call to the sync function - // needs to be issued at the end. - if (stylingMapsSyncFn) { - if (hostBindingsMode) { - mapsMode |= StylingMapsSyncMode.CheckValuesOnly; - } - stylingMapsSyncFn( - context, renderer, element, bindingData, 0, applyStylingFn, sanitizer, mapsMode); - } -} - -/** - * Applies the provided styling map to the element directly (without context resolution). - * - * This function is designed to be run from the styling instructions and will be called - * automatically. This function is intended to be used for performance reasons in the - * event that there is no need to apply styling via context resolution. - * - * This function has three different cases that can occur (for each item in the map): - * - * - Case 1: Attempt to apply the current value in the map to the element (if it's `non null`). - * - * - Case 2: If a map value fails to be applied then the algorithm will find a matching entry in - * the initial values present in the context and attempt to apply that. - * - * - Default Case: If the initial value cannot be applied then a default value of `null` will be - * applied (which will remove the style/class value from the element). - * - * See `allowDirectStylingApply` to learn the logic used to determine whether any style/class - * bindings can be directly applied. - * - * @returns whether or not the styling map was applied to the element. - */ -export function applyStylingMapDirectly( - renderer: any, context: TStylingContext, tNode: TStylingNode, element: RElement, - data: LStylingData, bindingIndex: number, value: {[key: string]: any} | string | null, - isClassBased: boolean, sanitizer: StyleSanitizeFn | null, forceUpdate: boolean, - bindingValueContainsInitial: boolean): void { - const oldValue = getValue(data, bindingIndex); - if (forceUpdate || hasValueChanged(oldValue, value)) { - const hasInitial = hasConfig(tNode, TNodeFlags.hasInitialStyling); - const initialValue = - hasInitial && !bindingValueContainsInitial ? getInitialStylingValue(context) : null; - setValue(data, bindingIndex, value); - - // the cached value is the last snapshot of the style or class - // attribute value and is used in the if statement below to - // keep track of internal/external changes. - const cachedValueIndex = bindingIndex + 1; - let cachedValue = getValue(data, cachedValueIndex); - if (cachedValue === NO_CHANGE) { - cachedValue = initialValue; - } - cachedValue = typeof cachedValue !== 'string' ? '' : cachedValue; - - // If a class/style value was modified externally then the styling - // fast pass cannot guarantee that the external values are retained. - // When this happens, the algorithm will bail out and not write to - // the style or className attribute directly. - const propBindingsFlag = - isClassBased ? TNodeFlags.hasClassPropBindings : TNodeFlags.hasStylePropBindings; - let writeToAttrDirectly = !hasConfig(tNode, propBindingsFlag); - if (writeToAttrDirectly && - checkIfExternallyModified(element as HTMLElement, cachedValue, isClassBased)) { - writeToAttrDirectly = false; - if (oldValue !== VALUE_IS_EXTERNALLY_MODIFIED) { - // direct styling will reset the attribute entirely each time, - // and, for this reason, if the algorithm decides it cannot - // write to the class/style attributes directly then it must - // reset all the previous style/class values before it starts - // to apply values in the non-direct way. - removeStylingValues(renderer, element, oldValue, isClassBased); - - // this will instruct the algorithm not to apply class or style - // values directly anymore. - setValue(data, cachedValueIndex, VALUE_IS_EXTERNALLY_MODIFIED); - } - } - - if (writeToAttrDirectly) { - const initialValue = - hasInitial && !bindingValueContainsInitial ? getInitialStylingValue(context) : null; - const valueToApply = - writeStylingValueDirectly(renderer, element, value, isClassBased, initialValue); - setValue(data, cachedValueIndex, valueToApply || null); - } else { - const applyFn = isClassBased ? setClass : setStyle; - const map = normalizeIntoStylingMap(oldValue, value, !isClassBased); - const initialStyles = hasInitial ? getStylingMapArray(context) : null; - - for (let i = StylingMapArrayIndex.ValuesStartPosition; i < map.length; - i += StylingMapArrayIndex.TupleSize) { - const prop = getMapProp(map, i); - const value = getMapValue(map, i); - - // case 1: apply the map value (if it exists) - let applied = - applyStylingValue(renderer, element, prop, value, applyFn, bindingIndex, sanitizer); - - // case 2: apply the initial value (if it exists) - if (!applied && initialStyles) { - applied = findAndApplyMapValue( - renderer, element, applyFn, initialStyles, prop, bindingIndex, sanitizer); - } - - // default case: apply `null` to remove the value - if (!applied) { - applyFn(renderer, element, prop, null, bindingIndex); - } - } - - const state = getStylingState(element, TEMPLATE_DIRECTIVE_INDEX); - if (isClassBased) { - state.lastDirectClassMap = map; - } else { - state.lastDirectStyleMap = map; - } - } - } -} - -export function writeStylingValueDirectly( - renderer: any, element: RElement, value: {[key: string]: any} | string | null, - isClassBased: boolean, initialValue: string | null): string { - let valueToApply: string; - if (isClassBased) { - valueToApply = typeof value === 'string' ? value : objectToClassName(value); - if (initialValue !== null) { - valueToApply = concatString(initialValue, valueToApply, ' '); - } - setClassName(renderer, element, valueToApply); - } else { - valueToApply = forceStylesAsString(value, true); - if (initialValue !== null) { - valueToApply = initialValue + ';' + valueToApply; - } - setStyleAttr(renderer, element, valueToApply); - } - return valueToApply; -} - -/** - * Applies the provided styling prop/value to the element directly (without context resolution). - * - * This function is designed to be run from the styling instructions and will be called - * automatically. This function is intended to be used for performance reasons in the - * event that there is no need to apply styling via context resolution. - * - * This function has four different cases that can occur: - * - * - Case 1: Apply the provided prop/value (style or class) entry to the element - * (if it is `non null`). - * - * - Case 2: If value does not get applied (because its `null` or `undefined`) then the algorithm - * will check to see if a styling map value was applied to the element as well just - * before this (via `styleMap` or `classMap`). If and when a map is present then the - * algorithm will find the matching property in the map and apply its value. - * - * - Case 3: If a map value fails to be applied then the algorithm will check to see if there - * are any initial values present and attempt to apply a matching value based on - * the target prop. - * - * - Default Case: If a matching initial value cannot be applied then a default value - * of `null` will be applied (which will remove the style/class value - * from the element). - * - * See `allowDirectStylingApply` to learn the logic used to determine whether any style/class - * bindings can be directly applied. - * - * @returns whether or not the prop/value styling was applied to the element. - */ -export function applyStylingValueDirectly( - renderer: any, context: TStylingContext, tNode: TStylingNode, element: RElement, - data: LStylingData, bindingIndex: number, prop: string, value: any, isClassBased: boolean, - sanitizer?: StyleSanitizeFn | null): boolean { - let applied = false; - if (hasValueChanged(data[bindingIndex], value)) { - setValue(data, bindingIndex, value); - const applyFn = isClassBased ? setClass : setStyle; - - // case 1: apply the provided value (if it exists) - applied = applyStylingValue(renderer, element, prop, value, applyFn, bindingIndex, sanitizer); - - // case 2: find the matching property in a styling map and apply the detected value - const mapBindingsFlag = - isClassBased ? TNodeFlags.hasClassMapBindings : TNodeFlags.hasStyleMapBindings; - if (!applied && hasConfig(tNode, mapBindingsFlag)) { - const state = getStylingState(element, TEMPLATE_DIRECTIVE_INDEX); - const map = isClassBased ? state.lastDirectClassMap : state.lastDirectStyleMap; - applied = map ? - findAndApplyMapValue(renderer, element, applyFn, map, prop, bindingIndex, sanitizer) : - false; - } - - // case 3: apply the initial value (if it exists) - if (!applied && hasConfig(tNode, TNodeFlags.hasInitialStyling)) { - const map = getStylingMapArray(context); - applied = - map ? findAndApplyMapValue(renderer, element, applyFn, map, prop, bindingIndex) : false; - } - - // default case: apply `null` to remove the value - if (!applied) { - applyFn(renderer, element, prop, null, bindingIndex); - } - } - return applied; -} - -function applyStylingValue( - renderer: any, element: RElement, prop: string, value: any, applyFn: ApplyStylingFn, - bindingIndex: number, sanitizer?: StyleSanitizeFn | null): boolean { - let valueToApply: string|null = unwrapSafeValue(value); - if (isStylingValueDefined(valueToApply)) { - valueToApply = - sanitizer ? sanitizer(prop, value, StyleSanitizeMode.ValidateAndSanitize) : valueToApply; - applyFn(renderer, element, prop, valueToApply, bindingIndex); - return true; - } - return false; -} - -function findAndApplyMapValue( - renderer: any, element: RElement, applyFn: ApplyStylingFn, map: StylingMapArray, prop: string, - bindingIndex: number, sanitizer?: StyleSanitizeFn | null) { - for (let i = StylingMapArrayIndex.ValuesStartPosition; i < map.length; - i += StylingMapArrayIndex.TupleSize) { - const p = getMapProp(map, i); - if (p === prop) { - let valueToApply = getMapValue(map, i); - valueToApply = sanitizer ? - sanitizer(prop, valueToApply, StyleSanitizeMode.ValidateAndSanitize) : - valueToApply; - applyFn(renderer, element, prop, valueToApply, bindingIndex); - return true; - } - if (p > prop) { - break; - } - } - return false; -} - -function normalizeBitMaskValue(value: number | boolean): number { - // if pass => apply all values (-1 implies that all bits are flipped to true) - if (value === true) return -1; - - // if pass => skip all values - if (value === false) return 0; - - // return the bit mask value as is - return value; -} - -let _activeStylingMapApplyFn: SyncStylingMapsFn|null = null; -export function getStylingMapsSyncFn() { - return _activeStylingMapApplyFn; -} - -export function setStylingMapsSyncFn(fn: SyncStylingMapsFn) { - _activeStylingMapApplyFn = fn; -} - -/** - * Assigns a style value to a style property for the given element. - */ -export const setStyle: ApplyStylingFn = - (renderer: Renderer3 | null, native: RElement, prop: string, value: string | null) => { - if (renderer !== null) { - // Use `isStylingValueDefined` to account for falsy values that should be bound like 0. - if (isStylingValueDefined(value)) { - // opacity, z-index and flexbox all have number values - // and these need to be converted into strings so that - // they can be assigned properly. - value = value.toString(); - ngDevMode && ngDevMode.rendererSetStyle++; - if (isProceduralRenderer(renderer)) { - renderer.setStyle(native, prop, value, RendererStyleFlags3.DashCase); - } else { - // The reason why native style may be `null` is either because - // it's a container element or it's a part of a test - // environment that doesn't have styling. In either - // case it's safe not to apply styling to the element. - const nativeStyle = native.style; - if (nativeStyle != null) { - nativeStyle.setProperty(prop, value); - } - } - } else { - ngDevMode && ngDevMode.rendererRemoveStyle++; - - if (isProceduralRenderer(renderer)) { - renderer.removeStyle(native, prop, RendererStyleFlags3.DashCase); - } else { - const nativeStyle = native.style; - if (nativeStyle != null) { - nativeStyle.removeProperty(prop); - } - } - } - } - }; - -/** - * Adds/removes the provided className value to the provided element. - */ -export const setClass: ApplyStylingFn = - (renderer: Renderer3 | null, native: RElement, className: string, value: any) => { - if (renderer !== null && className !== '') { - if (value) { - ngDevMode && ngDevMode.rendererAddClass++; - if (isProceduralRenderer(renderer)) { - renderer.addClass(native, className); - } else { - // the reason why classList may be `null` is either because - // it's a container element or it's a part of a test - // environment that doesn't have styling. In either - // case it's safe not to apply styling to the element. - const classList = native.classList; - if (classList != null) { - classList.add(className); - } - } - } else { - ngDevMode && ngDevMode.rendererRemoveClass++; - if (isProceduralRenderer(renderer)) { - renderer.removeClass(native, className); - } else { - const classList = native.classList; - if (classList != null) { - classList.remove(className); - } - } - } - } - }; - -export const setClassName = (renderer: Renderer3 | null, native: RElement, className: string) => { - if (renderer !== null) { - if (isProceduralRenderer(renderer)) { - renderer.setAttribute(native, 'class', className); - } else { - native.className = className; - } - } -}; - -export const setStyleAttr = (renderer: Renderer3 | null, native: RElement, value: string) => { - if (renderer !== null) { - if (isProceduralRenderer(renderer)) { - renderer.setAttribute(native, 'style', value); - } else { - native.setAttribute('style', value); - } - } -}; - -/** - * Iterates over all provided styling entries and renders them on the element. - * - * This function is used alongside a `StylingMapArray` entry. This entry is not - * the same as the `TStylingContext` and is only really used when an element contains - * initial styling values (e.g. `
`), but no style/class bindings - * are present. If and when that happens then this function will be called to render all - * initial styling values on an element. - */ -export function renderStylingMap( - renderer: Renderer3, element: RElement, stylingValues: TStylingContext | StylingMapArray | null, - isClassBased: boolean): void { - const stylingMapArr = getStylingMapArray(stylingValues); - if (stylingMapArr) { - for (let i = StylingMapArrayIndex.ValuesStartPosition; i < stylingMapArr.length; - i += StylingMapArrayIndex.TupleSize) { - const prop = getMapProp(stylingMapArr, i); - const value = getMapValue(stylingMapArr, i); - if (isClassBased) { - setClass(renderer, element, prop, value, null); - } else { - setStyle(renderer, element, prop, value, null); - } - } - } -} - -function objectToClassName(obj: {[key: string]: any} | null): string { - let str = ''; - if (obj) { - for (let key in obj) { - const value = obj[key]; - if (value) { - str += (str.length ? ' ' : '') + key; - } - } - } - return str; -} - -/** - * Determines whether or not an element style/className value has changed since the last update. - * - * This function helps Angular determine if a style or class attribute value was - * modified by an external plugin or API outside of the style binding code. This - * means any JS code that adds/removes class/style values on an element outside - * of Angular's styling binding algorithm. - * - * @returns true when the value was modified externally. - */ -function checkIfExternallyModified(element: HTMLElement, cachedValue: any, isClassBased: boolean) { - // this means it was checked before and there is no reason - // to compare the style/class values again. Either that or - // web workers are being used. - if (global.Node === 'undefined' || cachedValue === VALUE_IS_EXTERNALLY_MODIFIED) return true; - - // comparing the DOM value against the cached value is the best way to - // see if something has changed. - const currentValue = - (isClassBased ? element.className : (element.style && element.style.cssText)) || ''; - return currentValue !== (cachedValue || ''); -} - -/** - * Removes provided styling values from the element - */ -function removeStylingValues( - renderer: any, element: RElement, values: string | {[key: string]: any} | StylingMapArray, - isClassBased: boolean) { - let arr: StylingMapArray; - if (isStylingMapArray(values)) { - arr = values as StylingMapArray; - } else { - arr = normalizeIntoStylingMap(null, values, !isClassBased); - } - - const applyFn = isClassBased ? setClass : setStyle; - for (let i = StylingMapArrayIndex.ValuesStartPosition; i < arr.length; - i += StylingMapArrayIndex.TupleSize) { - const value = getMapValue(arr, i); - if (value) { - const prop = getMapProp(arr, i); - applyFn(renderer, element, prop, null); - } - } -} diff --git a/packages/core/src/render3/styling/class_differ.ts b/packages/core/src/render3/styling/class_differ.ts new file mode 100644 index 0000000000..36b8f05c0b --- /dev/null +++ b/packages/core/src/render3/styling/class_differ.ts @@ -0,0 +1,42 @@ +/** +* @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 {assertNotEqual} from '../../util/assert'; +import {CharCode} from '../../util/char_code'; + + +/** + * Returns an index of `classToSearch` in `className` taking token boundaries into account. + * + * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`) + * + * @param className A string containing classes (whitespace separated) + * @param classToSearch A class name to locate + * @param startingIndex Starting location of search + * @returns an index of the located class (or -1 if not found) + */ +export function classIndexOf( + className: string, classToSearch: string, startingIndex: number): number { + ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.'); + let end = className.length; + while (true) { + const foundIndex = className.indexOf(classToSearch, startingIndex); + if (foundIndex === -1) return foundIndex; + if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= CharCode.SPACE) { + // Ensure that it has leading whitespace + const length = classToSearch.length; + if (foundIndex + length === end || + className.charCodeAt(foundIndex + length) <= CharCode.SPACE) { + // Ensure that it has trailing whitespace + return foundIndex; + } + } + // False positive, keep searching from where we left off. + startingIndex = foundIndex + 1; + } +} \ No newline at end of file diff --git a/packages/core/src/render3/styling/map_based_bindings.ts b/packages/core/src/render3/styling/map_based_bindings.ts deleted file mode 100644 index 2b6974f833..0000000000 --- a/packages/core/src/render3/styling/map_based_bindings.ts +++ /dev/null @@ -1,362 +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 {unwrapSafeValue} from '../../sanitization/bypass'; -import {StyleSanitizeFn, StyleSanitizeMode} from '../../sanitization/style_sanitizer'; -import {ProceduralRenderer3, RElement, Renderer3} from '../interfaces/renderer'; -import {ApplyStylingFn, LStylingData, StylingMapArray, StylingMapArrayIndex, StylingMapsSyncMode, SyncStylingMapsFn, TStylingContext, TStylingContextIndex} from '../interfaces/styling'; -import {getBindingValue, getMapProp, getMapValue, getValue, getValuesCount, isStylingValueDefined} from '../util/styling_utils'; - -import {setStylingMapsSyncFn} from './bindings'; - - -/** - * -------- - * - * This file contains the algorithm logic for applying map-based bindings - * such as `[style]` and `[class]`. - * - * -------- - */ - -/** - * Enables support for map-based styling bindings (e.g. `[style]` and `[class]` bindings). - */ -export function activateStylingMapFeature() { - setStylingMapsSyncFn(syncStylingMap); -} - -/** - * Used to apply styling values presently within any map-based bindings on an element. - * - * Angular supports map-based styling bindings which can be applied via the - * `[style]` and `[class]` bindings which can be placed on any HTML element. - * These bindings can work independently, together or alongside prop-based - * styling bindings (e.g. `
`). - * - * If a map-based styling binding is detected by the compiler, the following - * AOT code is produced: - * - * ```typescript - * styleMap(ctx.styles); // styles = {key:value} - * classMap(ctx.classes); // classes = {key:value}|string - * ``` - * - * If and when either of the instructions above are evaluated, then the code - * present in this file is included into the bundle. The mechanism used, to - * activate support for map-based bindings at runtime is possible via the - * `activeStylingMapFeature` function (which is also present in this file). - * - * # The Algorithm - * Whenever a map-based binding updates (which is when the identity of the - * map-value changes) then the map is iterated over and a `StylingMapArray` array - * is produced. The `StylingMapArray` instance is stored in the binding location - * where the `BINDING_INDEX` is situated when the `styleMap()` or `classMap()` - * instruction were called. Once the binding changes, then the internal `bitMask` - * value is marked as dirty. - * - * Styling values are applied once CD exits the element (which happens when - * the `advance(n)` instruction is called or the template function exits). When - * this occurs, all prop-based bindings are applied. If a map-based binding is - * present then a special flushing function (called a sync function) is made - * available and it will be called each time a styling property is flushed. - * - * The flushing algorithm is designed to apply styling for a property (which is - * a CSS property or a className value) one by one. If map-based bindings - * are present, then the flushing algorithm will keep calling the maps styling - * sync function each time a property is visited. This way, the flushing - * behavior of map-based bindings will always be at the same property level - * as the current prop-based property being iterated over (because everything - * is alphabetically sorted). - * - * Let's imagine we have the following HTML template code: - * - * ```html - *
...
- * ``` - * - * When CD occurs, both the `[style]` and `[style.width]` bindings - * are evaluated. Then when the styles are flushed on screen, the - * following operations happen: - * - * 1. `[style.width]` is attempted to be written to the element. - * - * 2. Once that happens, the algorithm instructs the map-based - * entries (`[style]` in this case) to "catch up" and apply - * all values up to the `width` value. When this happens the - * `height` value is applied to the element (since it is - * alphabetically situated before the `width` property). - * - * 3. Since there are no more prop-based entries anymore, the - * loop exits and then, just before the flushing ends, it - * instructs all map-based bindings to "finish up" applying - * their values. - * - * 4. The only remaining value within the map-based entries is - * the `z-index` value (`width` got skipped because it was - * successfully applied via the prop-based `[style.width]` - * binding). Since all map-based entries are told to "finish up", - * the `z-index` value is iterated over and it is then applied - * to the element. - * - * The most important thing to take note of here is that prop-based - * bindings are evaluated in order alongside map-based bindings. - * This allows all styling across an element to be applied in O(n) - * time (a similar algorithm is that of the array merge algorithm - * in merge sort). - */ -export const syncStylingMap: SyncStylingMapsFn = - (context: TStylingContext, renderer: Renderer3 | ProceduralRenderer3 | null, element: RElement, - data: LStylingData, sourceIndex: number, applyStylingFn: ApplyStylingFn, - sanitizer: StyleSanitizeFn | null, mode: StylingMapsSyncMode, targetProp?: string | null, - defaultValue?: string | boolean | null): boolean => { - let targetPropValueWasApplied = false; - - // once the map-based styling code is activate it is never deactivated. For this reason a - // check to see if the current styling context has any map based bindings is required. - const totalMaps = getValuesCount(context); - if (totalMaps) { - let runTheSyncAlgorithm = true; - const loopUntilEnd = !targetProp; - - // If the code is told to finish up (run until the end), but the mode - // hasn't been flagged to apply values (it only traverses values) then - // there is no point in iterating over the array because nothing will - // be applied to the element. - if (loopUntilEnd && (mode & StylingMapsSyncMode.ApplyAllValues) === 0) { - runTheSyncAlgorithm = false; - targetPropValueWasApplied = true; - } - - if (runTheSyncAlgorithm) { - targetPropValueWasApplied = innerSyncStylingMap( - context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp || null, - sourceIndex, defaultValue || null); - } - - if (loopUntilEnd) { - resetSyncCursors(); - } - } - - return targetPropValueWasApplied; - }; - -/** - * Recursive function designed to apply map-based styling to an element one map at a time. - * - * This function is designed to be called from the `syncStylingMap` function and will - * apply map-based styling data one map at a time to the provided `element`. - * - * This function is recursive and it will call itself if a follow-up map value is to be - * processed. To learn more about how the algorithm works, see `syncStylingMap`. - */ -function innerSyncStylingMap( - context: TStylingContext, renderer: Renderer3 | ProceduralRenderer3 | null, element: RElement, - data: LStylingData, applyStylingFn: ApplyStylingFn, sanitizer: StyleSanitizeFn | null, - mode: StylingMapsSyncMode, targetProp: string | null, currentMapIndex: number, - defaultValue: string | boolean | null): boolean { - const totalMaps = getValuesCount(context) - 1; // maps have no default value - const mapsLimit = totalMaps - 1; - const recurseInnerMaps = - currentMapIndex < mapsLimit && (mode & StylingMapsSyncMode.RecurseInnerMaps) !== 0; - const checkValuesOnly = (mode & StylingMapsSyncMode.CheckValuesOnly) !== 0; - - if (checkValuesOnly) { - // inner modes do not check values ever (that can only happen - // when sourceIndex === 0) - mode &= ~StylingMapsSyncMode.CheckValuesOnly; - } - - let targetPropValueWasApplied = false; - if (currentMapIndex <= mapsLimit) { - let cursor = getCurrentSyncCursor(currentMapIndex); - const bindingIndex = getBindingValue( - context, TStylingContextIndex.ValuesStartPosition, currentMapIndex) as number; - const stylingMapArr = getValue(data, bindingIndex); - - if (stylingMapArr) { - while (cursor < stylingMapArr.length) { - const prop = getMapProp(stylingMapArr, cursor); - const iteratedTooFar = targetProp && prop > targetProp; - const isTargetPropMatched = !iteratedTooFar && prop === targetProp; - const value = getMapValue(stylingMapArr, cursor); - const valueIsDefined = isStylingValueDefined(value); - - // the recursive code is designed to keep applying until - // it reaches or goes past the target prop. If and when - // this happens then it will stop processing values, but - // all other map values must also catch up to the same - // point. This is why a recursive call is still issued - // even if the code has iterated too far. - const innerMode = - iteratedTooFar ? mode : resolveInnerMapMode(mode, valueIsDefined, isTargetPropMatched); - - const innerProp = iteratedTooFar ? targetProp : prop; - let valueApplied = recurseInnerMaps ? - innerSyncStylingMap( - context, renderer, element, data, applyStylingFn, sanitizer, innerMode, innerProp, - currentMapIndex + 1, defaultValue) : - false; - - if (iteratedTooFar) { - if (!targetPropValueWasApplied) { - targetPropValueWasApplied = valueApplied; - } - break; - } - - if (!valueApplied && isValueAllowedToBeApplied(mode, isTargetPropMatched)) { - valueApplied = true; - - if (!checkValuesOnly) { - const useDefault = isTargetPropMatched && !valueIsDefined; - const bindingIndexToApply = isTargetPropMatched ? bindingIndex : null; - - let finalValue: any; - if (useDefault) { - finalValue = defaultValue; - } else { - finalValue = sanitizer ? - sanitizer(prop, value, StyleSanitizeMode.ValidateAndSanitize) : - (value ? unwrapSafeValue(value) : null); - } - - applyStylingFn(renderer, element, prop, finalValue, bindingIndexToApply); - } - } - - targetPropValueWasApplied = valueApplied && isTargetPropMatched; - cursor += StylingMapArrayIndex.TupleSize; - } - setCurrentSyncCursor(currentMapIndex, cursor); - - // this is a fallback case in the event that the styling map is `null` for this - // binding but there are other map-based bindings that need to be evaluated - // afterwards. If the `prop` value is falsy then the intention is to cycle - // through all of the properties in the remaining maps as well. If the current - // styling map is too short then there are no values to iterate over. In either - // case the follow-up maps need to be iterated over. - if (recurseInnerMaps && - (stylingMapArr.length === StylingMapArrayIndex.ValuesStartPosition || !targetProp)) { - targetPropValueWasApplied = innerSyncStylingMap( - context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp, - currentMapIndex + 1, defaultValue); - } - } else if (recurseInnerMaps) { - targetPropValueWasApplied = innerSyncStylingMap( - context, renderer, element, data, applyStylingFn, sanitizer, mode, targetProp, - currentMapIndex + 1, defaultValue); - } - } - - return targetPropValueWasApplied; -} - -/** - * Used to determine the mode for the inner recursive call. - * - * If an inner map is iterated on then this is done so for one - * of two reasons: - * - * - value is being applied: - * if the value is being applied from this current styling - * map then there is no need to apply it in a deeper map - * (i.e. the `SkipTargetProp` flag is set) - * - * - value is being not applied: - * apply the value if it is found in a deeper map. - * (i.e. the `SkipTargetProp` flag is unset) - * - * When these reasons are encountered the flags will for the - * inner map mode will be configured. - */ -function resolveInnerMapMode( - currentMode: number, valueIsDefined: boolean, isTargetPropMatched: boolean): number { - let innerMode = currentMode; - - // the statements below figures out whether or not an inner styling map - // is allowed to apply its value or not. The main thing to keep note - // of is that if the target prop isn't matched then its expected that - // all values before it are allowed to be applied so long as "apply all values" - // is set to true. - const applyAllValues = currentMode & StylingMapsSyncMode.ApplyAllValues; - const applyTargetProp = currentMode & StylingMapsSyncMode.ApplyTargetProp; - const allowInnerApply = - !valueIsDefined && (isTargetPropMatched ? applyTargetProp : applyAllValues); - - if (allowInnerApply) { - // case 1: set the mode to apply the targeted prop value if it - // ends up being encountered in another map value - innerMode |= StylingMapsSyncMode.ApplyTargetProp; - innerMode &= ~StylingMapsSyncMode.SkipTargetProp; - } else { - // case 2: set the mode to skip the targeted prop value if it - // ends up being encountered in another map value - innerMode |= StylingMapsSyncMode.SkipTargetProp; - innerMode &= ~StylingMapsSyncMode.ApplyTargetProp; - } - - return innerMode; -} - -/** - * Decides whether or not a prop/value entry will be applied to an element. - * - * To determine whether or not a value is to be applied, - * the following procedure is evaluated: - * - * First check to see the current `mode` status: - * 1. If the mode value permits all props to be applied then allow. - * - But do not allow if the current prop is set to be skipped. - * 2. Otherwise if the current prop is permitted then allow. - */ -function isValueAllowedToBeApplied(mode: StylingMapsSyncMode, isTargetPropMatched: boolean) { - let doApplyValue = (mode & StylingMapsSyncMode.ApplyAllValues) !== 0; - if (!doApplyValue) { - if (mode & StylingMapsSyncMode.ApplyTargetProp) { - doApplyValue = isTargetPropMatched; - } - } else if ((mode & StylingMapsSyncMode.SkipTargetProp) && isTargetPropMatched) { - doApplyValue = false; - } - return doApplyValue; -} - -/** - * Used to keep track of concurrent cursor values for multiple map-based styling bindings present on - * an element. - */ -const MAP_CURSORS: number[] = []; - -/** - * Used to reset the state of each cursor value being used to iterate over map-based styling - * bindings. - */ -function resetSyncCursors() { - for (let i = 0; i < MAP_CURSORS.length; i++) { - MAP_CURSORS[i] = StylingMapArrayIndex.ValuesStartPosition; - } -} - -/** - * Returns an active cursor value at a given mapIndex location. - */ -function getCurrentSyncCursor(mapIndex: number) { - if (mapIndex >= MAP_CURSORS.length) { - MAP_CURSORS.push(StylingMapArrayIndex.ValuesStartPosition); - } - return MAP_CURSORS[mapIndex]; -} - -/** - * Sets a cursor value at a given mapIndex location. - */ -function setCurrentSyncCursor(mapIndex: number, indexValue: number) { - MAP_CURSORS[mapIndex] = indexValue; -} diff --git a/packages/core/src/render3/styling/state.ts b/packages/core/src/render3/styling/state.ts deleted file mode 100644 index 73f5fc42e1..0000000000 --- a/packages/core/src/render3/styling/state.ts +++ /dev/null @@ -1,139 +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 {RElement} from '../interfaces/renderer'; -import {StylingMapArray} from '../interfaces/styling'; -import {TEMPLATE_DIRECTIVE_INDEX} from '../util/styling_utils'; - -/** - * -------- - * - * This file contains all state-based logic for styling in Angular. - * - * Styling in Angular is evaluated with a series of styling-specific - * template instructions which are called one after another each time - * change detection occurs in Angular. - * - * Styling makes use of various temporary, state-based variables between - * instructions so that it can better cache and optimize its values. - * These values are usually populated and cleared when an element is - * exited in change detection (once all the instructions are run for - * that element). - * - * To learn more about the algorithm see `TStylingContext`. - * - * -------- - */ - -/** - * Used as a state reference for update values between style/class binding instructions. - * - * In addition to storing the element and bit-mask related values, the state also - * stores the `sourceIndex` value. The `sourceIndex` value is an incremented value - * that identifies what "source" (i.e. the template, a specific directive by index or - * component) is currently applying its styling bindings to the element. - */ -export interface StylingState { - /** The element that is currently being processed */ - element: RElement|null; - - /** The directive index that is currently active (`0` === template) */ - directiveIndex: number; - - /** The source (column) index that is currently active (`0` === template) */ - sourceIndex: number; - - /** The classes update bit mask value that is processed during each class binding */ - classesBitMask: number; - - /** The classes update bit index value that is processed during each class binding */ - classesIndex: number; - - /** The styles update bit mask value that is processed during each style binding */ - stylesBitMask: number; - - /** The styles update bit index value that is processed during each style binding */ - stylesIndex: number; - - /** - * The last class map that was applied (i.e. `[class]="x"`). - * - * Note that this property is only populated when direct class values are applied - * (i.e. context resolution is not used). - * - * See `allowDirectStyling` for more info. - */ - lastDirectClassMap: StylingMapArray|null; - - /** - * The last style map that was applied (i.e. `[style]="x"`) - * - * Note that this property is only populated when direct style values are applied - * (i.e. context resolution is not used). - * - * See `allowDirectStyling` for more info. - */ - lastDirectStyleMap: StylingMapArray|null; -} - -// these values will get filled in the very first time this is accessed... -const _state: StylingState = { - element: null, - directiveIndex: -1, - sourceIndex: -1, - classesBitMask: -1, - classesIndex: -1, - stylesBitMask: -1, - stylesIndex: -1, - lastDirectClassMap: null, - lastDirectStyleMap: null, -}; - -const BIT_MASK_START_VALUE = 0; - -// the `0` start value is reserved for [map]-based entries -const INDEX_START_VALUE = 1; - -/** - * Returns (or instantiates) the styling state for the given element. - * - * Styling state is accessed and processed each time a style or class binding - * is evaluated. - * - * If and when the provided `element` doesn't match the current element in the - * state then this means that styling was recently cleared or the element has - * changed in change detection. In both cases the styling state is fully reset. - * - * If and when the provided `directiveIndex` doesn't match the current directive - * index in the state then this means that a new source has introduced itself into - * the styling code (or, in other words, another directive or component has started - * to apply its styling host bindings to the element). - */ -export function getStylingState(element: RElement, directiveIndex: number): StylingState { - if (_state.element !== element) { - _state.element = element; - _state.directiveIndex = directiveIndex; - _state.sourceIndex = directiveIndex === TEMPLATE_DIRECTIVE_INDEX ? 0 : 1; - _state.classesBitMask = BIT_MASK_START_VALUE; - _state.classesIndex = INDEX_START_VALUE; - _state.stylesBitMask = BIT_MASK_START_VALUE; - _state.stylesIndex = INDEX_START_VALUE; - _state.lastDirectClassMap = null; - _state.lastDirectStyleMap = null; - } else if (_state.directiveIndex !== directiveIndex) { - _state.directiveIndex = directiveIndex; - _state.sourceIndex++; - } - return _state; -} - -/** - * Clears the styling state so that it can be used by another element's styling code. - */ -export function resetStylingState() { - _state.element = null; -} diff --git a/packages/core/src/render3/styling/static_styling.ts b/packages/core/src/render3/styling/static_styling.ts new file mode 100644 index 0000000000..9a54073ac9 --- /dev/null +++ b/packages/core/src/render3/styling/static_styling.ts @@ -0,0 +1,42 @@ +/** +* @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 {concatStringsWithSpace} from '../../util/stringify'; +import {assertFirstCreatePass} from '../assert'; +import {AttributeMarker, TAttributes, TNode} from '../interfaces/node'; +import {getTView} from '../state'; + +/** + * Compute the static styling (class/style) from `TAttributes`. + * + * This function should be called during `firstCreatePass` only. + * + * @param tNode The `TNode` into which the styling information should be loaded. + * @param attrs `TAttributes` containing the styling information. + */ +export function computeStaticStyling(tNode: TNode, attrs: TAttributes): void { + ngDevMode && + assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only'); + let styles: string|null = tNode.styles; + let classes: string|null = tNode.classes; + let mode: AttributeMarker|0 = 0; + for (let i = 0; i < attrs.length; i++) { + const value = attrs[i]; + if (typeof value === 'number') { + mode = value; + } else if (mode == AttributeMarker.Classes) { + classes = concatStringsWithSpace(classes, value as string); + } else if (mode == AttributeMarker.Styles) { + const style = value as string; + const styleValue = attrs[++i] as string; + styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';'); + } + } + styles !== null && (tNode.styles = styles); + classes !== null && (tNode.classes = classes); +} \ No newline at end of file diff --git a/packages/core/src/render3/styling/style_binding_list.ts b/packages/core/src/render3/styling/style_binding_list.ts new file mode 100644 index 0000000000..808e4e11eb --- /dev/null +++ b/packages/core/src/render3/styling/style_binding_list.ts @@ -0,0 +1,427 @@ +/** +* @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 {KeyValueArray, keyValueArrayIndexOf} from '../../util/array_utils'; +import {assertDataInRange, assertEqual, assertNotEqual} from '../../util/assert'; +import {assertFirstUpdatePass} from '../assert'; +import {TNode} from '../interfaces/node'; +import {TStylingKey, TStylingKeyPrimitive, TStylingRange, getTStylingRangeNext, getTStylingRangePrev, setTStylingRangeNext, setTStylingRangeNextDuplicate, setTStylingRangePrev, setTStylingRangePrevDuplicate, toTStylingRange} from '../interfaces/styling'; +import {TData} from '../interfaces/view'; +import {getTView} from '../state'; + + +/** + * NOTE: The word `styling` is used interchangeably as style or class styling. + * + * This file contains code to link styling instructions together so that they can be replayed in + * priority order. The file exists because Ivy styling instruction execution order does not match + * that of the priority order. The purpose of this code is to create a linked list so that the + * instructions can be traversed in priority order when computing the styles. + * + * Assume we are dealing with the following code: + * ``` + * @Component({ + * template: ` + * ` + * }) + * class ExampleComponent { + * static ngComp = ... { + * ... + * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap` + * ɵɵstyleMap({color: '#001'}); + * ɵɵstyleProp('color', '#002'); + * ... + * } + * } + * + * @Directive({ + * selector: `[dir-style-color-1]', + * }) + * class Style1Directive { + * @HostBinding('style') style = {color: '#005'}; + * @HostBinding('style.color') color = '#006'; + * + * static ngDir = ... { + * ... + * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap` + * ɵɵstyleMap({color: '#005'}); + * ɵɵstyleProp('color', '#006'); + * ... + * } + * } + * + * @Directive({ + * selector: `[dir-style-color-2]', + * }) + * class Style2Directive { + * @HostBinding('style') style = {color: '#007'}; + * @HostBinding('style.color') color = '#008'; + * + * static ngDir = ... { + * ... + * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap` + * ɵɵstyleMap({color: '#007'}); + * ɵɵstyleProp('color', '#008'); + * ... + * } + * } + * + * @Directive({ + * selector: `my-cmp', + * }) + * class MyComponent { + * @HostBinding('style') style = {color: '#003'}; + * @HostBinding('style.color') color = '#004'; + * + * static ngComp = ... { + * ... + * // Compiler ensures that `ɵɵstyleProp` is after `ɵɵstyleMap` + * ɵɵstyleMap({color: '#003'}); + * ɵɵstyleProp('color', '#004'); + * ... + * } + * } + * ``` + * + * The Order of instruction execution is: + * + * NOTE: the comment binding location is for illustrative purposes only. + * + * ``` + * // Template: (ExampleComponent) + * ɵɵstyleMap({color: '#001'}); // Binding index: 10 + * ɵɵstyleProp('color', '#002'); // Binding index: 12 + * // MyComponent + * ɵɵstyleMap({color: '#003'}); // Binding index: 20 + * ɵɵstyleProp('color', '#004'); // Binding index: 22 + * // Style1Directive + * ɵɵstyleMap({color: '#005'}); // Binding index: 24 + * ɵɵstyleProp('color', '#006'); // Binding index: 26 + * // Style2Directive + * ɵɵstyleMap({color: '#007'}); // Binding index: 28 + * ɵɵstyleProp('color', '#008'); // Binding index: 30 + * ``` + * + * The correct priority order of concatenation is: + * + * ``` + * // MyComponent + * ɵɵstyleMap({color: '#003'}); // Binding index: 20 + * ɵɵstyleProp('color', '#004'); // Binding index: 22 + * // Style1Directive + * ɵɵstyleMap({color: '#005'}); // Binding index: 24 + * ɵɵstyleProp('color', '#006'); // Binding index: 26 + * // Style2Directive + * ɵɵstyleMap({color: '#007'}); // Binding index: 28 + * ɵɵstyleProp('color', '#008'); // Binding index: 30 + * // Template: (ExampleComponent) + * ɵɵstyleMap({color: '#001'}); // Binding index: 10 + * ɵɵstyleProp('color', '#002'); // Binding index: 12 + * ``` + * + * What color should be rendered? + * + * Once the items are correctly sorted in the list, the answer is simply the last item in the + * concatenation list which is `#002`. + * + * To do so we keep a linked list of all of the bindings which pertain to this element. + * Notice that the bindings are inserted in the order of execution, but the `TView.data` allows + * us to traverse them in the order of priority. + * + * |Idx|`TView.data`|`LView` | Notes + * |---|------------|-----------------|-------------- + * |...| | | + * |10 |`null` |`{color: '#001'}`| `ɵɵstyleMap('color', {color: '#001'})` + * |11 |`30 | 12` | ... | + * |12 |`color` |`'#002'` | `ɵɵstyleProp('color', '#002')` + * |13 |`10 | 0` | ... | + * |...| | | + * |20 |`null` |`{color: '#003'}`| `ɵɵstyleMap('color', {color: '#003'})` + * |21 |`0 | 22` | ... | + * |22 |`color` |`'#004'` | `ɵɵstyleProp('color', '#004')` + * |23 |`20 | 24` | ... | + * |24 |`null` |`{color: '#005'}`| `ɵɵstyleMap('color', {color: '#005'})` + * |25 |`22 | 26` | ... | + * |26 |`color` |`'#006'` | `ɵɵstyleProp('color', '#006')` + * |27 |`24 | 28` | ... | + * |28 |`null` |`{color: '#007'}`| `ɵɵstyleMap('color', {color: '#007'})` + * |29 |`26 | 30` | ... | + * |30 |`color` |`'#008'` | `ɵɵstyleProp('color', '#008')` + * |31 |`28 | 10` | ... | + * + * The above data structure allows us to re-concatenate the styling no matter which data binding + * changes. + * + * NOTE: in addition to keeping track of next/previous index the `TView.data` also stores prev/next + * duplicate bit. The duplicate bit if true says there either is a binding with the same name or + * there is a map (which may contain the name). This information is useful in knowing if other + * styles with higher priority need to be searched for overwrites. + * + * NOTE: See `should support example in 'tnode_linked_list.ts' documentation` in + * `tnode_linked_list_spec.ts` for working example. + */ +let __unused_const_as_closure_does_not_like_standalone_comment_blocks__: undefined; + +/** + * Insert new `tStyleValue` at `TData` and link existing style bindings such that we maintain linked + * list of styles and compute the duplicate flag. + * + * Note: this function is executed during `firstUpdatePass` only to populate the `TView.data`. + * + * The function works by keeping track of `tStylingRange` which contains two pointers pointing to + * the head/tail of the template portion of the styles. + * - if `isHost === false` (we are template) then insertion is at tail of `TStylingRange` + * - if `isHost === true` (we are host binding) then insertion is at head of `TStylingRange` + * + * @param tData The `TData` to insert into. + * @param tNode `TNode` associated with the styling element. + * @param tStylingKey See `TStylingKey`. + * @param index location of where `tStyleValue` should be stored (and linked into list.) + * @param isHostBinding `true` if the insertion is for a `hostBinding`. (insertion is in front of + * template.) + * @param isClassBinding True if the associated `tStylingKey` as a `class` styling. + * `tNode.classBindings` should be used (or `tNode.styleBindings` otherwise.) + */ +export function insertTStylingBinding( + tData: TData, tNode: TNode, tStylingKeyWithStatic: TStylingKey, index: number, + isHostBinding: boolean, isClassBinding: boolean): void { + ngDevMode && assertFirstUpdatePass(getTView()); + let tBindings = isClassBinding ? tNode.classBindings : tNode.styleBindings; + let tmplHead = getTStylingRangePrev(tBindings); + let tmplTail = getTStylingRangeNext(tBindings); + + tData[index] = tStylingKeyWithStatic; + let isKeyDuplicateOfStatic = false; + let tStylingKey: TStylingKeyPrimitive; + if (Array.isArray(tStylingKeyWithStatic)) { + // We are case when the `TStylingKey` contains static fields as well. + const staticKeyValueArray = tStylingKeyWithStatic as KeyValueArray; + tStylingKey = staticKeyValueArray[1]; // unwrap. + // We need to check if our key is present in the static so that we can mark it as duplicate. + if (tStylingKey === null || + keyValueArrayIndexOf(staticKeyValueArray, tStylingKey as string) > 0) { + // tStylingKey is present in the statics, need to mark it as duplicate. + isKeyDuplicateOfStatic = true; + } + } else { + tStylingKey = tStylingKeyWithStatic; + } + if (isHostBinding) { + // We are inserting host bindings + + // If we don't have template bindings then `tail` is 0. + const hasTemplateBindings = tmplTail !== 0; + // This is important to know because that means that the `head` can't point to the first + // template bindings (there are none.) Instead the head points to the tail of the template. + if (hasTemplateBindings) { + // template head's "prev" will point to last host binding or to 0 if no host bindings yet + const previousNode = getTStylingRangePrev(tData[tmplHead + 1] as TStylingRange); + tData[index + 1] = toTStylingRange(previousNode, tmplHead); + // if a host binding has already been registered, we need to update the next of that host + // binding to point to this one + if (previousNode !== 0) { + // We need to update the template-tail value to point to us. + tData[previousNode + 1] = + setTStylingRangeNext(tData[previousNode + 1] as TStylingRange, index); + } + // The "previous" of the template binding head should point to this host binding + tData[tmplHead + 1] = setTStylingRangePrev(tData[tmplHead + 1] as TStylingRange, index); + } else { + tData[index + 1] = toTStylingRange(tmplHead, 0); + // if a host binding has already been registered, we need to update the next of that host + // binding to point to this one + if (tmplHead !== 0) { + // We need to update the template-tail value to point to us. + tData[tmplHead + 1] = setTStylingRangeNext(tData[tmplHead + 1] as TStylingRange, index); + } + // if we don't have template, the head points to template-tail, and needs to be advanced. + tmplHead = index; + } + } else { + // We are inserting in template section. + // We need to set this binding's "previous" to the current template tail + tData[index + 1] = toTStylingRange(tmplTail, 0); + ngDevMode && assertEqual( + tmplHead !== 0 && tmplTail === 0, false, + 'Adding template bindings after hostBindings is not allowed.'); + if (tmplHead === 0) { + tmplHead = index; + } else { + // We need to update the previous value "next" to point to this binding + tData[tmplTail + 1] = setTStylingRangeNext(tData[tmplTail + 1] as TStylingRange, index); + } + tmplTail = index; + } + + // Now we need to update / compute the duplicates. + // Starting with our location search towards head (least priority) + if (isKeyDuplicateOfStatic) { + tData[index + 1] = setTStylingRangePrevDuplicate(tData[index + 1] as TStylingRange); + } + markDuplicates(tData, tStylingKey, index, true, isClassBinding); + markDuplicates(tData, tStylingKey, index, false, isClassBinding); + markDuplicateOfResidualStyling(tNode, tStylingKey, tData, index, isClassBinding); + + tBindings = toTStylingRange(tmplHead, tmplTail); + if (isClassBinding) { + tNode.classBindings = tBindings; + } else { + tNode.styleBindings = tBindings; + } +} + +/** + * Look into the residual styling to see if the current `tStylingKey` is duplicate of residual. + * + * @param tNode `TNode` where the residual is stored. + * @param tStylingKey `TStylingKey` to store. + * @param tData `TData` associated with the current `LView`. + * @param index location of where `tStyleValue` should be stored (and linked into list.) + * @param isClassBinding True if the associated `tStylingKey` as a `class` styling. + * `tNode.classBindings` should be used (or `tNode.styleBindings` otherwise.) + */ +function markDuplicateOfResidualStyling( + tNode: TNode, tStylingKey: TStylingKey, tData: TData, index: number, isClassBinding: boolean) { + const residual = isClassBinding ? tNode.residualClasses : tNode.residualStyles; + if (residual != null /* or undefined */ && typeof tStylingKey == 'string' && + keyValueArrayIndexOf(residual, tStylingKey) >= 0) { + // We have duplicate in the residual so mark ourselves as duplicate. + tData[index + 1] = setTStylingRangeNextDuplicate(tData[index + 1] as TStylingRange); + } +} + + +/** + * Marks `TStyleValue`s as duplicates if another style binding in the list has the same + * `TStyleValue`. + * + * NOTE: this function is intended to be called twice once with `isPrevDir` set to `true` and once + * with it set to `false` to search both the previous as well as next items in the list. + * + * No duplicate case + * ``` + * [style.color] + * [style.width.px] <<- index + * [style.height.px] + * ``` + * + * In the above case adding `[style.width.px]` to the existing `[style.color]` produces no + * duplicates because `width` is not found in any other part of the linked list. + * + * Duplicate case + * ``` + * [style.color] + * [style.width.em] + * [style.width.px] <<- index + * ``` + * In the above case adding `[style.width.px]` will produce a duplicate with `[style.width.em]` + * because `width` is found in the chain. + * + * Map case 1 + * ``` + * [style.width.px] + * [style.color] + * [style] <<- index + * ``` + * In the above case adding `[style]` will produce a duplicate with any other bindings because + * `[style]` is a Map and as such is fully dynamic and could produce `color` or `width`. + * + * Map case 2 + * ``` + * [style] + * [style.width.px] + * [style.color] <<- index + * ``` + * In the above case adding `[style.color]` will produce a duplicate because there is already a + * `[style]` binding which is a Map and as such is fully dynamic and could produce `color` or + * `width`. + * + * NOTE: Once `[style]` (Map) is added into the system all things are mapped as duplicates. + * NOTE: We use `style` as example, but same logic is applied to `class`es as well. + * + * @param tData `TData` where the linked list is stored. + * @param tStylingKey `TStylingKeyPrimitive` which contains the value to compare to other keys in + * the linked list. + * @param index Starting location in the linked list to search from + * @param isPrevDir Direction. + * - `true` for previous (lower priority); + * - `false` for next (higher priority). + */ +function markDuplicates( + tData: TData, tStylingKey: TStylingKeyPrimitive, index: number, isPrevDir: boolean, + isClassBinding: boolean) { + const tStylingAtIndex = tData[index + 1] as TStylingRange; + const isMap = tStylingKey === null; + let cursor = + isPrevDir ? getTStylingRangePrev(tStylingAtIndex) : getTStylingRangeNext(tStylingAtIndex); + let foundDuplicate = false; + // We keep iterating as long as we have a cursor + // AND either: + // - we found what we are looking for, OR + // - we are a map in which case we have to continue searching even after we find what we were + // looking for since we are a wild card and everything needs to be flipped to duplicate. + while (cursor !== 0 && (foundDuplicate === false || isMap)) { + ngDevMode && assertDataInRange(tData, cursor); + const tStylingValueAtCursor = tData[cursor] as TStylingKey; + const tStyleRangeAtCursor = tData[cursor + 1] as TStylingRange; + if (isStylingMatch(tStylingValueAtCursor, tStylingKey)) { + foundDuplicate = true; + tData[cursor + 1] = isPrevDir ? setTStylingRangeNextDuplicate(tStyleRangeAtCursor) : + setTStylingRangePrevDuplicate(tStyleRangeAtCursor); + } + cursor = isPrevDir ? getTStylingRangePrev(tStyleRangeAtCursor) : + getTStylingRangeNext(tStyleRangeAtCursor); + } + if (foundDuplicate) { + // if we found a duplicate, than mark ourselves. + tData[index + 1] = isPrevDir ? setTStylingRangePrevDuplicate(tStylingAtIndex) : + setTStylingRangeNextDuplicate(tStylingAtIndex); + } +} + +/** + * Determines if two `TStylingKey`s are a match. + * + * When computing weather a binding contains a duplicate, we need to compare if the instruction + * `TStylingKey` has a match. + * + * Here are examples of `TStylingKey`s which match given `tStylingKeyCursor` is: + * - `color` + * - `color` // Match another color + * - `null` // That means that `tStylingKey` is a `classMap`/`styleMap` instruction + * - `['', 'color', 'other', true]` // wrapped `color` so match + * - `['', null, 'other', true]` // wrapped `null` so match + * - `['', 'width', 'color', 'value']` // wrapped static value contains a match on `'color'` + * - `null` // `tStylingKeyCursor` always match as it is `classMap`/`styleMap` instruction + * + * @param tStylingKeyCursor + * @param tStylingKey + */ +function isStylingMatch(tStylingKeyCursor: TStylingKey, tStylingKey: TStylingKeyPrimitive) { + ngDevMode && + assertNotEqual( + Array.isArray(tStylingKey), true, 'Expected that \'tStylingKey\' has been unwrapped'); + if (tStylingKeyCursor === null || // If the cursor is `null` it means that we have map at that + // location so we must assume that we have a match. + tStylingKey == null || // If `tStylingKey` is `null` then it is a map therefor assume that it + // contains a match. + (Array.isArray(tStylingKeyCursor) ? tStylingKeyCursor[1] : tStylingKeyCursor) === + tStylingKey // If the keys match explicitly than we are a match. + ) { + return true; + } else if (Array.isArray(tStylingKeyCursor) && typeof tStylingKey === 'string') { + // if we did not find a match, but `tStylingKeyCursor` is `KeyValueArray` that means cursor has + // statics and we need to check those as well. + return keyValueArrayIndexOf(tStylingKeyCursor, tStylingKey) >= + 0; // see if we are matching the key + } + return false; +} diff --git a/packages/core/src/render3/styling/styling_debug.ts b/packages/core/src/render3/styling/styling_debug.ts deleted file mode 100644 index ae87ca6e93..0000000000 --- a/packages/core/src/render3/styling/styling_debug.ts +++ /dev/null @@ -1,497 +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 {StyleSanitizeFn} from '../../sanitization/style_sanitizer'; -import {TNodeFlags} from '../interfaces/node'; -import {RElement} from '../interfaces/renderer'; -import {ApplyStylingFn, LStylingData, TStylingContext, TStylingContextIndex, TStylingNode} from '../interfaces/styling'; -import {getCurrentStyleSanitizer} from '../state'; -import {attachDebugObject} from '../util/debug_utils'; -import {MAP_BASED_ENTRY_PROP_NAME, TEMPLATE_DIRECTIVE_INDEX, allowDirectStyling as _allowDirectStyling, getBindingValue, getDefaultValue, getGuardMask, getProp, getPropValuesStartPosition, getValue, getValuesCount, hasConfig, isSanitizationRequired, isStylingContext, normalizeIntoStylingMap, setValue} from '../util/styling_utils'; - -import {applyStylingViaContext} from './bindings'; -import {activateStylingMapFeature} from './map_based_bindings'; - - - -/** - * -------- - * - * This file contains the core debug functionality for styling in Angular. - * - * To learn more about the algorithm see `TStylingContext`. - * - * -------- - */ - -/** - * A debug-friendly version of `TStylingContext`. - * - * An instance of this is attached to `tStylingContext.debug` when `ngDevMode` is active. - */ -export interface DebugStylingContext { - /** The configuration settings of the associated `TStylingContext` */ - config: DebugStylingConfig; - - /** The associated TStylingContext instance */ - context: TStylingContext; - - /** The associated TStylingContext instance */ - entries: {[prop: string]: DebugStylingContextEntry}; - - /** A status report of all the sources within the context */ - printSources(): void; - - /** A status report of all the entire context as a table */ - printTable(): void; -} - - -/** - * A debug/testing-oriented summary of all styling information in `TNode.flags`. - */ -export interface DebugStylingConfig { - hasMapBindings: boolean; // - hasPropBindings: boolean; // - hasCollisions: boolean; // - hasTemplateBindings: boolean; // - hasHostBindings: boolean; // - allowDirectStyling: boolean; // -} - - -/** - * A debug/testing-oriented summary of all styling entries within a `TStylingContext`. - */ -export interface DebugStylingContextEntry { - /** The property (style or class property) that this entry represents */ - prop: string; - - /** The total amount of styling entries a part of this entry */ - valuesCount: number; - - /** - * The bit guard mask that is used to compare and protect against - * styling changes when any template style/class bindings update - */ - templateBitMask: number; - - /** - * The bit guard mask that is used to compare and protect against - * styling changes when any host style/class bindings update - */ - hostBindingsBitMask: number; - - /** - * Whether or not the entry requires sanitization - */ - sanitizationRequired: boolean; - - /** - * The default value that will be applied if any bindings are falsy - */ - defaultValue: string|boolean|null; - - /** - * All bindingIndex sources that have been registered for this style - */ - sources: (number|null|string)[]; -} - - -/** - * A debug/testing-oriented summary of all styling entries for a `DebugNode` instance. - */ -export interface DebugNodeStyling { - /** The associated debug context of the TStylingContext instance */ - context: DebugStylingContext; - - /** - * A summarization of each style/class property - * present in the context - */ - summary: {[propertyName: string]: DebugNodeStylingEntry}; - - /** - * A key/value map of all styling properties and their - * runtime values - */ - values: {[propertyName: string]: string | number | null | boolean}; - - /** - * Overrides the sanitizer used to process styles - */ - overrideSanitizer(sanitizer: StyleSanitizeFn|null): void; -} - - -/** - * A debug/testing-oriented summary of a styling entry. - * - * A value such as this is generated as an artifact of the `DebugStyling` - * summary. - */ -export interface DebugNodeStylingEntry { - /** The style/class property that the summary is attached to */ - prop: string; - - /** The last applied value for the style/class property */ - value: string|null; - - /** The binding index of the last applied style/class property */ - bindingIndex: number|null; -} - - -/** - * Instantiates and attaches an instance of `TStylingContextDebug` to the provided context - */ -export function attachStylingDebugObject( - context: TStylingContext, tNode: TStylingNode, isClassBased: boolean) { - const debug = new TStylingContextDebug(context, tNode, isClassBased); - attachDebugObject(context, debug); - return debug; -} - -/** - * A human-readable debug summary of the styling data present within `TStylingContext`. - * - * This class is designed to be used within testing code or when an - * application has `ngDevMode` activated. - */ -class TStylingContextDebug implements DebugStylingContext { - constructor( - public readonly context: TStylingContext, private _tNode: TStylingNode, - private _isClassBased: boolean) {} - - get config(): DebugStylingConfig { return buildConfig(this._tNode, this._isClassBased); } - - /** - * Returns a detailed summary of each styling entry in the context. - * - * See `DebugStylingContextEntry`. - */ - get entries(): {[prop: string]: DebugStylingContextEntry} { - const context = this.context; - const totalColumns = getValuesCount(context); - const entries: {[prop: string]: DebugStylingContextEntry} = {}; - const start = getPropValuesStartPosition(context, this._tNode, this._isClassBased); - let i = start; - while (i < context.length) { - const prop = getProp(context, i); - const templateBitMask = getGuardMask(context, i, false); - const hostBindingsBitMask = getGuardMask(context, i, true); - const defaultValue = getDefaultValue(context, i); - const sanitizationRequired = isSanitizationRequired(context, i); - const bindingsStartPosition = i + TStylingContextIndex.BindingsStartOffset; - - const sources: (number | string | null)[] = []; - - for (let j = 0; j < totalColumns; j++) { - const bindingIndex = context[bindingsStartPosition + j] as number | string | null; - if (bindingIndex !== 0) { - sources.push(bindingIndex); - } - } - - entries[prop] = { - prop, - templateBitMask, - hostBindingsBitMask, - sanitizationRequired, - valuesCount: sources.length, defaultValue, sources, - }; - - i += TStylingContextIndex.BindingsStartOffset + totalColumns; - } - return entries; - } - - /** - * Prints a detailed summary of each styling source grouped together with each binding index in - * the context. - */ - printSources(): void { - let output = '\n'; - - const context = this.context; - const prefix = this._isClassBased ? 'class' : 'style'; - const bindingsBySource: { - type: string, - entries: {binding: string, bindingIndex: number, value: any, bitMask: number}[] - }[] = []; - - const totalColumns = getValuesCount(context); - const itemsPerRow = TStylingContextIndex.BindingsStartOffset + totalColumns; - - for (let i = 0; i < totalColumns; i++) { - const isDefaultColumn = i === totalColumns - 1; - const hostBindingsMode = i !== TEMPLATE_DIRECTIVE_INDEX; - const type = getTypeFromColumn(i, totalColumns); - const entries: {binding: string, value: any, bindingIndex: number, bitMask: number}[] = []; - - let j = TStylingContextIndex.ValuesStartPosition; - while (j < context.length) { - const value = getBindingValue(context, j, i); - if (isDefaultColumn || value > 0) { - const bitMask = getGuardMask(context, j, hostBindingsMode); - const bindingIndex = isDefaultColumn ? -1 : value as number; - const prop = getProp(context, j); - const isMapBased = prop === MAP_BASED_ENTRY_PROP_NAME; - const binding = `${prefix}${isMapBased ? '' : '.' + prop}`; - entries.push({binding, value, bindingIndex, bitMask}); - } - j += itemsPerRow; - } - - bindingsBySource.push( - {type, entries: entries.sort((a, b) => a.bindingIndex - b.bindingIndex)}); - } - - bindingsBySource.forEach(entry => { - output += `[${entry.type.toUpperCase()}]\n`; - output += repeat('-', entry.type.length + 2) + '\n'; - - let tab = ' '; - entry.entries.forEach(entry => { - const isDefault = typeof entry.value !== 'number'; - const value = entry.value; - if (!isDefault || value !== null) { - output += `${tab}[${entry.binding}] = \`${value}\``; - output += '\n'; - } - }); - output += '\n'; - }); - - /* tslint:disable */ - console.log(output); - } - - /** - * Prints a detailed table of the entire styling context. - */ - printTable(): void { - // IE (not Edge) is the only browser that doesn't support this feature. Because - // these debugging tools are not apart of the core of Angular (they are just - // extra tools) we can skip-out on older browsers. - if (!console.table) { - throw new Error('This feature is not supported in your browser'); - } - - const context = this.context; - const table: any[] = []; - const totalColumns = getValuesCount(context); - const itemsPerRow = TStylingContextIndex.BindingsStartOffset + totalColumns; - const totalProps = Math.floor(context.length / itemsPerRow); - - let i = TStylingContextIndex.ValuesStartPosition; - while (i < context.length) { - const prop = getProp(context, i); - const isMapBased = prop === MAP_BASED_ENTRY_PROP_NAME; - const entry: {[key: string]: any} = { - prop, - 'tpl mask': generateBitString(getGuardMask(context, i, false), isMapBased, totalProps), - 'host mask': generateBitString(getGuardMask(context, i, true), isMapBased, totalProps), - }; - - for (let j = 0; j < totalColumns; j++) { - const key = getTypeFromColumn(j, totalColumns); - const value = getBindingValue(context, i, j); - entry[key] = value; - } - - i += itemsPerRow; - table.push(entry); - } - - /* tslint:disable */ - console.table(table); - } -} - -function generateBitString(value: number, isMapBased: boolean, totalProps: number) { - if (isMapBased || value > 1) { - return `0b${leftPad(value.toString(2), totalProps, '0')}`; - } - return null; -} - -function leftPad(value: string, max: number, pad: string) { - return repeat(pad, max - value.length) + value; -} - -function getTypeFromColumn(index: number, totalColumns: number) { - if (index === TEMPLATE_DIRECTIVE_INDEX) { - return 'template'; - } else if (index === totalColumns - 1) { - return 'defaults'; - } else { - return `dir #${index}`; - } -} - -function repeat(c: string, times: number) { - let s = ''; - for (let i = 0; i < times; i++) { - s += c; - } - return s; -} - -/** - * A human-readable debug summary of the styling data present for a `DebugNode` instance. - * - * This class is designed to be used within testing code or when an - * application has `ngDevMode` activated. - */ -export class NodeStylingDebug implements DebugNodeStyling { - private _sanitizer: StyleSanitizeFn|null = null; - private _debugContext: DebugStylingContext; - - constructor( - context: TStylingContext|DebugStylingContext, private _tNode: TStylingNode, - private _data: LStylingData, private _isClassBased: boolean) { - this._debugContext = isStylingContext(context) ? - new TStylingContextDebug(context as TStylingContext, _tNode, _isClassBased) : - (context as DebugStylingContext); - } - - get context() { return this._debugContext; } - - /** - * Overrides the sanitizer used to process styles. - */ - overrideSanitizer(sanitizer: StyleSanitizeFn|null) { this._sanitizer = sanitizer; } - - /** - * Returns a detailed summary of each styling entry in the context and - * what their runtime representation is. - * - * See `LStylingSummary`. - */ - get summary(): {[key: string]: DebugNodeStylingEntry} { - const entries: {[key: string]: DebugNodeStylingEntry} = {}; - const config = this.config; - - let data = this._data; - - // the direct pass code doesn't convert [style] or [class] values - // into StylingMapArray instances. For this reason, the values - // need to be converted ahead of time since the styling debug - // relies on context resolution to figure out what styling - // values have been added/removed on the element. - if (config.allowDirectStyling && config.hasMapBindings) { - data = data.concat([]); // make a copy - this._convertMapBindingsToStylingMapArrays(data); - } - - this._mapValues(data, (prop: string, value: any, bindingIndex: number | null) => { - entries[prop] = {prop, value, bindingIndex}; - }); - - return entries; - } - - get config() { return buildConfig(this._tNode, this._isClassBased); } - - /** - * Returns a key/value map of all the styles/classes that were last applied to the element. - */ - get values(): {[key: string]: any} { - const entries: {[key: string]: any} = {}; - const config = this.config; - let data = this._data; - - // the direct pass code doesn't convert [style] or [class] values - // into StylingMapArray instances. For this reason, the values - // need to be converted ahead of time since the styling debug - // relies on context resolution to figure out what styling - // values have been added/removed on the element. - if (config.allowDirectStyling && config.hasMapBindings) { - data = data.concat([]); // make a copy - this._convertMapBindingsToStylingMapArrays(data); - } - - this._mapValues(data, (prop: string, value: any) => { entries[prop] = value; }); - return entries; - } - - private _convertMapBindingsToStylingMapArrays(data: LStylingData) { - const context = this.context.context; - const limit = getPropValuesStartPosition(context, this._tNode, this._isClassBased); - for (let i = - TStylingContextIndex.ValuesStartPosition + TStylingContextIndex.BindingsStartOffset; - i < limit; i++) { - const bindingIndex = context[i] as number; - const bindingValue = bindingIndex !== 0 ? getValue(data, bindingIndex) : null; - if (bindingValue && !Array.isArray(bindingValue)) { - const stylingMapArray = normalizeIntoStylingMap(null, bindingValue, !this._isClassBased); - setValue(data, bindingIndex, stylingMapArray); - } - } - } - - private _mapValues( - data: LStylingData, - fn: (prop: string, value: string|null, bindingIndex: number|null) => any) { - // there is no need to store/track an element instance. The - // element is only used when the styling algorithm attempts to - // style the value (and we mock out the stylingApplyFn anyway). - const mockElement = {} as any; - const mapBindingsFlag = - this._isClassBased ? TNodeFlags.hasClassMapBindings : TNodeFlags.hasStyleMapBindings; - const hasMaps = hasConfig(this._tNode, mapBindingsFlag); - if (hasMaps) { - activateStylingMapFeature(); - } - - const mapFn: ApplyStylingFn = - (renderer: any, element: RElement, prop: string, value: string | null, - bindingIndex?: number | null) => fn(prop, value, bindingIndex || null); - - const sanitizer = this._isClassBased ? null : (this._sanitizer || getCurrentStyleSanitizer()); - - // run the template bindings - applyStylingViaContext( - this.context.context, this._tNode, null, mockElement, data, true, mapFn, sanitizer, false, - this._isClassBased); - - // and also the host bindings - applyStylingViaContext( - this.context.context, this._tNode, null, mockElement, data, true, mapFn, sanitizer, true, - this._isClassBased); - } -} - -function buildConfig(tNode: TStylingNode, isClassBased: boolean): DebugStylingConfig { - const hasMapBindings = hasConfig( - tNode, isClassBased ? TNodeFlags.hasClassMapBindings : TNodeFlags.hasStyleMapBindings); - const hasPropBindings = hasConfig( - tNode, isClassBased ? TNodeFlags.hasClassPropBindings : TNodeFlags.hasStylePropBindings); - const hasCollisions = hasConfig( - tNode, - isClassBased ? TNodeFlags.hasDuplicateClassBindings : TNodeFlags.hasDuplicateStyleBindings); - const hasTemplateBindings = hasConfig( - tNode, - isClassBased ? TNodeFlags.hasTemplateClassBindings : TNodeFlags.hasTemplateStyleBindings); - const hasHostBindings = hasConfig( - tNode, isClassBased ? TNodeFlags.hasHostClassBindings : TNodeFlags.hasHostStyleBindings); - - // `firstTemplatePass` here is false because the context has already been constructed - // directly within the behavior of the debugging tools (outside of style/class debugging, - // the context is constructed during the first template pass). - const allowDirectStyling = _allowDirectStyling(tNode, isClassBased, false); - return { - hasMapBindings, // - hasPropBindings, // - hasCollisions, // - hasTemplateBindings, // - hasHostBindings, // - allowDirectStyling, // - }; -} diff --git a/packages/core/src/render3/styling/styling_parser.ts b/packages/core/src/render3/styling/styling_parser.ts new file mode 100644 index 0000000000..89f24757a1 --- /dev/null +++ b/packages/core/src/render3/styling/styling_parser.ts @@ -0,0 +1,313 @@ +/** + * @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 {assertEqual, throwError} from '../../util/assert'; +import {CharCode} from '../../util/char_code'; + +/** + * Stores the locations of key/value indexes while parsing styling. + * + * In case of `cssText` parsing the indexes are like so: + * ``` + * "key1: value1; key2: value2; key3: value3" + * ^ ^ ^ ^ ^ + * | | | | +-- textEnd + * | | | +---------------- valueEnd + * | | +---------------------- value + * | +------------------------ keyEnd + * +---------------------------- key + * ``` + * + * In case of `className` parsing the indexes are like so: + * ``` + * "key1 key2 key3" + * ^ ^ ^ + * | | +-- textEnd + * | +------------------------ keyEnd + * +---------------------------- key + * ``` + * NOTE: `value` and `valueEnd` are used only for styles, not classes. + */ +interface ParserState { + textEnd: number; + key: number; + keyEnd: number; + value: number; + valueEnd: number; +} +// Global state of the parser. (This makes parser non-reentrant, but that is not an issue) +const parserState: ParserState = { + textEnd: 0, + key: 0, + keyEnd: 0, + value: 0, + valueEnd: 0, +}; + +/** + * Retrieves the last parsed `key` of style. + * @param text the text to substring the key from. + */ +export function getLastParsedKey(text: string): string { + return text.substring(parserState.key, parserState.keyEnd); +} + +/** + * Retrieves the last parsed `value` of style. + * @param text the text to substring the key from. + */ +export function getLastParsedValue(text: string): string { + return text.substring(parserState.value, parserState.valueEnd); +} + +/** + * Initializes `className` string for parsing and parses the first token. + * + * This function is intended to be used in this format: + * ``` + * for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) { + * const key = getLastParsedKey(); + * ... + * } + * ``` + * @param text `className` to parse + * @returns index where the next invocation of `parseClassNameNext` should resume. + */ +export function parseClassName(text: string): number { + resetParserState(text); + return parseClassNameNext(text, consumeWhitespace(text, 0, parserState.textEnd)); +} + +/** + * Parses next `className` token. + * + * This function is intended to be used in this format: + * ``` + * for (let i = parseClassName(text); i >= 0; i = parseClassNameNext(text, i)) { + * const key = getLastParsedKey(); + * ... + * } + * ``` + * + * @param text `className` to parse + * @param index where the parsing should resume. + * @returns index where the next invocation of `parseClassNameNext` should resume. + */ +export function parseClassNameNext(text: string, index: number): number { + const end = parserState.textEnd; + if (end === index) { + return -1; + } + index = parserState.keyEnd = consumeClassToken(text, parserState.key = index, end); + return consumeWhitespace(text, index, end); +} + +/** + * Initializes `cssText` string for parsing and parses the first key/values. + * + * This function is intended to be used in this format: + * ``` + * for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i))) { + * const key = getLastParsedKey(); + * const value = getLastParsedValue(); + * ... + * } + * ``` + * @param text `cssText` to parse + * @returns index where the next invocation of `parseStyleNext` should resume. + */ +export function parseStyle(text: string): number { + resetParserState(text); + return parseStyleNext(text, consumeWhitespace(text, 0, parserState.textEnd)); +} + +/** + * Parses the next `cssText` key/values. + * + * This function is intended to be used in this format: + * ``` + * for (let i = parseStyle(text); i >= 0; i = parseStyleNext(text, i))) { + * const key = getLastParsedKey(); + * const value = getLastParsedValue(); + * ... + * } + * + * @param text `cssText` to parse + * @param index where the parsing should resume. + * @returns index where the next invocation of `parseStyleNext` should resume. + */ +export function parseStyleNext(text: string, startIndex: number): number { + const end = parserState.textEnd; + let index = parserState.key = consumeWhitespace(text, startIndex, end); + if (end === index) { + // we reached an end so just quit + return -1; + } + index = parserState.keyEnd = consumeStyleKey(text, index, end); + index = consumeSeparator(text, index, end, CharCode.COLON); + index = parserState.value = consumeWhitespace(text, index, end); + index = parserState.valueEnd = consumeStyleValue(text, index, end); + return consumeSeparator(text, index, end, CharCode.SEMI_COLON); +} + +/** + * Reset the global state of the styling parser. + * @param text The styling text to parse. + */ +export function resetParserState(text: string): void { + parserState.key = 0; + parserState.keyEnd = 0; + parserState.value = 0; + parserState.valueEnd = 0; + parserState.textEnd = text.length; +} + +/** + * Returns index of next non-whitespace character. + * + * @param text Text to scan + * @param startIndex Starting index of character where the scan should start. + * @param endIndex Ending index of character where the scan should end. + * @returns Index of next non-whitespace character (May be the same as `start` if no whitespace at + * that location.) + */ +export function consumeWhitespace(text: string, startIndex: number, endIndex: number): number { + while (startIndex < endIndex && text.charCodeAt(startIndex) <= CharCode.SPACE) { + startIndex++; + } + return startIndex; +} + +/** + * Returns index of last char in class token. + * + * @param text Text to scan + * @param startIndex Starting index of character where the scan should start. + * @param endIndex Ending index of character where the scan should end. + * @returns Index after last char in class token. + */ +export function consumeClassToken(text: string, startIndex: number, endIndex: number): number { + while (startIndex < endIndex && text.charCodeAt(startIndex) > CharCode.SPACE) { + startIndex++; + } + return startIndex; +} + +/** + * Consumes all of the characters belonging to style key and token. + * + * @param text Text to scan + * @param startIndex Starting index of character where the scan should start. + * @param endIndex Ending index of character where the scan should end. + * @returns Index after last style key character. + */ +export function consumeStyleKey(text: string, startIndex: number, endIndex: number): number { + let ch: number; + while (startIndex < endIndex && + ((ch = text.charCodeAt(startIndex)) === CharCode.DASH || ch === CharCode.UNDERSCORE || + ((ch & CharCode.UPPER_CASE) >= CharCode.A && (ch & CharCode.UPPER_CASE) <= CharCode.Z))) { + startIndex++; + } + return startIndex; +} + +/** + * Consumes all whitespace and the separator `:` after the style key. + * + * @param text Text to scan + * @param startIndex Starting index of character where the scan should start. + * @param endIndex Ending index of character where the scan should end. + * @returns Index after separator and surrounding whitespace. + */ +export function consumeSeparator( + text: string, startIndex: number, endIndex: number, separator: number): number { + startIndex = consumeWhitespace(text, startIndex, endIndex); + if (startIndex < endIndex) { + if (ngDevMode && text.charCodeAt(startIndex) !== separator) { + malformedStyleError(text, String.fromCharCode(separator), startIndex); + } + startIndex++; + } + return startIndex; +} + + +/** + * Consumes style value honoring `url()` and `""` text. + * + * @param text Text to scan + * @param startIndex Starting index of character where the scan should start. + * @param endIndex Ending index of character where the scan should end. + * @returns Index after last style value character. +*/ +export function consumeStyleValue(text: string, startIndex: number, endIndex: number): number { + let ch1 = -1; // 1st previous character + let ch2 = -1; // 2nd previous character + let ch3 = -1; // 3rd previous character + let i = startIndex; + let lastChIndex = i; + while (i < endIndex) { + const ch: number = text.charCodeAt(i++); + if (ch === CharCode.SEMI_COLON) { + return lastChIndex; + } else if (ch === CharCode.DOUBLE_QUOTE || ch === CharCode.SINGLE_QUOTE) { + lastChIndex = i = consumeQuotedText(text, ch, i, endIndex); + } else if ( + startIndex === + i - 4 && // We have seen only 4 characters so far "URL(" (Ignore "foo_URL()") + ch3 === CharCode.U && + ch2 === CharCode.R && ch1 === CharCode.L && ch === CharCode.OPEN_PAREN) { + lastChIndex = i = consumeQuotedText(text, CharCode.CLOSE_PAREN, i, endIndex); + } else if (ch > CharCode.SPACE) { + // if we have a non-whitespace character then capture its location + lastChIndex = i; + } + ch3 = ch2; + ch2 = ch1; + ch1 = ch & CharCode.UPPER_CASE; + } + return lastChIndex; +} + +/** + * Consumes all of the quoted characters. + * + * @param text Text to scan + * @param quoteCharCode CharCode of either `"` or `'` quote or `)` for `url(...)`. + * @param startIndex Starting index of character where the scan should start. + * @param endIndex Ending index of character where the scan should end. + * @returns Index after quoted characters. + */ +export function consumeQuotedText( + text: string, quoteCharCode: number, startIndex: number, endIndex: number): number { + let ch1 = -1; // 1st previous character + let index = startIndex; + while (index < endIndex) { + const ch = text.charCodeAt(index++); + if (ch == quoteCharCode && ch1 !== CharCode.BACK_SLASH) { + return index; + } + if (ch == CharCode.BACK_SLASH && ch1 === CharCode.BACK_SLASH) { + // two back slashes cancel each other out. For example `"\\"` should properly end the + // quotation. (It should not assume that the last `"` is escaped.) + ch1 = 0; + } else { + ch1 = ch; + } + } + throw ngDevMode ? malformedStyleError(text, String.fromCharCode(quoteCharCode), endIndex) : + new Error(); +} + +function malformedStyleError(text: string, expecting: string, index: number): never { + ngDevMode && assertEqual(typeof text === 'string', true, 'String expected here'); + throw throwError( + `Malformed style at location ${index} in string '` + text.substring(0, index) + '[>>' + + text.substring(index, index + 1) + '<<]' + text.substr(index + 1) + + `'. Expecting '${expecting}'.`); +} diff --git a/packages/core/src/render3/tokens.ts b/packages/core/src/render3/tokens.ts index 2ef57c0ab6..9c53282f2e 100644 --- a/packages/core/src/render3/tokens.ts +++ b/packages/core/src/render3/tokens.ts @@ -8,8 +8,9 @@ export interface NO_CHANGE { // This is a brand that ensures that this type can never match anything else - brand: 'NO_CHANGE'; + __brand__: 'NO_CHANGE'; } /** A special value which designates that a value has not changed. */ -export const NO_CHANGE = {} as NO_CHANGE; +export const NO_CHANGE: NO_CHANGE = + (typeof ngDevMode === 'undefined' || ngDevMode) ? {__brand__: 'NO_CHANGE'} : ({} as NO_CHANGE); diff --git a/packages/core/src/render3/util/attrs_utils.ts b/packages/core/src/render3/util/attrs_utils.ts index dd0009ecba..4b6201dfa4 100644 --- a/packages/core/src/render3/util/attrs_utils.ts +++ b/packages/core/src/render3/util/attrs_utils.ts @@ -5,11 +5,13 @@ * 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 {CharCode} from '../../util/char_code'; import {AttributeMarker, TAttributes} from '../interfaces/node'; import {CssSelector} from '../interfaces/projection'; import {ProceduralRenderer3, RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer'; + /** * Assigns all attribute values to the provided element via the inferred renderer. * @@ -103,5 +105,116 @@ export function isAnimationProp(name: string): boolean { // Perf note: accessing charCodeAt to check for the first character of a string is faster as // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that // charCodeAt doesn't allocate memory to return a substring. - return name.charCodeAt(0) === 64; // @ + return name.charCodeAt(0) === CharCode.AT_SIGN; } + +/** + * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process. + * + * This merge function keeps the order of attrs same. + * + * @param dst Location of where the merged `TAttributes` should end up. + * @param src `TAttributes` which should be appended to `dst` + */ +export function mergeHostAttrs(dst: TAttributes | null, src: TAttributes | null): TAttributes|null { + if (src === null || src.length === 0) { + // do nothing + } else if (dst === null || dst.length === 0) { + // We have source, but dst is empty, just make a copy. + dst = src.slice(); + } else { + let srcMarker: AttributeMarker = AttributeMarker.ImplicitAttributes; + for (let i = 0; i < src.length; i++) { + const item = src[i]; + if (typeof item === 'number') { + srcMarker = item; + } else { + if (srcMarker === AttributeMarker.NamespaceURI) { + // Case where we need to consume `key1`, `key2`, `value` items. + } else if ( + srcMarker === AttributeMarker.ImplicitAttributes || + srcMarker === AttributeMarker.Styles) { + // Case where we have to consume `key1` and `value` only. + mergeHostAttribute(dst, srcMarker, item as string, null, src[++i] as string); + } else { + // Case where we have to consume `key1` only. + mergeHostAttribute(dst, srcMarker, item as string, null, null); + } + } + } + } + return dst; +} + +/** + * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account. + * + * @param dst `TAttributes` to append to. + * @param marker Region where the `key`/`value` should be added. + * @param key1 Key to add to `TAttributes` + * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`) + * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class. + */ +export function mergeHostAttribute( + dst: TAttributes, marker: AttributeMarker, key1: string, key2: string | null, + value: string | null): void { + let i = 0; + // Assume that new markers will be inserted at the end. + let markerInsertPosition = dst.length; + // scan until correct type. + if (marker === AttributeMarker.ImplicitAttributes) { + markerInsertPosition = -1; + } else { + while (i < dst.length) { + const dstValue = dst[i++]; + if (typeof dstValue === 'number') { + if (dstValue === marker) { + markerInsertPosition = -1; + break; + } else if (dstValue > marker) { + // We need to save this as we want the markers to be inserted in specific order. + markerInsertPosition = i - 1; + break; + } + } + } + } + + // search until you find place of insertion + while (i < dst.length) { + const item = dst[i]; + if (typeof item === 'number') { + // since `i` started as the index after the marker, we did not find it if we are at the next + // marker + break; + } else if (item === key1) { + // We already have same token + if (key2 === null) { + if (value !== null) { + dst[i + 1] = value; + } + return; + } else if (key2 === dst[i + 1]) { + dst[i + 2] = value !; + return; + } + } + // Increment counter. + i++; + if (key2 !== null) i++; + if (value !== null) i++; + } + + // insert at location. + if (markerInsertPosition !== -1) { + dst.splice(markerInsertPosition, 0, marker); + i = markerInsertPosition + 1; + } + dst.splice(i++, 0, key1); + if (key2 !== null) { + dst.splice(i++, 0, key2); + } + if (value !== null) { + dst.splice(i++, 0, value); + } +} \ No newline at end of file diff --git a/packages/core/src/render3/util/change_detection_utils.ts b/packages/core/src/render3/util/change_detection_utils.ts new file mode 100644 index 0000000000..30c5b4a20a --- /dev/null +++ b/packages/core/src/render3/util/change_detection_utils.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 {detectChanges, markDirty} from '../instructions/all'; +import {getRootComponents} from './discovery_utils'; + +/** + * Marks a component for check (in case of OnPush components) and synchronously + * performs change detection on the application this component belongs to. + * + * @param component Component to {@link ChangeDetectorRef#markForCheck mark for check}. + * + * @publicApi + * @globalApi ng + */ +export function applyChanges(component: {}): void { + markDirty(component); + getRootComponents(component).forEach(rootComponent => detectChanges(rootComponent)); +} diff --git a/packages/core/src/render3/util/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts index 4553e88923..695d2899ff 100644 --- a/packages/core/src/render3/util/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -16,7 +16,6 @@ import {DirectiveDef} from '../interfaces/definition'; import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node'; import {isLView} from '../interfaces/type_checks'; import {CLEANUP, CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TVIEW, T_HOST} from '../interfaces/view'; - import {stringifyForError} from './misc_utils'; import {getLViewParent, getRootContext} from './view_traversal_utils'; import {getTNode, unwrapRNode} from './view_utils'; @@ -24,31 +23,35 @@ import {getTNode, unwrapRNode} from './view_utils'; /** - * Returns the component instance associated with a given DOM host element. - * Elements which don't represent components return `null`. + * Retrieves the component instance associated with a given DOM element. * - * @param element Host DOM element from which the component should be retrieved. - * - * ``` + * @usageNotes + * Given the following DOM structure: + * ```html * - * #VIEW - *
- * - *
- * - * - * expect(getComponent() instanceof ChildComponent).toBeTruthy(); - * expect(getComponent() instanceof MyApp).toBeTruthy(); + *
+ * + *
+ *
* ``` + * Calling `getComponent` on `` will return the instance of `ChildComponent` + * associated with this DOM element. + * + * Calling the function on `` will return the `MyApp` instance. + * + * + * @param element DOM element from which the component should be retrieved. + * @returns Component instance associated with the element or `null` if there + * is no component associated with it. * * @publicApi + * @globalApi ng */ -export function getComponent(element: Element): T|null { - if (!(element instanceof Node)) throw new Error('Expecting instance of DOM Node'); +export function getComponent(element: Element): T|null { + assertDomElement(element); const context = loadLContext(element, false); if (context === null) return null; - if (context.component === undefined) { context.component = getComponentAtNodeIndex(context.nodeIndex, context.lView); } @@ -56,56 +59,42 @@ export function getComponent(element: Element): T|null { return context.component as T; } + /** - * Returns the component instance associated with a given DOM host element. - * Elements which don't represent components return `null`. + * If inside an embedded view (e.g. `*ngIf` or `*ngFor`), retrieves the context of the embedded + * view that the element is part of. Otherwise retrieves the instance of the component whose view + * owns the element (in this case, the result is the same as calling `getOwningComponent`). * - * @param element Host DOM element from which the component should be retrieved. - * - * ``` - * - * #VIEW - *
- * - *
- * - * - * expect(getComponent() instanceof ChildComponent).toBeTruthy(); - * expect(getComponent() instanceof MyApp).toBeTruthy(); - * ``` + * @param element Element for which to get the surrounding component instance. + * @returns Instance of the component that is around the element or null if the element isn't + * inside any component. * * @publicApi + * @globalApi ng */ -export function getContext(element: Element): T|null { - if (!(element instanceof Node)) throw new Error('Expecting instance of DOM Node'); +export function getContext(element: Element): T|null { + assertDomElement(element); const context = loadLContext(element, false); - if (context === null) return null; - - return context.lView[CONTEXT] as T; + return context === null ? null : context.lView[CONTEXT] as T; } /** - * Returns the component instance associated with view which owns the DOM element (`null` - * otherwise). + * Retrieves the component instance whose view contains the DOM element. * - * @param element DOM element which is owned by an existing component's view. + * For example, if `` is used in the template of `` + * (i.e. a `ViewChild` of ``), calling `getOwningComponent` on `` + * would return ``. * - * ``` - * - * #VIEW - *
- * - *
- * - * - * expect(getViewComponent() instanceof MyApp).toBeTruthy(); - * expect(getViewComponent()).toEqual(null); - * ``` + * @param elementOrDir DOM element, component or directive instance + * for which to retrieve the root components. + * @returns Component instance whose view owns the DOM element or null if the element is not + * part of a component view. * * @publicApi + * @globalApi ng */ -export function getViewComponent(element: Element | {}): T|null { - const context = loadLContext(element, false); +export function getOwningComponent(elementOrDir: Element | {}): T|null { + const context = loadLContext(elementOrDir, false); if (context === null) return null; let lView = context.lView; @@ -119,27 +108,32 @@ export function getViewComponent(element: Element | {}): T|null { } /** - * Retrieve all root components. - * + * Retrieves all root components associated with a DOM element, directive or component instance. * Root components are those which have been bootstrapped by Angular. * - * @param target A DOM element, component or directive instance. + * @param elementOrDir DOM element, component or directive instance + * for which to retrieve the root components. + * @returns Root components associated with the target object. * * @publicApi + * @globalApi ng */ -export function getRootComponents(target: {}): any[] { - return [...getRootContext(target).components]; +export function getRootComponents(elementOrDir: Element | {}): {}[] { + return [...getRootContext(elementOrDir).components]; } /** - * Retrieves an `Injector` associated with the element, component or directive. + * Retrieves an `Injector` associated with an element, component or directive instance. * - * @param target A DOM element, component or directive instance. + * @param elementOrDir DOM element, component or directive instance for which to + * retrieve the injector. + * @returns Injector associated with the element, component or directive instance. * * @publicApi + * @globalApi ng */ -export function getInjector(target: {}): Injector { - const context = loadLContext(target, false); +export function getInjector(elementOrDir: Element | {}): Injector { + const context = loadLContext(elementOrDir, false); if (context === null) return Injector.NULL; const tNode = context.lView[TVIEW].data[context.nodeIndex] as TElementNode; @@ -150,7 +144,6 @@ export function getInjector(target: {}): Injector { * Retrieve a set of injection tokens at a given DOM node. * * @param element Element for which the injection tokens should be retrieved. - * @publicApi */ export function getInjectionTokens(element: Element): any[] { const context = loadLContext(element, false); @@ -176,26 +169,43 @@ export function getInjectionTokens(element: Element): any[] { } /** - * Retrieves directives associated with a given DOM host element. + * Retrieves directive instances associated with a given DOM element. Does not include + * component instances. * - * @param target A DOM element, component or directive instance. + * @usageNotes + * Given the following DOM structure: + * ``` + * + * + * + * + * ``` + * Calling `getDirectives` on `', async() => { try { - const ngModuleRef = await platformBrowserDynamic().bootstrapModule(MyAppModule); - expect(document.body.textContent).toEqual('works!'); + const ngModuleRef = await platformBrowserDynamic().bootstrapModule(IdSelectorAppModule); + expect(document.body.textContent).toEqual('before|works!'); + ngModuleRef.destroy(); + } catch (err) { + console.error(err); + } + })); + + it('should bootstrap using one of selectors from the list', + withBody('
before|
', async() => { + try { + const ngModuleRef = + await platformBrowserDynamic().bootstrapModule(MultipleSelectorsAppModule); + expect(document.body.textContent).toEqual('before|works!'); ngModuleRef.destroy(); } catch (err) { console.error(err); @@ -28,9 +40,28 @@ describe('bootstrap', () => { selector: '#my-app', template: 'works!', }) -export class MyAppComponent { +export class IdSelectorAppComponent { } -@NgModule({imports: [BrowserModule], declarations: [MyAppComponent], bootstrap: [MyAppComponent]}) -export class MyAppModule { +@NgModule({ + imports: [BrowserModule], + declarations: [IdSelectorAppComponent], + bootstrap: [IdSelectorAppComponent], +}) +export class IdSelectorAppModule { } + +@Component({ + selector: '[foo],span,.bar', + template: 'works!', +}) +export class MultipleSelectorsAppComponent { +} + +@NgModule({ + imports: [BrowserModule], + declarations: [MultipleSelectorsAppComponent], + bootstrap: [MultipleSelectorsAppComponent], +}) +export class MultipleSelectorsAppModule { +} \ No newline at end of file diff --git a/packages/core/test/acceptance/change_detection_spec.ts b/packages/core/test/acceptance/change_detection_spec.ts index 10da2521b4..a5d6b41b2e 100644 --- a/packages/core/test/acceptance/change_detection_spec.ts +++ b/packages/core/test/acceptance/change_detection_spec.ts @@ -9,10 +9,10 @@ import {CommonModule} from '@angular/common'; import {ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, DoCheck, EmbeddedViewRef, ErrorHandler, Input, NgModule, OnInit, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core'; -import {AfterContentChecked, AfterViewChecked} from '@angular/core/src/core'; +import {AfterViewChecked} from '@angular/core/src/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; +import {ivyEnabled} from '@angular/private/testing'; import {BehaviorSubject} from 'rxjs'; describe('change detection', () => { @@ -22,10 +22,10 @@ describe('change detection', () => { @Directive({selector: '[viewManipulation]', exportAs: 'vm'}) class ViewManipulation { constructor( - private _tplRef: TemplateRef<{}>, private _vcRef: ViewContainerRef, + private _tplRef: TemplateRef<{}>, public vcRef: ViewContainerRef, private _appRef: ApplicationRef) {} - insertIntoVcRef() { this._vcRef.createEmbeddedView(this._tplRef); } + insertIntoVcRef() { return this.vcRef.createEmbeddedView(this._tplRef); } insertIntoAppRef(): EmbeddedViewRef<{}> { const viewRef = this._tplRef.createEmbeddedView({}); @@ -43,11 +43,8 @@ describe('change detection', () => { class TestCmpt { } - beforeEach(() => { - TestBed.configureTestingModule({declarations: [TestCmpt, ViewManipulation]}); - }); - it('should detect changes for embedded views inserted through ViewContainerRef', () => { + TestBed.configureTestingModule({declarations: [TestCmpt, ViewManipulation]}); const fixture = TestBed.createComponent(TestCmpt); const vm = fixture.debugElement.childNodes[0].references['vm'] as ViewManipulation; @@ -58,6 +55,7 @@ describe('change detection', () => { }); it('should detect changes for embedded views attached to ApplicationRef', () => { + TestBed.configureTestingModule({declarations: [TestCmpt, ViewManipulation]}); const fixture = TestBed.createComponent(TestCmpt); const vm = fixture.debugElement.childNodes[0].references['vm'] as ViewManipulation; @@ -70,6 +68,109 @@ describe('change detection', () => { expect(viewRef.rootNodes[0]).toHaveText('change-detected'); }); + it('should not detect changes in child embedded views while they are detached', () => { + const counters = {componentView: 0, embeddedView: 0}; + + @Component({ + template: ` + +
{{increment('componentView')}}
+ {{increment('embeddedView')}} + `, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class App { + increment(counter: 'componentView'|'embeddedView') { counters[counter]++; } + noop() {} + } + + TestBed.configureTestingModule({declarations: [App, ViewManipulation]}); + const fixture = TestBed.createComponent(App); + const vm: ViewManipulation = fixture.debugElement.childNodes[2].references['vm']; + const button = fixture.nativeElement.querySelector('button'); + const viewRef = vm.insertIntoVcRef(); + fixture.detectChanges(); + + expect(counters).toEqual({componentView: 1, embeddedView: 1}); + + button.click(); + fixture.detectChanges(); + expect(counters).toEqual({componentView: 2, embeddedView: 2}); + + viewRef.detach(); + button.click(); + fixture.detectChanges(); + + expect(counters).toEqual({componentView: 3, embeddedView: 2}); + + // Re-attach the view to ensure that the process can be reversed. + viewRef.reattach(); + button.click(); + fixture.detectChanges(); + + expect(counters).toEqual({componentView: 4, embeddedView: 3}); + }); + + it('should not detect changes in child component views while they are detached', () => { + let counter = 0; + + @Component({ + template: ``, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class App { + } + + @Component({ + template: ` + +
{{increment()}}
+ `, + changeDetection: ChangeDetectionStrategy.OnPush + }) + class DynamicComp { + increment() { counter++; } + noop() {} + } + + // We need to declare a module so that we can specify `entryComponents` + // for when the test is run against ViewEngine. + @NgModule({ + declarations: [App, ViewManipulation, DynamicComp], + exports: [App, ViewManipulation, DynamicComp], + entryComponents: [DynamicComp] + }) + class AppModule { + } + + TestBed.configureTestingModule({imports: [AppModule]}); + const fixture = TestBed.createComponent(App); + const vm: ViewManipulation = fixture.debugElement.childNodes[0].references['vm']; + const factory = TestBed.get(ComponentFactoryResolver).resolveComponentFactory(DynamicComp); + const componentRef = vm.vcRef.createComponent(factory); + const button = fixture.nativeElement.querySelector('button'); + fixture.detectChanges(); + + expect(counter).toBe(1); + + button.click(); + fixture.detectChanges(); + expect(counter).toBe(2); + + componentRef.changeDetectorRef.detach(); + button.click(); + fixture.detectChanges(); + + expect(counter).toBe(2); + + // Re-attach the change detector to ensure that the process can be reversed. + componentRef.changeDetectorRef.reattach(); + button.click(); + fixture.detectChanges(); + + expect(counter).toBe(3); + }); + }); describe('markForCheck', () => { @@ -1249,6 +1350,105 @@ describe('change detection', () => { }); }); + describe('OnPush markForCheck in lifecycle hooks', () => { + describe('with check no changes enabled', () => createOnPushMarkForCheckTests(true)); + describe('with check no changes disabled', () => createOnPushMarkForCheckTests(false)); + + function createOnPushMarkForCheckTests(checkNoChanges: boolean) { + const detectChanges = (f: ComponentFixture) => f.detectChanges(checkNoChanges); + + // 1. ngAfterViewInit and ngAfterViewChecked lifecycle hooks run after "OnPushComp" has + // been refreshed. They can mark the component as dirty. Meaning that the "OnPushComp" + // can be checked/refreshed in a subsequent change detection cycle. + // 2. ngDoCheck and ngAfterContentChecked lifecycle hooks run before "OnPushComp" is + // refreshed. This means that those hooks cannot leave the component as dirty because + // the dirty state is reset afterwards. Though these hooks run every change detection + // cycle before "OnPushComp" is considered for refreshing. Hence marking as dirty from + // within such a hook can cause the component to checked/refreshed as intended. + ['ngAfterViewInit', 'ngAfterViewChecked', 'ngAfterContentChecked', 'ngDoCheck'].forEach( + hookName => { + it(`should be able to mark component as dirty from within ${hookName}`, () => { + @Component({ + selector: 'on-push-comp', + changeDetection: ChangeDetectionStrategy.OnPush, + template: `

{{text}}

`, + }) + class OnPushComp { + text = 'initial'; + + constructor(private _cdRef: ChangeDetectorRef){} + + [hookName]() { + this._cdRef.markForCheck(); + } + } + + @Component({template: ``}) + class TestApp { + @ViewChild(OnPushComp) onPushComp !: OnPushComp; + } + + TestBed.configureTestingModule( + {declarations: [TestApp, OnPushComp], imports: [CommonModule]}); + const fixture = TestBed.createComponent(TestApp); + const pElement = fixture.nativeElement.querySelector('p') as HTMLElement; + + detectChanges(fixture); + expect(pElement.textContent).toBe('initial'); + + // "OnPushComp" component should be re-checked since it has been left dirty + // in the first change detection (through the lifecycle hook). Hence, setting + // a programmatic value and triggering a new change detection cycle should cause + // the text to be updated in the view. + fixture.componentInstance.onPushComp.text = 'new'; + detectChanges(fixture); + expect(pElement.textContent).toBe('new'); + }); + }); + + // ngOnInit and ngAfterContentInit lifecycle hooks run once before "OnPushComp" is + // refreshed/checked. This means they cannot mark the component as dirty because the + // component dirty state will immediately reset after these hooks complete. + ['ngOnInit', 'ngAfterContentInit'].forEach(hookName => { + it(`should not be able to mark component as dirty from within ${hookName}`, () => { + @Component({ + selector: 'on-push-comp', + changeDetection: ChangeDetectionStrategy.OnPush, + template: `

{{text}}

`, + }) + class OnPushComp { + text = 'initial'; + + constructor(private _cdRef: ChangeDetectorRef){} + + [hookName]() { + this._cdRef.markForCheck(); + } + } + + @Component({template: ``}) + class TestApp { + @ViewChild(OnPushComp) onPushComp !: OnPushComp; + } + + TestBed.configureTestingModule( + {declarations: [TestApp, OnPushComp], imports: [CommonModule]}); + const fixture = TestBed.createComponent(TestApp); + const pElement = fixture.nativeElement.querySelector('p') as HTMLElement; + + detectChanges(fixture); + expect(pElement.textContent).toBe('initial'); + + fixture.componentInstance.onPushComp.text = 'new'; + // this is a noop since the "OnPushComp" component is not marked as dirty. The + // programmatically updated value will not be reflected in the rendered view. + detectChanges(fixture); + expect(pElement.textContent).toBe('initial'); + }); + }); + } + }); + describe('ExpressionChangedAfterItHasBeenCheckedError', () => { @Component({template: '...'}) class MyApp { @@ -1336,16 +1536,15 @@ describe('change detection', () => { }); it('should include style prop name in case of style binding', () => { - const message = ivyEnabled ? - `Previous value for 'style.color': 'red'. Current value: 'green'` : - `Previous value: 'color: red'. Current value: 'color: green'`; + const message = ivyEnabled ? `Previous value for 'color': 'red'. Current value: 'green'` : + `Previous value: 'color: red'. Current value: 'color: green'`; expect(() => initWithTemplate('
')) .toThrowError(new RegExp(message)); }); it('should include class name in case of class binding', () => { const message = ivyEnabled ? - `Previous value for 'class.someClass': 'true'. Current value: 'false'` : + `Previous value for 'someClass': 'true'. Current value: 'false'` : `Previous value: 'someClass: true'. Current value: 'someClass: false'`; expect(() => initWithTemplate('
')) .toThrowError(new RegExp(message)); @@ -1374,16 +1573,15 @@ describe('change detection', () => { }); it('should include style prop name in case of host style bindings', () => { - const message = ivyEnabled ? - `Previous value for 'style.color': 'red'. Current value: 'green'` : - `Previous value: 'color: red'. Current value: 'color: green'`; + const message = ivyEnabled ? `Previous value for 'color': 'red'. Current value: 'green'` : + `Previous value: 'color: red'. Current value: 'color: green'`; expect(() => initWithHostBindings({'[style.color]': 'unstableColorExpression'})) .toThrowError(new RegExp(message)); }); it('should include class name in case of host class bindings', () => { const message = ivyEnabled ? - `Previous value for 'class.someClass': 'true'. Current value: 'false'` : + `Previous value for 'someClass': 'true'. Current value: 'false'` : `Previous value: 'someClass: true'. Current value: 'someClass: false'`; expect(() => initWithHostBindings({'[class.someClass]': 'unstableBooleanExpression'})) .toThrowError(new RegExp(message)); diff --git a/packages/core/test/acceptance/component_spec.ts b/packages/core/test/acceptance/component_spec.ts index f80ac4c3a0..352cb57ce8 100644 --- a/packages/core/test/acceptance/component_spec.ts +++ b/packages/core/test/acceptance/component_spec.ts @@ -340,6 +340,44 @@ describe('component', () => { expect(log).toEqual(['CompB:ngDoCheck']); }); + it('should preserve simple component selector in a component factory', () => { + @Component({selector: '[foo]', template: ''}) + class AttSelectorCmp { + } + + @NgModule({ + declarations: [AttSelectorCmp], + entryComponents: [AttSelectorCmp], + }) + class AppModule { + } + + TestBed.configureTestingModule({imports: [AppModule]}); + const cmpFactoryResolver = TestBed.inject(ComponentFactoryResolver); + const cmpFactory = cmpFactoryResolver.resolveComponentFactory(AttSelectorCmp); + + expect(cmpFactory.selector).toBe('[foo]'); + }); + + it('should preserve complex component selector in a component factory', () => { + @Component({selector: '[foo],div:not(.bar)', template: ''}) + class ComplexSelectorCmp { + } + + @NgModule({ + declarations: [ComplexSelectorCmp], + entryComponents: [ComplexSelectorCmp], + }) + class AppModule { + } + + TestBed.configureTestingModule({imports: [AppModule]}); + const cmpFactoryResolver = TestBed.inject(ComponentFactoryResolver); + const cmpFactory = cmpFactoryResolver.resolveComponentFactory(ComplexSelectorCmp); + + expect(cmpFactory.selector).toBe('[foo],div:not(.bar)'); + }); + describe('should clear host element if provided in ComponentFactory.create', () => { function runTestWithRenderer(rendererProviders: any[]) { @Component({ diff --git a/packages/core/test/acceptance/di_spec.ts b/packages/core/test/acceptance/di_spec.ts index 9a2df0297c..fa8ed2783c 100644 --- a/packages/core/test/acceptance/di_spec.ts +++ b/packages/core/test/acceptance/di_spec.ts @@ -470,6 +470,64 @@ describe('di', () => { fixture.detectChanges(); expect(divElement.id).toBe('bar'); }); + + it('dynamic components should find dependencies when parent is projected', () => { + @Directive({selector: '[dirA]'}) + class DirA { + } + @Directive({selector: '[dirB]'}) + class DirB { + } + @Component({selector: 'child', template: ''}) + class Child { + constructor(@Optional() readonly dirA: DirA, @Optional() readonly dirB: DirB) {} + } + @Component({ + selector: 'projector', + template: '', + }) + class Projector { + } + + @Component({ + template: ` + +
+ + +
+
`, + entryComponents: [Child] + }) + class MyApp { + @ViewChild('childOrigin', {read: ViewContainerRef, static: true}) + childOrigin !: ViewContainerRef; + @ViewChild('childOriginWithDirB', {read: ViewContainerRef, static: true}) + childOriginWithDirB !: ViewContainerRef; + childFactory = this.resolver.resolveComponentFactory(Child); + + constructor(readonly resolver: ComponentFactoryResolver, readonly injector: Injector) {} + + addChild() { return this.childOrigin.createComponent(this.childFactory); } + addChildWithDirB() { return this.childOriginWithDirB.createComponent(this.childFactory); } + } + + const fixture = + TestBed.configureTestingModule({declarations: [Child, DirA, DirB, Projector, MyApp]}) + .createComponent(MyApp); + const child = fixture.componentInstance.addChild(); + expect(child).toBeDefined(); + expect(child.instance.dirA) + .not.toBeNull('dirA should be found. It is on the parent of the viewContainerRef.'); + const child2 = fixture.componentInstance.addChildWithDirB(); + expect(child2).toBeDefined(); + expect(child2.instance.dirA) + .not.toBeNull('dirA should be found. It is on the parent of the viewContainerRef.'); + expect(child2.instance.dirB) + .toBeNull( + 'dirB appears on the ng-container and should not be found because the ' + + 'viewContainerRef.createComponent node is inserted next to the container.'); + }); }); it('should throw if directive is not found anywhere', () => { @@ -982,6 +1040,30 @@ describe('di', () => { `This will become an error in v10. Please add @Injectable() to the "MyRootService" class.`); } }); + + it('should inject services in constructor with overloads', () => { + @Injectable({providedIn: 'root'}) + class MyService { + } + + @Injectable({providedIn: 'root'}) + class MyOtherService { + } + + @Component({template: ''}) + class MyComp { + constructor(myService: MyService); + constructor( + public myService: MyService, @Optional() public myOtherService?: MyOtherService) {} + } + TestBed.configureTestingModule({declarations: [MyComp]}); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + + expect(fixture.componentInstance.myService instanceof MyService).toBe(true); + expect(fixture.componentInstance.myOtherService instanceof MyOtherService).toBe(true); + }); + }); describe('inject', () => { diff --git a/packages/core/test/acceptance/discover_utils_spec.ts b/packages/core/test/acceptance/discover_utils_spec.ts index 9aa1e1d7b5..101750b3d1 100644 --- a/packages/core/test/acceptance/discover_utils_spec.ts +++ b/packages/core/test/acceptance/discover_utils_spec.ts @@ -10,10 +10,12 @@ import {Component, Directive, HostBinding, InjectionToken, ViewChild} from '@ang import {isLView} from '@angular/core/src/render3/interfaces/type_checks'; import {CONTEXT} from '@angular/core/src/render3/interfaces/view'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {getElementStyles} from '@angular/core/testing/src/styling'; +import {expect} from '@angular/core/testing/src/testing_internal'; import {onlyInIvy} from '@angular/private/testing'; import {getHostElement, markDirty} from '../../src/render3/index'; -import {getComponent, getComponentLView, getContext, getDebugNode, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getRootComponents, getViewComponent, loadLContext} from '../../src/render3/util/discovery_utils'; +import {getComponent, getComponentLView, getContext, getDebugNode, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getOwningComponent, getRootComponents, loadLContext} from '../../src/render3/util/discovery_utils'; onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { let fixture: ComponentFixture; @@ -79,8 +81,8 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(getComponent(p[0])).toEqual(null); }); it('should throw when called on non-element', () => { - expect(() => getComponent(dirA[0] as any)).toThrowError(/Expecting instance of DOM Node/); - expect(() => getComponent(dirA[1] as any)).toThrowError(/Expecting instance of DOM Node/); + expect(() => getComponent(dirA[0] as any)).toThrowError(/Expecting instance of DOM Element/); + expect(() => getComponent(dirA[1] as any)).toThrowError(/Expecting instance of DOM Element/); }); it('should return component from element', () => { expect(getComponent(fixture.nativeElement)).toEqual(myApp); @@ -105,8 +107,8 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { describe('getContext', () => { it('should throw when called on non-element', () => { - expect(() => getContext(dirA[0] as any)).toThrowError(/Expecting instance of DOM Node/); - expect(() => getContext(dirA[1] as any)).toThrowError(/Expecting instance of DOM Node/); + expect(() => getContext(dirA[0] as any)).toThrowError(/Expecting instance of DOM Element/); + expect(() => getContext(dirA[1] as any)).toThrowError(/Expecting instance of DOM Element/); }); it('should return context from element', () => { expect(getContext(child[0])).toEqual(myApp); @@ -159,30 +161,30 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { }); }); - describe('getViewComponent', () => { + describe('getOwningComponent', () => { it('should return null when called on root component', () => { - expect(getViewComponent(fixture.nativeElement)).toEqual(null); - expect(getViewComponent(myApp)).toEqual(null); + expect(getOwningComponent(fixture.nativeElement)).toEqual(null); + expect(getOwningComponent(myApp)).toEqual(null); }); it('should return containing component of child component', () => { - expect(getViewComponent(child[0])).toEqual(myApp); - expect(getViewComponent(child[1])).toEqual(myApp); - expect(getViewComponent(child[2])).toEqual(myApp); + expect(getOwningComponent(child[0])).toEqual(myApp); + expect(getOwningComponent(child[1])).toEqual(myApp); + expect(getOwningComponent(child[2])).toEqual(myApp); - expect(getViewComponent(childComponent[0])).toEqual(myApp); - expect(getViewComponent(childComponent[1])).toEqual(myApp); - expect(getViewComponent(childComponent[2])).toEqual(myApp); + expect(getOwningComponent(childComponent[0])).toEqual(myApp); + expect(getOwningComponent(childComponent[1])).toEqual(myApp); + expect(getOwningComponent(childComponent[2])).toEqual(myApp); }); it('should return containing component of any view element', () => { - expect(getViewComponent(span[0])).toEqual(myApp); - expect(getViewComponent(div[0])).toEqual(myApp); - expect(getViewComponent(p[0])).toEqual(childComponent[0]); - expect(getViewComponent(p[1])).toEqual(childComponent[1]); - expect(getViewComponent(p[2])).toEqual(childComponent[2]); + expect(getOwningComponent(span[0])).toEqual(myApp); + expect(getOwningComponent(div[0])).toEqual(myApp); + expect(getOwningComponent(p[0])).toEqual(childComponent[0]); + expect(getOwningComponent(p[1])).toEqual(childComponent[1]); + expect(getOwningComponent(p[2])).toEqual(childComponent[2]); }); it('should return containing component of child directive', () => { - expect(getViewComponent(dirA[0])).toEqual(myApp); - expect(getViewComponent(dirA[1])).toEqual(myApp); + expect(getOwningComponent(dirA[0])).toEqual(myApp); + expect(getOwningComponent(dirA[1])).toEqual(myApp); }); }); @@ -229,6 +231,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { expect(listeners[0].name).toEqual('click'); expect(listeners[0].element).toEqual(span[0]); expect(listeners[0].useCapture).toEqual(false); + expect(listeners[0].type).toEqual('dom'); listeners[0].callback('CLICKED'); expect(log).toEqual(['CLICKED']); }); @@ -473,11 +476,10 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => const childDebug = getDebugNode(child) !; expect(childDebug.native).toBe(child); - expect(childDebug.styles).toBeTruthy(); - - const styles = childDebug.styles !.values; - expect(styles['width']).toEqual('200px'); - expect(styles['height']).toEqual('400px'); + expect(getElementStyles(child)).toEqual({ + width: '200px', + height: '400px', + }); }); }); }); diff --git a/packages/core/test/acceptance/host_binding_spec.ts b/packages/core/test/acceptance/host_binding_spec.ts index 320209c0b3..6ed4077660 100644 --- a/packages/core/test/acceptance/host_binding_spec.ts +++ b/packages/core/test/acceptance/host_binding_spec.ts @@ -93,7 +93,7 @@ describe('host bindings', () => { * - That executes a **different template**, that has host bindings * - this executes `setHostBindings` * - Inside of `setHostBindings` we are currently updating the selected index **global - * state** via `setActiveHostElement`. + * state** via `setSelectedIndex`. * 3. We attempt to update the next property in the **original template**. * - But the selected index has been altered, and we get errors. */ @@ -254,7 +254,7 @@ describe('host bindings', () => { } TestBed.configureTestingModule( - {declarations: [MyApp, ParentDir, ChildDir, SiblingDir]}); + {declarations: [MyApp, ParentDir, SiblingDir, ChildDir]}); const fixture = TestBed.createComponent(MyApp); const element = fixture.nativeElement; fixture.detectChanges(); @@ -262,10 +262,9 @@ describe('host bindings', () => { const childElement = element.querySelector('div'); // width/height values were set in all directives, but the sub-class directive - // (ChildDir) - // had priority over the parent directive (ParentDir) which is why its value won. It - // also - // won over Dir because the SiblingDir directive was evaluated later on. + // (ChildDir) had priority over the parent directive (ParentDir) which is why its + // value won. It also won over Dir because the SiblingDir directive was declared + // later in `declarations`. expect(childElement.style.width).toEqual('200px'); expect(childElement.style.height).toEqual('200px'); @@ -830,6 +829,30 @@ describe('host bindings', () => { expect(hostElement.title).toBe('other title'); }); + it('should merge attributes on host and template', () => { + @Directive({selector: '[dir1]', host: {id: 'dir1'}}) + class MyDir1 { + } + @Directive({selector: '[dir2]', host: {id: 'dir2'}}) + class MyDir2 { + } + + @Component({template: `
`}) + class MyComp { + } + + TestBed.configureTestingModule({declarations: [MyComp, MyDir1, MyDir2]}); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + const div: HTMLElement = fixture.debugElement.nativeElement.firstChild; + expect(div.id).toEqual( + ivyEnabled ? + // In ivy the correct result is `tmpl` because template has the highest priority. + 'tmpl' : + // In VE the order was simply that of execution and so dir2 would win. + 'dir2'); + }); + onlyInIvy('Host bindings do not get merged in ViewEngine') .it('should work correctly with inherited directives with hostBindings', () => { @Directive({selector: '[superDir]', host: {'[id]': 'id'}}) diff --git a/packages/core/test/acceptance/inherit_definition_feature_spec.ts b/packages/core/test/acceptance/inherit_definition_feature_spec.ts index 85d953dc74..745df8146c 100644 --- a/packages/core/test/acceptance/inherit_definition_feature_spec.ts +++ b/packages/core/test/acceptance/inherit_definition_feature_spec.ts @@ -7,6 +7,8 @@ */ import {Component, ContentChildren, Directive, EventEmitter, HostBinding, HostListener, Input, OnChanges, Output, QueryList, ViewChildren} from '@angular/core'; +import {ivyEnabled} from '@angular/core/src/ivy_switch'; +import {getDirectiveDef} from '@angular/core/src/render3/definition'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {onlyInIvy} from '@angular/private/testing'; @@ -42,6 +44,86 @@ describe('inheritance', () => { }).toThrowError('Directives cannot inherit Components'); }); + describe('multiple children', () => { + it('should ensure that multiple child classes don\'t cause multiple parent execution', () => { + // Assume this inheritance: + // Base + // | + // Super + // / \ + // Sub1 Sub2 + // + // In the above case: + // 1. Sub1 as will walk the inheritance Sub1, Super, Base + // 2. Sub2 as will walk the inheritance Sub2, Super, Base + // + // Notice that Super, Base will get walked twice. Because inheritance works by wrapping parent + // hostBindings function in a delegate which calls the hostBindings of the directive as well + // as super, we need to ensure that we don't double wrap the hostBindings function. Doing so + // would result in calling the hostBindings multiple times (unnecessarily). This would be + // especially an issue if we have a lot of sub-classes (as is common in component libraries) + const log: string[] = []; + + @Directive({selector: '[superDir]'}) + class BaseDirective { + @HostBinding('style.background-color') + get backgroundColor() { + log.push('Base.backgroundColor'); + return 'white'; + } + } + + @Directive({selector: '[superDir]'}) + class SuperDirective extends BaseDirective { + @HostBinding('style.color') + get color() { + log.push('Super.color'); + return 'blue'; + } + } + + @Directive({selector: '[subDir1]'}) + class Sub1Directive extends SuperDirective { + @HostBinding('style.height') + get height() { + log.push('Sub1.height'); + return '200px'; + } + } + + @Directive({selector: '[subDir2]'}) + class Sub2Directive extends SuperDirective { + @HostBinding('style.width') + get width() { + log.push('Sub2.width'); + return '100px'; + } + } + + @Component({template: `
`}) + class App { + } + + TestBed.configureTestingModule({ + declarations: [App, Sub1Directive, Sub2Directive, SuperDirective], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(false); // Don't check for no changes (so that assertion does not need + // to worry about it.) + + expect(log).toEqual([ + 'Base.backgroundColor', 'Super.color', 'Sub1.height', // + 'Base.backgroundColor', 'Super.color', 'Sub2.width', // + ]); + if (ivyEnabled) { + expect(getDirectiveDef(BaseDirective) !.hostVars).toEqual(2); + expect(getDirectiveDef(SuperDirective) !.hostVars).toEqual(4); + expect(getDirectiveDef(Sub1Directive) !.hostVars).toEqual(6); + expect(getDirectiveDef(Sub2Directive) !.hostVars).toEqual(6); + } + }); + }); + describe('ngOnChanges', () => { it('should be inherited when super is a directive', () => { const log: string[] = []; diff --git a/packages/core/test/acceptance/integration_spec.ts b/packages/core/test/acceptance/integration_spec.ts index 1a8762a838..d53825871c 100644 --- a/packages/core/test/acceptance/integration_spec.ts +++ b/packages/core/test/acceptance/integration_spec.ts @@ -9,7 +9,6 @@ import {CommonModule} from '@angular/common'; import {Component, ContentChild, Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, NgModule, OnInit, Output, Pipe, QueryList, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core'; import {TVIEW} from '@angular/core/src/render3/interfaces/view'; import {getLView} from '@angular/core/src/render3/state'; -import {loadLContext} from '@angular/core/src/render3/util/discovery_utils'; import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; @@ -1033,7 +1032,7 @@ describe('acceptance integration tests', () => { fixture.componentInstance.value = false; fixture.detectChanges(); - expect(structuralCompEl.getAttribute('class')).toEqual(''); + expect(structuralCompEl.getAttribute('class')).toBeFalsy(); }); @Directive({selector: '[DirWithClass]'}) @@ -1072,7 +1071,7 @@ describe('acceptance integration tests', () => { it('should delegate initial styles to a [style] input binding if present on a directive on the same element', () => { - @Component({template: '
'}) + @Component({template: '
'}) class App { @ViewChild(DirWithStyleDirective) mockStyleDirective !: DirWithStyleDirective; @@ -1085,8 +1084,8 @@ describe('acceptance integration tests', () => { const styles = fixture.componentInstance.mockStyleDirective.stylesVal; // Use `toContain` since Ivy and ViewEngine have some slight differences in formatting. - expect(styles).toContain('width:100px'); - expect(styles).toContain('height:200px'); + expect(styles).toContain('width: 100px'); + expect(styles).toContain('height: 200px'); }); it('should update `[class]` and bindings in the provided directive if the input is matched', @@ -1123,7 +1122,7 @@ describe('acceptance integration tests', () => { fixture.detectChanges(); expect(fixture.componentInstance.mockStyleDirective.stylesVal) - .toEqual({'width': '200px', 'height': '500px'}); + .toEqual({width: '200px', height: '500px'}); }); onlyInIvy('Style binding merging works differently in Ivy') @@ -1178,14 +1177,14 @@ describe('acceptance integration tests', () => { } }) class DirWithSingleStylingBindings { - width: null|string = null; - height: null|string = null; + width: string|null|undefined = undefined; + height: string|null|undefined = undefined; activateXYZClass: boolean = false; } @Component({ template: ` -
+
` }) class App { @@ -1199,7 +1198,7 @@ describe('acceptance integration tests', () => { const dirInstance = fixture.componentInstance.dirInstance; const target: HTMLDivElement = fixture.nativeElement.querySelector('div'); expect(target.style.getPropertyValue('width')).toEqual('100px'); - expect(target.style.getPropertyValue('height')).toEqual('200px'); + expect(target.style.getPropertyValue('height')).toEqual(''); expect(target.classList.contains('abc')).toBeTruthy(); expect(target.classList.contains('def')).toBeTruthy(); expect(target.classList.contains('xyz')).toBeFalsy(); @@ -1209,18 +1208,18 @@ describe('acceptance integration tests', () => { dirInstance.activateXYZClass = true; fixture.detectChanges(); - expect(target.style.getPropertyValue('width')).toEqual('444px'); + expect(target.style.getPropertyValue('width')).toEqual('100px'); expect(target.style.getPropertyValue('height')).toEqual('999px'); expect(target.classList.contains('abc')).toBeTruthy(); expect(target.classList.contains('def')).toBeTruthy(); expect(target.classList.contains('xyz')).toBeTruthy(); - dirInstance.width = null; - dirInstance.height = null; + dirInstance.width = undefined; + dirInstance.height = undefined; fixture.detectChanges(); expect(target.style.getPropertyValue('width')).toEqual('100px'); - expect(target.style.getPropertyValue('height')).toEqual('200px'); + expect(target.style.getPropertyValue('height')).toEqual(''); expect(target.classList.contains('abc')).toBeTruthy(); expect(target.classList.contains('def')).toBeTruthy(); expect(target.classList.contains('xyz')).toBeTruthy(); @@ -1231,7 +1230,7 @@ describe('acceptance integration tests', () => { () => { @Directive({selector: '[Dir1WithStyle]', host: {'[style.width]': 'width'}}) class Dir1WithStyle { - width: null|string = null; + width: null|string|undefined = undefined; } @Directive({ @@ -1239,7 +1238,7 @@ describe('acceptance integration tests', () => { host: {'style': 'width: 111px', '[style.width]': 'width'} }) class Dir2WithStyle { - width: null|string = null; + width: null|string|undefined = undefined; } @Component( @@ -1247,10 +1246,10 @@ describe('acceptance integration tests', () => { class App { @ViewChild(Dir1WithStyle) dir1Instance !: Dir1WithStyle; @ViewChild(Dir2WithStyle) dir2Instance !: Dir2WithStyle; - width: string|null = null; + width: string|null|undefined = undefined; } - TestBed.configureTestingModule({declarations: [App, Dir1WithStyle, Dir2WithStyle]}); + TestBed.configureTestingModule({declarations: [App, Dir2WithStyle, Dir1WithStyle]}); const fixture = TestBed.createComponent(App); fixture.detectChanges(); const {dir1Instance, dir2Instance} = fixture.componentInstance; @@ -1264,15 +1263,15 @@ describe('acceptance integration tests', () => { fixture.detectChanges(); expect(target.style.getPropertyValue('width')).toEqual('999px'); - fixture.componentInstance.width = null; + fixture.componentInstance.width = undefined; fixture.detectChanges(); expect(target.style.getPropertyValue('width')).toEqual('222px'); - dir1Instance.width = null; + dir1Instance.width = undefined; fixture.detectChanges(); expect(target.style.getPropertyValue('width')).toEqual('333px'); - dir2Instance.width = null; + dir2Instance.width = undefined; fixture.detectChanges(); expect(target.style.getPropertyValue('width')).toEqual('111px'); @@ -1317,7 +1316,7 @@ describe('acceptance integration tests', () => { } TestBed.configureTestingModule( - {declarations: [App, Dir1WithStyling, Dir2WithStyling]}); + {declarations: [App, Dir2WithStyling, Dir1WithStyling]}); const fixture = TestBed.createComponent(App); fixture.detectChanges(); const {dir1Instance, dir2Instance} = fixture.componentInstance; @@ -1326,7 +1325,7 @@ describe('acceptance integration tests', () => { expect(target.style.getPropertyValue('width')).toEqual('111px'); const compInstance = fixture.componentInstance; - compInstance.stylesExp = {width: '999px', height: null}; + compInstance.stylesExp = {width: '999px', height: undefined}; compInstance.classesExp = {one: true, two: false}; dir1Instance.stylesExp = {width: '222px'}; dir1Instance.classesExp = {two: true, three: false}; diff --git a/packages/core/test/acceptance/renderer_factory_spec.ts b/packages/core/test/acceptance/renderer_factory_spec.ts index 324d08b5a7..f10269cf63 100644 --- a/packages/core/test/acceptance/renderer_factory_spec.ts +++ b/packages/core/test/acceptance/renderer_factory_spec.ts @@ -73,7 +73,6 @@ describe('renderer factory lifecycle', () => { fixture.detectChanges(); expect(logs).toEqual( ['create', 'create', 'begin', 'some_component create', 'some_component update', 'end']); - logs = []; fixture.detectChanges(); expect(logs).toEqual(['begin', 'some_component update', 'end']); diff --git a/packages/core/test/acceptance/styling_spec.ts b/packages/core/test/acceptance/styling_spec.ts index 9a74b70d63..cee91e5718 100644 --- a/packages/core/test/acceptance/styling_spec.ts +++ b/packages/core/test/acceptance/styling_spec.ts @@ -7,16 +7,472 @@ */ import {CommonModule} from '@angular/common'; import {Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, HostBinding, Input, NgModule, Renderer2, ViewChild, ViewContainerRef} from '@angular/core'; -import {getDebugNode} from '@angular/core/src/render3/util/discovery_utils'; +import {bypassSanitizationTrustStyle} from '@angular/core/src/sanitization/bypass'; import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode'; import {TestBed} from '@angular/core/testing'; +import {getElementClasses, getElementStyles, getSortedClassName, getSortedStyle} from '@angular/core/testing/src/styling'; import {By, DomSanitizer, SafeStyle} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; +import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; describe('styling', () => { beforeEach(ngDevModeResetPerfCounters); + describe('apply in prioritization order', () => { + it('should perform static bindings', () => { + @Component({template: `
`}) + class Cmp { + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + + const [staticDiv] = fixture.nativeElement.querySelectorAll('div'); + expect(getSortedClassName(staticDiv)).toEqual('STATIC'); + expect(getSortedStyle(staticDiv)).toEqual('color: blue;'); + }); + + it('should perform prop bindings', () => { + @Component({ + template: `
` + }) + class Cmp { + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(getSortedClassName(div)).toEqual('dynamic'); + expect(getSortedStyle(div)).toEqual('color: blue; width: 100px;'); + }); + + onlyInIvy('style merging is ivy only feature').it('should perform map bindings', () => { + @Component({ + template: `
` + }) + class Cmp { + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(getSortedClassName(div)).toEqual('dynamic'); + expect(getSortedStyle(div)).toEqual('color: blue; width: 100px;'); + }); + + onlyInIvy('style merging is ivy only feature') + .it('should perform interpolation bindings', () => { + @Component({ + // TODO(misko): change `style-x` to `style` once #34202 lands + template: `
` + }) + class Cmp { + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(getSortedClassName(div)).toEqual('dynamic static'); + expect(getSortedStyle(div)).toEqual('color: blue;'); + }); + + onlyInIvy('style merging is ivy only feature').it('should support hostBindings', () => { + @Component({ + template: + `
` + }) + class Cmp { + } + @Directive({ + selector: '[my-host-bindings-1]', + host: {'class': 'HOST_STATIC_1', 'style': 'font-family: "c1"'} + }) + class Dir1 { + } + + @Directive({ + selector: '[my-host-bindings-2]', + host: {'class': 'HOST_STATIC_2', 'style': 'font-family: "c2"'} + }) + class Dir2 { + } + + TestBed.configureTestingModule({ + declarations: [ + // Order of directives in the template does not matter. + // Order of declarations matters as it determines the relative priority for overrides. + Dir1, + Dir2, + // Even thought component is at the end, it will still have lowest priority because + // components are special that way. + Cmp, + ] + }); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(getSortedClassName(div)).toEqual('HOST_STATIC_1 HOST_STATIC_2 STATIC'); + expect(getSortedStyle(div)).toEqual('color: blue; font-family: c2;'); + }); + + it('should support hostBindings inheritance', () => { + @Component({template: `
`}) + class Cmp { + } + @Directive({host: {'class': 'SUPER_STATIC', 'style': 'font-family: "super"; width: "1px";'}}) + class SuperDir { + } + @Directive({ + selector: '[my-host-bindings]', + host: {'class': 'HOST_STATIC', 'style': 'font-family: "host font"'} + }) + class Dir extends SuperDir { + } + + TestBed.configureTestingModule({declarations: [Cmp, Dir]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(getSortedClassName(div)) + .toEqual(ivyEnabled ? 'HOST_STATIC STATIC SUPER_STATIC' : 'HOST_STATIC STATIC'); + // Browsers keep the '"' around the font name, but Domino removes it some we do search and + // replace. Yes we could do `replace(/"/g, '')` but that fails on android. + expect(getSortedStyle(div).replace('"', '').replace('"', '')) + .toEqual( + ivyEnabled ? 'color: blue; font-family: host font; width: 1px;' : + 'color: blue; font-family: host font;'); + }); + + onlyInIvy('style merging is ivy only feature') + .it('should apply template classes in correct order', () => { + @Component({ + template: ` +
+ ` + }) + class Cmp { + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const classDiv = fixture.nativeElement.querySelector('div'); + expect(getSortedClassName(classDiv)).toEqual('STATIC bar foo'); + }); + + onlyInIvy('style merging is ivy only feature') + .it('should apply template styles in correct order', () => { + @Component({ + template: ` +
+ ` + }) + class Cmp { + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const styleDiv = fixture.nativeElement.querySelector('div'); + expect(getSortedStyle(styleDiv)) + .toEqual('background-color: yellow; color: blue; width: 110px;'); + }); + + it('should work with ngClass/ngStyle', () => { + @Component( + {template: `
`}) + class Cmp { + } + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(getSortedClassName(div)).toEqual('dynamic'); + expect(getSortedStyle(div)).toEqual('font-family: dynamic;'); + }); + }); + + describe('css variables', () => { + onlyInIvy('css variables').it('should support css variables', () => { + // This test only works in browsers which support CSS variables. + if (!(typeof getComputedStyle !== 'undefined' && typeof CSS !== 'undefined' && + typeof CSS.supports !== 'undefined' && CSS.supports('color', 'var(--fake-var)'))) + return; + @Component({ + template: ` +
+ CONTENT +
` + }) + class Cmp { + } + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + // document.body.appendChild(fixture.nativeElement); + fixture.detectChanges(); + + const span = fixture.nativeElement.querySelector('span') as HTMLElement; + expect(getComputedStyle(span).getPropertyValue('width')).toEqual('100px'); + }); + }); + + modifiedInIvy('shadow bindings include static portion') + .it('should bind [class] as input to directive', () => { + // VE Behavior https://stackblitz.com/edit/angular-cycpsf + // IVY behavior is slightly different see next test with same name. + @Component({ + template: ` +
+
+ ` + }) + class Cmp { + } + + @Directive({selector: '[dir-shadows-class-input]'}) + class DirectiveShadowsClassInput { + constructor(private elementRef: ElementRef) {} + @Input('class') + set klass(value: string) { + this.elementRef.nativeElement.setAttribute('shadow-class', value); + } + } + + TestBed.configureTestingModule({declarations: [Cmp, DirectiveShadowsClassInput]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const [div1, div2] = fixture.nativeElement.querySelectorAll('div'); + // Static value `class="s1"` is always written to the DOM. + expect(div1.className).toEqual('s1'); + // VE passes the dynamic portion of `class` to the directive. + expect(div1.getAttribute('shadow-class')).toEqual('d1'); + // Interpolation `class="s2 {{'d2'}}"` does not have a static portion and so no value is + // written to DOM. + expect(div2.className).toEqual(''); + expect(div2.getAttribute('shadow-class')).toEqual('s2 d2'); + }); + + + onlyInIvy('shadow bindings include static portion') + .it('should bind [class] as input to directive', () => { + // VE Behavior https://stackblitz.com/edit/angular-cycpsf + // IVY behavior is slightly different see next test with same name. + @Component({ + template: ` +
+
+ ` + }) + class Cmp { + } + + @Directive({selector: '[dir-shadows-class-input]'}) + class DirectiveShadowsClassInput { + constructor(private elementRef: ElementRef) {} + @Input('class') + set klass(value: string) { + this.elementRef.nativeElement.setAttribute('shadow-class', value); + } + } + + TestBed.configureTestingModule({declarations: [Cmp, DirectiveShadowsClassInput]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const [div1, div2] = fixture.nativeElement.querySelectorAll('div'); + // Static value `class="s1"` is always written to the DOM. + expect(div1.className).toEqual('s1'); + // VE has weird behavior where it calls the @Input('class') with either `class="static` or + // `[class]="dynamic"` but never both. This is determined at compile time. Due to locality + // we don't know if `[class]` is coming if we see `class` only. So we need to combine the + // static and dynamic parte. This results in slightly different calling sequence, but should + // result in the same final DOM. + expect(div1.getAttribute('shadow-class')).toEqual('s1 d1'); + + expect(div2.className).toEqual(''); + expect(div2.getAttribute('shadow-class')).toEqual('s2 d2'); + }); + + + modifiedInIvy('shadow bindings include static portion') + .it('should bind [style] as input to directive', () => { + // VE Behavior https://stackblitz.com/edit/angular-cycpsf + @Component({ + template: ` +
+ ` + }) + class Cmp { + } + + @Directive({selector: '[dir-shadows-style-input]'}) + class DirectiveShadowsClassInput { + constructor(private elementRef: ElementRef) {} + @Input('style') + set style(value: string) { + this.elementRef.nativeElement.setAttribute('shadow-style', value); + } + } + + TestBed.configureTestingModule({declarations: [Cmp, DirectiveShadowsClassInput]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(div.style.cssText).toEqual('color: red;'); + // VE has weird behavior where it calls the @Input('class') with either `class="static` or + // `[class]="dynamic"` but never both. This is determined at compile time. Due to locality + // we + // don't know if `[class]` is coming if we see `class` only. So we need to combine the two + // This results in slightly different calling sequence, but should result in the same final + // DOM. + expect(div.getAttribute('shadow-style')).toEqual('width: 100px;'); + }); + + onlyInIvy('shadow bindings include static portion') + .it('should bind [style] as input to directive', () => { + // VE Behavior https://stackblitz.com/edit/angular-cycpsf + @Component({ + template: ` +
+ ` + }) + class Cmp { + } + + @Directive({selector: '[dir-shadows-style-input]'}) + class DirectiveShadowsClassInput { + constructor(private elementRef: ElementRef) {} + @Input('style') + set style(value: string) { + this.elementRef.nativeElement.setAttribute('shadow-style', value); + } + } + + TestBed.configureTestingModule({declarations: [Cmp, DirectiveShadowsClassInput]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + expect(div.style.cssText).toEqual('color: red;'); + // VE has weird behavior where it calls the @Input('class') with either `class="static` or + // `[class]="dynamic"` but never both. This is determined at compile time. Due to locality + // we + // don't know if `[class]` is coming if we see `class` only. So we need to combine the two + // This results in slightly different calling sequence, but should result in the same final + // DOM. + expect(div.getAttribute('shadow-style')).toEqual('color: red; width: 100px;'); + }); + + it('should prevent circular ExpressionChangedAfterItHasBeenCheckedError on shadow inputs', () => { + @Component({template: `
`}) + class Cmp { + } + + @Directive({selector: '[dir-shadows-class-input]'}) + class DirectiveShadowsClassInput { + @Input('class') + klass: string|undefined; + + @HostBinding('class') + get hostClasses() { return `${this.klass} SUFFIX`; } + } + + TestBed.configureTestingModule({declarations: [Cmp, DirectiveShadowsClassInput]}); + const fixture = TestBed.createComponent(Cmp); + expect(() => fixture.detectChanges()).not.toThrow(); + + const div = fixture.nativeElement.querySelector('div'); + expect(div.className).toEqual('s1 SUFFIX'); + }); + + it('should recover from exceptions', () => { + @Component({ + template: ` +
+ +
+ ` + }) + class Cmp { + id = 'throw_id'; + klass: string|string[] = 'throw_klass'; + foo = `throw_foo`; + + maybeThrow(value: any) { + if (typeof value === 'string' && value.indexOf('throw') === 0) { + throw new Error(value); + } + return value; + } + } + + let myDirHostBinding = false; + @Directive({selector: '[my-dir]'}) + class MyDirective { + @HostBinding('class.myDir') + get myDir(): boolean { + if (myDirHostBinding === false) { + throw new Error('class.myDir'); + } + return myDirHostBinding; + } + } + + TestBed.configureTestingModule({declarations: [Cmp, MyDirective]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + const div = fixture.nativeElement.querySelector('div'); + const span = fixture.nativeElement.querySelector('span'); + + expect(() => fixture.detectChanges()).toThrowError(/throw_id/); + expect(div.id).toBeFalsy(); + expectClass(span).toEqual({}); + + cmp.id = 'myId'; + expect(() => fixture.detectChanges()).toThrowError(/throw_klass/); + expect(div.id).toEqual('myId'); + expectClass(span).toEqual({}); + + cmp.klass = ['BAR']; + expect(() => fixture.detectChanges()).toThrowError(/throw_foo/); + expect(div.id).toEqual('myId'); + expectClass(span).toEqual(ivyEnabled ? {BAR: true} : {}); + + cmp.foo = 'foo'; + expect(() => fixture.detectChanges()).toThrowError(/class.myDir/); + expect(div.id).toEqual('myId'); + expectClass(span).toEqual(ivyEnabled ? {BAR: true, foo: true} : {}); + + myDirHostBinding = true; + fixture.detectChanges(); + expect(div.id).toEqual('myId'); + expectClass(span).toEqual({BAR: true, foo: true, myDir: true}); + }); + it('should render inline style and class attribute values on the element before a directive is instantiated', () => { @Component({ @@ -197,16 +653,15 @@ describe('styling', () => { expect(div.style.backgroundImage).toBe('url("#test")'); onlyInIvy('perf counters').expectPerfCounters({ - styleProp: 2, - stylePropCacheMiss: 1, + rendererSetStyle: 1, tNode: 3, }); }); - it('should not throw if host style binding is on a template node', () => { - // This ex is a bit contrived. In real apps, you might have a shared class that is extended both - // by components with host elements and by directives on template nodes. In that case, the host - // styles for the template directives should just be ignored. + it('should not write to the native element if a directive shadows the class input', () => { + // This ex is a bit contrived. In real apps, you might have a shared class that is extended + // both by components with host elements and by directives on template nodes. In that case, the + // host styles for the template directives should just be ignored. @Directive({selector: 'ng-template[styleDir]', host: {'[style.display]': 'display'}}) class StyleDir { display = 'block'; @@ -217,10 +672,7 @@ describe('styling', () => { } TestBed.configureTestingModule({declarations: [MyApp, StyleDir]}); - expect(() => { - const fixture = TestBed.createComponent(MyApp); - fixture.detectChanges(); - }).not.toThrow(); + TestBed.createComponent(MyApp).detectChanges(); }); it('should be able to bind a SafeValue to clip-path', () => { @@ -496,23 +948,18 @@ describe('styling', () => { } } - // Ivy does an extra `[class]` write with a falsy value since the value - // is applied during creation mode. This is a deviation from VE and should - // be (Jira Issue = FW-1467). - let totalWrites = ivyEnabled ? 1 : 0; - TestBed.configureTestingModule({declarations: [Cmp, MyClassDir]}); const fixture = TestBed.createComponent(Cmp); - expect(capturedClassBindingCount).toEqual(totalWrites++); + expect(capturedClassBindingCount).toEqual(0); fixture.detectChanges(); - expect(capturedClassBindingCount).toEqual(totalWrites++); + expect(capturedClassBindingCount).toEqual(1); expect(capturedClassBindingValue as any).toEqual('bar'); fixture.componentInstance.c = 'dynamic-bar'; fixture.detectChanges(); - expect(capturedClassBindingCount).toEqual(totalWrites++); + expect(capturedClassBindingCount).toEqual(2); expect(capturedClassBindingValue !).toEqual('dynamic-bar'); }); @@ -653,15 +1100,28 @@ describe('styling', () => { const fixture = TestBed.createComponent(Cmp); fixture.detectChanges(); - expect(capturedClassBindingCount).toEqual(1); - expect(capturedClassBindingValue !).toEqual('static-val'); + expect(capturedClassBindingCount) + .toEqual( + 2 + // '2' is not ideal as '1' would be preferred. + // The reason for two writes is that one is for the static + // `class="static-val"` and one for `[class]="c"`. This means that + // `class="static-val"` is written during the create block which is not ideal. + // To do this correctly we would have to delay the `class="static-val"` until + // the update block, but that would be expensive since it would require that we + // would check if we possibly have this situation on every `advance()` + // instruction. We don't think this is worth it, and we are just going to live + // with this. + ); + expect(capturedClassBindingValue).toEqual(null); expect(capturedMyClassBindingCount).toEqual(1); expect(capturedMyClassBindingValue !).toEqual('foo'); + capturedClassBindingCount = 0; fixture.componentInstance.c = 'dynamic-val'; fixture.detectChanges(); - expect(capturedClassBindingCount).toEqual(2); + expect(capturedClassBindingCount).toEqual(1); expect(capturedClassBindingValue !).toEqual('static-val dynamic-val'); expect(capturedMyClassBindingCount).toEqual(1); expect(capturedMyClassBindingValue !).toEqual('foo'); @@ -791,17 +1251,17 @@ describe('styling', () => { @Component({ template: `
+ [style.height]="h" + [style.opacity]="o" + style="width:200px; height:200px;" + [class.abc]="abc" + [class.xyz]="xyz">
` }) class Cmp { - w: string|null = '100px'; - h: string|null = '100px'; - o: string|null = '0.5'; + w: string|null|undefined = '100px'; + h: string|null|undefined = '100px'; + o: string|null|undefined = '0.5'; abc = true; xyz = false; } @@ -817,9 +1277,9 @@ describe('styling', () => { expect(element.classList.contains('abc')).toBeTruthy(); expect(element.classList.contains('xyz')).toBeFalsy(); - fixture.componentInstance.w = null; - fixture.componentInstance.h = null; - fixture.componentInstance.o = null; + fixture.componentInstance.w = undefined; + fixture.componentInstance.h = undefined; + fixture.componentInstance.o = undefined; fixture.componentInstance.abc = false; fixture.componentInstance.xyz = true; fixture.detectChanges(); @@ -829,6 +1289,14 @@ describe('styling', () => { expect(element.style.opacity).toBeFalsy(); expect(element.classList.contains('abc')).toBeFalsy(); expect(element.classList.contains('xyz')).toBeTruthy(); + + fixture.componentInstance.w = null; + fixture.componentInstance.h = null; + fixture.componentInstance.o = null; + fixture.detectChanges(); + expect(element.style.width).toBeFalsy(); + expect(element.style.height).toBeFalsy(); + expect(element.style.opacity).toBeFalsy(); }); onlyInIvy('ivy resolves styling across directives, components and templates in unison') @@ -846,14 +1314,14 @@ describe('styling', () => { @Component({ template: `
+ [dir-that-sets-width]="w1" + [another-dir-that-sets-width]="w2"> ` }) class Cmp { - w0: string|null = null; - w1: string|null = null; - w2: string|null = null; + w0: string|null|undefined = null; + w1: string|null|undefined = null; + w2: string|null|undefined = null; } TestBed.configureTestingModule( @@ -867,17 +1335,17 @@ describe('styling', () => { const element = fixture.nativeElement.querySelector('div'); expect(element.style.width).toEqual('100px'); - fixture.componentInstance.w0 = null; - fixture.detectChanges(); - - expect(element.style.width).toEqual('200px'); - - fixture.componentInstance.w1 = null; + fixture.componentInstance.w0 = undefined; fixture.detectChanges(); expect(element.style.width).toEqual('300px'); - fixture.componentInstance.w2 = null; + fixture.componentInstance.w2 = undefined; + fixture.detectChanges(); + + expect(element.style.width).toEqual('200px'); + + fixture.componentInstance.w1 = undefined; fixture.detectChanges(); expect(element.style.width).toBeFalsy(); @@ -920,7 +1388,8 @@ describe('styling', () => { opacity: string|null = '0.5'; @ViewChild(CompWithStyling, {static: true}) compWithStyling: CompWithStyling|null = null; - @ViewChild(DirWithStyling, {static: true}) dirWithStyling: DirWithStyling|null = null; + @ViewChild(DirWithStyling, {static: true}) + dirWithStyling: DirWithStyling|null = null; } TestBed.configureTestingModule({declarations: [Cmp, DirWithStyling, CompWithStyling]}); @@ -929,14 +1398,6 @@ describe('styling', () => { const component = fixture.componentInstance; const element = fixture.nativeElement.querySelector('comp-with-styling'); - const node = getDebugNode(element) !; - - const styles = node.styles !; - const config = styles.context.config; - expect(config.hasCollisions).toBeFalsy(); - expect(config.hasMapBindings).toBeFalsy(); - expect(config.hasPropBindings).toBeTruthy(); - expect(config.allowDirectStyling).toBeTruthy(); expect(element.style.opacity).toEqual('0.5'); expect(element.style.width).toEqual('900px'); @@ -944,7 +1405,7 @@ describe('styling', () => { expect(element.style.fontSize).toEqual('100px'); // once for the template flush and again for the host bindings - expect(ngDevMode !.flushStyling).toEqual(2); + expect(ngDevMode !.rendererSetStyle).toEqual(4); ngDevModeResetPerfCounters(); component.opacity = '0.6'; @@ -958,8 +1419,8 @@ describe('styling', () => { expect(element.style.height).toEqual('100px'); expect(element.style.fontSize).toEqual('50px'); - // there is no need to flush styling since the styles are applied directly - expect(ngDevMode !.flushStyling).toEqual(0); + // once for the template flush and again for the host bindings + expect(ngDevMode !.rendererSetStyle).toEqual(4); }); onlyInIvy('ivy resolves styling across directives, components and templates in unison') @@ -993,8 +1454,8 @@ describe('styling', () => { ` }) class Cmp { - opacity: string|null = '0.5'; - width: string|null = 'auto'; + opacity: string|null|undefined = '0.5'; + width: string|null|undefined = 'auto'; tplClass = true; } @@ -1004,40 +1465,36 @@ describe('styling', () => { const element = fixture.nativeElement.querySelector('comp-with-styling'); - const node = getDebugNode(element) !; - const styles = node.styles !; - const classes = node.classes !; - - expect(styles.values).toEqual({ + expectStyle(element).toEqual({ 'color': 'red', - 'width': 'auto', - 'opacity': '0.5', + 'font-size': '100px', 'height': '900px', - 'font-size': '100px' + 'opacity': '0.5', + 'width': 'auto', }); - expect(classes.values).toEqual({ + expectClass(element).toEqual({ 'dir': true, 'comp': true, 'tpl': true, }); - fixture.componentInstance.width = null; - fixture.componentInstance.opacity = null; + fixture.componentInstance.width = undefined; + fixture.componentInstance.opacity = undefined; fixture.componentInstance.tplClass = false; fixture.detectChanges(); - expect(styles.values).toEqual({ - 'color': 'red', - 'width': '900px', - 'opacity': null, - 'height': '900px', - 'font-size': '100px' - }); - expect(classes.values).toEqual({ + expectStyle(element).toEqual( + {'color': 'red', 'width': '900px', 'height': '900px', 'font-size': '100px'}); + expectClass(element).toEqual({ 'dir': true, 'comp': true, - 'tpl': false, }); + + fixture.componentInstance.width = null; + fixture.componentInstance.opacity = null; + fixture.detectChanges(); + + expectStyle(element).toEqual({'color': 'red', 'height': '900px', 'font-size': '100px'}); }); onlyInIvy('ivy resolves styling across directives, components and templates in unison') @@ -1059,7 +1516,7 @@ describe('styling', () => { ` }) class Cmp { - w3: string|null = '300px'; + w3: string|null|undefined = '300px'; } TestBed.configureTestingModule( @@ -1069,80 +1526,23 @@ describe('styling', () => { const element = fixture.nativeElement.querySelector('div'); - const node = getDebugNode(element) !; - const styles = node.styles !; - - expect(styles.values).toEqual({ + expectStyle(element).toEqual({ 'width': '300px', }); fixture.componentInstance.w3 = null; fixture.detectChanges(); - expect(styles.values).toEqual({ + expectStyle(element).toEqual({}); + + fixture.componentInstance.w3 = undefined; + fixture.detectChanges(); + + expectStyle(element).toEqual({ 'width': '200px', }); }); - onlyInIvy('only ivy has style/class bindings debugging support') - .it('should support situations where there are more than 32 bindings', () => { - const TOTAL_BINDINGS = 34; - - let bindingsHTML = ''; - let bindingsArr: any[] = []; - for (let i = 0; i < TOTAL_BINDINGS; i++) { - bindingsHTML += `[style.prop${i}]="bindings[${i}]" `; - bindingsArr.push(null); - } - - @Component({template: `
`}) - class Cmp { - bindings = bindingsArr; - - updateBindings(value: string) { - for (let i = 0; i < TOTAL_BINDINGS; i++) { - this.bindings[i] = value + i; - } - } - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - - let testValue = 'initial'; - fixture.componentInstance.updateBindings('initial'); - fixture.detectChanges(); - - const element = fixture.nativeElement.querySelector('div'); - - const node = getDebugNode(element) !; - const styles = node.styles !; - - let values = styles.values; - let props = Object.keys(values); - expect(props.length).toEqual(TOTAL_BINDINGS); - - for (let i = 0; i < props.length; i++) { - const prop = props[i]; - const value = values[prop] as string; - const num = value.substr(testValue.length); - expect(value).toEqual(`initial${num}`); - } - - testValue = 'final'; - fixture.componentInstance.updateBindings('final'); - fixture.detectChanges(); - - values = styles.values; - props = Object.keys(values); - expect(props.length).toEqual(TOTAL_BINDINGS); - for (let i = 0; i < props.length; i++) { - const prop = props[i]; - const value = values[prop] as string; - const num = value.substr(testValue.length); - expect(value).toEqual(`final${num}`); - } - }); onlyInIvy('only ivy has style debugging support') .it('should apply map-based style and class entries', () => { @@ -1176,23 +1576,8 @@ describe('styling', () => { fixture.detectChanges(); const element = fixture.nativeElement.querySelector('div'); - const node = getDebugNode(element) !; - let styles = node.styles !; - let classes = node.classes !; - - let stylesSummary = styles.summary; - let widthSummary = stylesSummary['width']; - expect(widthSummary.prop).toEqual('width'); - expect(widthSummary.value).toEqual('100px'); - - let heightSummary = stylesSummary['height']; - expect(heightSummary.prop).toEqual('height'); - expect(heightSummary.value).toEqual('200px'); - - let classesSummary = classes.summary; - let abcSummary = classesSummary['abc']; - expect(abcSummary.prop).toEqual('abc'); - expect(abcSummary.value).toBeTruthy(); + expectStyle(element).toEqual({width: '100px', height: '200px'}); + expectClass(element).toEqual({abc: true}); comp.reset(); comp.updateStyles('width', '500px'); @@ -1200,23 +1585,8 @@ describe('styling', () => { comp.updateClasses('def'); fixture.detectChanges(); - styles = node.styles !; - classes = node.classes !; - - stylesSummary = styles.summary; - widthSummary = stylesSummary['width']; - expect(widthSummary.value).toEqual('500px'); - - heightSummary = stylesSummary['height']; - expect(heightSummary.value).toEqual(null); - - classesSummary = classes.summary; - abcSummary = classesSummary['abc']; - expect(abcSummary).toBeUndefined(); - - let defSummary = classesSummary['def']; - expect(defSummary.prop).toEqual('def'); - expect(defSummary.value).toBeTruthy(); + expectStyle(element).toEqual({width: '500px'}); + expectClass(element).toEqual({def: true}); }); onlyInIvy('ivy resolves styling across directives, components and templates in unison') @@ -1230,16 +1600,16 @@ describe('styling', () => { @Component({ template: `
+ [style]="map" + style="width:200px; font-size:99px" + dir-that-sets-styling + #dir + [class.xyz]="xyz">
` }) class Cmp { map: any = {width: '111px', opacity: '0.5'}; - width: string|null = '555px'; + width: string|null|undefined = '555px'; @ViewChild('dir', {read: DirThatSetsStyling, static: true}) dir !: DirThatSetsStyling; @@ -1251,21 +1621,17 @@ describe('styling', () => { fixture.detectChanges(); const element = fixture.nativeElement.querySelector('div'); - const node = getDebugNode(element) !; - - const styles = node.styles !; - - expect(styles.values).toEqual({ + expectStyle(element).toEqual({ 'width': '555px', 'color': 'red', 'font-size': '99px', 'opacity': '0.5', }); - comp.width = null; + comp.width = undefined; fixture.detectChanges(); - expect(styles.values).toEqual({ + expectStyle(element).toEqual({ 'width': '111px', 'color': 'red', 'font-size': '99px', @@ -1275,28 +1641,26 @@ describe('styling', () => { comp.map = null; fixture.detectChanges(); - expect(styles.values).toEqual({ - 'width': '777px', + expectStyle(element).toEqual({ + 'width': '200px', 'color': 'red', 'font-size': '99px', - 'opacity': null, }); comp.dir.map = null; fixture.detectChanges(); - expect(styles.values).toEqual({ + expectStyle(element).toEqual({ 'width': '200px', - 'color': null, 'font-size': '99px', - 'opacity': null, }); }); onlyInIvy('ivy resolves styling across directives, components and templates in unison') .it('should only apply each styling property once per CD across templates, components, directives', () => { - @Directive({selector: '[dir-that-sets-styling]'}) + @Directive( + {selector: '[dir-that-sets-styling]', host: {'style': 'width:0px; height:0px'}}) class DirThatSetsStyling { @HostBinding('style') public map: any = {width: '999px', height: '999px'}; } @@ -1304,7 +1668,6 @@ describe('styling', () => { @Component({ template: `
{ ` }) class Cmp { - width: string|null = '111px'; - height: string|null = '111px'; + width: string|null|undefined = '111px'; + height: string|null|undefined = '111px'; map: any = {width: '555px', height: '555px'}; @@ -1329,8 +1692,7 @@ describe('styling', () => { fixture.detectChanges(); const element = fixture.nativeElement.querySelector('div'); - // both are applied because this is the first pass - assertStyleCounters(2, 0); + assertStyleCounters(4, 0); assertStyle(element, 'width', '111px'); assertStyle(element, 'height', '111px'); @@ -1350,7 +1712,7 @@ describe('styling', () => { assertStyle(element, 'width', '222px'); assertStyle(element, 'height', '222px'); - comp.width = null; + comp.width = undefined; ngDevModeResetPerfCounters(); fixture.detectChanges(); @@ -1370,17 +1732,16 @@ describe('styling', () => { ngDevModeResetPerfCounters(); fixture.detectChanges(); - // both are applied because the map was altered - assertStyleCounters(2, 0); + // No change, hence no write + assertStyleCounters(0, 0); assertStyle(element, 'width', '123px'); assertStyle(element, 'height', '123px'); - comp.width = null; + comp.width = undefined; ngDevModeResetPerfCounters(); fixture.detectChanges(); - // the width is applied both in TEMPLATE and in HOST_BINDINGS mode - assertStyleCounters(2, 0); + assertStyleCounters(1, 0); assertStyle(element, 'width', '999px'); assertStyle(element, 'height', '123px'); @@ -1393,34 +1754,33 @@ describe('styling', () => { assertStyle(element, 'width', '0px'); assertStyle(element, 'height', '123px'); - comp.dir.map = {width: '1000px', height: '1000px', color: 'red'}; + comp.dir.map = {width: '1000px', height: '1100px', color: 'red'}; ngDevModeResetPerfCounters(); fixture.detectChanges(); - // only the width and color have changed assertStyleCounters(2, 0); assertStyle(element, 'width', '1000px'); assertStyle(element, 'height', '123px'); assertStyle(element, 'color', 'red'); - comp.height = null; + comp.height = undefined; ngDevModeResetPerfCounters(); fixture.detectChanges(); // height gets applied twice and all other // values get applied - assertStyleCounters(4, 0); + assertStyleCounters(1, 0); assertStyle(element, 'width', '1000px'); - assertStyle(element, 'height', '1000px'); + assertStyle(element, 'height', '1100px'); assertStyle(element, 'color', 'red'); comp.map = {color: 'blue', width: '2000px', opacity: '0.5'}; ngDevModeResetPerfCounters(); fixture.detectChanges(); - assertStyleCounters(5, 0); + assertStyleCounters(3, 0); assertStyle(element, 'width', '2000px'); - assertStyle(element, 'height', '1000px'); + assertStyle(element, 'height', '1100px'); assertStyle(element, 'color', 'blue'); assertStyle(element, 'opacity', '0.5'); @@ -1429,21 +1789,20 @@ describe('styling', () => { fixture.detectChanges(); // all four are applied because the map was altered - assertStyleCounters(4, 1); + assertStyleCounters(0, 1); assertStyle(element, 'width', '2000px'); - assertStyle(element, 'height', '1000px'); + assertStyle(element, 'height', '1100px'); assertStyle(element, 'color', 'blue'); assertStyle(element, 'opacity', ''); }); - onlyInIvy('only ivy has style/class bindings debugging support') + onlyInIvy('only ivy has [style.prop] support') .it('should sanitize style values before writing them', () => { @Component({ template: ` -
- ` +
+ ` }) class Cmp { widthExp = ''; @@ -1456,63 +1815,35 @@ describe('styling', () => { const comp = fixture.componentInstance; fixture.detectChanges(); - const element = fixture.nativeElement.querySelector('div'); - const node = getDebugNode(element) !; - const styles = node.styles !; + const div = fixture.nativeElement.querySelector('div'); - const lastSanitizedProps: any[] = []; - styles.overrideSanitizer((prop, value) => { - lastSanitizedProps.push(prop); - return value; - }); - - comp.bgImageExp = '123'; + comp.bgImageExp = 'url("javascript:img")'; fixture.detectChanges(); - - expect(styles.values).toEqual({ - 'background-image': '123', - 'width': null, - }); - - expect(lastSanitizedProps).toEqual(['background-image']); - lastSanitizedProps.length = 0; - - comp.styleMapExp = {'clip-path': '456'}; + // for some reasons `background-image: unsafe` is suppressed + expect(getSortedStyle(div)).toEqual(''); fixture.detectChanges(); + expect(getSortedStyle(div)).not.toContain('javascript'); - expect(styles.values).toEqual({ - 'background-image': '123', - 'clip-path': '456', - 'width': null, - }); - - expect(lastSanitizedProps).toEqual(['background-image', 'clip-path']); - lastSanitizedProps.length = 0; - + // Prove that bindings work. comp.widthExp = '789px'; + comp.bgImageExp = bypassSanitizationTrustStyle(comp.bgImageExp) as string; fixture.detectChanges(); - expect(styles.values).toEqual({ - 'background-image': '123', - 'clip-path': '456', - 'width': '789px', - }); - - expect(lastSanitizedProps).toEqual(['background-image', 'clip-path']); - lastSanitizedProps.length = 0; + expect(div.style.getPropertyValue('background-image')).toEqual('url("javascript:img")'); + expect(div.style.getPropertyValue('width')).toEqual('789px'); }); - onlyInIvy('only ivy has style/class bindings debugging support') - .it('should apply a unit to a style before writing it', () => { + onlyInIvy('only ivy has [style] support') + .it('should sanitize style values before writing them', () => { @Component({ template: ` -
- ` +
+ ` }) class Cmp { - widthExp: string|number|null = ''; - heightExp: string|number|null = ''; + widthExp = ''; + styleMapExp: {[key: string]: any} = {}; } TestBed.configureTestingModule({declarations: [Cmp]}); @@ -1520,29 +1851,60 @@ describe('styling', () => { const comp = fixture.componentInstance; fixture.detectChanges(); - const element = fixture.nativeElement.querySelector('div'); - const node = getDebugNode(element) !; - const styles = node.styles !; + const div = fixture.nativeElement.querySelector('div'); - comp.widthExp = '200'; - comp.heightExp = 10; + comp.styleMapExp['background-image'] = 'url("javascript:img")'; + fixture.detectChanges(); + // for some reasons `background-image: unsafe` is suppressed + expect(getSortedStyle(div)).toEqual(''); + + // for some reasons `border-image: unsafe` is NOT suppressed + fixture.detectChanges(); + expect(getSortedStyle(div)).not.toContain('javascript'); + + // Prove that bindings work. + comp.widthExp = '789px'; + comp.styleMapExp = { + 'background-image': bypassSanitizationTrustStyle(comp.styleMapExp['background-image']) + }; fixture.detectChanges(); - expect(styles.values).toEqual({ - 'width': '200px', - 'height': '10em', - }); - - comp.widthExp = 0; - comp.heightExp = null; - fixture.detectChanges(); - - expect(styles.values).toEqual({ - 'width': '0px', - 'height': null, - }); + expect(div.style.getPropertyValue('background-image')).toEqual('url("javascript:img")'); + expect(div.style.getPropertyValue('width')).toEqual('789px'); }); + it('should apply a unit to a style before writing it', () => { + @Component({ + template: ` +
+ ` + }) + class Cmp { + widthExp: string|number|null = ''; + heightExp: string|number|null = ''; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const comp = fixture.componentInstance; + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div'); + + comp.widthExp = '200'; + comp.heightExp = 10; + fixture.detectChanges(); + + expect(getSortedStyle(div)).toEqual('height: 10em; width: 200px;'); + + comp.widthExp = 0; + comp.heightExp = null; + fixture.detectChanges(); + + expect(getSortedStyle(div)).toEqual('width: 0px;'); + }); + it('should be able to bind a SafeValue to clip-path', () => { @Component({template: '
'}) class Cmp { @@ -1657,15 +2019,10 @@ describe('styling', () => { fixture.detectChanges(); const element = fixture.nativeElement.querySelector('div'); - const node = getDebugNode(element) !; - const styles = node.styles !; - - const values = styles.values; - const props = Object.keys(values).sort(); - expect(props).toEqual(['color', 'width']); - - expect(values['width']).toEqual('200px'); - expect(values['color']).toEqual('red'); + expectStyle(element).toEqual({ + color: 'red', + width: '200px', + }); }); onlyInIvy('only ivy has style/class bindings debugging support') @@ -2350,12 +2707,12 @@ describe('styling', () => { ` }) class Cmp { - style: any = {width: '100px'}; - klass: any = {foo: true, bar: false}; + style: any = 'width: 100px'; + klass: any = 'foo'; ngAfterViewInit() { - this.style = {height: '200px'}; - this.klass = {foo: false}; + this.style = 'height: 200px'; + this.klass = 'bar'; } } @@ -2486,29 +2843,415 @@ describe('styling', () => { expect(getComputedStyle(div).width).toBe('10px'); }); - it('should allow classes with trailing and leading spaces in [ngClass]', () => { - @Component({ - template: ` -
-
- ` - }) - class Cmp { - applyClasses = true; + onlyInIvy('[style] binding is supported in Ivy only') + .it('should allow multiple styling bindings to work alongside property/attribute bindings', + () => { + @Component({ + template: ` +
+
` + }) + class MyComp { + } + + @Directive({selector: '[dir-that-sets-styles]'}) + class DirThatSetsStyling { + @HostBinding('style.width') public w = '100px'; + @HostBinding('style.height') public h = '200px'; + } + + const fixture = + TestBed.configureTestingModule({declarations: [MyComp, DirThatSetsStyling]}) + .createComponent(MyComp); + fixture.detectChanges(); + const div = fixture.nativeElement.querySelector('div') !; + expect(div.style.getPropertyValue('width')).toEqual('100px'); + expect(div.style.getPropertyValue('height')).toEqual('200px'); + expect(div.style.getPropertyValue('font-size')).toEqual('300px'); + expect(div.getAttribute('title')).toEqual('my-title'); + expect(div.getAttribute('data-foo')).toEqual('my-foo'); + }); + + onlyInIvy('VE clobers in case of @HostBinding("class")') + .it('should allow host styling on the root element with external styling', () => { + @Component({template: '...'}) + class MyComp { + @HostBinding('class') public classes = ''; + } + + const fixture = + TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); + fixture.detectChanges(); + const root = fixture.nativeElement as HTMLElement; + expect(root.className).toEqual(''); + + fixture.componentInstance.classes = '1 2 3'; + fixture.detectChanges(); + expect(root.className.split(/\s+/).sort().join(' ')).toEqual('1 2 3'); + + root.classList.add('0'); + expect(root.className.split(/\s+/).sort().join(' ')).toEqual('0 1 2 3'); + + fixture.componentInstance.classes = '1 2 3 4'; + fixture.detectChanges(); + expect(root.className.split(/\s+/).sort().join(' ')).toEqual('0 1 2 3 4'); + }); + + it('should apply camelCased class names', () => { + @Component({template: `
`}) + class MyComp { } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({ + declarations: [MyComp], + }); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + + const classList = (fixture.nativeElement.querySelector('div') as HTMLDivElement).classList; + expect(classList.contains('fooBar')).toBeTruthy(); + expect(classList.contains('barFoo')).toBeTruthy(); + }); + + onlyInIvy('[style] bindings are ivy only') + .it('should convert camelCased style property names to snake-case', () => { + @Component({template: `
`}) + class MyComp { + myStyles = {}; + } + + TestBed.configureTestingModule({ + declarations: [MyComp], + }); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + + const div = fixture.nativeElement.querySelector('div') as HTMLDivElement; + fixture.componentInstance.myStyles = {fontSize: '200px'}; + fixture.detectChanges(); + + expect(div.style.getPropertyValue('font-size')).toEqual('200px'); + }); + + it('should recover from an error thrown in styling bindings', () => { + let raiseWidthError = false; + + @Component({template: `
`}) + class MyComp { + get myWidth() { + if (raiseWidthError) { + throw new Error('...'); + } + return '100px'; + } + } + + TestBed.configureTestingModule({declarations: [MyComp]}); + const fixture = TestBed.createComponent(MyComp); + + raiseWidthError = true; + expect(() => fixture.detectChanges()).toThrow(); + + raiseWidthError = false; + fixture.detectChanges(); + const div = fixture.nativeElement.querySelector('div') as HTMLDivElement; + expect(div.style.getPropertyValue('width')).toEqual('100px'); + expect(div.style.getPropertyValue('height')).toEqual('200px'); + }); + + onlyInIvy('Prioritization works in Ivy only') + .it('should prioritize host bindings for templates first, then directives and finally components', + () => { + @Component({selector: 'my-comp-with-styling', template: ''}) + class MyCompWithStyling { + @HostBinding('style') + myStyles: any = {width: '300px'}; + + @HostBinding('style.height') + myHeight: any = '305px'; + } + + @Directive({selector: '[my-dir-with-styling]'}) + class MyDirWithStyling { + @HostBinding('style') + myStyles: any = {width: '200px'}; + + @HostBinding('style.height') + myHeight: any = '205px'; + } + + @Component({ + template: ` + + + ` + }) + class MyComp { + myStyles: {width?: string} = {width: '100px'}; + myHeight: string|null|undefined = '100px'; + + @ViewChild(MyDirWithStyling) dir !: MyDirWithStyling; + @ViewChild(MyCompWithStyling) comp !: MyCompWithStyling; + } + + TestBed.configureTestingModule( + {declarations: [MyComp, MyCompWithStyling, MyDirWithStyling]}); + const fixture = TestBed.createComponent(MyComp); + const comp = fixture.componentInstance; + const elm = fixture.nativeElement.querySelector('my-comp-with-styling') !; + + fixture.detectChanges(); + expect(elm.style.width).toEqual('100px'); + expect(elm.style.height).toEqual('100px'); + + comp.myStyles = {}; + comp.myHeight = undefined; + fixture.detectChanges(); + expect(elm.style.width).toEqual('2px'); + expect(elm.style.height).toEqual('1px'); + + comp.comp.myStyles = {}; + comp.comp.myHeight = undefined; + fixture.detectChanges(); + expect(elm.style.width).toEqual('2px'); + expect(elm.style.height).toEqual('1px'); + + comp.dir.myStyles = {}; + comp.dir.myHeight = undefined; + fixture.detectChanges(); + expect(elm.style.width).toEqual('2px'); + expect(elm.style.height).toEqual('1px'); + }); + + onlyInIvy('Prioritization works in Ivy only') + .it('should prioritize directive static bindings over components', () => { + @Component({selector: 'my-comp-with-styling', host: {style: 'color: blue'}, template: ''}) + class MyCompWithStyling { + } + + @Directive({selector: '[my-dir-with-styling]', host: {style: 'color: red'}}) + class MyDirWithStyling { + } + + @Component({template: ``}) + class MyComp { + } + + TestBed.configureTestingModule( + {declarations: [MyComp, MyCompWithStyling, MyDirWithStyling]}); + const fixture = TestBed.createComponent(MyComp); + const elm = fixture.nativeElement.querySelector('my-comp-with-styling') !; + + fixture.detectChanges(); + expect(elm.style.color).toEqual('red'); + }); + + + it('should combine host class.foo bindings from multiple directives', () => { + + @Directive({ + selector: '[dir-that-sets-one-two]', + exportAs: 'one', + }) + class DirThatSetsOneTwo { + @HostBinding('class.one') one = false; + @HostBinding('class.two') two = false; + } + + @Directive({ + selector: '[dir-that-sets-three-four]', + exportAs: 'two', + }) + class DirThatSetsThreeFour { + @HostBinding('class.three') three = false; + @HostBinding('class.four') four = false; + } + + @Component({ + template: ` +
+
+ ` + }) + class MyComp { + @ViewChild('div1', {static: true, read: DirThatSetsOneTwo}) + public dirOneA: DirThatSetsOneTwo|null = null; + + @ViewChild('div1', {static: true, read: DirThatSetsThreeFour}) + public dirTwoA: DirThatSetsThreeFour|null = null; + + @ViewChild('div2', {static: true, read: DirThatSetsOneTwo}) + public dirOneB: DirThatSetsOneTwo|null = null; + + @ViewChild('div2', {static: true, read: DirThatSetsThreeFour}) + public dirTwoB: DirThatSetsThreeFour|null = null; + + zero = false; + } + + TestBed.configureTestingModule( + {declarations: [MyComp, DirThatSetsThreeFour, DirThatSetsOneTwo]}); + + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + + const [div1, div2] = fixture.nativeElement.querySelectorAll('div') as HTMLDivElement[]; + + expect(div1.className).toBe(''); + expect(div2.className).toBe(''); + + const comp = fixture.componentInstance; + comp.dirOneA !.one = comp.dirOneB !.one = true; + comp.dirOneA !.two = comp.dirOneB !.two = true; + fixture.detectChanges(); + + expect(div1.classList.contains('one')).toBeTruthy(); + expect(div1.classList.contains('two')).toBeTruthy(); + expect(div1.classList.contains('three')).toBeFalsy(); + expect(div1.classList.contains('four')).toBeFalsy(); + expect(div2.classList.contains('one')).toBeTruthy(); + expect(div2.classList.contains('two')).toBeTruthy(); + expect(div2.classList.contains('three')).toBeFalsy(); + expect(div2.classList.contains('four')).toBeFalsy(); + expect(div2.classList.contains('zero')).toBeFalsy(); + + comp.dirTwoA !.three = comp.dirTwoB !.three = true; + comp.dirTwoA !.four = comp.dirTwoB !.four = true; + fixture.detectChanges(); + + expect(div1.classList.contains('one')).toBeTruthy(); + expect(div1.classList.contains('two')).toBeTruthy(); + expect(div1.classList.contains('three')).toBeTruthy(); + expect(div1.classList.contains('four')).toBeTruthy(); + expect(div2.classList.contains('one')).toBeTruthy(); + expect(div2.classList.contains('two')).toBeTruthy(); + expect(div2.classList.contains('three')).toBeTruthy(); + expect(div2.classList.contains('four')).toBeTruthy(); + expect(div2.classList.contains('zero')).toBeFalsy(); + + comp.zero = true; + fixture.detectChanges(); + + expect(div1.classList.contains('one')).toBeTruthy(); + expect(div1.classList.contains('two')).toBeTruthy(); + expect(div1.classList.contains('three')).toBeTruthy(); + expect(div1.classList.contains('four')).toBeTruthy(); + expect(div2.classList.contains('one')).toBeTruthy(); + expect(div2.classList.contains('two')).toBeTruthy(); + expect(div2.classList.contains('three')).toBeTruthy(); + expect(div2.classList.contains('four')).toBeTruthy(); + expect(div2.classList.contains('zero')).toBeTruthy(); + }); + + it('should combine static host classes with component "class" host attribute', () => { + @Component({selector: 'comp-with-classes', template: '', host: {'class': 'host'}}) + class CompWithClasses { + constructor(ref: ElementRef) { ref.nativeElement.classList.add('custom'); } + } + + @Component({ + template: `` + }) + class MyComp { + items = [1, 2, 3]; + } + + const fixture = TestBed + .configureTestingModule({ + declarations: [MyComp, CompWithClasses], + }) + .createComponent(MyComp); + fixture.detectChanges(); + + const [one, two, three] = + fixture.nativeElement.querySelectorAll('comp-with-classes') as HTMLDivElement[]; + + expect(one.classList.contains('custom')).toBeTruthy(); + expect(one.classList.contains('inline')).toBeTruthy(); + expect(one.classList.contains('host')).toBeTruthy(); + + expect(two.classList.contains('custom')).toBeTruthy(); + expect(two.classList.contains('inline')).toBeTruthy(); + expect(two.classList.contains('host')).toBeTruthy(); + + expect(three.classList.contains('custom')).toBeTruthy(); + expect(three.classList.contains('inline')).toBeTruthy(); + expect(three.classList.contains('host')).toBeTruthy(); + }); + + it('should allow a single style host binding on an element', () => { + @Component({template: `
`}) + class Cmp { + } + + @Directive({selector: '[single-host-style-dir]'}) + class SingleHostStyleDir { + @HostBinding('style.width') + width = '100px'; + } + + TestBed.configureTestingModule({declarations: [Cmp, SingleHostStyleDir]}); const fixture = TestBed.createComponent(Cmp); fixture.detectChanges(); - const leading = fixture.nativeElement.querySelector('[leading-space]'); - const trailing = fixture.nativeElement.querySelector('[trailing-space]'); - expect(leading.className).toBe('foo', 'Expected class to be applied despite leading space.'); - expect(trailing.className).toBe('foo', 'Expected class to be applied despite trailing space.'); + const element = fixture.nativeElement.querySelector('div'); + expect(element.style.width).toEqual('100px'); }); - // TODO(FW-1360): re-enable this test once the new styling changes are in place. - xit('should not set inputs called class if they are not being used in the template', () => { + it('should override class bindings when a directive extends another directive', () => { + @Component({template: ``}) + class Cmp { + } + + @Component({ + selector: 'parent-comp', + host: {'class': 'parent-comp', '[class.parent-comp-active]': 'true'}, + template: '...', + }) + class ParentComp { + } + + @Component({ + selector: 'child-comp', + host: { + 'class': 'child-comp', + '[class.child-comp-active]': 'true', + '[class.parent-comp]': 'false', + '[class.parent-comp-active]': 'false' + }, + template: '...', + }) + class ChildComp extends ParentComp { + } + + TestBed.configureTestingModule({declarations: [Cmp, ChildComp, ParentComp]}); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + + const element = fixture.nativeElement.querySelector('child-comp'); + expect(element.classList.contains('template')).toBeTruthy(); + + expect(element.classList.contains('child-comp')).toBeTruthy(); + expect(element.classList.contains('child-comp-active')).toBeTruthy(); + + expect(element.classList.contains('parent-comp')).toBeFalsy(); + expect(element.classList.contains('parent-comp-active')).toBeFalsy(); + }); + + it('should not set inputs called class if they are not being used in the template', () => { const logs: string[] = []; @Directive({selector: '[test]'}) @@ -2531,6 +3274,51 @@ describe('styling', () => { expect(logs).toEqual([]); }); + describe('regression', () => { + onlyInIvy('styling priority resolution is Ivy only feature.') + .it('should allow lookahead binding on second pass #35118', () => { + @Component({ + selector: 'my-cmp', + template: ``, + host: { + '[class.foo]': 'hostClass', + } + }) + class MyCmp { + hostClass = true; + } + + @Directive({ + selector: '[host-styling]', + host: { + '[class]': 'hostClass', + } + }) + class HostStylingsDir { + hostClass = {'bar': true}; + } + + @Component({template: ``}) + class MyApp { + // When the first view in the list gets CD-ed, everything works. + // When the second view gets CD-ed, the styling has already created the data structures + // in the `TView`. As a result when + // `[class.foo]` runs it already knows that `[class]` is a duplicate and hence it + // should check with it. While the resolution is happening it reads the value of the + // `[class]`, however `[class]` has not yet executed and therefore it does not have + // normalized value in its `LView`. The result is that the assertions fails as it + // expects an + // `KeyValueArray`. + } + + TestBed.configureTestingModule({declarations: [MyApp, MyCmp, HostStylingsDir]}); + const fixture = TestBed.createComponent(MyApp); + expect(() => fixture.detectChanges()).not.toThrow(); + const [cmp1, cmp2] = fixture.nativeElement.querySelectorAll('my-cmp'); + expectClass(cmp1).toEqual({foo: true, bar: true}); + expectClass(cmp2).toEqual({foo: true, bar: true}); + }); + }); }); function assertStyleCounters(countForSet: number, countForRemove: number) { @@ -2541,3 +3329,11 @@ function assertStyleCounters(countForSet: number, countForRemove: number) { function assertStyle(element: HTMLElement, prop: string, value: any) { expect((element.style as any)[prop]).toEqual(value); } + +function expectStyle(element: HTMLElement) { + return expect(getElementStyles(element)); +} + +function expectClass(element: HTMLElement) { + return expect(getElementClasses(element)); +} \ 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 4087eff1f4..d2034fb6a2 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -932,6 +932,53 @@ const DEFAULT_COMPONENT_ID = '1'; expect(fixture.debugElement.nativeElement.children.length).toBe(0); })); + it('should wait for child animations before removing parent', fakeAsync(() => { + @Component({ + template: '', + animations: [trigger( + 'parentTrigger', [transition(':leave', [group([query('@*', animateChild())])])])] + }) + class ParentCmp { + exp = true; + } + + @Component({ + selector: 'child-cmp', + template: '

Hello there

', + animations: [trigger( + 'childTrigger', + [transition( + ':leave', [style({opacity: 1}), animate('200ms', style({opacity: 0}))])])] + }) + class ChildCmp { + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toBe(0); + + fixture.componentInstance.exp = false; + fixture.detectChanges(); + expect(fixture.nativeElement.children.length).toBe(1); + + engine.flush(); + expect(getLog().length).toBe(1); + + const player = getLog()[0]; + expect(player.keyframes).toEqual([ + {opacity: '1', offset: 0}, + {opacity: '0', offset: 1}, + ]); + + player.finish(); + flushMicrotasks(); + expect(fixture.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', fakeAsync(() => { diff --git a/packages/core/test/application_module_spec.ts b/packages/core/test/application_module_spec.ts index ea97692f3f..2cb36d26b5 100644 --- a/packages/core/test/application_module_spec.ts +++ b/packages/core/test/application_module_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {LOCALE_ID} from '@angular/core'; +import {DEFAULT_CURRENCY_CODE, LOCALE_ID} from '@angular/core'; import {ivyEnabled} from '@angular/private/testing'; import {getLocaleId} from '../src/render3'; @@ -19,6 +19,11 @@ import {describe, expect, inject, it} from '../testing/src/testing_internal'; it('should set the default locale to "en-US"', inject([LOCALE_ID], (defaultLocale: string) => { expect(defaultLocale).toEqual('en-US'); })); + it('should set the default currency code to "USD"', + inject([DEFAULT_CURRENCY_CODE], (defaultCurrencyCode: string) => { + expect(defaultCurrencyCode).toEqual('USD'); + })); + if (ivyEnabled) { it('should set the ivy locale with the configured LOCALE_ID', () => { TestBed.configureTestingModule({providers: [{provide: LOCALE_ID, useValue: 'fr'}]}); diff --git a/packages/core/test/application_ref_spec.ts b/packages/core/test/application_ref_spec.ts index 54c4ae825d..8639cbe0db 100644 --- a/packages/core/test/application_ref_spec.ts +++ b/packages/core/test/application_ref_spec.ts @@ -346,11 +346,9 @@ class SomeComponent { it('should wait for APP_INITIALIZER to set providers for `LOCALE_ID`', async() => { let locale: string = ''; - const promise = Promise.resolve().then(() => { locale = 'fr-FR'; }); - const testModule = createModule({ providers: [ - {provide: APP_INITIALIZER, useValue: () => promise, multi: true}, + {provide: APP_INITIALIZER, useValue: () => locale = 'fr-FR', multi: true}, {provide: LOCALE_ID, useFactory: () => locale} ] }); diff --git a/packages/core/test/bundling/README.md b/packages/core/test/bundling/README.md new file mode 100644 index 0000000000..9eb215b81e --- /dev/null +++ b/packages/core/test/bundling/README.md @@ -0,0 +1,13 @@ +# Bundle + +## `js_expected_symbol_test` +This folder contains tests which assert that most of the code is tree shaken away. +This is asserted by keeping gold files of all symbols which are expected to be retained. +When doing renaming it is often necessary to update the gold files, to do so use these commands: + +``` +yarn bazel run --config=ivy //packages/core/test/bundling/cyclic_import:symbol_test.accept +yarn bazel run --config=ivy //packages/core/test/bundling/hello_world:symbol_test.accept +yarn bazel run --config=ivy //packages/core/test/bundling/injection:symbol_test.accept +yarn bazel run --config=ivy //packages/core/test/bundling/todo:symbol_test.accept +``` \ 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 index 98675d41e9..b2c2a743f7 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -113,9 +113,6 @@ { "name": "RENDERER_FACTORY" }, - { - "name": "RendererStyleFlags3" - }, { "name": "SANITIZER" }, @@ -156,7 +153,7 @@ "name": "addComponentLogic" }, { - "name": "addItemToStylingMap" + "name": "addHostBindingsToExpandoInstructions" }, { "name": "addToViewTree" @@ -164,9 +161,6 @@ { "name": "allocLFrame" }, - { - "name": "allocStylingMapArray" - }, { "name": "appendChild" }, @@ -189,7 +183,13 @@ "name": "callHooks" }, { - "name": "concatString" + "name": "classIndexOf" + }, + { + "name": "computeStaticStyling" + }, + { + "name": "concatStringsWithSpace" }, { "name": "createDirectivesInstances" @@ -254,9 +254,6 @@ { "name": "executeContentQueries" }, - { - "name": "executeElementExitFn" - }, { "name": "executeInitAndCheckHooks" }, @@ -276,10 +273,7 @@ "name": "findAttrIndexInNode" }, { - "name": "findDirectiveMatches" - }, - { - "name": "forceStylesAsString" + "name": "findDirectiveDefMatches" }, { "name": "generateExpandoInstructionBlock" @@ -329,9 +323,6 @@ { "name": "getFirstNativeNode" }, - { - "name": "getInitialStylingValue" - }, { "name": "getInjectorIndex" }, @@ -347,12 +338,6 @@ { "name": "getLViewParent" }, - { - "name": "getMapProp" - }, - { - "name": "getMapValue" - }, { "name": "getNameOnlyMarkerIndex" }, @@ -402,10 +387,10 @@ "name": "getSelectedIndex" }, { - "name": "getStylingMapArray" + "name": "getTView" }, { - "name": "hasActiveElementFlag" + "name": "growHostVarsSpace" }, { "name": "hasClassInput" @@ -419,23 +404,17 @@ { "name": "hasTagAndTypeMatch" }, - { - "name": "hyphenate" - }, { "name": "includeViewProviders" }, { "name": "increaseElementDepthCount" }, - { - "name": "incrementActiveDirectiveId" - }, { "name": "incrementInitPhaseFlags" }, { - "name": "initNodeFlags" + "name": "initTNodeFlags" }, { "name": "initializeInputAndOutputAliases" @@ -500,21 +479,12 @@ { "name": "isProceduralRenderer" }, - { - "name": "isStylingContext" - }, - { - "name": "isStylingValueDefined" - }, { "name": "leaveDI" }, { "name": "leaveView" }, - { - "name": "leaveViewProcessExit" - }, { "name": "locateHostElement" }, @@ -524,6 +494,12 @@ { "name": "matchTemplateAttribute" }, + { + "name": "mergeHostAttribute" + }, + { + "name": "mergeHostAttrs" + }, { "name": "nativeAppendChild" }, @@ -542,9 +518,6 @@ { "name": "noSideEffects" }, - { - "name": "objectToClassName" - }, { "name": "refreshChildComponents" }, @@ -563,9 +536,6 @@ { "name": "refreshView" }, - { - "name": "registerInitialStylingOnTNode" - }, { "name": "registerPostOrderHooks" }, @@ -581,15 +551,9 @@ { "name": "renderComponent" }, - { - "name": "renderInitialStyling" - }, { "name": "renderStringify" }, - { - "name": "renderStylingMap" - }, { "name": "renderView" }, @@ -605,38 +569,23 @@ { "name": "saveResolvedLocalsInData" }, - { - "name": "selectClassBasedInputName" - }, { "name": "selectIndexInternal" }, - { - "name": "setActiveHostElement" - }, { "name": "setBindingIndex" }, { - "name": "setBindingRoot" - }, - { - "name": "setClass" - }, - { - "name": "setClassName" - }, - { - "name": "setCurrentDirectiveDef" + "name": "setBindingRootForHostBindings" }, { "name": "setCurrentQueryIndex" }, { - "name": "setDirectiveStylingInput" + "name": "setDirectiveInputsWhichShadowsStyling" }, { - "name": "setHostBindings" + "name": "setHostBindingsByExecutingExpandoInstructions" }, { "name": "setIncludeViewProviders" @@ -653,30 +602,18 @@ { "name": "setIsNotParent" }, - { - "name": "setMapValue" - }, { "name": "setPreviousOrParentTNode" }, { "name": "setSelectedIndex" }, - { - "name": "setStyle" - }, - { - "name": "setStyleAttr" - }, { "name": "setUpAttributes" }, { "name": "stringifyForError" }, - { - "name": "stylingMapToString" - }, { "name": "syncViewWithBlueprint" }, @@ -686,14 +623,14 @@ { "name": "unwrapRNode" }, - { - "name": "updateRawValueOnContext" - }, { "name": "viewAttachedToChangeDetector" }, { - "name": "writeStylingValueDirectly" + "name": "writeDirectClass" + }, + { + "name": "writeDirectStyle" }, { "name": "ɵɵdefineComponent" 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 7bfaa2eccd..3198731638 100644 --- a/packages/core/test/bundling/hello_world/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hello_world/bundle.golden_symbols.json @@ -137,6 +137,9 @@ { "name": "_renderCompCount" }, + { + "name": "addHostBindingsToExpandoInstructions" + }, { "name": "addToViewTree" }, @@ -161,6 +164,12 @@ { "name": "callHooks" }, + { + "name": "computeStaticStyling" + }, + { + "name": "concatStringsWithSpace" + }, { "name": "createLFrame" }, @@ -209,9 +218,6 @@ { "name": "executeCheckHooks" }, - { - "name": "executeElementExitFn" - }, { "name": "executeInitAndCheckHooks" }, @@ -318,7 +324,10 @@ "name": "getSelectedIndex" }, { - "name": "hasActiveElementFlag" + "name": "getTView" + }, + { + "name": "growHostVarsSpace" }, { "name": "hasParentInjector" @@ -326,14 +335,11 @@ { "name": "includeViewProviders" }, - { - "name": "incrementActiveDirectiveId" - }, { "name": "incrementInitPhaseFlags" }, { - "name": "initNodeFlags" + "name": "initTNodeFlags" }, { "name": "insertBloom" @@ -350,6 +356,9 @@ { "name": "invokeHostBindingsInCreationMode" }, + { + "name": "isAnimationProp" + }, { "name": "isComponentDef" }, @@ -371,9 +380,6 @@ { "name": "leaveView" }, - { - "name": "leaveViewProcessExit" - }, { "name": "locateHostElement" }, @@ -440,23 +446,17 @@ { "name": "selectIndexInternal" }, - { - "name": "setActiveHostElement" - }, { "name": "setBindingIndex" }, { - "name": "setBindingRoot" - }, - { - "name": "setCurrentDirectiveDef" + "name": "setBindingRootForHostBindings" }, { "name": "setCurrentQueryIndex" }, { - "name": "setHostBindings" + "name": "setHostBindingsByExecutingExpandoInstructions" }, { "name": "setIncludeViewProviders" @@ -470,6 +470,9 @@ { "name": "setSelectedIndex" }, + { + "name": "setUpAttributes" + }, { "name": "stringifyForError" }, @@ -482,6 +485,12 @@ { "name": "viewAttachedToChangeDetector" }, + { + "name": "writeDirectClass" + }, + { + "name": "writeDirectStyle" + }, { "name": "ɵɵdefineComponent" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 316535c207..9b6679651a 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -2,9 +2,6 @@ { "name": "ACTIVE_INDEX" }, - { - "name": "BIT_MASK_START_VALUE" - }, { "name": "BLOOM_MASK" }, @@ -38,18 +35,6 @@ { "name": "DECLARATION_VIEW" }, - { - "name": "DEFAULT_BINDING_INDEX" - }, - { - "name": "DEFAULT_BINDING_VALUE" - }, - { - "name": "DEFAULT_GUARD_MASK_VALUE" - }, - { - "name": "DEFAULT_TOTAL_SOURCES" - }, { "name": "DOCUMENT" }, @@ -62,6 +47,9 @@ { "name": "EMPTY_ARRAY" }, + { + "name": "EMPTY_ARRAY" + }, { "name": "EMPTY_OBJ" }, @@ -89,9 +77,6 @@ { "name": "HOST" }, - { - "name": "INDEX_START_VALUE" - }, { "name": "INJECTOR" }, @@ -107,12 +92,6 @@ { "name": "IterableDiffers" }, - { - "name": "MAP_BASED_ENTRY_PROP_NAME" - }, - { - "name": "MAP_DIRTY_VALUE" - }, { "name": "MONKEY_PATCH_KEY_NAME" }, @@ -206,15 +185,9 @@ { "name": "RecordViewTuple" }, - { - "name": "RendererStyleFlags3" - }, { "name": "SANITIZER" }, - { - "name": "STYLING_INDEX_FOR_MAP_BINDING" - }, { "name": "SWITCH_ELEMENT_REF_FACTORY" }, @@ -230,9 +203,6 @@ { "name": "SkipSelf" }, - { - "name": "TEMPLATE_DIRECTIVE_INDEX" - }, { "name": "TNODE" }, @@ -318,7 +288,7 @@ "name": "__window" }, { - "name": "_activeStylingMapApplyFn" + "name": "_arrayIndexOfSorted" }, { "name": "_currentInjector" @@ -332,23 +302,14 @@ { "name": "_renderCompCount" }, - { - "name": "_state" - }, { "name": "_symbolIterator" }, - { - "name": "addBindingIntoContext" - }, { "name": "addComponentLogic" }, { - "name": "addItemToStylingMap" - }, - { - "name": "addNewSourceColumn" + "name": "addHostBindingsToExpandoInstructions" }, { "name": "addRemoveViewFromContainer" @@ -362,18 +323,6 @@ { "name": "allocLFrame" }, - { - "name": "allocStylingMapArray" - }, - { - "name": "allocTStylingContext" - }, - { - "name": "allocateNewContextEntry" - }, - { - "name": "allowDirectStyling" - }, { "name": "appendChild" }, @@ -387,13 +336,7 @@ "name": "applyProjectionRecursive" }, { - "name": "applyStylingValue" - }, - { - "name": "applyStylingValueDirectly" - }, - { - "name": "applyStylingViaContext" + "name": "applyStyling" }, { "name": "applyToElementOrContainer" @@ -401,6 +344,9 @@ { "name": "applyView" }, + { + "name": "arrayInsert2" + }, { "name": "assertTemplate" }, @@ -434,6 +380,12 @@ { "name": "checkNoChangesInternal" }, + { + "name": "checkStylingProperty" + }, + { + "name": "classIndexOf" + }, { "name": "cleanUpView" }, @@ -441,7 +393,19 @@ "name": "collectNativeNodes" }, { - "name": "concatString" + "name": "collectResidual" + }, + { + "name": "collectStylingFromDirectives" + }, + { + "name": "collectStylingFromTAttrs" + }, + { + "name": "computeStaticStyling" + }, + { + "name": "concatStringsWithSpace" }, { "name": "createContainerRef" @@ -542,9 +506,6 @@ { "name": "executeContentQueries" }, - { - "name": "executeElementExitFn" - }, { "name": "executeInitAndCheckHooks" }, @@ -569,27 +530,21 @@ { "name": "extractPipeDef" }, - { - "name": "findAndApplyMapValue" - }, { "name": "findAttrIndexInNode" }, { - "name": "findDirectiveMatches" + "name": "findDirectiveDefMatches" }, { "name": "findExistingListener" }, + { + "name": "findStylingValue" + }, { "name": "findViaComponent" }, - { - "name": "flushStyling" - }, - { - "name": "forceStylesAsString" - }, { "name": "forwardRef" }, @@ -602,27 +557,15 @@ { "name": "generatePropertyAliases" }, - { - "name": "getActiveDirectiveId" - }, { "name": "getBeforeNodeForView" }, - { - "name": "getBindingValue" - }, { "name": "getBindingsEnabled" }, { "name": "getCheckNoChangesMode" }, - { - "name": "getClassesContext" - }, - { - "name": "getCleanup" - }, { "name": "getClosureSafeProperty" }, @@ -642,10 +585,10 @@ "name": "getContainerRenderParent" }, { - "name": "getContext" + "name": "getContextLView" }, { - "name": "getContextLView" + "name": "getCurrentDirectiveIndex" }, { "name": "getCurrentStyleSanitizer" @@ -653,9 +596,6 @@ { "name": "getDebugContext" }, - { - "name": "getDefaultValue" - }, { "name": "getDirectiveDef" }, @@ -675,10 +615,7 @@ "name": "getFirstNativeNode" }, { - "name": "getGuardMask" - }, - { - "name": "getInitialStylingValue" + "name": "getHostDirectiveDef" }, { "name": "getInjectableDef" @@ -689,6 +626,9 @@ { "name": "getIsParent" }, + { + "name": "getLCleanup" + }, { "name": "getLContainer" }, @@ -698,12 +638,6 @@ { "name": "getLViewParent" }, - { - "name": "getMapProp" - }, - { - "name": "getMapValue" - }, { "name": "getNameOnlyMarkerIndex" }, @@ -767,47 +701,38 @@ { "name": "getPreviousOrParentTNode" }, - { - "name": "getProp" - }, - { - "name": "getPropConfig" - }, - { - "name": "getPropValuesStartPosition" - }, { "name": "getRenderParent" }, - { - "name": "getRenderer" - }, { "name": "getSelectedIndex" }, - { - "name": "getStylesContext" - }, - { - "name": "getStylingMapArray" - }, - { - "name": "getStylingMapsSyncFn" - }, - { - "name": "getStylingState" - }, { "name": "getSymbolIterator" }, { "name": "getTNode" }, + { + "name": "getTStylingRangeNext" + }, + { + "name": "getTStylingRangeNextDuplicate" + }, + { + "name": "getTStylingRangePrev" + }, + { + "name": "getTStylingRangePrevDuplicate" + }, + { + "name": "getTView" + }, { "name": "getTViewCleanup" }, { - "name": "getTotalSources" + "name": "getTemplateHeadTStylingKey" }, { "name": "getTypeName" @@ -816,38 +741,26 @@ "name": "getTypeNameForDebugging" }, { - "name": "getValue" - }, - { - "name": "getValuesCount" + "name": "growHostVarsSpace" }, { "name": "handleError" }, - { - "name": "hasActiveElementFlag" - }, { "name": "hasClassInput" }, - { - "name": "hasConfig" - }, { "name": "hasParentInjector" }, { "name": "hasStyleInput" }, + { + "name": "hasStylingInputShadow" + }, { "name": "hasTagAndTypeMatch" }, - { - "name": "hasValueChanged" - }, - { - "name": "hyphenate" - }, { "name": "includeViewProviders" }, @@ -855,13 +768,13 @@ "name": "increaseElementDepthCount" }, { - "name": "incrementActiveDirectiveId" + "name": "incrementBindingIndex" }, { "name": "incrementInitPhaseFlags" }, { - "name": "initNodeFlags" + "name": "initTNodeFlags" }, { "name": "initializeInputAndOutputAliases" @@ -884,6 +797,9 @@ { "name": "insertBloom" }, + { + "name": "insertTStylingBinding" + }, { "name": "insertView" }, @@ -939,10 +855,7 @@ "name": "isForwardRef" }, { - "name": "isHostStyling" - }, - { - "name": "isHostStylingActive" + "name": "isInHostBindings" }, { "name": "isJsObject" @@ -975,26 +888,29 @@ "name": "isRootView" }, { - "name": "isSanitizationRequired" + "name": "isStylingMatch" }, { - "name": "isStylingContext" - }, - { - "name": "isStylingValueDefined" + "name": "isStylingValuePresent" }, { "name": "iterateListLike" }, + { + "name": "keyValueArrayGet" + }, + { + "name": "keyValueArrayIndexOf" + }, + { + "name": "keyValueArraySet" + }, { "name": "leaveDI" }, { "name": "leaveView" }, - { - "name": "leaveViewProcessExit" - }, { "name": "listenerInternal" }, @@ -1028,12 +944,24 @@ { "name": "markDirtyIfOnPush" }, + { + "name": "markDuplicateOfResidualStyling" + }, + { + "name": "markDuplicates" + }, { "name": "markViewDirty" }, { "name": "matchTemplateAttribute" }, + { + "name": "mergeHostAttribute" + }, + { + "name": "mergeHostAttrs" + }, { "name": "nativeAppendChild" }, @@ -1068,16 +996,7 @@ "name": "noSideEffects" }, { - "name": "normalizeBitMaskValue" - }, - { - "name": "objectToClassName" - }, - { - "name": "patchConfig" - }, - { - "name": "patchHostStylingFlag" + "name": "normalizeAndApplySuffixOrSanitizer" }, { "name": "readPatchedData" @@ -1103,12 +1022,6 @@ { "name": "refreshView" }, - { - "name": "registerBinding" - }, - { - "name": "registerInitialStylingOnTNode" - }, { "name": "registerPostOrderHooks" }, @@ -1139,30 +1052,15 @@ { "name": "renderDetachView" }, - { - "name": "renderHostBindingsAsStale" - }, - { - "name": "renderInitialStyling" - }, { "name": "renderStringify" }, - { - "name": "renderStylingMap" - }, { "name": "renderView" }, - { - "name": "resetCurrentStyleSanitizer" - }, { "name": "resetPreOrderHookFlags" }, - { - "name": "resetStylingState" - }, { "name": "resolveDirectives" }, @@ -1181,56 +1079,26 @@ { "name": "searchTokensOnInjector" }, - { - "name": "selectClassBasedInputName" - }, { "name": "selectIndexInternal" }, - { - "name": "setActiveElementFlag" - }, - { - "name": "setActiveHostElement" - }, { "name": "setBindingIndex" }, { - "name": "setBindingRoot" + "name": "setBindingRootForHostBindings" }, { "name": "setCheckNoChangesMode" }, - { - "name": "setClass" - }, - { - "name": "setClassName" - }, - { - "name": "setCurrentDirectiveDef" - }, { "name": "setCurrentQueryIndex" }, { - "name": "setCurrentStyleSanitizer" + "name": "setDirectiveInputsWhichShadowsStyling" }, { - "name": "setDefaultValue" - }, - { - "name": "setDirectiveStylingInput" - }, - { - "name": "setElementExitFn" - }, - { - "name": "setGuardMask" - }, - { - "name": "setHostBindings" + "name": "setHostBindingsByExecutingExpandoInstructions" }, { "name": "setIncludeViewProviders" @@ -1250,12 +1118,6 @@ { "name": "setLContainerActiveIndex" }, - { - "name": "setMapAsDirty" - }, - { - "name": "setMapValue" - }, { "name": "setPreviousOrParentTNode" }, @@ -1263,17 +1125,23 @@ "name": "setSelectedIndex" }, { - "name": "setStyle" + "name": "setTStylingRangeNext" }, { - "name": "setStyleAttr" + "name": "setTStylingRangeNextDuplicate" + }, + { + "name": "setTStylingRangePrev" + }, + { + "name": "setTStylingRangePrevDuplicate" + }, + { + "name": "setTemplateHeadTStylingKey" }, { "name": "setUpAttributes" }, - { - "name": "setValue" - }, { "name": "shouldSearchParent" }, @@ -1287,16 +1155,7 @@ "name": "stringifyForError" }, { - "name": "stylingApply" - }, - { - "name": "stylingMapToString" - }, - { - "name": "stylingProp" - }, - { - "name": "syncContextInitialStyling" + "name": "stylingFirstUpdatePass" }, { "name": "syncViewWithBlueprint" @@ -1313,6 +1172,9 @@ { "name": "tickRootContext" }, + { + "name": "toTStylingRange" + }, { "name": "trackByIdentity" }, @@ -1326,19 +1188,7 @@ "name": "unwrapSafeValue" }, { - "name": "updateBindingData" - }, - { - "name": "updateClassViaContext" - }, - { - "name": "updateInitialStylingOnContext" - }, - { - "name": "updateRawValueOnContext" - }, - { - "name": "updateStyleViaContext" + "name": "updateStyling" }, { "name": "viewAttachedToChangeDetector" @@ -1349,11 +1199,17 @@ { "name": "walkUpViews" }, + { + "name": "wrapInStaticStylingKey" + }, { "name": "wrapListener" }, { - "name": "writeStylingValueDirectly" + "name": "writeDirectClass" + }, + { + "name": "writeDirectStyle" }, { "name": "ɵɵadvance" diff --git a/packages/core/test/debug/debug_node_spec.ts b/packages/core/test/debug/debug_node_spec.ts index f86394c741..255a8057dd 100644 --- a/packages/core/test/debug/debug_node_spec.ts +++ b/packages/core/test/debug/debug_node_spec.ts @@ -12,7 +12,7 @@ import {Component, DebugElement, DebugNode, Directive, ElementRef, EmbeddedViewR import {NgZone} from '@angular/core/src/zone'; import {ComponentFixture, TestBed, async} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; -import {hasClass} from '@angular/platform-browser/testing/src/browser_util'; +import {createMouseEvent, hasClass} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; @@ -368,6 +368,22 @@ class TestCmptWithPropInterpolation { .toBeFalsy('Expected bound host CSS class "absent-class" to be absent'); }); + it('should list classes on SVG nodes', () => { + // Class bindings on SVG elements require a polyfill + // on IE which we don't include when running tests. + if (typeof SVGElement !== 'undefined' && !('classList' in SVGElement.prototype)) { + return; + } + + TestBed.overrideTemplate(TestApp, ``); + fixture = TestBed.createComponent(TestApp); + fixture.detectChanges(); + const classes = fixture.debugElement.children[0].classes; + + expect(classes['foo']).toBe(true); + expect(classes['bar']).toBe(true); + }); + it('should list element styles', () => { fixture = TestBed.createComponent(TestApp); fixture.detectChanges(); @@ -577,38 +593,51 @@ class TestCmptWithPropInterpolation { expect(fixture.debugElement.query(By.css('.myclass'))).toBeTruthy(); }); - it('DebugElement.query should work with dynamically created descendant elements', () => { - @Directive({ - selector: '[dir]', - }) - class MyDir { - @Input('dir') dir: number|undefined; + describe('DebugElement.query with dynamically created descendant elements', () => { + let fixture: ComponentFixture<{}>; + beforeEach(() => { - constructor(renderer: Renderer2, element: ElementRef) { - const outerDiv = renderer.createElement('div'); - const innerDiv = renderer.createElement('div'); - const div = renderer.createElement('div'); + @Directive({ + selector: '[dir]', + }) + class MyDir { + @Input('dir') dir: number|undefined; - div.classList.add('myclass'); + constructor(renderer: Renderer2, element: ElementRef) { + const outerDiv = renderer.createElement('div'); + const innerDiv = renderer.createElement('div'); + innerDiv.classList.add('inner'); + const div = renderer.createElement('div'); - renderer.appendChild(innerDiv, div); - renderer.appendChild(outerDiv, innerDiv); - renderer.appendChild(element.nativeElement, outerDiv); + div.classList.add('myclass'); + + renderer.appendChild(innerDiv, div); + renderer.appendChild(outerDiv, innerDiv); + renderer.appendChild(element.nativeElement, outerDiv); + } } - } - @Component({ - selector: 'app-test', - template: '
', - }) - class MyComponent { - } + @Component({ + selector: 'app-test', + template: '
', + }) + class MyComponent { + } - TestBed.configureTestingModule({declarations: [MyComponent, MyDir]}); - const fixture = TestBed.createComponent(MyComponent); - fixture.detectChanges(); + TestBed.configureTestingModule({declarations: [MyComponent, MyDir]}); + fixture = TestBed.createComponent(MyComponent); + fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('.myclass'))).toBeTruthy(); + }); + + it('should find the dynamic elements from fixture root', + () => { expect(fixture.debugElement.query(By.css('.myclass'))).toBeTruthy(); }); + + it('can use a dynamic element as root for another query', () => { + const inner = fixture.debugElement.query(By.css('.inner')); + expect(inner).toBeTruthy(); + expect(inner.query(By.css('.myclass'))).toBeTruthy(); + }); }); describe('DebugElement.query doesn\'t fail on elements outside Angular context', () => { @@ -617,7 +646,9 @@ class TestCmptWithPropInterpolation { constructor(private elementRef: ElementRef) {} ngAfterViewInit() { - this.elementRef.nativeElement.children[0].appendChild(document.createElement('p')); + const ul = document.createElement('ul'); + ul.appendChild(document.createElement('li')); + this.elementRef.nativeElement.children[0].appendChild(ul); } } @@ -664,6 +695,13 @@ class TestCmptWithPropInterpolation { it('when searching by injector', () => { expect(() => el.query(e => e.injector === null)).not.toThrow(); }); + + onlyInIvy('VE does not match elements created outside Angular context') + .it('when using the out-of-context element as the DebugElement query root', () => { + const debugElOutsideAngularContext = el.query(By.css('ul')); + expect(debugElOutsideAngularContext.queryAll(By.css('li')).length).toBe(1); + expect(debugElOutsideAngularContext.query(By.css('li'))).toBeDefined(); + }); }); it('DebugElement.queryAll should pick up both elements inserted via the view and through Renderer2', @@ -1215,4 +1253,23 @@ class TestCmptWithPropInterpolation { expect(fixture.debugElement.query(e => e.name === 'myComponent')).toBeTruthy(); expect(fixture.debugElement.query(e => e.name === 'div')).toBeTruthy(); }); + + it('does not call event listeners added outside angular context', () => { + let listenerCalled = false; + const eventToTrigger = createMouseEvent('mouseenter'); + function listener() { listenerCalled = true; } + @Component({template: ''}) + class MyComp { + constructor(private readonly zone: NgZone, private readonly element: ElementRef) {} + ngOnInit() { + this.zone.runOutsideAngular( + () => { this.element.nativeElement.addEventListener('mouseenter', listener); }); + } + } + const fixture = + TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); + fixture.detectChanges(); + fixture.debugElement.triggerEventHandler('mouseenter', eventToTrigger); + expect(listenerCalled).toBe(false); + }); } diff --git a/packages/core/test/i18n/locale_data_api_spec.ts b/packages/core/test/i18n/locale_data_api_spec.ts index 9121e3b2cb..3c995a61d3 100644 --- a/packages/core/test/i18n/locale_data_api_spec.ts +++ b/packages/core/test/i18n/locale_data_api_spec.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 {findLocaleData, registerLocaleData, unregisterAllLocaleData} from '../../src/i18n/locale_data_api'; +import {LocaleDataIndex, findLocaleData, getLocaleCurrencyCode, registerLocaleData, unregisterAllLocaleData} from '../../src/i18n/locale_data_api'; import {global} from '../../src/util/global'; { @@ -15,6 +15,7 @@ import {global} from '../../src/util/global'; const localeDeCH: any[] = ['de-CH']; const localeEn: any[] = ['en']; const localeFr: any[] = ['fr']; + localeFr[LocaleDataIndex.CurrencyCode] = 'EUR'; const localeFrCA: any[] = ['fr-CA']; const localeZh: any[] = ['zh']; const localeEnAU: any[] = ['en-AU']; @@ -81,5 +82,13 @@ import {global} from '../../src/util/global'; it('should find the registered LOCALE_DATA even if the same locale is on the global object', () => { expect(findLocaleData('fr')).not.toBe(fakeGlobalFr); }); }); + + describe('getLocaleCurrencyCode()', () => { + it('should return `null` if the given locale does not provide a currency code', + () => { expect(getLocaleCurrencyCode('de')).toBe(null); }); + + it('should return the code at the `LocaleDataIndex.CurrencyCode` of the given locale`s data', + () => { expect(getLocaleCurrencyCode('fr')).toEqual('EUR'); }); + }); }); } diff --git a/packages/core/test/render3/BUILD.bazel b/packages/core/test/render3/BUILD.bazel index 6323d85252..4886dc17ac 100644 --- a/packages/core/test/render3/BUILD.bazel +++ b/packages/core/test/render3/BUILD.bazel @@ -61,9 +61,7 @@ ts_library( jasmine_node_test( name = "render3", - bootstrap = [ - "angular/packages/core/test/render3/load_domino", - ], + bootstrap = [":domino_es5"], deps = [ ":render3_node_lib", "//packages/zone.js/lib", diff --git a/packages/core/test/render3/component_ref_spec.ts b/packages/core/test/render3/component_ref_spec.ts index 9380dbe432..6d5b4375ab 100644 --- a/packages/core/test/render3/component_ref_spec.ts +++ b/packages/core/test/render3/component_ref_spec.ts @@ -8,10 +8,10 @@ import {Injector, NgModuleRef, ViewEncapsulation} from '../../src/core'; import {ComponentFactory} from '../../src/linker/component_factory'; -import {RendererFactory2} from '../../src/render/api'; +import {RendererFactory2, RendererType2} from '../../src/render/api'; import {injectComponentFactoryResolver} from '../../src/render3/component_ref'; -import {ɵɵdefineComponent} from '../../src/render3/index'; -import {domRendererFactory3} from '../../src/render3/interfaces/renderer'; +import {AttributeMarker, ɵɵdefineComponent} from '../../src/render3/index'; +import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; import {Sanitizer} from '../../src/sanitization/sanitizer'; describe('ComponentFactory', () => { @@ -23,7 +23,7 @@ describe('ComponentFactory', () => { static ɵfac = () => new TestComponent(); static ɵcmp = ɵɵdefineComponent({ type: TestComponent, - selectors: [['test', 'foo'], ['bar']], + selectors: [['test', 'foo', ''], ['bar']], decls: 0, vars: 0, template: () => undefined, @@ -32,7 +32,7 @@ describe('ComponentFactory', () => { const cf = cfr.resolveComponentFactory(TestComponent); - expect(cf.selector).toBe('test'); + expect(cf.selector).toBe('test[foo],bar'); expect(cf.componentType).toBe(TestComponent); expect(cf.ngContentSelectors).toEqual([]); expect(cf.inputs).toEqual([]); @@ -45,7 +45,7 @@ describe('ComponentFactory', () => { static ɵcmp = ɵɵdefineComponent({ type: TestComponent, encapsulation: ViewEncapsulation.None, - selectors: [['test', 'foo'], ['bar']], + selectors: [['test', 'foo', ''], ['bar']], decls: 0, vars: 0, template: () => undefined, @@ -65,7 +65,7 @@ describe('ComponentFactory', () => { expect(cf.componentType).toBe(TestComponent); expect(cf.ngContentSelectors).toEqual(['*', 'a', 'b']); - expect(cf.selector).toBe('test'); + expect(cf.selector).toBe('test[foo],bar'); expect(cf.inputs).toEqual([ {propName: 'in1', templateName: 'in1'}, @@ -97,6 +97,7 @@ describe('ComponentFactory', () => { decls: 0, vars: 0, template: () => undefined, + hostAttrs: [AttributeMarker.Classes, 'HOST_COMPONENT'] }); } @@ -291,5 +292,24 @@ describe('ComponentFactory', () => { expect(mSanitizerFactorySpy).toHaveBeenCalled(); }); }); + + it('should ensure that rendererFactory is called after initial styling is set', () => { + const myRendererFactory: RendererFactory3 = { + createRenderer: function(hostElement: RElement|null, rendererType: RendererType2|null): + Renderer3 { + if (hostElement) { + hostElement.classList.add('HOST_RENDERER'); + } + return document; + } + }; + const injector = Injector.create([ + {provide: RendererFactory2, useValue: myRendererFactory}, + ]); + + const hostNode = document.createElement('div'); + const componentRef = cf.create(injector, undefined, hostNode); + expect(hostNode.className).toEqual('HOST_COMPONENT HOST_RENDERER'); + }); }); }); diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index 894feb8eb9..1bcd79c5a1 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -17,7 +17,7 @@ import {TNODE} from '../../src/render3/interfaces/injector'; import {TNodeType} from '../../src/render3/interfaces/node'; import {isProceduralRenderer} from '../../src/render3/interfaces/renderer'; import {LViewFlags, TVIEW, TViewType} from '../../src/render3/interfaces/view'; -import {enterView, leaveViewProcessExit} from '../../src/render3/state'; +import {enterView, leaveView} from '../../src/render3/state'; import {getRendererFactory2} from './imported_renderer2'; import {ComponentFixture, createComponent, createDirective} from './render_util'; @@ -237,7 +237,7 @@ describe('di', () => { const injector = getOrCreateNodeInjectorForNode(parentTNode, contentView); expect(injector).not.toEqual(-1); } finally { - leaveViewProcessExit(); + leaveView(); } }); }); diff --git a/packages/core/test/render3/global_utils_spec.ts b/packages/core/test/render3/global_utils_spec.ts index ff7bb39ffe..a0923bb02f 100644 --- a/packages/core/test/render3/global_utils_spec.ts +++ b/packages/core/test/render3/global_utils_spec.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 {ɵmarkDirty as markDirty} from '@angular/core'; -import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getRootComponents, getViewComponent} from '../../src/render3/util/discovery_utils'; +import {applyChanges} from '../../src/render3/util/change_detection_utils'; +import {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getOwningComponent, getRootComponents} from '../../src/render3/util/discovery_utils'; import {GLOBAL_PUBLISH_EXPANDO_KEY, GlobalDevModeContainer, publishDefaultGlobalUtils, publishGlobalUtil} from '../../src/render3/util/global_utils'; import {global} from '../../src/util/global'; @@ -31,8 +31,8 @@ describe('global utils', () => { it('should publish getListeners', () => { assertPublished('getListeners', getListeners); }); - it('should publish getViewComponent', - () => { assertPublished('getViewComponent', getViewComponent); }); + it('should publish getOwningComponent', + () => { assertPublished('getOwningComponent', getOwningComponent); }); it('should publish getRootComponents', () => { assertPublished('getRootComponents', getRootComponents); }); @@ -44,7 +44,7 @@ describe('global utils', () => { it('should publish getInjector', () => { assertPublished('getInjector', getInjector); }); - it('should publish markDirty', () => { assertPublished('markDirty', markDirty); }); + it('should publish applyChanges', () => { assertPublished('applyChanges', applyChanges); }); }); }); diff --git a/packages/core/test/render3/instructions/lview_debug_spec.ts b/packages/core/test/render3/instructions/lview_debug_spec.ts new file mode 100644 index 0000000000..28d51c3002 --- /dev/null +++ b/packages/core/test/render3/instructions/lview_debug_spec.ts @@ -0,0 +1,154 @@ +/** + * @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 {TNodeDebug} from '@angular/core/src/render3/instructions/lview_debug'; +import {createTNode, createTView} from '@angular/core/src/render3/instructions/shared'; +import {TNodeType} from '@angular/core/src/render3/interfaces/node'; +import {LView, TView, TViewType} from '@angular/core/src/render3/interfaces/view'; +import {enterView, leaveView} from '@angular/core/src/render3/state'; +import {insertTStylingBinding} from '@angular/core/src/render3/styling/style_binding_list'; +import {KeyValueArray} from '@angular/core/src/util/array_utils'; + + +describe('lView_debug', () => { + const mockFirstUpdatePassLView: LView = [null, {firstUpdatePass: true}] as any; + beforeEach(() => enterView(mockFirstUpdatePassLView, null)); + afterEach(() => leaveView()); + + describe('TNode', () => { + let tNode !: TNodeDebug; + let tView !: TView; + beforeEach(() => { + tView = createTView(TViewType.Component, 0, null, 0, 0, null, null, null, null, null); + tNode = createTNode(tView, null !, TNodeType.Element, 0, '', null) as TNodeDebug; + }); + afterEach(() => tNode = tView = null !); + + describe('styling', () => { + it('should decode no styling', () => { + expect(tNode.styleBindings_).toEqual([null]); + expect(tNode.classBindings_).toEqual([null]); + }); + + it('should decode static styling', () => { + tNode.residualStyles = ['color', 'blue'] as KeyValueArray; + tNode.residualClasses = ['STATIC', true] as KeyValueArray; + expect(tNode.styleBindings_).toEqual([['color', 'blue'] as KeyValueArray]); + expect(tNode.classBindings_).toEqual([['STATIC', true] as KeyValueArray]); + }); + + it('should decode no-template property binding', () => { + tNode.residualClasses = ['STATIC', true] as KeyValueArray; + insertTStylingBinding(tView.data, tNode, 'CLASS', 2, true, true); + insertTStylingBinding(tView.data, tNode, 'color', 4, true, false); + + expect(tNode.styleBindings_).toEqual([ + { + index: 4, + key: 'color', + isTemplate: false, + prevDuplicate: false, + nextDuplicate: false, + prevIndex: 0, + nextIndex: 0, + }, + null + ]); + expect(tNode.classBindings_).toEqual([ + { + index: 2, + key: 'CLASS', + isTemplate: false, + prevDuplicate: false, + nextDuplicate: false, + prevIndex: 0, + nextIndex: 0, + }, + ['STATIC', true] as KeyValueArray + ]); + }); + + it('should decode template and directive property binding', () => { + tNode.residualClasses = ['STATIC', true] as KeyValueArray; + insertTStylingBinding(tView.data, tNode, 'CLASS', 2, false, true); + insertTStylingBinding(tView.data, tNode, 'color', 4, false, false); + + expect(tNode.styleBindings_).toEqual([ + { + index: 4, + key: 'color', + isTemplate: true, + prevDuplicate: false, + nextDuplicate: false, + prevIndex: 0, + nextIndex: 0, + }, + null + ]); + expect(tNode.classBindings_).toEqual([ + { + index: 2, + key: 'CLASS', + isTemplate: true, + prevDuplicate: false, + nextDuplicate: false, + prevIndex: 0, + nextIndex: 0, + }, + ['STATIC', true] as KeyValueArray + ]); + + insertTStylingBinding(tView.data, tNode, null, 6, true, true); + insertTStylingBinding(tView.data, tNode, null, 8, true, false); + + expect(tNode.styleBindings_).toEqual([ + { + index: 8, + key: null, + isTemplate: false, + prevDuplicate: false, + nextDuplicate: true, + prevIndex: 0, + nextIndex: 4, + }, + { + index: 4, + key: 'color', + isTemplate: true, + prevDuplicate: true, + nextDuplicate: false, + prevIndex: 8, + nextIndex: 0, + }, + null + ]); + expect(tNode.classBindings_).toEqual([ + { + index: 6, + key: null, + isTemplate: false, + prevDuplicate: false, + nextDuplicate: true, + prevIndex: 0, + nextIndex: 2, + }, + { + index: 2, + key: 'CLASS', + isTemplate: true, + prevDuplicate: true, + nextDuplicate: false, + prevIndex: 6, + nextIndex: 0, + }, + ['STATIC', true] as KeyValueArray + ]); + }); + }); + }); +}); \ No newline at end of file diff --git a/packages/core/test/render3/instructions/shared_spec.ts b/packages/core/test/render3/instructions/shared_spec.ts new file mode 100644 index 0000000000..1649d8dfe8 --- /dev/null +++ b/packages/core/test/render3/instructions/shared_spec.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 {createLView, createTNode, createTView} from '@angular/core/src/render3/instructions/shared'; +import {TNodeType} from '@angular/core/src/render3/interfaces/node'; +import {domRendererFactory3} from '@angular/core/src/render3/interfaces/renderer'; +import {HEADER_OFFSET, LViewFlags, TVIEW, TViewType} from '@angular/core/src/render3/interfaces/view'; +import {enterView, getBindingRoot, getLView, setBindingIndex} from '@angular/core/src/render3/state'; + + + +/** + * Setups a simple `LView` so that it is possible to do unit tests on instructions. + * + * ``` + * describe('styling', () => { + * beforeEach(enterViewWithOneDiv); + * afterEach(leaveView); + * + * it('should ...', () => { + * expect(getLView()).toBeDefined(); + * const div = getNativeByIndex(1, getLView()); + * }); + * }); + * ``` + */ +export function enterViewWithOneDiv() { + const renderer = domRendererFactory3.createRenderer(null, null); + const div = renderer.createElement('div'); + const consts = 1; + const vars = 60; // Space for directive expando, template, component + 3 directives if we assume + // that each consume 10 slots. + const tView = createTView( + TViewType.Component, -1, emptyTemplate, consts, vars, null, null, null, null, null); + // Just assume that the expando starts after 10 initial bindings. + tView.expandoStartIndex = HEADER_OFFSET + 10; + const tNode = tView.firstChild = createTNode(tView, null !, TNodeType.Element, 0, 'div', null); + const lView = createLView( + null, tView, null, LViewFlags.CheckAlways, null, null, domRendererFactory3, renderer, null, + null); + lView[0 + HEADER_OFFSET] = div; + tView.data[0 + HEADER_OFFSET] = tNode; + enterView(lView, tNode); +} + +export function clearFirstUpdatePass() { + getLView()[TVIEW].firstUpdatePass = false; +} +export function rewindBindingIndex() { + setBindingIndex(getBindingRoot()); +} + +function emptyTemplate() {} \ No newline at end of file diff --git a/packages/core/test/render3/instructions/styling_spec.ts b/packages/core/test/render3/instructions/styling_spec.ts new file mode 100644 index 0000000000..bc71737c69 --- /dev/null +++ b/packages/core/test/render3/instructions/styling_spec.ts @@ -0,0 +1,595 @@ +/** + * @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 {DirectiveDef} from '@angular/core/src/render3'; +import {ɵɵdefineDirective} from '@angular/core/src/render3/definition'; +import {classStringParser, styleStringParser, toStylingKeyValueArray, ɵɵclassProp, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyleSanitizer} from '@angular/core/src/render3/instructions/styling'; +import {AttributeMarker, TAttributes} from '@angular/core/src/render3/interfaces/node'; +import {StylingRange, TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, setTStylingRangeNext, setTStylingRangePrev, toTStylingRange} from '@angular/core/src/render3/interfaces/styling'; +import {HEADER_OFFSET, TVIEW} from '@angular/core/src/render3/interfaces/view'; +import {getLView, leaveView, setBindingRootForHostBindings} from '@angular/core/src/render3/state'; +import {getNativeByIndex} from '@angular/core/src/render3/util/view_utils'; +import {bypassSanitizationTrustStyle} from '@angular/core/src/sanitization/bypass'; +import {ɵɵsanitizeStyle} from '@angular/core/src/sanitization/sanitization'; +import {keyValueArraySet} from '@angular/core/src/util/array_utils'; +import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode'; +import {getElementClasses, getElementStyles} from '@angular/core/testing/src/styling'; +import {expect} from '@angular/core/testing/src/testing_internal'; + +import {clearFirstUpdatePass, enterViewWithOneDiv, rewindBindingIndex} from './shared_spec'; + +describe('styling', () => { + beforeEach(enterViewWithOneDiv); + afterEach(leaveView); + + let div !: HTMLElement; + beforeEach(() => div = getNativeByIndex(0, getLView()) as HTMLElement); + + it('should do set basic style', () => { + ɵɵstyleProp('color', 'red'); + expectStyle(div).toEqual({color: 'red'}); + }); + + it('should search across multiple instructions backwards', () => { + ɵɵstyleProp('color', 'red'); + ɵɵstyleProp('color', undefined); + ɵɵstyleProp('color', 'blue'); + expectStyle(div).toEqual({color: 'blue'}); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleProp('color', 'red'); + ɵɵstyleProp('color', undefined); + ɵɵstyleProp('color', undefined); + expectStyle(div).toEqual({color: 'red'}); + }); + + it('should search across multiple instructions forwards', () => { + ɵɵstyleProp('color', 'red'); + ɵɵstyleProp('color', 'green'); + ɵɵstyleProp('color', 'blue'); + expectStyle(div).toEqual({color: 'blue'}); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleProp('color', 'white'); + expectStyle(div).toEqual({color: 'blue'}); + }); + + it('should set style based on priority', () => { + ɵɵstyleProp('color', 'red'); + ɵɵstyleProp('color', 'blue'); // Higher priority, should win. + expectStyle(div).toEqual({color: 'blue'}); + // The intermediate value has to set since it does not know if it is last one. + expect(ngDevMode !.rendererSetStyle).toEqual(2); + ngDevModeResetPerfCounters(); + + clearFirstUpdatePass(); + rewindBindingIndex(); + ɵɵstyleProp('color', 'red'); // no change + ɵɵstyleProp('color', 'green'); // change to green + expectStyle(div).toEqual({color: 'green'}); + expect(ngDevMode !.rendererSetStyle).toEqual(1); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵstyleProp('color', 'black'); // First binding update + expectStyle(div).toEqual({color: 'green'}); // Green still has priority. + expect(ngDevMode !.rendererSetStyle).toEqual(0); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵstyleProp('color', 'black'); // no change + ɵɵstyleProp('color', undefined); // Clear second binding + expectStyle(div).toEqual({color: 'black'}); // default to first binding + expect(ngDevMode !.rendererSetStyle).toEqual(1); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵstyleProp('color', null); + expectStyle(div).toEqual({}); // default to first binding + expect(ngDevMode !.rendererSetStyle).toEqual(0); + expect(ngDevMode !.rendererRemoveStyle).toEqual(1); + }); + + it('should set class based on priority', () => { + ɵɵclassProp('foo', false); + ɵɵclassProp('foo', true); // Higher priority, should win. + expectClass(div).toEqual({foo: true}); + expect(ngDevMode !.rendererAddClass).toEqual(1); + ngDevModeResetPerfCounters(); + + clearFirstUpdatePass(); + rewindBindingIndex(); + ɵɵclassProp('foo', false); // no change + ɵɵclassProp('foo', undefined); // change (have no opinion) + expectClass(div).toEqual({}); + expect(ngDevMode !.rendererAddClass).toEqual(0); + expect(ngDevMode !.rendererRemoveClass).toEqual(1); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵclassProp('foo', false); // no change + ɵɵclassProp('foo', 'truthy' as any); + expectClass(div).toEqual({foo: true}); + + rewindBindingIndex(); + ɵɵclassProp('foo', true); // change + ɵɵclassProp('foo', undefined); // change + expectClass(div).toEqual({foo: true}); + }); + + describe('styleMap', () => { + it('should work with maps', () => { + ɵɵstyleMap({}); + expectStyle(div).toEqual({}); + expect(ngDevMode !.rendererSetStyle).toEqual(0); + expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + ngDevModeResetPerfCounters(); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleMap({color: 'blue'}); + expectStyle(div).toEqual({color: 'blue'}); + expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵstyleMap({color: 'red'}); + expectStyle(div).toEqual({color: 'red'}); + expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵstyleMap({color: null, width: '100px'}); + expectStyle(div).toEqual({width: '100px'}); + expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode !.rendererRemoveStyle).toEqual(1); + ngDevModeResetPerfCounters(); + }); + + it('should work with object literal and strings', () => { + ɵɵstyleMap(''); + expectStyle(div).toEqual({}); + expect(ngDevMode !.rendererSetStyle).toEqual(0); + expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + ngDevModeResetPerfCounters(); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleMap('color: blue'); + expectStyle(div).toEqual({color: 'blue'}); + expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵstyleMap('color: red'); + expectStyle(div).toEqual({color: 'red'}); + expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + ngDevModeResetPerfCounters(); + + rewindBindingIndex(); + ɵɵstyleMap('width: 100px'); + expectStyle(div).toEqual({width: '100px'}); + expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode !.rendererRemoveStyle).toEqual(1); + ngDevModeResetPerfCounters(); + }); + + it('should collaborate with properties', () => { + ɵɵstyleProp('color', 'red'); + ɵɵstyleMap({color: 'blue', width: '100px'}); + expectStyle(div).toEqual({color: 'blue', width: '100px'}); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleProp('color', 'red'); + ɵɵstyleMap({width: '200px'}); + expectStyle(div).toEqual({color: 'red', width: '200px'}); + }); + + it('should collaborate with other maps', () => { + ɵɵstyleMap('color: red'); + ɵɵstyleMap({color: 'blue', width: '100px'}); + expectStyle(div).toEqual({color: 'blue', width: '100px'}); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleMap('color: red'); + ɵɵstyleMap({width: '200px'}); + expectStyle(div).toEqual({color: 'red', width: '200px'}); + }); + + describe('suffix', () => { + it('should append suffix', () => { + ɵɵstyleProp('width', 200, 'px'); + ɵɵstyleProp('width', 100, 'px'); + expectStyle(div).toEqual({width: '100px'}); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleProp('width', 200, 'px'); + ɵɵstyleProp('width', undefined, 'px'); + expectStyle(div).toEqual({width: '200px'}); + }); + + it('should append suffix and non-suffix bindings', () => { + ɵɵstyleProp('width', 200, 'px'); + ɵɵstyleProp('width', '100px'); + expectStyle(div).toEqual({width: '100px'}); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleProp('width', 200, 'px'); + ɵɵstyleProp('width', undefined, 'px'); + expectStyle(div).toEqual({width: '200px'}); + }); + }); + + describe('sanitization', () => { + it('should sanitize property', () => { + ɵɵstyleSanitizer(ɵɵsanitizeStyle); + ɵɵstyleProp('background', 'url("javascript:/unsafe")'); + expect(div.style.getPropertyValue('background')).not.toContain('javascript'); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleProp('background', bypassSanitizationTrustStyle('url("javascript:/trusted")')); + expect(div.style.getPropertyValue('background')).toContain('url("javascript:/trusted")'); + }); + + it('should sanitize map', () => { + ɵɵstyleSanitizer(ɵɵsanitizeStyle); + ɵɵstyleMap('background: url("javascript:/unsafe")'); + expect(div.style.getPropertyValue('background')).not.toContain('javascript'); + + clearFirstUpdatePass(); + + rewindBindingIndex(); + ɵɵstyleMap({'background': bypassSanitizationTrustStyle('url("javascript:/trusted")')}); + expect(div.style.getPropertyValue('background')).toContain('url("javascript:/trusted")'); + }); + }); + }); + + describe('static', () => { + describe('template only', () => { + it('should capture static values in TStylingKey', () => { + givenTemplateAttrs([AttributeMarker.Styles, 'content', '"TEMPLATE"']); + + ɵɵstyleProp('content', '"dynamic"'); + expectTStylingKeys('style').toEqual([ + ['', 'content', 'content', '"TEMPLATE"'], 'prev', // contains statics + null // residual + ]); + expectStyle(div).toEqual({content: '"dynamic"'}); + + ɵɵstyleProp('content', undefined); + expectTStylingKeys('style').toEqual([ + ['', 'content', 'content', '"TEMPLATE"'], 'both', // contains statics + 'content', 'prev', // Making sure that second instruction does not have statics again. + null // residual + ]); + expectStyle(div).toEqual({content: '"dynamic"'}); + }); + }); + + describe('directives only', () => { + it('should update residual on second directive', () => { + givenDirectiveAttrs([ + [AttributeMarker.Styles, 'content', '"lowest"'], // 0 + [AttributeMarker.Styles, 'content', '"middle"'], // 1 + ]); + expectStyle(div).toEqual({content: '"middle"'}); + + activateHostBindings(0); + ɵɵstyleProp('content', '"dynamic"'); + expectTStylingKeys('style').toEqual([ + ['', 'content', 'content', '"lowest"'], 'both', // 1: contains statics + ['content', '"middle"'], // residual + ]); + expectStyle(div).toEqual({content: '"middle"'}); + + // second binding should not get statics + ɵɵstyleProp('content', '"dynamic2"'); + expectTStylingKeys('style').toEqual([ + ['', 'content', 'content', '"lowest"'], 'both', // 1: contains statics + 'content', 'both', // 1: Should not get statics + ['content', '"middle"'] // residual + ]); + expectStyle(div).toEqual({content: '"middle"'}); + + activateHostBindings(1); + ɵɵstyleProp('content', '"dynamic3"'); + expectTStylingKeys('style').toEqual([ + ['', 'content', 'content', '"lowest"'], 'both', // 1: contains statics + 'content', 'both', // 1: Should not get statics + ['', 'content', 'content', '"middle"'], 'prev', // 0: contains statics + null // residual + ]); + expectStyle(div).toEqual({content: '"dynamic3"'}); + }); + }); + + describe('template and directives', () => { + it('should combine property and map', () => { + givenDirectiveAttrs([ + [AttributeMarker.Styles, 'content', '"lowest"', 'color', 'blue'], // 0 + [AttributeMarker.Styles, 'content', '"middle"', 'width', '100px'], // 1 + ]); + givenTemplateAttrs([AttributeMarker.Styles, 'content', '"TEMPLATE"', 'color', 'red']); + + // TEMPLATE + ɵɵstyleProp('content', undefined); + expectTStylingKeys('style').toEqual([ + // TEMPLATE + ['', 'content', 'color', 'red', 'content', '"TEMPLATE"', 'width', '100px'], 'prev', + // RESIDUAL + null + ]); + expectStyle(div).toEqual({content: '"TEMPLATE"', color: 'red', width: '100px'}); + + // Directive 0 + activateHostBindings(0); + ɵɵstyleMap('color: red; width: 0px; height: 50px'); + expectTStylingKeys('style').toEqual([ + // Host Binding 0 + ['', null, 'color', 'blue', 'content', '"lowest"'], 'both', + // TEMPLATE + ['', 'content', 'color', 'red', 'content', '"TEMPLATE"', 'width', '100px'], 'prev', + // RESIDUAL + null + ]); + expectStyle(div).toEqual( + {content: '"TEMPLATE"', color: 'red', width: '100px', height: '50px'}); + + // Directive 1 + activateHostBindings(1); + ɵɵstyleMap('color: red; width: 0px; height: 50px'); + expectTStylingKeys('style').toEqual([ + // Host Binding 0 + ['', null, 'color', 'blue', 'content', '"lowest"'], 'both', + // Host Binding 1 + ['', null, 'content', '"middle"', 'width', '100px'], 'both', + // TEMPLATE + ['', 'content', 'color', 'red', 'content', '"TEMPLATE"'], 'prev', + // RESIDUAL + null + ]); + expectStyle(div).toEqual( + {content: '"TEMPLATE"', color: 'red', width: '0px', height: '50px'}); + }); + + it('should read value from residual', () => { + givenDirectiveAttrs([ + [AttributeMarker.Styles, 'content', '"lowest"', 'color', 'blue'], // 0 + [AttributeMarker.Styles, 'content', '"middle"', 'width', '100px'], // 1 + ]); + givenTemplateAttrs([AttributeMarker.Styles, 'content', '"TEMPLATE"', 'color', 'red']); + + // Directive 1 + activateHostBindings(1); + ɵɵstyleProp('color', 'white'); + expectTStylingKeys('style').toEqual([ + // Host Binding 0 + 1 + ['', 'color', 'color', 'blue', 'content', '"middle"', 'width', '100px'], 'both', + // RESIDUAL + ['color', 'red', 'content', '"TEMPLATE"'] + ]); + expectStyle(div).toEqual({content: '"TEMPLATE"', color: 'red', width: '100px'}); + + }); + }); + }); + + + describe('toStylingArray', () => { + describe('falsy', () => { + it('should return empty KeyValueArray', () => { + expect(toStylingKeyValueArray(keyValueArraySet, null !, '')).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null !, null)).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null !, undefined)).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null !, [])).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null !, {})).toEqual([] as any); + }); + describe('string', () => { + it('should parse classes', () => { + expect(toStylingKeyValueArray(keyValueArraySet, classStringParser, ' ')).toEqual([ + ] as any); + expect(toStylingKeyValueArray(keyValueArraySet, classStringParser, ' X A ')).toEqual([ + 'A', true, 'X', true + ] as any); + }); + it('should parse styles', () => { + expect(toStylingKeyValueArray(keyValueArraySet, styleStringParser, ' ')).toEqual([ + ] as any); + expect(toStylingKeyValueArray(keyValueArraySet, styleStringParser, 'B:b;A:a')).toEqual([ + 'A', 'a', 'B', 'b' + ] as any); + }); + }); + describe('array', () => { + it('should parse', () => { + expect(toStylingKeyValueArray(keyValueArraySet, null !, ['X', 'A'])).toEqual([ + 'A', true, 'X', true + ] as any); + }); + }); + describe('object', () => { + it('should parse', () => { + expect(toStylingKeyValueArray(keyValueArraySet, null !, {X: 'x', A: 'a'})).toEqual([ + 'A', 'a', 'X', 'x' + ] as any); + }); + }); + describe('Map', () => { + it('should parse', () => { + expect(toStylingKeyValueArray( + keyValueArraySet, null !, new Map([['X', 'x'], ['A', 'a']]))) + .toEqual(['A', 'a', 'X', 'x'] as any); + }); + }); + describe('Iterable', () => { + it('should parse', () => { + expect(toStylingKeyValueArray(keyValueArraySet, null !, new Set(['X', 'A']))) + .toEqual(['A', true, 'X', true] as any); + }); + }); + }); + }); + + + describe('TStylingRange', () => { + const MAX_VALUE = StylingRange.UNSIGNED_MASK; + + it('should throw on negative values', () => { + expect(() => toTStylingRange(0, -1)).toThrow(); + expect(() => toTStylingRange(-1, 0)).toThrow(); + }); + + it('should throw on overflow', () => { + expect(() => toTStylingRange(0, MAX_VALUE + 1)).toThrow(); + expect(() => toTStylingRange(MAX_VALUE + 1, 0)).toThrow(); + }); + + it('should retrieve the same value which went in just below overflow', () => { + const range = toTStylingRange(MAX_VALUE, MAX_VALUE); + expect(getTStylingRangePrev(range)).toEqual(MAX_VALUE); + expect(getTStylingRangeNext(range)).toEqual(MAX_VALUE); + }); + + it('should correctly increment', () => { + let range = toTStylingRange(0, 0); + for (let i = 0; i <= MAX_VALUE; i++) { + range = setTStylingRangeNext(range, i); + range = setTStylingRangePrev(range, i); + expect(getTStylingRangeNext(range)).toEqual(i); + expect(getTStylingRangePrev(range)).toEqual(i); + if (i == 10) { + // Skip the boring stuff in the middle. + i = MAX_VALUE - 10; + } + } + }); + }); +}); + + +function expectStyle(element: HTMLElement) { + return expect(getElementStyles(element)); +} + +function expectClass(element: HTMLElement) { + return expect(getElementClasses(element)); +} + +function givenTemplateAttrs(tAttrs: TAttributes) { + const tNode = getTNode(); + tNode.attrs = tAttrs; + applyTAttributes(tAttrs); +} + +function getTNode() { + return getLView()[TVIEW].firstChild !; +} + +function getTData() { + return getLView()[TVIEW].data; +} + +class MockDir {} + +function givenDirectiveAttrs(tAttrs: TAttributes[]) { + const tNode = getTNode(); + const tData = getTData(); + tNode.directiveStart = getTDataIndexFromDirectiveIndex(0); + tNode.directiveEnd = getTDataIndexFromDirectiveIndex(tAttrs.length); + for (let i = 0; i < tAttrs.length; i++) { + const tAttr = tAttrs[i]; + const directiveDef = ɵɵdefineDirective({type: MockDir, hostAttrs: tAttr}) as DirectiveDef; + applyTAttributes(directiveDef.hostAttrs); + tData[getTDataIndexFromDirectiveIndex(i)] = directiveDef; + } +} + +function applyTAttributes(attrs: TAttributes | null) { + if (attrs === null) return; + const div: HTMLElement = getLView()[HEADER_OFFSET]; + let mode: AttributeMarker = AttributeMarker.ImplicitAttributes; + for (let i = 0; i < attrs.length; i++) { + const item = attrs[i]; + if (typeof item === 'number') { + mode = item; + } else if (typeof item === 'string') { + if (mode == AttributeMarker.ImplicitAttributes) { + div.setAttribute(item, attrs[++i] as string); + } else if (mode == AttributeMarker.Classes) { + div.classList.add(item); + } else if (mode == AttributeMarker.Styles) { + div.style.setProperty(item, attrs[++i] as string); + } + } + } +} + +function activateHostBindings(directiveIndex: number) { + const bindingRootIndex = getBindingRootIndexFromDirectiveIndex(directiveIndex); + const currentDirectiveIndex = getTDataIndexFromDirectiveIndex(directiveIndex); + setBindingRootForHostBindings(bindingRootIndex, currentDirectiveIndex); +} + +function getBindingRootIndexFromDirectiveIndex(index: number) { + // For simplicity assume that each directive has 10 vars. + // We need to offset 1 for template, and 1 for expando. + return HEADER_OFFSET + (index + 2) * 10; +} + +function getTDataIndexFromDirectiveIndex(index: number) { + return HEADER_OFFSET + index + 10; // offset to give template bindings space. +} + +function expectTStylingKeys(styling: 'style' | 'class') { + const tNode = getTNode(); + const tData = getTData(); + const isClassBased = styling === 'class'; + const headIndex = getTStylingRangePrev(isClassBased ? tNode.classBindings : tNode.styleBindings); + const tStylingKeys: (string | (null | string)[] | null)[] = []; + let index = headIndex; + let prevIndex = index; + // rewind to beginning of list. + while ((prevIndex = getTStylingRangePrev(tData[index + 1] as TStylingRange)) !== 0) { + index = prevIndex; + } + + // insert into array. + while (index !== 0) { + const tStylingKey = tData[index] as TStylingKey; + const prevDup = getTStylingRangePrevDuplicate(tData[index + 1] as TStylingRange); + const nextDup = getTStylingRangeNextDuplicate(tData[index + 1] as TStylingRange); + tStylingKeys.push(tStylingKey as string[] | string | null); + tStylingKeys.push(prevDup ? (nextDup ? 'both' : 'prev') : (nextDup ? 'next' : '')); + index = getTStylingRangeNext(tData[index + 1] as TStylingRange); + } + tStylingKeys.push( + (isClassBased ? tNode.residualClasses : tNode.residualStyles) as null | string[]); + + return expect(tStylingKeys); +} \ No newline at end of file diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index be6f6b5fa2..09139881ad 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -7,11 +7,12 @@ */ import {NgForOfContext} from '@angular/common'; +import {getSortedClassName} from '@angular/core/testing/src/styling'; import {ɵɵdefineComponent} from '../../src/render3/definition'; import {RenderFlags, ɵɵattribute, ɵɵclassMap, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyleSanitizer, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate1} from '../../src/render3/index'; import {AttributeMarker} from '../../src/render3/interfaces/node'; -import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, getSanitizationBypassType, unwrapSafeValue} from '../../src/sanitization/bypass'; +import {SafeValue, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, getSanitizationBypassType, unwrapSafeValue} from '../../src/sanitization/bypass'; import {ɵɵdefaultStyleSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization'; import {Sanitizer} from '../../src/sanitization/sanitizer'; import {SecurityContext} from '../../src/sanitization/security'; @@ -137,18 +138,20 @@ describe('instructions', () => { describe('styleProp', () => { it('should automatically sanitize unless a bypass operation is applied', () => { - const t = new TemplateFixture(() => { return createDiv(); }, () => {}, 1); - t.update(() => { - ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer); - ɵɵstyleProp('background-image', 'url("http://server")'); - }); + let backgroundImage: string|SafeValue = 'url("http://server")'; + const t = new TemplateFixture( + () => { return createDiv(); }, + () => { + ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer); + ɵɵstyleProp('background-image', backgroundImage); + }, + 2, 2); // nothing is set because sanitizer suppresses it. - expect(t.html).toEqual('
'); + expect((t.hostElement.firstChild as HTMLElement).style.getPropertyValue('background-image')) + .toEqual(''); - t.update(() => { - ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer); - ɵɵstyleProp('background-image', bypassSanitizationTrustStyle('url("http://server2")')); - }); + backgroundImage = bypassSanitizationTrustStyle('url("http://server2")'); + t.update(); expect((t.hostElement.firstChild as HTMLElement).style.getPropertyValue('background-image')) .toEqual('url("http://server2")'); }); @@ -160,9 +163,10 @@ describe('instructions', () => { function createDivWithStyle() { ɵɵelement(0, 'div', 0); } it('should add style', () => { - const fixture = new TemplateFixture( - createDivWithStyle, () => {}, 1, 0, null, null, null, undefined, attrs); - fixture.update(() => { ɵɵstyleMap({'background-color': 'red'}); }); + const fixture = new TemplateFixture(createDivWithStyle, () => { + ɵɵstyleMap({'background-color': 'red'}); + }, 1, 2, null, null, null, undefined, attrs); + fixture.update(); expect(fixture.html).toEqual('
'); }); @@ -184,7 +188,7 @@ describe('instructions', () => { 'width': 'width' }); }, - 1, 0, null, null, sanitizerInterceptor); + 1, 2, null, null, sanitizerInterceptor); const props = detectedValues.sort(); expect(props).toEqual([ @@ -197,9 +201,10 @@ describe('instructions', () => { function createDivWithStyling() { ɵɵelement(0, 'div'); } it('should add class', () => { - const fixture = - new TemplateFixture(createDivWithStyling, () => { ɵɵclassMap('multiple classes'); }, 1); - expect(fixture.html).toEqual('
'); + const fixture = new TemplateFixture( + createDivWithStyling, () => { ɵɵclassMap('multiple classes'); }, 1, 2); + const div = fixture.containerElement.querySelector('div.multiple') !; + expect(getSortedClassName(div)).toEqual('classes multiple'); }); }); diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index 041613ad86..cba57eb192 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -9,7 +9,7 @@ import {RendererType2} from '../../src/render/api'; import {getLContext} from '../../src/render3/context_discovery'; import {AttributeMarker, ɵɵadvance, ɵɵattribute, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵhostProperty, ɵɵproperty} from '../../src/render3/index'; -import {ɵɵallocHostVars, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all'; +import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all'; import {MONKEY_PATCH_KEY_NAME} from '../../src/render3/interfaces/context'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; @@ -1112,10 +1112,8 @@ describe('sanitization', () => { static ɵdir = ɵɵdefineDirective({ type: UnsafeUrlHostBindingDir, selectors: [['', 'unsafeUrlHostBindingDir', '']], + hostVars: 1, hostBindings: (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Create) { - ɵɵallocHostVars(1); - } if (rf & RenderFlags.Update) { ɵɵhostProperty('cite', ctx.cite, ɵɵsanitizeUrl); } diff --git a/packages/core/test/render3/ivy/BUILD.bazel b/packages/core/test/render3/ivy/BUILD.bazel index 9855dfd764..3982b9357a 100644 --- a/packages/core/test/render3/ivy/BUILD.bazel +++ b/packages/core/test/render3/ivy/BUILD.bazel @@ -16,15 +16,12 @@ ts_library( jasmine_node_test( name = "ivy", - bootstrap = [ - "angular/packages/core/test/render3/load_domino", - ], + bootstrap = ["//packages/core/test/render3:domino_es5"], tags = [ "ivy-only", ], deps = [ ":ivy_lib", - "//packages/core/test/render3:domino", "//packages/zone.js/lib", ], ) diff --git a/packages/core/test/render3/ivy/jit_spec.ts b/packages/core/test/render3/ivy/jit_spec.ts index 37d9572772..6b14b3fe8b 100644 --- a/packages/core/test/render3/ivy/jit_spec.ts +++ b/packages/core/test/render3/ivy/jit_spec.ts @@ -233,7 +233,7 @@ ivyEnabled && describe('render3 jit', () => { const cmpDef = (Cmp as any).ɵcmp as ComponentDef; expect(cmpDef.hostBindings).toBeDefined(); - expect(cmpDef.hostBindings !.length).toBe(3); + expect(cmpDef.hostBindings !.length).toBe(2); }); it('should compile @Pipes without errors', () => { diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index d2af7aa923..27455f6836 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -77,8 +77,7 @@ describe('event listeners', () => { ɵɵtext(0, 'Some text'); } }, - hostBindings: function HostListenerDir_HostBindings( - rf: RenderFlags, ctx: any, elIndex: number) { + hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵlistener('custom', function() { return ctx.onDocumentCustomEvent(); @@ -102,8 +101,7 @@ describe('event listeners', () => { static ɵdir = ɵɵdefineDirective({ type: GlobalHostListenerDir, selectors: [['', 'hostListenerDir', '']], - hostBindings: function HostListenerDir_HostBindings( - rf: RenderFlags, ctx: any, elIndex: number) { + hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵlistener('custom', function() { return ctx.onDocumentCustomEvent(); @@ -537,8 +535,7 @@ describe('event listeners', () => { ɵɵtext(0, 'Some text'); } }, - hostBindings: function HostListenerDir_HostBindings( - rf: RenderFlags, ctx: any, elIndex: number) { + hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵlistener('click', function() { return ctx.onClick(); }); } @@ -581,8 +578,7 @@ describe('event listeners', () => { static ɵdir = ɵɵdefineDirective({ type: HostListenerDir, selectors: [['', 'hostListenerDir', '']], - hostBindings: function HostListenerDir_HostBindings( - rf: RenderFlags, ctx: any, elIndex: number) { + hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵlistener('click', function() { return ctx.onClick(); }); } diff --git a/packages/core/test/render3/node_selector_matcher_spec.ts b/packages/core/test/render3/node_selector_matcher_spec.ts index b6d5c3dc5d..42cfa7b0de 100644 --- a/packages/core/test/render3/node_selector_matcher_spec.ts +++ b/packages/core/test/render3/node_selector_matcher_spec.ts @@ -10,7 +10,7 @@ import {createTNode} from '@angular/core/src/render3/instructions/shared'; import {AttributeMarker, TAttributes, TNode, TNodeType} from '../../src/render3/interfaces/node'; import {CssSelector, CssSelectorList, SelectorFlags} from '../../src/render3/interfaces/projection'; -import {getProjectAsAttrValue, isNodeMatchingSelector, isNodeMatchingSelectorList} from '../../src/render3/node_selector_matcher'; +import {getProjectAsAttrValue, isNodeMatchingSelector, isNodeMatchingSelectorList, stringifyCSSSelectorList} from '../../src/render3/node_selector_matcher'; function testLStaticData(tagName: string, attrs: TAttributes | null): TNode { return createTNode(null !, null, TNodeType.Element, 0, tagName, attrs); @@ -22,7 +22,7 @@ describe('css selector matching', () => { const tNode = (!attrsOrTNode || Array.isArray(attrsOrTNode)) ? createTNode(null !, null, TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes) : (attrsOrTNode as TNode); - return isNodeMatchingSelector(tNode, selector, false); + return isNodeMatchingSelector(tNode, selector, true); } describe('isNodeMatchingSimpleSelector', () => { @@ -322,26 +322,6 @@ 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 !, 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.classes = null; - expect(isMatching('div', tNode, selector)).toBeTruthy(); - - //
(with styling context but without attrs) - tNode.classes = ['abc', 'abc', true]; - tNode.attrs = null; - expect(isMatching('div', tNode, selector)).toBeTruthy(); - }); }); }); @@ -508,3 +488,84 @@ describe('css selector matching', () => { }); }); + +describe('stringifyCSSSelectorList', () => { + + it('should stringify selector with a tag name only', + () => { expect(stringifyCSSSelectorList([['button']])).toBe('button'); }); + + it('should stringify selector with attributes', () => { + expect(stringifyCSSSelectorList([['', 'id', '']])).toBe('[id]'); + expect(stringifyCSSSelectorList([['button', 'id', '']])).toBe('button[id]'); + expect(stringifyCSSSelectorList([['button', 'id', 'value']])).toBe('button[id="value"]'); + expect(stringifyCSSSelectorList([['button', 'id', 'value', 'title', 'other']])) + .toBe('button[id="value"][title="other"]'); + }); + + it('should stringify selector with class names', () => { + expect(stringifyCSSSelectorList([['', SelectorFlags.CLASS, 'foo']])).toBe('.foo'); + expect(stringifyCSSSelectorList([['button', SelectorFlags.CLASS, 'foo']])).toBe('button.foo'); + + expect(stringifyCSSSelectorList([['button', SelectorFlags.CLASS, 'foo', 'bar']])) + .toBe('button.foo.bar'); + + expect(stringifyCSSSelectorList([ + ['button', 'id', 'value', 'title', 'other', SelectorFlags.CLASS, 'foo', 'bar'] + ])).toBe('button[id="value"][title="other"].foo.bar'); + }); + + it('should stringify selector with `:not()` rules', () => { + expect(stringifyCSSSelectorList([['', SelectorFlags.CLASS | SelectorFlags.NOT, 'foo', 'bar']])) + .toBe(':not(.foo.bar)'); + + expect(stringifyCSSSelectorList([ + ['button', SelectorFlags.ATTRIBUTE | SelectorFlags.NOT, 'foo', 'bar'] + ])).toBe('button:not([foo="bar"])'); + + expect(stringifyCSSSelectorList([['', SelectorFlags.ELEMENT | SelectorFlags.NOT, 'foo']])) + .toBe(':not(foo)'); + + expect(stringifyCSSSelectorList([ + ['span', SelectorFlags.CLASS, 'foo', SelectorFlags.CLASS | SelectorFlags.NOT, 'bar', 'baz'] + ])).toBe('span.foo:not(.bar.baz)'); + + expect(stringifyCSSSelectorList([ + ['span', 'id', 'value', SelectorFlags.ATTRIBUTE | SelectorFlags.NOT, 'title', 'other'] + ])).toBe('span[id="value"]:not([title="other"])'); + + expect(stringifyCSSSelectorList([[ + '', SelectorFlags.CLASS, 'bar', SelectorFlags.ATTRIBUTE | SelectorFlags.NOT, 'foo', '', + SelectorFlags.ELEMENT | SelectorFlags.NOT, 'div' + ]])).toBe('.bar:not([foo]):not(div)'); + + expect(stringifyCSSSelectorList([[ + 'div', SelectorFlags.ATTRIBUTE | SelectorFlags.NOT, 'foo', '', SelectorFlags.CLASS, 'bar', + SelectorFlags.CLASS | SelectorFlags.NOT, 'baz' + ]])).toBe('div:not([foo].bar):not(.baz)'); + + expect(stringifyCSSSelectorList([[ + 'div', SelectorFlags.ELEMENT | SelectorFlags.NOT, 'p', SelectorFlags.CLASS, 'bar', + SelectorFlags.CLASS | SelectorFlags.NOT, 'baz' + ]])).toBe('div:not(p.bar):not(.baz)'); + }); + + it('should stringify multiple comma-separated selectors', () => { + expect(stringifyCSSSelectorList([ + ['', 'id', ''], ['button', 'id', 'value'] + ])).toBe('[id],button[id="value"]'); + + expect(stringifyCSSSelectorList([ + ['', 'id', ''], ['button', 'id', 'value'], + ['div', SelectorFlags.ATTRIBUTE | SelectorFlags.NOT, 'foo', ''] + ])).toBe('[id],button[id="value"],div:not([foo])'); + + expect(stringifyCSSSelectorList([ + ['', 'id', ''], ['button', 'id', 'value'], + ['div', SelectorFlags.ATTRIBUTE | SelectorFlags.NOT, 'foo', ''], + [ + 'div', SelectorFlags.ELEMENT | SelectorFlags.NOT, 'p', SelectorFlags.CLASS, 'bar', + SelectorFlags.CLASS | SelectorFlags.NOT, 'baz' + ] + ])).toBe('[id],button[id="value"],div:not([foo]),div:not(p.bar):not(.baz)'); + }); +}); diff --git a/packages/core/test/render3/perf/BUILD.bazel b/packages/core/test/render3/perf/BUILD.bazel index 3369880398..a580272711 100644 --- a/packages/core/test/render3/perf/BUILD.bazel +++ b/packages/core/test/render3/perf/BUILD.bazel @@ -9,6 +9,7 @@ ts_library( ), deps = [ "//packages/core", + "//packages/core/src/util", "@npm//@types/jasmine", "@npm//@types/node", ], diff --git a/packages/core/test/render3/perf/README.md b/packages/core/test/render3/perf/README.md index 6fe43f71e0..561711022a 100644 --- a/packages/core/test/render3/perf/README.md +++ b/packages/core/test/render3/perf/README.md @@ -78,3 +78,7 @@ To profile, append `_profile` to the target name and attach a debugger via chrom - `yarn bazel run --config=ivy //packages/core/test/render3/perf:noop_change_detection_profile` To interactively edit/rerun benchmarks use `ibazel` instead of `bazel`. + +To debug +- `yarn bazel build --config=ivy //packages/core/test/render3/perf:noop_change_detection` +- `node --inspect-brk bazel-out/darwin-fastbuild/bin/packages/core/test/render3/perf/noop_change_detection.min_debug.es2015.js` \ No newline at end of file diff --git a/packages/core/test/render3/perf/class_binding/index.ts b/packages/core/test/render3/perf/class_binding/index.ts index af0ff662ed..3085bd3ee4 100644 --- a/packages/core/test/render3/perf/class_binding/index.ts +++ b/packages/core/test/render3/perf/class_binding/index.ts @@ -26,8 +26,8 @@ const benchmarks: Benchmark[] = []; function benchmark( name: string, template: ComponentTemplate, baselineTemplate: ComponentTemplate) { - const ivyHarness = setupTestHarness(template, 1, 1, 1000, context, consts); - const baseHarness = setupTestHarness(baselineTemplate, 1, 1, 1000, context, consts); + const ivyHarness = setupTestHarness(template, 1, 4, 1000, context, consts); + const baseHarness = setupTestHarness(baselineTemplate, 1, 4, 1000, context, consts); if (PROFILE_CREATE) { const benchmark = createBenchmark('class binding[create]: ' + name); diff --git a/packages/core/test/render3/perf/directive_inputs/index.ts b/packages/core/test/render3/perf/directive_inputs/index.ts index 1898e6fef5..3129875312 100644 --- a/packages/core/test/render3/perf/directive_inputs/index.ts +++ b/packages/core/test/render3/perf/directive_inputs/index.ts @@ -61,7 +61,7 @@ const updateTime = directiveInputs('update'); console.profile('directive_inputs'); while (updateTime()) { ctx.counter++; - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts b/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts index db41dfae9f..b8d3a02b31 100644 --- a/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts +++ b/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts @@ -1,10 +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 - */ +* @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 {ɵɵadvance} from '../../../../src/render3/instructions/advance'; import {ɵɵelement, ɵɵelementEnd, ɵɵelementStart} from '../../../../src/render3/instructions/element'; import {refreshView} from '../../../../src/render3/instructions/shared'; @@ -149,7 +149,7 @@ function dirThatSetsFooClassesHostBindings(rf: RenderFlags, ctx: any) { } const rootLView = setupRootViewWithEmbeddedViews( - testTemplate, 11, 10, 1000, null, + testTemplate, 11, 40, 1000, null, [ ['dir-that-sets-width', '', 'dir-that-sets-foo-class', ''], ], @@ -167,7 +167,7 @@ const refreshTime = duplicateMapBasedStyleAndClassBindingsBenchmark('refresh'); // run change detection in the update mode console.profile('duplicate_map_based_style_and_class_bindings_refresh'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/duplicate_style_and_class_bindings/index.ts b/packages/core/test/render3/perf/duplicate_style_and_class_bindings/index.ts index 4ac9aea0f2..89ef94b473 100644 --- a/packages/core/test/render3/perf/duplicate_style_and_class_bindings/index.ts +++ b/packages/core/test/render3/perf/duplicate_style_and_class_bindings/index.ts @@ -167,7 +167,7 @@ const refreshTime = duplicateStyleAndClassBindingsBenchmark('refresh'); // run change detection in the update mode console.profile('duplicate_style_and_class_bindings_refresh'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/interpolation/index.ts b/packages/core/test/render3/perf/interpolation/index.ts index dea2c4f17d..e25efa1fb1 100644 --- a/packages/core/test/render3/perf/interpolation/index.ts +++ b/packages/core/test/render3/perf/interpolation/index.ts @@ -99,7 +99,7 @@ const refreshTime = interpolationRefresh('refresh'); // run change detection in the update mode console.profile('interpolation_refresh'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/map_based_style_and_class_bindings/index.ts b/packages/core/test/render3/perf/map_based_style_and_class_bindings/index.ts index f8f74bb2f8..61248bf009 100644 --- a/packages/core/test/render3/perf/map_based_style_and_class_bindings/index.ts +++ b/packages/core/test/render3/perf/map_based_style_and_class_bindings/index.ts @@ -78,7 +78,7 @@ function testTemplate(rf: RenderFlags, ctx: any) { } -const rootLView = setupRootViewWithEmbeddedViews(testTemplate, 11, 10, 1000); +const rootLView = setupRootViewWithEmbeddedViews(testTemplate, 11, 40, 1000); const rootTView = rootLView[TVIEW]; // scenario to benchmark @@ -88,7 +88,7 @@ const refreshTime = styleAndClassBindingMapBenchmark('refresh'); // run change detection in the update mode console.profile('style_and_class_map_binding_refresh'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/micro_bench.ts b/packages/core/test/render3/perf/micro_bench.ts index 4bcb5d7ffc..00c5ff1c49 100644 --- a/packages/core/test/render3/perf/micro_bench.ts +++ b/packages/core/test/render3/perf/micro_bench.ts @@ -65,7 +65,7 @@ export function createBenchmark(benchmarkName: string): Benchmark { if (!runAgain) { // tslint:disable-next-line:no-console console.log( - ` ${formatTime(iterationTime_ms)} (count: ${profile.sampleCount}, iterations: ${profile.iterationCount})`); + ` ${formatTime(profile.bestTime)} (count: ${profile.sampleCount}, iterations: ${profile.iterationCount})`); } } iterationCounter = profile.iterationCount; diff --git a/packages/core/test/render3/perf/noop_change_detection/index.ts b/packages/core/test/render3/perf/noop_change_detection/index.ts index b77b373e57..29ccaec750 100644 --- a/packages/core/test/render3/perf/noop_change_detection/index.ts +++ b/packages/core/test/render3/perf/noop_change_detection/index.ts @@ -20,7 +20,7 @@ const refreshTime = noopChangeDetection('refresh'); // run change detection in the update mode console.profile('noop_change_detection'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/property_binding/index.ts b/packages/core/test/render3/perf/property_binding/index.ts index fe403ecedb..810959f88c 100644 --- a/packages/core/test/render3/perf/property_binding/index.ts +++ b/packages/core/test/render3/perf/property_binding/index.ts @@ -78,7 +78,7 @@ const refreshTime = propertyBindingRefresh('refresh'); // run change detection in the update mode console.profile('property_binding_refresh'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/property_binding_update/index.ts b/packages/core/test/render3/perf/property_binding_update/index.ts index 860388c02b..2baacbf5f8 100644 --- a/packages/core/test/render3/perf/property_binding_update/index.ts +++ b/packages/core/test/render3/perf/property_binding_update/index.ts @@ -84,7 +84,7 @@ console.profile('element property update'); let i = 0; while (updateTime()) { ctx.value = `value${i++}`; - refreshView(rootLView, rootTView, null, ctx); + refreshView(rootTView, rootLView, null, ctx); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/setup.ts b/packages/core/test/render3/perf/setup.ts index 9c917cfd3e..2eddc4e5ec 100644 --- a/packages/core/test/render3/perf/setup.ts +++ b/packages/core/test/render3/perf/setup.ts @@ -9,7 +9,7 @@ import {addToViewTree, createLContainer, createLView, createTNode, createTView, import {ComponentTemplate, DirectiveDefList} from '../../../src/render3/interfaces/definition'; import {TAttributes, TNodeType, TViewNode} from '../../../src/render3/interfaces/node'; import {RendererFactory3, domRendererFactory3} from '../../../src/render3/interfaces/renderer'; -import {LView, LViewFlags, TView, TViewType} from '../../../src/render3/interfaces/view'; +import {LView, LViewFlags, TVIEW, TView, TViewType} from '../../../src/render3/interfaces/view'; import {insertView} from '../../../src/render3/node_manipulation'; import {MicroBenchmarkRendererFactory} from './noop_renderer'; @@ -22,7 +22,7 @@ const renderer = rendererFactory.createRenderer(null, null); export function createAndRenderLView(parentLView: LView, tView: TView, hostTNode: TViewNode) { const embeddedLView = createLView( parentLView, tView, {}, LViewFlags.CheckAlways, null, hostTNode, rendererFactory, renderer); - renderView(embeddedLView, tView, null); + renderView(tView, embeddedLView, null); } export function setupRootViewWithEmbeddedViews( @@ -68,17 +68,18 @@ export function setupTestHarness( const embeddedLView = createLView( hostLView, embeddedTView, embeddedViewContext, LViewFlags.CheckAlways, null, viewTNode, rendererFactory, renderer); - renderView(embeddedLView, embeddedTView, embeddedViewContext); + renderView(embeddedTView, embeddedLView, embeddedViewContext); return embeddedLView; } function detectChanges(): void { - refreshView(hostLView, hostTView, hostTView.template, embeddedViewContext); + refreshView(hostTView, hostLView, hostTView.template, embeddedViewContext); } // create embedded views and add them to the container for (let i = 0; i < noOfViews; i++) { - insertView(createEmbeddedLView(), lContainer, i); + const lView = createEmbeddedLView(); + insertView(lView[TVIEW], lView, lContainer, i); } return { diff --git a/packages/core/test/render3/perf/style_and_class_bindings/index.ts b/packages/core/test/render3/perf/style_and_class_bindings/index.ts index 1d1af47729..84a6cf4de9 100644 --- a/packages/core/test/render3/perf/style_and_class_bindings/index.ts +++ b/packages/core/test/render3/perf/style_and_class_bindings/index.ts @@ -92,7 +92,7 @@ const refreshTime = styleAndClassBindingBenchmark('refresh'); // run change detection in the update mode console.profile('style_and_class_binding_refresh'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/perf/style_binding/index.ts b/packages/core/test/render3/perf/style_binding/index.ts index 4457439545..5e63677bb1 100644 --- a/packages/core/test/render3/perf/style_binding/index.ts +++ b/packages/core/test/render3/perf/style_binding/index.ts @@ -78,7 +78,7 @@ const refreshTime = styleBindingBenchmark('refresh'); // run change detection in the update mode console.profile('style_binding_refresh'); while (refreshTime()) { - refreshView(rootLView, rootTView, null, null); + refreshView(rootTView, rootLView, null, null); } console.profileEnd(); diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index 5f3fb49a52..d4c84c4a0a 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -32,7 +32,7 @@ import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveT import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeDefList, PipeDefListOrFactory, 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, LViewFlags, TViewType, T_HOST} from '../../src/render3/interfaces/view'; +import {HEADER_OFFSET, LView, LViewFlags, TVIEW, TViewType, T_HOST} from '../../src/render3/interfaces/view'; import {destroyLView} from '../../src/render3/node_manipulation'; import {getRootView} from '../../src/render3/util/view_traversal_utils'; import {Sanitizer} from '../../src/sanitization/sanitizer'; @@ -139,7 +139,7 @@ export class TemplateFixture extends BaseFixture { destroy(): void { this.containerElement.removeChild(this.hostElement); - destroyLView(this.hostView); + destroyLView(this.hostView[TVIEW], this.hostView); } } @@ -190,7 +190,8 @@ export class ComponentFixture extends BaseFixture { this.containerElement.removeChild(this.hostElement); } - destroyLView(getRootView(this.component)); + const rootLView = getRootView(this.component); + destroyLView(rootLView[TVIEW], rootLView); } } @@ -279,7 +280,7 @@ export function renderTemplate( hostLView, componentTView, context, LViewFlags.CheckAlways, hostNode, hostTNode, providedRendererFactory, renderer, sanitizer); } - renderComponentOrTemplate(componentView, templateFn, context); + renderComponentOrTemplate(componentView[TVIEW], componentView, templateFn, context); return componentView; } diff --git a/packages/core/test/render3/styling_next/class_differ_spec.ts b/packages/core/test/render3/styling_next/class_differ_spec.ts new file mode 100644 index 0000000000..45aed5f4ca --- /dev/null +++ b/packages/core/test/render3/styling_next/class_differ_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 {classIndexOf} from '../../../src/render3/styling/class_differ'; + +describe('class differ', () => { + describe('classIndexOf', () => { + it('should match simple case', () => { + expect(classIndexOf('A', 'A', 0)).toEqual(0); + expect(classIndexOf('AA', 'A', 0)).toEqual(-1); + expect(classIndexOf('_A_', 'A', 0)).toEqual(-1); + expect(classIndexOf('_ A_', 'A', 0)).toEqual(-1); + expect(classIndexOf('_ A _', 'A', 0)).toEqual(2); + }); + + it('should not match on partial matches', () => { + expect(classIndexOf('ABC AB', 'AB', 0)).toEqual(4); + expect(classIndexOf('AB ABC', 'AB', 1)).toEqual(-1); + expect(classIndexOf('ABC BC', 'BC', 0)).toEqual(4); + expect(classIndexOf('BC ABC', 'BB', 1)).toEqual(-1); + }); + }); +}); diff --git a/packages/core/test/render3/styling_next/map_based_bindings_spec.ts b/packages/core/test/render3/styling_next/map_based_bindings_spec.ts deleted file mode 100644 index 6e5a55e3a0..0000000000 --- a/packages/core/test/render3/styling_next/map_based_bindings_spec.ts +++ /dev/null @@ -1,85 +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 {normalizeIntoStylingMap as createMap} from '../../../src/render3/util/styling_utils'; - -describe('map-based bindings', () => { - describe('StylingMapArray construction', () => { - it('should create a new StylingMapArray instance from a given value', () => { - createAndAssertValues(null, []); - createAndAssertValues(undefined, []); - createAndAssertValues({}, []); - createAndAssertValues({foo: 'bar'}, ['foo', 'bar']); - createAndAssertValues({bar: null}, ['bar', null]); - createAndAssertValues('', []); - createAndAssertValues('abc xyz', ['abc', true, 'xyz', true]); - createAndAssertValues([], []); - }); - - it('should list each entry in the context in alphabetical order', () => { - const value1 = {width: '200px', color: 'red', zIndex: -1}; - const map1 = createMap(null, value1); - expect(map1).toEqual([value1, 'color', 'red', 'width', '200px', 'zIndex', -1]); - - const value2 = 'yes no maybe'; - const map2 = createMap(null, value2); - expect(map2).toEqual([value2, 'maybe', true, 'no', true, 'yes', true]); - }); - - it('should patch an existing StylingMapArray entry with new values and retain the alphabetical order', - () => { - const value1 = {color: 'red'}; - const map1 = createMap(null, value1); - expect(map1).toEqual([value1, 'color', 'red']); - - const value2 = {backgroundColor: 'red', color: 'blue', opacity: '0.5'}; - const map2 = createMap(map1, value2); - expect(map1).toBe(map2); - expect(map1).toEqual( - [value2, 'backgroundColor', 'red', 'color', 'blue', 'opacity', '0.5']); - - const value3 = 'myClass'; - const map3 = createMap(null, value3); - expect(map3).toEqual([value3, 'myClass', true]); - - const value4 = 'yourClass everyonesClass myClass'; - const map4 = createMap(map3, value4); - expect(map3).toBe(map4); - expect(map4).toEqual([value4, 'everyonesClass', true, 'myClass', true, 'yourClass', true]); - }); - - it('should nullify old values that are not a part of the new set of values', () => { - const value1 = {color: 'red', fontSize: '20px'}; - const map1 = createMap(null, value1); - expect(map1).toEqual([value1, 'color', 'red', 'fontSize', '20px']); - - const value2 = {color: 'blue', borderColor: 'purple', opacity: '0.5'}; - const map2 = createMap(map1, value2); - expect(map2).toEqual( - [value2, 'borderColor', 'purple', 'color', 'blue', 'fontSize', null, 'opacity', '0.5']); - - const value3 = 'orange'; - const map3 = createMap(null, value3); - expect(map3).toEqual([value3, 'orange', true]); - - const value4 = 'apple banana'; - const map4 = createMap(map3, value4); - expect(map4).toEqual([value4, 'apple', true, 'banana', true, 'orange', null]); - }); - - it('should hyphenate property names ', () => { - const value1 = {fontSize: '50px', paddingTopLeft: '20px'}; - const map1 = createMap(null, value1, true); - expect(map1).toEqual([value1, 'font-size', '50px', 'padding-top-left', '20px']); - }); - }); -}); - -function createAndAssertValues(newValue: any, entries: any[]) { - const result = createMap(null, newValue); - expect(result).toEqual([newValue, ...entries]); -} diff --git a/packages/core/test/render3/styling_next/static_styling_spec.ts b/packages/core/test/render3/styling_next/static_styling_spec.ts new file mode 100644 index 0000000000..d9e5d8f2fa --- /dev/null +++ b/packages/core/test/render3/styling_next/static_styling_spec.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 {createTNode} from '@angular/core/src/render3/instructions/shared'; +import {AttributeMarker, TAttributes, TNode, TNodeType} from '@angular/core/src/render3/interfaces/node'; +import {LView} from '@angular/core/src/render3/interfaces/view'; +import {enterView} from '@angular/core/src/render3/state'; +import {computeStaticStyling} from '@angular/core/src/render3/styling/static_styling'; + +describe('static styling', () => { + const mockFirstCreatePassLView: LView = [null, {firstCreatePass: true}] as any; + let tNode !: TNode; + beforeEach(() => { + enterView(mockFirstCreatePassLView, null); + tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + }); + it('should initialize when no attrs', () => { + computeStaticStyling(tNode, []); + expect(tNode.classes).toEqual(null); + expect(tNode.styles).toEqual(null); + }); + + it('should initialize from attrs', () => { + const tAttrs: TAttributes = [ + 'ignore', // + AttributeMarker.Classes, 'my-class', // + AttributeMarker.Styles, 'color', 'red' // + ]; + computeStaticStyling(tNode, tAttrs); + expect(tNode.classes).toEqual('my-class'); + expect(tNode.styles).toEqual('color: red;'); + }); + + it('should initialize from attrs when multiple', () => { + const tAttrs: TAttributes = [ + 'ignore', // + AttributeMarker.Classes, 'my-class', 'other', // + AttributeMarker.Styles, 'color', 'red', 'width', '100px' // + ]; + computeStaticStyling(tNode, tAttrs); + expect(tNode.classes).toEqual('my-class other'); + expect(tNode.styles).toEqual('color: red; width: 100px;'); + }); +}); \ No newline at end of file diff --git a/packages/core/test/render3/styling_next/style_binding_list_spec.ts b/packages/core/test/render3/styling_next/style_binding_list_spec.ts new file mode 100644 index 0000000000..d5e66cc0a5 --- /dev/null +++ b/packages/core/test/render3/styling_next/style_binding_list_spec.ts @@ -0,0 +1,494 @@ +/** + * @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 {createTNode} from '@angular/core/src/render3/instructions/shared'; +import {TNode, TNodeType} from '@angular/core/src/render3/interfaces/node'; +import {TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate} from '@angular/core/src/render3/interfaces/styling'; +import {LView, TData} from '@angular/core/src/render3/interfaces/view'; +import {enterView, leaveView} from '@angular/core/src/render3/state'; +import {insertTStylingBinding} from '@angular/core/src/render3/styling/style_binding_list'; +import {newArray} from '@angular/core/src/util/array_utils'; + +describe('TNode styling linked list', () => { + const mockFirstUpdatePassLView: LView = [null, {firstUpdatePass: true}] as any; + beforeEach(() => enterView(mockFirstUpdatePassLView, null)); + afterEach(() => leaveView()); + describe('insertTStylingBinding', () => { + it('should append template only', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tData: TData = [null, null]; + + insertTStylingBinding(tData, tNode, 'tmpl1', 2, false, true); + expectRange(tNode.classBindings).toEqual([2, 2]); + expectTData(tData).toEqual([ + null, null, // 0 + 'tmpl1', [false, 0, false, 0], // 2 + ]); + + insertTStylingBinding(tData, tNode, 'tmpl2', 4, false, true); + expectRange(tNode.classBindings).toEqual([2, 4]); + expectTData(tData).toEqual([ + null, null, // 0 + 'tmpl1', [false, 0, false, 4], // 2 + 'tmpl2', [false, 2, false, 0], // 4 + ]); + + insertTStylingBinding(tData, tNode, 'host1', 6, true, true); + expectRange(tNode.classBindings).toEqual([2, 4]); + expectTData(tData).toEqual([ + null, null, // 0 + 'tmpl1', [false, 6, false, 4], // 2 + 'tmpl2', [false, 2, false, 0], // 4 + 'host1', [false, 0, false, 2], // 6 + ]); + + insertTStylingBinding(tData, tNode, 'host2', 8, true, true); + expectRange(tNode.classBindings).toEqual([2, 4]); + expectTData(tData).toEqual([ + null, null, // 0 + 'tmpl1', [false, 8, false, 4], // 2 + 'tmpl2', [false, 2, false, 0], // 4 + 'host1', [false, 0, false, 8], // 6 + 'host2', [false, 6, false, 2], // 8 + ]); + }); + + it('should append host only', () => { + const tData: TData = [null, null]; + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + + insertTStylingBinding(tData, tNode, 'host1', 2, true, true); + expectRange(tNode.classBindings).toEqual([2, 0 /* no template binding */]); + expectTData(tData).toEqual([ + null, null, // 0 + 'host1', [false, 0, false, 0], // 2 + ]); + + insertTStylingBinding(tData, tNode, 'host2', 4, true, true); + expectRange(tNode.classBindings).toEqual([4, 0 /* no template binding */]); + expectTData(tData).toEqual([ + null, null, // 0 + 'host1', [false, 0, false, 4], // 2 + 'host2', [false, 2, false, 0], // 4 + ]); + }); + + it('should append template and host', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tData: TData = [null, null]; + + insertTStylingBinding(tData, tNode, 'tmpl1', 2, false, true); + expectRange(tNode.classBindings).toEqual([2, 2]); + expectTData(tData).toEqual([ + null, null, // 0 + 'tmpl1', [false, 0, false, 0], // 2 + ]); + + insertTStylingBinding(tData, tNode, 'host1', 4, true, true); + expectRange(tNode.classBindings).toEqual([2, 2]); + expectTData(tData).toEqual([ + null, null, // 0 + 'tmpl1', [false, 4, false, 0], // 2 + 'host1', [false, 0, false, 2], // 4 + ]); + }); + + it('should support example in \'tnode_linked_list.ts\' documentation', () => { + // See: `tnode_linked_list.ts` file description for this example. + // Template: (ExampleComponent) + // ɵɵstyleMap({color: '#001'}); // Binding index: 10 + // ɵɵstyleProp('color', '#002'); // Binding index: 12 + // MyComponent + // ɵɵstyleMap({color: '#003'}); // Binding index: 20 + // ɵɵstyleProp('color', '#004'); // Binding index: 22 + // Style1Directive + // ɵɵstyleMap({color: '#005'}); // Binding index: 24 + // ɵɵstyleProp('color', '#006'); // Binding index: 26 + // Style2Directive + // ɵɵstyleMap({color: '#007'}); // Binding index: 28 + // ɵɵstyleProp('color', '#008'); // Binding index: 30 + + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + tNode.styles = ''; + const tData: TData = newArray(32, null); + + insertTStylingBinding(tData, tNode, null, 10, false, false); + expectRange(tNode.styleBindings).toEqual([10, 10]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // + null, [false, 0, false, 0], // 10 - Template: ɵɵstyleMap({color: '#001'}); + null, null, // 12 + ...empty_14_through_19, // 14-19 + null, null, // 20 + null, null, // 22 + null, null, // 24 + null, null, // 26 + null, null, // 28 + null, null, // 30 + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [10, null, false, false], // 10 - Template: ɵɵstyleMap({color: '#001'}); + ]); + + + insertTStylingBinding(tData, tNode, 'color', 12, false, false); + expectRange(tNode.styleBindings).toEqual([10, 12]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // + null, [false, 0, false, 12], // 10 - Template: ɵɵstyleMap({color: '#001'}); + 'color', [false, 10, false, 0], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ...empty_14_through_19, // 14-19 + null, null, // 20 + null, null, // 22 + null, null, // 24 + null, null, // 26 + null, null, // 28 + null, null, // 30 + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [10, null, false, true], // 10 - Template: ɵɵstyleMap({color: '#001'}); + [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ]); + + insertTStylingBinding(tData, tNode, null, 20, true, false); + expectRange(tNode.styleBindings).toEqual([10, 12]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // + null, [false, 20, false, 12], // 10 - Template: ɵɵstyleMap({color: '#001'}); + 'color', [false, 10, false, 0], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ...empty_14_through_19, // 14-19 + null, [false, 0, false, 10], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + null, null, // 22 + null, null, // 24 + null, null, // 26 + null, null, // 28 + null, null, // 30 + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [20, null, false, true], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + [10, null, true, true], // 10 - Template: ɵɵstyleMap({color: '#001'}); + [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ]); + + insertTStylingBinding(tData, tNode, 'color', 22, true, false); + expectRange(tNode.styleBindings).toEqual([10, 12]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // 00-09 + null, [false, 22, false, 12], // 10 - Template: ɵɵstyleMap({color: '#001'}); + 'color', [false, 10, false, 0], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ...empty_14_through_19, // 14-19 + null, [false, 0, false, 22], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + 'color', [false, 20, false, 10], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + null, null, // 24 + null, null, // 26 + null, null, // 28 + null, null, // 30 + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [20, null, false, true], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + [22, 'color', true, true], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + [10, null, true, true], // 10 - Template: ɵɵstyleMap({color: '#001'}); + [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ]); + + insertTStylingBinding(tData, tNode, null, 24, true, false); + expectRange(tNode.styleBindings).toEqual([10, 12]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // + null, [false, 24, false, 12], // 10 - Template: ɵɵstyleMap({color: '#001'}); + 'color', [false, 10, false, 0], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ...empty_14_through_19, // 14-19 + null, [false, 0, false, 22], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + 'color', [false, 20, false, 24], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + null, [false, 22, false, 10], // 24 - Style1Directive: ɵɵstyleMap({color: '#003'}); + null, null, // 26 + null, null, // 28 + null, null, // 30 + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [20, null, false, true], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + [22, 'color', true, true], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + [24, null, true, true], // 24 - Style1Directive: ɵɵstyleMap({color: '#003'}); + [10, null, true, true], // 10 - Template: ɵɵstyleMap({color: '#001'}); + [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ]); + + insertTStylingBinding(tData, tNode, 'color', 26, true, false); + expectRange(tNode.styleBindings).toEqual([10, 12]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // 00-09 + null, [false, 26, false, 12], // 10 - Template: ɵɵstyleMap({color: '#001'}); + 'color', [false, 10, false, 0], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ...empty_14_through_19, // 14-19 + null, [false, 0, false, 22], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + 'color', [false, 20, false, 24], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + null, [false, 22, false, 26], // 24 - Style1Directive: ɵɵstyleMap({color: '#005'}); + 'color', [false, 24, false, 10], // 26 - Style1Directive: ɵɵstyleProp('color', '#006'}); + null, null, // 28 + null, null, // 30 + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [20, null, false, true], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + [22, 'color', true, true], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + [24, null, true, true], // 24 - Style1Directive: ɵɵstyleMap({color: '#003'}); + [26, 'color', true, true], // 26 - Style1Directive: ɵɵstyleProp('color', '#006'}); + [10, null, true, true], // 10 - Template: ɵɵstyleMap({color: '#001'}); + [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ]); + + + insertTStylingBinding(tData, tNode, null, 28, true, false); + expectRange(tNode.styleBindings).toEqual([10, 12]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // + null, [false, 28, false, 12], // 10 - Template: ɵɵstyleMap({color: '#001'}); + 'color', [false, 10, false, 0], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ...empty_14_through_19, // 14-19 + null, [false, 0, false, 22], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + 'color', [false, 20, false, 24], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + null, [false, 22, false, 26], // 24 - Style1Directive: ɵɵstyleMap({color: '#005'}); + 'color', [false, 24, false, 28], // 26 - Style1Directive: ɵɵstyleProp('color', '#006'}); + null, [false, 26, false, 10], // 28 - Style2Directive: ɵɵstyleMap({color: '#007'}); + null, null, // 30 + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [20, null, false, true], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + [22, 'color', true, true], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + [24, null, true, true], // 24 - Style1Directive: ɵɵstyleMap({color: '#003'}); + [26, 'color', true, true], // 26 - Style1Directive: ɵɵstyleProp('color', '#006'}); + [28, null, true, true], // 28 - Style2Directive: ɵɵstyleMap({color: '#007'}); + [10, null, true, true], // 10 - Template: ɵɵstyleMap({color: '#001'}); + [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ]); + + insertTStylingBinding(tData, tNode, 'color', 30, true, false); + expectRange(tNode.styleBindings).toEqual([10, 12]); + expectTData(tData).toEqual([ + ...empty_0_through_9, // 00-09 + null, [false, 30, false, 12], // 10 - Template: ɵɵstyleMap({color: '#001'}); + 'color', [false, 10, false, 0], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ...empty_14_through_19, // 14-19 + null, [false, 0, false, 22], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + 'color', [false, 20, false, 24], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + null, [false, 22, false, 26], // 24 - Style1Directive: ɵɵstyleMap({color: '#005'}); + 'color', [false, 24, false, 28], // 26 - Style1Directive: ɵɵstyleProp('color', '#006'}); + null, [false, 26, false, 30], // 28 - Style2Directive: ɵɵstyleMap({color: '#007'}); + 'color', [false, 28, false, 10], // 30 - Style2Directive: ɵɵstyleProp('color', '#008'}); + ]); + expectPriorityOrder(tData, tNode, false).toEqual([ + [20, null, false, true], // 20 - MyComponent: ɵɵstyleMap({color: '#003'}); + [22, 'color', true, true], // 22 - MyComponent: ɵɵstyleProp('color', '#004'}); + [24, null, true, true], // 24 - Style1Directive: ɵɵstyleMap({color: '#005'}); + [26, 'color', true, true], // 26 - Style1Directive: ɵɵstyleProp('color', '#006'}); + [28, null, true, true], // 28 - Style2Directive: ɵɵstyleMap({color: '#007'}); + [30, 'color', true, true], // 30 - Style2Directive: ɵɵstyleProp('color', '#008'}); + [10, null, true, true], // 10 - Template: ɵɵstyleMap({color: '#001'}); + [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); + ]); + }); + + }); + + describe('markDuplicates', () => { + it('should not mark items as duplicate if names don\'t match', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tData: TData = [null, null]; + insertTStylingBinding(tData, tNode, 'color', 2, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'color', false, false], + ]); + + insertTStylingBinding(tData, tNode, 'width', 4, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'color', false, false], + [4, 'width', false, false], + ]); + + insertTStylingBinding(tData, tNode, 'height', 6, true, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [6, 'height', false, false], + [2, 'color', false, false], + [4, 'width', false, false], + ]); + }); + + it('should mark items as duplicate if names match', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tData: TData = [null, null]; + insertTStylingBinding(tData, tNode, 'color', 2, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'color', false, false], + ]); + insertTStylingBinding(tData, tNode, 'color', 4, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'color', false, true], + [4, 'color', true, false], + ]); + + insertTStylingBinding(tData, tNode, 'height', 6, true, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [6, 'height', false, false], + [2, 'color', false, true], + [4, 'color', true, false], + ]); + }); + + it('should treat maps as matching all', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tData: TData = [null, null]; + insertTStylingBinding(tData, tNode, 'color', 2, false, false); + insertTStylingBinding(tData, tNode, 'height', 4, true, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [4, 'height', false, false], + [2, 'color', false, false], + ]); + + insertTStylingBinding(tData, tNode, null /*Map*/, 6, true, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [4, 'height', false, true], + [6, null, true, true], + [2, 'color', true, false], + ]); + }); + + it('should mark all things after map as duplicate', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tData: TData = [null, null]; + insertTStylingBinding(tData, tNode, null, 2, false, false); + insertTStylingBinding(tData, tNode, 'height', 4, false, false); + insertTStylingBinding(tData, tNode, 'color', 6, true, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [6, 'color', false, true], + [2, null, true, true], + [4, 'height', true, false], + ]); + }); + + it('should mark duplicate on complex objects like width.px', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tData: TData = [null, null]; + insertTStylingBinding(tData, tNode, 'width', 2, false, false); + insertTStylingBinding(tData, tNode, 'height', 4, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'width', false, false], + [4, 'height', false, false], + ]); + insertTStylingBinding(tData, tNode, 'height', 6, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'width', false, false], + [4, 'height', false, true], + [6, 'height', true, false], + ]); + insertTStylingBinding(tData, tNode, 'width', 8, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'width', false, true], + [4, 'height', false, true], + [6, 'height', true, false], + [8, 'width', true, false], + ]); + }); + + it('should mark duplicate on static fields', () => { + const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + tNode.residualStyles = ['color', 'blue'] as any; + const tData: TData = [null, null]; + insertTStylingBinding(tData, tNode, 'width', 2, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'width', false, false], + ]); + + insertTStylingBinding(tData, tNode, 'color', 4, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'width', false, false], + [4, 'color', false, true], + ]); + + insertTStylingBinding(tData, tNode, null, 6, false, false); + expectPriorityOrder(tData, tNode, false).toEqual([ + // PREV, NEXT + [2, 'width', false, true], + [4, 'color', false, true], + [6, null, true, false], + ]); + }); + }); + +}); + +const empty_0_through_9 = [null, null, null, null, null, null, null, null, null, null]; +const empty_14_through_19 = [null, null, null, null, null, null]; + +function expectRange(tStylingRange: TStylingRange) { + return expect([ + getTStylingRangePrev(tStylingRange), // + getTStylingRangeNext(tStylingRange), // + ]); +} + +function expectTData(tData: TData) { + return expect(tData.map((tStylingRange: any) => { + return typeof tStylingRange === 'number' ? + [ + false, + getTStylingRangePrev(tStylingRange as any), // + false, + getTStylingRangeNext(tStylingRange as any), // + ] : + tStylingRange; + })); +} + +function expectPriorityOrder(tData: TData, tNode: TNode, isClassBinding: boolean) { + // first find head. + let index = getStylingBindingHead(tData, tNode, isClassBinding); + const indexes: [number, string | null, boolean, boolean][] = []; + while (index !== 0) { + let key = tData[index] as TStylingKey | null; + const tStylingRange = tData[index + 1] as TStylingRange; + indexes.push([ + index, // + key as string, // + getTStylingRangePrevDuplicate(tStylingRange), // + getTStylingRangeNextDuplicate(tStylingRange), // + ]); + index = getTStylingRangeNext(tStylingRange); + } + return expect(indexes); +} + + +/** + * Find the head of the styling binding linked list. + */ +export function getStylingBindingHead(tData: TData, tNode: TNode, isClassBinding: boolean): number { + let index = getTStylingRangePrev(isClassBinding ? tNode.classBindings : tNode.styleBindings); + while (true) { + const tStylingRange = tData[index + 1] as TStylingRange; + const prev = getTStylingRangePrev(tStylingRange); + if (prev === 0) { + // found head exit. + return index; + } else { + index = prev; + } + } +} \ No newline at end of file diff --git a/packages/core/test/render3/styling_next/styling_context_spec.ts b/packages/core/test/render3/styling_next/styling_context_spec.ts deleted file mode 100644 index 89e914cbca..0000000000 --- a/packages/core/test/render3/styling_next/styling_context_spec.ts +++ /dev/null @@ -1,136 +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 {TStylingContext, TStylingNode} from '@angular/core/src/render3/interfaces/styling'; -import {registerBinding as _registerBinding} from '@angular/core/src/render3/styling/bindings'; -import {attachStylingDebugObject} from '@angular/core/src/render3/styling/styling_debug'; - -import {DEFAULT_GUARD_MASK_VALUE, allocTStylingContext} from '../../../src/render3/util/styling_utils'; - -function registerBinding( - context: TStylingContext, countId: number, sourceIndex: number, prop: string | null, - value: any) { - let tNode: TStylingNode = (context as any).tNode; - if (!tNode) { - tNode = (context as any).tNode = {flags: 0}; - } - _registerBinding(context, tNode, countId, sourceIndex, prop, value, false, false); -} - -describe('styling context', () => { - it('should register a series of entries into the context', () => { - const debug = makeContextWithDebug(false); - const context = debug.context; - expect(debug.entries).toEqual({}); - - registerBinding(context, 1, 0, 'width', '100px'); - expect(debug.entries['width']).toEqual({ - prop: 'width', - valuesCount: 1, - sanitizationRequired: false, - templateBitMask: buildGuardMask(), - hostBindingsBitMask: buildGuardMask(), - defaultValue: '100px', - sources: ['100px'], - }); - - registerBinding(context, 2, 0, 'width', 20); - expect(debug.entries['width']).toEqual({ - prop: 'width', - sanitizationRequired: false, - valuesCount: 2, - templateBitMask: buildGuardMask(2), - hostBindingsBitMask: buildGuardMask(), - defaultValue: '100px', - sources: [20, '100px'], - }); - - registerBinding(context, 3, 0, 'height', 10); - registerBinding(context, 4, 1, 'height', 15); - expect(debug.entries['height']).toEqual({ - prop: 'height', - valuesCount: 3, - sanitizationRequired: false, - templateBitMask: buildGuardMask(3), - hostBindingsBitMask: buildGuardMask(4), - defaultValue: null, - sources: [10, 15, null], - }); - }); - - it('should only register the same binding index once per property', () => { - const debug = makeContextWithDebug(false); - const context = debug.context; - expect(debug.entries).toEqual({}); - - registerBinding(context, 1, 0, 'width', 123); - registerBinding(context, 1, 0, 'width', 123); - expect(debug.entries['width']).toEqual({ - prop: 'width', - valuesCount: 2, - sanitizationRequired: false, - templateBitMask: buildGuardMask(1), - hostBindingsBitMask: buildGuardMask(), - defaultValue: null, - sources: [123, null], - }); - }); - - it('should overwrite a default value for an entry only if it is non-null', () => { - const debug = makeContextWithDebug(false); - const context = debug.context; - - registerBinding(context, 1, 0, 'width', null); - const x = debug.entries['width']; - expect(debug.entries['width']).toEqual({ - prop: 'width', - valuesCount: 1, - sanitizationRequired: false, - templateBitMask: buildGuardMask(), - hostBindingsBitMask: buildGuardMask(), - defaultValue: null, - sources: [null] - }); - - registerBinding(context, 1, 0, 'width', '100px'); - expect(debug.entries['width']).toEqual({ - prop: 'width', - valuesCount: 1, - sanitizationRequired: false, - templateBitMask: buildGuardMask(), - hostBindingsBitMask: buildGuardMask(), - defaultValue: '100px', - sources: ['100px'] - }); - - registerBinding(context, 1, 0, 'width', '200px'); - expect(debug.entries['width']).toEqual({ - prop: 'width', - valuesCount: 1, - sanitizationRequired: false, - templateBitMask: buildGuardMask(), - hostBindingsBitMask: buildGuardMask(), - defaultValue: '100px', - sources: ['100px'] - }); - }); -}); - -function makeContextWithDebug(isClassBased: boolean) { - const ctx = allocTStylingContext(null, false); - const tNode: TStylingNode = {flags: 0}; - (ctx as any).tNode = ctx; - return attachStylingDebugObject(ctx, tNode, isClassBased); -} - -function buildGuardMask(...bindingIndices: number[]) { - let mask = DEFAULT_GUARD_MASK_VALUE; - for (let i = 0; i < bindingIndices.length; i++) { - mask |= 1 << bindingIndices[i]; - } - return mask; -} diff --git a/packages/core/test/render3/styling_next/styling_debug_spec.ts b/packages/core/test/render3/styling_next/styling_debug_spec.ts deleted file mode 100644 index 75cdf5decf..0000000000 --- a/packages/core/test/render3/styling_next/styling_debug_spec.ts +++ /dev/null @@ -1,85 +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 {TStylingNode} from '@angular/core/src/render3/interfaces/styling'; -import {registerBinding} from '@angular/core/src/render3/styling/bindings'; -import {NodeStylingDebug, attachStylingDebugObject} from '@angular/core/src/render3/styling/styling_debug'; -import {allocTStylingContext} from '@angular/core/src/render3/util/styling_utils'; - -describe('styling debugging tools', () => { - describe('NodeStylingDebug', () => { - it('should list out each of the values in the context paired together with the provided data', - () => { - if (isIE()) return; - - const values = makeContextWithDebug(false); - const context = values.context; - const tNode = values.tNode; - - const data: any[] = []; - const d = new NodeStylingDebug(context, tNode, data, false); - - registerBinding(context, tNode, 0, 0, 'width', null, false, false); - expect(d.summary).toEqual({ - width: { - prop: 'width', - value: null, - bindingIndex: null, - }, - }); - - registerBinding(context, tNode, 0, 0, 'width', '100px', false, false); - expect(d.summary).toEqual({ - width: { - prop: 'width', - value: '100px', - bindingIndex: null, - }, - }); - - const someBindingIndex1 = 1; - data[someBindingIndex1] = '200px'; - - registerBinding(context, tNode, 0, 0, 'width', someBindingIndex1, false, false); - expect(d.summary).toEqual({ - width: { - prop: 'width', - value: '200px', - bindingIndex: someBindingIndex1, - }, - }); - - const someBindingIndex2 = 2; - data[someBindingIndex2] = '500px'; - - registerBinding(context, tNode, 0, 1, 'width', someBindingIndex2, false, false); - expect(d.summary).toEqual({ - width: { - prop: 'width', - value: '200px', - bindingIndex: someBindingIndex1, - }, - }); - }); - }); -}); - -function makeContextWithDebug(isClassBased: boolean) { - const context = allocTStylingContext(null, false); - const tNode = createTStylingNode(); - attachStylingDebugObject(context, tNode, isClassBased); - return {context, tNode}; -} - -function createTStylingNode(): TStylingNode { - return {flags: 0}; -} - -function isIE() { - // note that this only applies to older IEs (not edge) - return typeof window !== 'undefined' && (window as any).document['documentMode'] ? true : false; -} diff --git a/packages/core/test/render3/util/attr_util_spec.ts b/packages/core/test/render3/util/attr_util_spec.ts new file mode 100644 index 0000000000..a3fb25542f --- /dev/null +++ b/packages/core/test/render3/util/attr_util_spec.ts @@ -0,0 +1,119 @@ +/** + * @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 {AttributeMarker} from '@angular/core/src/render3'; +import {TAttributes} from '@angular/core/src/render3/interfaces/node'; +import {mergeHostAttribute, mergeHostAttrs} from '@angular/core/src/render3/util/attrs_utils'; +import {describe} from '@angular/core/testing/src/testing_internal'; + +describe('attr_util', () => { + describe('mergeHostAttribute', () => { + it('should add new attributes', () => { + const attrs: TAttributes = []; + mergeHostAttribute(attrs, -1, 'Key', null, 'value'); + expect(attrs).toEqual(['Key', 'value']); + + mergeHostAttribute(attrs, -1, 'A', null, 'a'); + expect(attrs).toEqual(['Key', 'value', 'A', 'a']); + + mergeHostAttribute(attrs, -1, 'X', null, 'x'); + expect(attrs).toEqual(['Key', 'value', 'A', 'a', 'X', 'x']); + + mergeHostAttribute(attrs, -1, 'Key', null, 'new'); + expect(attrs).toEqual(['Key', 'new', 'A', 'a', 'X', 'x']); + }); + + it('should add new classes', () => { + const attrs: TAttributes = []; + mergeHostAttribute(attrs, AttributeMarker.Classes, 'CLASS', null, null); + expect(attrs).toEqual([AttributeMarker.Classes, 'CLASS']); + + mergeHostAttribute(attrs, AttributeMarker.Classes, 'A', null, null); + expect(attrs).toEqual([AttributeMarker.Classes, 'CLASS', 'A']); + + mergeHostAttribute(attrs, AttributeMarker.Classes, 'X', null, null); + expect(attrs).toEqual([AttributeMarker.Classes, 'CLASS', 'A', 'X']); + + mergeHostAttribute(attrs, AttributeMarker.Classes, 'CLASS', null, null); + expect(attrs).toEqual([AttributeMarker.Classes, 'CLASS', 'A', 'X']); + }); + + it('should add new styles', () => { + const attrs: TAttributes = []; + mergeHostAttribute(attrs, AttributeMarker.Styles, 'Style', null, 'v1'); + expect(attrs).toEqual([AttributeMarker.Styles, 'Style', 'v1']); + + mergeHostAttribute(attrs, AttributeMarker.Styles, 'A', null, 'v2'); + expect(attrs).toEqual([AttributeMarker.Styles, 'Style', 'v1', 'A', 'v2']); + + mergeHostAttribute(attrs, AttributeMarker.Styles, 'X', null, 'v3'); + expect(attrs).toEqual([AttributeMarker.Styles, 'Style', 'v1', 'A', 'v2', 'X', 'v3']); + + mergeHostAttribute(attrs, AttributeMarker.Styles, 'Style', null, 'new'); + expect(attrs).toEqual([AttributeMarker.Styles, 'Style', 'new', 'A', 'v2', 'X', 'v3']); + }); + + it('should keep different types together', () => { + const attrs: TAttributes = []; + mergeHostAttribute(attrs, -1, 'Key', null, 'value'); + expect(attrs).toEqual(['Key', 'value']); + + mergeHostAttribute(attrs, AttributeMarker.Classes, 'CLASS', null, null); + expect(attrs).toEqual(['Key', 'value', AttributeMarker.Classes, 'CLASS']); + + mergeHostAttribute(attrs, AttributeMarker.Styles, 'Style', null, 'v1'); + expect(attrs).toEqual([ + 'Key', 'value', AttributeMarker.Classes, 'CLASS', AttributeMarker.Styles, 'Style', 'v1' + ]); + + mergeHostAttribute(attrs, -1, 'Key2', null, 'value2'); + expect(attrs).toEqual([ + 'Key', 'value', 'Key2', 'value2', AttributeMarker.Classes, 'CLASS', AttributeMarker.Styles, + 'Style', 'v1' + ]); + + mergeHostAttribute(attrs, AttributeMarker.Classes, 'CLASS2', null, null); + expect(attrs).toEqual([ + 'Key', 'value', 'Key2', 'value2', AttributeMarker.Classes, 'CLASS', 'CLASS2', + AttributeMarker.Styles, 'Style', 'v1' + ]); + + mergeHostAttribute(attrs, AttributeMarker.Styles, 'Style2', null, 'v2'); + expect(attrs).toEqual([ + 'Key', 'value', 'Key2', 'value2', AttributeMarker.Classes, 'CLASS', 'CLASS2', + AttributeMarker.Styles, 'Style', 'v1', 'Style2', 'v2' + ]); + + mergeHostAttribute(attrs, AttributeMarker.NamespaceURI, 'uri', 'key', 'value'); + expect(attrs).toEqual([ + 'Key', 'value', 'Key2', 'value2', AttributeMarker.NamespaceURI, 'uri', 'key', 'value', + AttributeMarker.Classes, 'CLASS', 'CLASS2', AttributeMarker.Styles, 'Style', 'v1', 'Style2', + 'v2' + ]); + mergeHostAttribute(attrs, AttributeMarker.NamespaceURI, 'uri', 'key', 'new value'); + expect(attrs).toEqual([ + 'Key', 'value', 'Key2', 'value2', AttributeMarker.NamespaceURI, 'uri', 'key', 'new value', + AttributeMarker.Classes, 'CLASS', 'CLASS2', AttributeMarker.Styles, 'Style', 'v1', 'Style2', + 'v2' + ]); + }); + }); + + describe('mergeHostAttrs', () => { + it('should ignore nulls/empty', () => { + expect(mergeHostAttrs(null, null)).toEqual(null); + expect(mergeHostAttrs([], null)).toEqual([]); + expect(mergeHostAttrs(null, [])).toEqual(null); + }); + + it('should copy if dst is null', () => { + expect(mergeHostAttrs(null, ['K', 'v'])).toEqual(['K', 'v']); + expect(mergeHostAttrs(['K', '', 'X', 'x'], ['K', 'v'])).toEqual(['K', 'v', 'X', 'x']); + }); + }); +}); \ No newline at end of file diff --git a/packages/core/test/render3/util/styling_utils_spec.ts b/packages/core/test/render3/util/styling_utils_spec.ts deleted file mode 100644 index 3267e680ce..0000000000 --- a/packages/core/test/render3/util/styling_utils_spec.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 - */ - -import {splitOnWhitespace} from '@angular/core/src/render3/util/styling_utils'; - -describe('styling_utils', () => { - describe('splitOnWhitespace', () => { - it('should treat empty strings as null', () => { - expect(splitOnWhitespace('')).toEqual(null); - expect(splitOnWhitespace(' ')).toEqual(null); - expect(splitOnWhitespace(' \n\r\t ')).toEqual(null); - }); - - it('should split strings into parts', () => { - expect(splitOnWhitespace('a\nb\rc')).toEqual(['a', 'b', 'c']); - expect(splitOnWhitespace('\ta-long\nb-long\rc-long ')).toEqual([ - 'a-long', 'b-long', 'c-long' - ]); - }); - }); -}); \ No newline at end of file diff --git a/packages/core/test/strict_types/BUILD.bazel b/packages/core/test/strict_types/BUILD.bazel index ca42c4422d..3af746a341 100644 --- a/packages/core/test/strict_types/BUILD.bazel +++ b/packages/core/test/strict_types/BUILD.bazel @@ -27,6 +27,5 @@ jasmine_node_test( name = "strict_types", deps = [ ":strict_types_lib", - "//tools/testing:node", ], ) diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 2c28381644..1f064d1833 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -345,13 +345,19 @@ describe('TestBed', () => { describe('multi providers', () => { const multiToken = new InjectionToken('multiToken'); const singleToken = new InjectionToken('singleToken'); + const multiTokenToOverrideAtModuleLevel = + new InjectionToken('moduleLevelMultiOverride'); @NgModule({providers: [{provide: multiToken, useValue: 'valueFromModule', multi: true}]}) class MyModule { } @NgModule({ providers: [ - {provide: singleToken, useValue: 't1'}, + {provide: singleToken, useValue: 't1'}, { + provide: multiTokenToOverrideAtModuleLevel, + useValue: 'multiTokenToOverrideAtModuleLevelOriginal', + multi: true + }, {provide: multiToken, useValue: 'valueFromModule2', multi: true}, {provide: multiToken, useValue: 'secondValueFromModule2', multi: true} ] @@ -361,14 +367,23 @@ describe('TestBed', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MyModule, MyModule2], + imports: [ + MyModule, { + ngModule: MyModule2, + providers: + [{provide: multiTokenToOverrideAtModuleLevel, useValue: 'override', multi: true}] + } + ], }); }); it('is preserved when other provider is overridden', () => { TestBed.overrideProvider(singleToken, {useValue: ''}); - const value = TestBed.inject(multiToken); - expect(value.length).toEqual(3); + expect(TestBed.inject(multiToken).length).toEqual(3); + expect(TestBed.inject(multiTokenToOverrideAtModuleLevel).length).toEqual(2); + expect(TestBed.inject(multiTokenToOverrideAtModuleLevel)).toEqual([ + 'multiTokenToOverrideAtModuleLevelOriginal', 'override' + ]); }); it('overridden with an array', () => { diff --git a/packages/core/test/util/array_utils_spec.ts b/packages/core/test/util/array_utils_spec.ts index 9754b10f1b..5d2fdd6cef 100644 --- a/packages/core/test/util/array_utils_spec.ts +++ b/packages/core/test/util/array_utils_spec.ts @@ -6,20 +6,173 @@ * found in the LICENSE file at https://angular.io/license */ -import {flatten} from '../../src/util/array_utils'; +import {KeyValueArray, arrayIndexOfSorted, arrayInsert, arrayInsert2, arrayInsertSorted, arrayRemoveSorted, arraySplice, flatten, keyValueArrayDelete, keyValueArrayGet, keyValueArrayIndexOf, keyValueArraySet} from '../../src/util/array_utils'; -describe('flatten', () => { +describe('array_utils', () => { - it('should flatten an empty array', () => { expect(flatten([])).toEqual([]); }); + describe('flatten', () => { - it('should flatten a flat array', () => { expect(flatten([1, 2, 3])).toEqual([1, 2, 3]); }); + it('should flatten an empty array', () => { expect(flatten([])).toEqual([]); }); - it('should flatten a nested array depth-first', () => { - expect(flatten([1, [2], 3])).toEqual([1, 2, 3]); - expect(flatten([[1], 2, [3]])).toEqual([1, 2, 3]); - expect(flatten([1, [2, [3]], 4])).toEqual([1, 2, 3, 4]); - expect(flatten([1, [2, [3]], [4]])).toEqual([1, 2, 3, 4]); - expect(flatten([1, [2, [3]], [[[4]]]])).toEqual([1, 2, 3, 4]); - expect(flatten([1, [], 2])).toEqual([1, 2]); + it('should flatten a flat array', () => { expect(flatten([1, 2, 3])).toEqual([1, 2, 3]); }); + + it('should flatten a nested array depth-first', () => { + expect(flatten([1, [2], 3])).toEqual([1, 2, 3]); + expect(flatten([[1], 2, [3]])).toEqual([1, 2, 3]); + expect(flatten([1, [2, [3]], 4])).toEqual([1, 2, 3, 4]); + expect(flatten([1, [2, [3]], [4]])).toEqual([1, 2, 3, 4]); + expect(flatten([1, [2, [3]], [[[4]]]])).toEqual([1, 2, 3, 4]); + expect(flatten([1, [], 2])).toEqual([1, 2]); + }); }); -}); \ No newline at end of file + + describe('fast arraySplice', () => { + function expectArraySplice(array: any[], index: number) { + arraySplice(array, index, 1); + return expect(array); + } + + it('should remove items', () => { + expectArraySplice([0, 1, 2], 0).toEqual([1, 2]); + expectArraySplice([0, 1, 2], 1).toEqual([0, 2]); + expectArraySplice([0, 1, 2], 2).toEqual([0, 1]); + }); + }); + + describe('arrayInsertSorted', () => { + function expectArrayInsert(array: any[], index: number, value: any) { + arrayInsert(array, index, value); + return expect(array); + } + + function expectArrayInsert2(array: any[], index: number, value1: any, value2: any) { + arrayInsert2(array, index, value1, value2); + return expect(array); + } + + it('should insert items', () => { + expectArrayInsert([], 0, 'A').toEqual(['A']); + expectArrayInsert([0], 0, 'A').toEqual(['A', 0]); + expectArrayInsert([0], 1, 'A').toEqual([0, 'A']); + expectArrayInsert([0, 1, 2], 0, 'A').toEqual(['A', 0, 1, 2]); + expectArrayInsert([0, 1, 2], 1, 'A').toEqual([0, 'A', 1, 2]); + expectArrayInsert([0, 1, 2], 2, 'A').toEqual([0, 1, 'A', 2]); + expectArrayInsert([0, 1, 2], 3, 'A').toEqual([0, 1, 2, 'A']); + }); + + it('should insert items', () => { + expectArrayInsert2([], 0, 'A', 'B').toEqual(['A', 'B']); + expectArrayInsert2([0], 0, 'A', 'B').toEqual(['A', 'B', 0]); + expectArrayInsert2([0], 1, 'A', 'B').toEqual([0, 'A', 'B']); + expectArrayInsert2([0, 1, 2], 0, 'A', 'B').toEqual(['A', 'B', 0, 1, 2]); + expectArrayInsert2([0, 1, 2], 1, 'A', 'B').toEqual([0, 'A', 'B', 1, 2]); + expectArrayInsert2([0, 1, 2], 2, 'A', 'B').toEqual([0, 1, 'A', 'B', 2]); + expectArrayInsert2([0, 1, 2], 3, 'A', 'B').toEqual([0, 1, 2, 'A', 'B']); + expectArrayInsert2(['height', '1px', 'width', '2000px'], 0, 'color', 'red').toEqual([ + 'color', 'red', 'height', '1px', 'width', '2000px' + ]); + }); + }); + + describe('arrayInsertSorted', () => { + + it('should insert items don\'t allow duplicates', () => { + let a; + a = ['a', 'c', 'e', 'g', 'i']; + expect(arrayInsertSorted(a, 'a')).toEqual(0); + expect(a).toEqual(['a', 'c', 'e', 'g', 'i']); + + a = ['a', 'c', 'e', 'g', 'i']; + expect(arrayInsertSorted(a, 'b')).toEqual(1); + expect(a).toEqual(['a', 'b', 'c', 'e', 'g', 'i']); + + a = ['a', 'c', 'e', 'g', 'i']; + expect(arrayInsertSorted(a, 'c')).toEqual(1); + expect(a).toEqual(['a', 'c', 'e', 'g', 'i']); + + a = ['a', 'c', 'e', 'g', 'i']; + expect(arrayInsertSorted(a, 'd')).toEqual(2); + expect(a).toEqual(['a', 'c', 'd', 'e', 'g', 'i']); + + a = ['a', 'c', 'e', 'g', 'i']; + expect(arrayInsertSorted(a, 'e')).toEqual(2); + expect(a).toEqual(['a', 'c', 'e', 'g', 'i']); + }); + }); + + + + describe('arrayRemoveSorted', () => { + + it('should remove items', () => { + let a; + a = ['a', 'b', 'c', 'd', 'e']; + expect(arrayRemoveSorted(a, 'a')).toEqual(0); + expect(a).toEqual(['b', 'c', 'd', 'e']); + + a = ['a', 'b', 'c', 'd', 'e']; + expect(arrayRemoveSorted(a, 'b')).toEqual(1); + expect(a).toEqual(['a', 'c', 'd', 'e']); + + a = ['a', 'b', 'c', 'd', 'e']; + expect(arrayRemoveSorted(a, 'c')).toEqual(2); + expect(a).toEqual(['a', 'b', 'd', 'e']); + + a = ['a', 'b', 'c', 'd', 'e']; + expect(arrayRemoveSorted(a, 'd')).toEqual(3); + expect(a).toEqual(['a', 'b', 'c', 'e']); + + a = ['a', 'b', 'c', 'd', 'e']; + expect(arrayRemoveSorted(a, 'e')).toEqual(4); + expect(a).toEqual(['a', 'b', 'c', 'd']); + }); + }); + + + describe('arrayIndexOfSorted', () => { + it('should get index of', () => { + const a = ['a', 'b', 'c', 'd', 'e']; + expect(arrayIndexOfSorted(a, 'a')).toEqual(0); + expect(arrayIndexOfSorted(a, 'b')).toEqual(1); + expect(arrayIndexOfSorted(a, 'c')).toEqual(2); + expect(arrayIndexOfSorted(a, 'd')).toEqual(3); + expect(arrayIndexOfSorted(a, 'e')).toEqual(4); + }); + }); + + describe('KeyValueArray', () => { + it('should support basic operations', () => { + const map: KeyValueArray = [] as any; + + expect(keyValueArrayIndexOf(map, 'A')).toEqual(~0); + + expect(keyValueArraySet(map, 'B', 1)).toEqual(0); + expect(map).toEqual(['B', 1]); + expect(keyValueArrayIndexOf(map, 'B')).toEqual(0); + + expect(keyValueArraySet(map, 'A', 0)).toEqual(0); + expect(map).toEqual(['A', 0, 'B', 1]); + expect(keyValueArrayIndexOf(map, 'B')).toEqual(2); + expect(keyValueArrayIndexOf(map, 'AA')).toEqual(~2); + + expect(keyValueArraySet(map, 'C', 2)).toEqual(4); + expect(map).toEqual(['A', 0, 'B', 1, 'C', 2]); + + expect(keyValueArrayGet(map, 'A')).toEqual(0); + expect(keyValueArrayGet(map, 'B')).toEqual(1); + expect(keyValueArrayGet(map, 'C')).toEqual(2); + expect(keyValueArrayGet(map, 'AA')).toEqual(undefined); + + expect(keyValueArraySet(map, 'B', -1)).toEqual(2); + expect(map).toEqual(['A', 0, 'B', -1, 'C', 2]); + + expect(keyValueArrayDelete(map, 'AA')).toEqual(~2); + expect(keyValueArrayDelete(map, 'B')).toEqual(2); + expect(map).toEqual(['A', 0, 'C', 2]); + expect(keyValueArrayDelete(map, 'A')).toEqual(0); + expect(map).toEqual(['C', 2]); + expect(keyValueArrayDelete(map, 'C')).toEqual(0); + expect(map).toEqual([]); + }); + }); +}); diff --git a/packages/core/test/util/stringify_spec.ts b/packages/core/test/util/stringify_spec.ts new file mode 100644 index 0000000000..e5ce710f6c --- /dev/null +++ b/packages/core/test/util/stringify_spec.ts @@ -0,0 +1,27 @@ +/** + * @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 {concatStringsWithSpace} from '@angular/core/src/util/stringify'; + +describe('stringify', () => { + describe('concatStringsWithSpace', () => { + it('should concat with null', () => { + expect(concatStringsWithSpace(null, null)).toEqual(''); + expect(concatStringsWithSpace('a', null)).toEqual('a'); + expect(concatStringsWithSpace(null, 'b')).toEqual('b'); + }); + + it('should concat when empty', () => { + expect(concatStringsWithSpace('', '')).toEqual(''); + expect(concatStringsWithSpace('a', '')).toEqual('a'); + expect(concatStringsWithSpace('', 'b')).toEqual('b'); + }); + + it('should concat when not empty', + () => { expect(concatStringsWithSpace('before', 'after')).toEqual('before after'); }); + }); +}); diff --git a/packages/core/test/view/BUILD.bazel b/packages/core/test/view/BUILD.bazel index 481f1bcdf1..1c7e919622 100644 --- a/packages/core/test/view/BUILD.bazel +++ b/packages/core/test/view/BUILD.bazel @@ -34,14 +34,13 @@ ts_library( jasmine_node_test( name = "view", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], tags = [ "no-ivy-aot", ], deps = [ ":view_lib", ":view_node_only_lib", - "//tools/testing:node", ], ) diff --git a/packages/core/testing/src/r3_test_bed.ts b/packages/core/testing/src/r3_test_bed.ts index 3f4b285e57..6a749280fe 100644 --- a/packages/core/testing/src/r3_test_bed.ts +++ b/packages/core/testing/src/r3_test_bed.ts @@ -351,6 +351,10 @@ export class TestBedRender3 implements TestBed { return fixture; } + /** + * @internal strip this from published d.ts files due to + * https://github.com/microsoft/TypeScript/issues/36216 + */ private get compiler(): R3TestBedCompiler { if (this._compiler === null) { throw new Error(`Need to call TestBed.initTestEnvironment() first`); @@ -358,6 +362,10 @@ export class TestBedRender3 implements TestBed { return this._compiler; } + /** + * @internal strip this from published d.ts files due to + * https://github.com/microsoft/TypeScript/issues/36216 + */ private get testModuleRef(): NgModuleRef { if (this._testModuleRef === null) { this._testModuleRef = this.compiler.finalize(); diff --git a/packages/core/testing/src/r3_test_bed_compiler.ts b/packages/core/testing/src/r3_test_bed_compiler.ts index f64995cf71..c4028b9ec1 100644 --- a/packages/core/testing/src/r3_test_bed_compiler.ts +++ b/packages/core/testing/src/r3_test_bed_compiler.ts @@ -394,15 +394,8 @@ export class R3TestBedCompiler { const injectorDef: any = (moduleType as any)[NG_INJ_DEF]; if (this.providerOverridesByToken.size > 0) { - // Extract the list of providers from ModuleWithProviders, so we can define the final list of - // providers that might have overrides. - // Note: second `flatten` operation is needed to convert an array of providers - // (e.g. `[[], []]`) into one flat list, also eliminating empty arrays. - const providersFromModules = flatten(flatten( - injectorDef.imports, (imported: NgModuleType| ModuleWithProviders) => - isModuleWithProviders(imported) ? imported.providers : [])); const providers = [ - ...providersFromModules, ...injectorDef.providers, + ...injectorDef.providers, ...(this.providerOverridesByModule.get(moduleType as InjectorType) || []) ]; if (this.hasProviderOverrides(providers)) { diff --git a/packages/core/testing/src/styling.ts b/packages/core/testing/src/styling.ts new file mode 100644 index 0000000000..dcb4ba904f --- /dev/null +++ b/packages/core/testing/src/styling.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 + */ + +/** + * Returns element classes in form of a stable (sorted) string. + * + * @param element HTML Element. + * @returns Returns element classes in form of a stable (sorted) string. + */ +export function getSortedClassName(element: Element): string { + const names: string[] = Object.keys(getElementClasses(element)); + names.sort(); + return names.join(' '); +} + +/** + * Returns element classes in form of a map. + * + * @param element HTML Element. + * @returns Map of class values. + */ +export function getElementClasses(element: Element): {[key: string]: true} { + const classes: {[key: string]: true} = {}; + if (element.nodeType === Node.ELEMENT_NODE) { + const classList = element.classList; + for (let i = 0; i < classList.length; i++) { + const key = classList[i]; + classes[key] = true; + } + } + return classes; +} + +/** + * Returns element styles in form of a stable (sorted) string. + * + * @param element HTML Element. + * @returns Returns element styles in form of a stable (sorted) string. + */ +export function getSortedStyle(element: Element): string { + const styles = getElementStyles(element); + const names: string[] = Object.keys(styles); + names.sort(); + let sorted = ''; + names.forEach(key => { + const value = styles[key]; + if (value != null && value !== '') { + if (sorted !== '') sorted += ' '; + sorted += key + ': ' + value + ';'; + } + }); + return sorted; +} + +/** + * Returns element styles in form of a map. + * + * @param element HTML Element. + * @returns Map of style values. + */ +export function getElementStyles(element: Element): {[key: string]: string} { + const styles: {[key: string]: string} = {}; + if (element.nodeType === Node.ELEMENT_NODE) { + const style = (element as HTMLElement).style; + // reading `style.color` is a work around for a bug in Domino. The issue is that Domino has + // stale value for `style.length`. It seems that reading a property from the element causes the + // stale value to be updated. (As of Domino v 2.1.3) + style.color; + for (let i = 0; i < style.length; i++) { + const key = style.item(i); + const value = style.getPropertyValue(key); + if (value !== '') { + // Workaround for IE not clearing properties, instead it just sets them to blank value. + styles[key] = value; + } + } + } + return styles; +} \ No newline at end of file diff --git a/packages/elements/BUILD.bazel b/packages/elements/BUILD.bazel index e134ab4393..9915c87c87 100644 --- a/packages/elements/BUILD.bazel +++ b/packages/elements/BUILD.bazel @@ -24,7 +24,7 @@ ng_package( "**/package.json", ]), entry_point = ":index.ts", - packages = [ + nested_packages = [ "//packages/elements/schematics:npm_package", ], tags = [ diff --git a/packages/elements/schematics/BUILD.bazel b/packages/elements/schematics/BUILD.bazel index f3d17d4571..45b9fa8c11 100644 --- a/packages/elements/schematics/BUILD.bazel +++ b/packages/elements/schematics/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "npm_package") +load("//tools:defaults.bzl", "pkg_npm") package(default_visibility = ["//visibility:public"]) @@ -15,7 +15,7 @@ genrule( output_to_bindir = 1, ) -npm_package( +pkg_npm( name = "npm_package", srcs = [ "collection.json", diff --git a/packages/elements/test/BUILD.bazel b/packages/elements/test/BUILD.bazel index f7a77e8857..7261036483 100644 --- a/packages/elements/test/BUILD.bazel +++ b/packages/elements/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/elements/index.js", + deps = ["//packages/elements"], +) ts_library( name = "test_lib", 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 def858d4a6..6c75ea63d8 100644 --- a/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts +++ b/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts @@ -77,7 +77,7 @@ describe('pipe', () => { expect(examples.get(0).getText()).toEqual('e (no formatting): 2.718'); expect(examples.get(1).getText()).toEqual('e (3.1-5): 002.71828'); expect(examples.get(2).getText()).toEqual('e (4.5-5): 0,002.71828'); - expect(examples.get(3).getText()).toEqual('e (french): 0 002,71828'); + expect(examples.get(3).getText()).toEqual('e (french): 0\u202f002,71828'); expect(examples.get(4).getText()).toEqual('pi (no formatting): 3.14'); expect(examples.get(5).getText()).toEqual('pi (3.1-5): 003.14'); expect(examples.get(6).getText()).toEqual('pi (3.5-5): 003.14000'); @@ -92,7 +92,7 @@ describe('pipe', () => { const examples = element.all(by.css('percent-pipe p')); expect(examples.get(0).getText()).toEqual('A: 26%'); expect(examples.get(1).getText()).toEqual('B: 0,134.950%'); - expect(examples.get(2).getText()).toEqual('B: 0 134,950 %'); + expect(examples.get(2).getText()).toEqual('B: 0\u202f134,950 %'); }); }); @@ -106,7 +106,7 @@ describe('pipe', () => { expect(examples.get(2).getText()).toEqual('A: CAD0.26'); expect(examples.get(3).getText()).toEqual('B: CA$0,001.35'); expect(examples.get(4).getText()).toEqual('B: $0,001.35'); - expect(examples.get(5).getText()).toEqual('B: 0 001,35 CA$'); + expect(examples.get(5).getText()).toEqual('B: 0\u202f001,35 $CA'); expect(examples.get(6).getText()).toEqual('B: CLP1'); }); }); diff --git a/packages/examples/common/pipes/ts/locale-fr.ts b/packages/examples/common/pipes/ts/locale-fr.ts index d5fa4e9d30..991e0ad0cc 100644 --- a/packages/examples/common/pipes/ts/locale-fr.ts +++ b/packages/examples/common/pipes/ts/locale-fr.ts @@ -9,19 +9,24 @@ // THIS CODE IS GENERATED - DO NOT MODIFY // See angular/tools/gulp-tasks/cldr/extract.js +const u = undefined; + +function plural(n: number): number { + let i = Math.floor(Math.abs(n)); + if (i === 0 || i === 1) return 1; + return 5; +} + export default [ 'fr', - [ - ['AM', 'PM'], - , - ], - , + [['AM', 'PM'], u, u], + u, [ ['D', 'L', 'M', 'M', 'J', 'V', 'S'], ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'], ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'], ['di', 'lu', 'ma', 'me', 'je', 've', 'sa'] ], - , + u, [ ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'], [ @@ -33,20 +38,64 @@ export default [ 'octobre', 'novembre', 'décembre' ] ], - , [['av. J.-C.', 'ap. J.-C.'], , ['avant Jésus-Christ', 'après Jésus-Christ']], 1, [6, 0], + u, + [['av. J.-C.', 'ap. J.-C.'], u, ['avant Jésus-Christ', 'après Jésus-Christ']], + 1, + [6, 0], ['dd/MM/y', 'd MMM y', 'd MMMM y', 'EEEE d MMMM y'], ['HH:mm', 'HH:mm:ss', 'HH:mm:ss z', 'HH:mm:ss zzzz'], - [ - '{1} {0}', - '{1} \'à\' {0}', - , - ], - [',', ' ', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], - ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], '€', 'euro', function(n: number): - number { - let i = Math.floor(Math.abs(n)); - if (i === 0 || i === 1) - return 1; - return 5; - } + ['{1} {0}', '{1} \'à\' {0}', u, u], + [',', '\u202f', ';', '%', '+', '-', 'E', '×', '‰', '∞', 'NaN', ':'], + ['#,##0.###', '#,##0 %', '#,##0.00 ¤', '#E0'], + 'EUR', + '€', + 'euro', + { + 'ARS': ['$AR', '$'], + 'AUD': ['$AU', '$'], + 'BEF': ['FB'], + 'BMD': ['$BM', '$'], + 'BND': ['$BN', '$'], + 'BZD': ['$BZ', '$'], + 'CAD': ['$CA', '$'], + 'CLP': ['$CL', '$'], + 'CNY': [u, '¥'], + 'COP': ['$CO', '$'], + 'CYP': ['£CY'], + 'EGP': [u, '£E'], + 'FJD': ['$FJ', '$'], + 'FKP': ['£FK', '£'], + 'FRF': ['F'], + 'GBP': ['£GB', '£'], + 'GIP': ['£GI', '£'], + 'HKD': [u, '$'], + 'IEP': ['£IE'], + 'ILP': ['£IL'], + 'ITL': ['₤IT'], + 'JPY': [u, '¥'], + 'KMF': [u, 'FC'], + 'LBP': ['£LB', '£L'], + 'MTP': ['£MT'], + 'MXN': ['$MX', '$'], + 'NAD': ['$NA', '$'], + 'NIO': [u, '$C'], + 'NZD': ['$NZ', '$'], + 'RHD': ['$RH'], + 'RON': [u, 'L'], + 'RWF': [u, 'FR'], + 'SBD': ['$SB', '$'], + 'SGD': ['$SG', '$'], + 'SRD': ['$SR', '$'], + 'TOP': [u, '$T'], + 'TTD': ['$TT', '$'], + 'TWD': [u, 'NT$'], + 'USD': ['$US', '$'], + 'UYU': ['$UY', '$'], + 'WST': ['$WS'], + 'XCD': [u, '$'], + 'XPF': ['FCFP'], + 'ZMW': [u, 'Kw'] + }, + 'ltr', + plural ]; diff --git a/packages/examples/core/BUILD.bazel b/packages/examples/core/BUILD.bazel index fce592cd19..8ee6574f02 100644 --- a/packages/examples/core/BUILD.bazel +++ b/packages/examples/core/BUILD.bazel @@ -78,9 +78,8 @@ protractor_web_test_suite( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":core_tests_lib", - "//tools/testing:node", ], ) diff --git a/packages/examples/core/testing/ts/BUILD.bazel b/packages/examples/core/testing/ts/BUILD.bazel index cbfb89fcca..d845f648ea 100644 --- a/packages/examples/core/testing/ts/BUILD.bazel +++ b/packages/examples/core/testing/ts/BUILD.bazel @@ -15,9 +15,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":fake_async_lib", - "//tools/testing:node", ], ) diff --git a/packages/examples/upgrade/static/ts/full/module.ts b/packages/examples/upgrade/static/ts/full/module.ts index 217de1a4d6..2e908f0ed0 100644 --- a/packages/examples/upgrade/static/ts/full/module.ts +++ b/packages/examples/upgrade/static/ts/full/module.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ // #docplaster -import {Component, Directive, ElementRef, EventEmitter, Inject, Injectable, Injector, Input, NgModule, Output} from '@angular/core'; +import {Component, Directive, ElementRef, EventEmitter, Injectable, Injector, Input, NgModule, Output} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {UpgradeComponent, UpgradeModule, downgradeComponent, downgradeInjectable} from '@angular/upgrade/static'; @@ -176,6 +176,6 @@ ng1AppModule.component('exampleApp', { // #docregion bootstrap-ng2 // We bootstrap the Angular module as we would do in a normal Angular app. -// (We are using the dynamic browser platform as this example has not been compiled AoT.) +// (We are using the dynamic browser platform as this example has not been compiled AOT.) platformBrowserDynamic().bootstrapModule(Ng2AppModule); // #enddocregion diff --git a/packages/examples/upgrade/static/ts/lite/module.ts b/packages/examples/upgrade/static/ts/lite/module.ts index dec1613ebb..806c8022e8 100644 --- a/packages/examples/upgrade/static/ts/lite/module.ts +++ b/packages/examples/upgrade/static/ts/lite/module.ts @@ -141,7 +141,7 @@ class MyLazyAngularModule { const ng2BootstrapFn = (extraProviders: StaticProvider[]) => platformBrowserDynamic(extraProviders).bootstrapModule(MyLazyAngularModule); // #enddocregion -// (We are using the dynamic browser platform, as this example has not been compiled AoT.) +// (We are using the dynamic browser platform, as this example has not been compiled AOT.) // #docregion basic-how-to diff --git a/packages/forms/src/directives/validators.ts b/packages/forms/src/directives/validators.ts index 98bf2ed034..7a64e003f2 100644 --- a/packages/forms/src/directives/validators.ts +++ b/packages/forms/src/directives/validators.ts @@ -359,7 +359,7 @@ export const MIN_LENGTH_VALIDATOR: any = { /** * A directive that adds minimum length validation to controls marked with the - * `minlength` attribute. The directive is provided with the `NG_VALIDATORS` mult-provider list. + * `minlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list. * * 该指令用于为带有 `minlength` 属性的控件添加最小长度验证器。该指令会提供 `NG_VALIDATORS` 多重提供商列表。 * @@ -401,7 +401,7 @@ export class MinLengthValidator implements Validator, * Tracks changes to the the minimum length bound to this directive. */ // TODO(issue/24571): remove '!'. - @Input() minlength !: string; + @Input() minlength !: string | number; /** * @description @@ -435,7 +435,8 @@ export class MinLengthValidator implements Validator, registerOnValidatorChange(fn: () => void): void { this._onChange = fn; } private _createValidator(): void { - this._validator = Validators.minLength(parseInt(this.minlength, 10)); + this._validator = Validators.minLength( + typeof this.minlength === 'number' ? this.minlength : parseInt(this.minlength, 10)); } } @@ -496,7 +497,7 @@ export class MaxLengthValidator implements Validator, * Tracks changes to the the maximum length bound to this directive. */ // TODO(issue/24571): remove '!'. - @Input() maxlength !: string; + @Input() maxlength !: string | number; /** * @description @@ -530,7 +531,8 @@ export class MaxLengthValidator implements Validator, registerOnValidatorChange(fn: () => void): void { this._onChange = fn; } private _createValidator(): void { - this._validator = Validators.maxLength(parseInt(this.maxlength, 10)); + this._validator = Validators.maxLength( + typeof this.maxlength === 'number' ? this.maxlength : parseInt(this.maxlength, 10)); } } diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index 1b002aa297..328915045c 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -406,9 +406,10 @@ export abstract class AbstractControl { /** * A multicasting observable that emits an event every time the value of the control changes, in - * the UI or programmatically. + * the UI or programmatically. It also emits an event each time you call enable() or disable() + * without passing along {emitEvent: false} as a function argument. * - * 一个多播 Observable(可观察对象),每当控件的值发生变化时,它就会发出一个事件 —— 无论是通过 UI 还是通过程序。 + * 一个多播 Observable(可观察对象),每当控件的值发生变化时,它就会发出一个事件 —— 无论是通过 UI 还是通过程序。每当你调用 `enable()` 或 `disable()`,但没有传入 `{emitEvent: false}` 参数时,它也同样会发出一个事件。 */ // TODO(issue/24571): remove '!'. public readonly valueChanges !: Observable; diff --git a/packages/forms/test/BUILD.bazel b/packages/forms/test/BUILD.bazel index 679a2af5c0..f9a3325516 100644 --- a/packages/forms/test/BUILD.bazel +++ b/packages/forms/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/forms/index.js", + deps = ["//packages/forms"], +) ts_library( name = "test_lib", @@ -20,10 +27,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/http/src/body.ts b/packages/http/src/body.ts index 97f7f04b7b..18e4c7b7e4 100644 --- a/packages/http/src/body.ts +++ b/packages/http/src/body.ts @@ -57,9 +57,13 @@ export abstract class Body { if (this._body instanceof ArrayBuffer) { switch (encodingHint) { case 'legacy': - return String.fromCharCode.apply(null, new Uint16Array(this._body)); + // TODO: Argument of type 'Uint16Array' is not assignable to parameter of type + // 'number[]'. + return String.fromCharCode.apply(null, new Uint16Array(this._body) as any); case 'iso-8859': - return String.fromCharCode.apply(null, new Uint8Array(this._body)); + // TODO: Argument of type 'Uint8Array' is not assignable to parameter of type + // 'number[]'. + return String.fromCharCode.apply(null, new Uint8Array(this._body) as any); default: throw new Error(`Invalid value for encodingHint: ${encodingHint}`); } diff --git a/packages/http/test/BUILD.bazel b/packages/http/test/BUILD.bazel index f7d5d2bc1d..687e270459 100644 --- a/packages/http/test/BUILD.bazel +++ b/packages/http/test/BUILD.bazel @@ -20,10 +20,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/language-service/BUILD.bazel b/packages/language-service/BUILD.bazel index db9d9e1229..177cd98d52 100644 --- a/packages/language-service/BUILD.bazel +++ b/packages/language-service/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "npm_package", "ts_library") +load("//tools:defaults.bzl", "pkg_npm", "ts_library") package(default_visibility = ["//visibility:public"]) @@ -20,7 +20,7 @@ ts_library( ], ) -npm_package( +pkg_npm( name = "npm_package", srcs = ["package.json"], tags = [ diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index acdc478d4d..64abe85f5b 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, AstPath, AttrAst, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, Element, ElementAst, ImplicitReceiver, NAMED_ENTITIES, Node as HtmlAst, NullTemplateVisitor, ParseSpan, PropertyRead, ReferenceAst, TagContentType, TemplateBinding, Text, getHtmlTagDefinition} from '@angular/compiler'; +import {AST, AstPath, AttrAst, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, Element, ElementAst, HtmlAstPath, NAMED_ENTITIES, Node as HtmlAst, NullTemplateVisitor, ReferenceAst, TagContentType, TemplateBinding, Text, getHtmlTagDefinition} from '@angular/compiler'; import {$$, $_, isAsciiLetter, isDigit} from '@angular/compiler/src/chars'; import {AstResult} from './common'; @@ -169,19 +169,15 @@ export function getTemplateCompletions( result = attributeCompletionsForElement(templateInfo, ast.name); } }, - visitAttribute(ast) { - const bindParts = ast.name.match(BIND_NAME_REGEXP); - const isReference = bindParts && bindParts[ATTR.KW_REF_IDX] !== undefined; - if (!isReference && - (!ast.valueSpan || !inSpan(templatePosition, spanOf(ast.valueSpan)))) { - // We are in the name of an attribute. Show attribute completions. + visitAttribute(ast: Attribute) { + // An attribute consists of two parts, LHS="RHS". + // Determine if completions are requested for LHS or RHS + if (ast.valueSpan && inSpan(templatePosition, spanOf(ast.valueSpan))) { + // RHS completion + result = attributeValueCompletions(templateInfo, path); + } else { + // LHS completion result = attributeCompletions(templateInfo, path); - } else if (ast.valueSpan && inSpan(templatePosition, spanOf(ast.valueSpan))) { - if (isReference) { - result = referenceAttributeValueCompletions(templateInfo, templatePosition, ast); - } else { - result = attributeValueCompletions(templateInfo, templatePosition, ast); - } } }, visitText(ast) { @@ -208,9 +204,9 @@ export function getTemplateCompletions( } } }, - visitComment(ast) {}, - visitExpansion(ast) {}, - visitExpansionCase(ast) {} + visitComment() {}, + visitExpansion() {}, + visitExpansionCase() {} }, null); } @@ -300,43 +296,52 @@ function attributeCompletionsForElement( return results; } -function attributeValueCompletions( - info: AstResult, position: number, attr: Attribute): ng.CompletionEntry[] { - const path = findTemplateAstAt(info.templateAst, position); - if (!path.tail) { - return []; +/** + * Provide completions to the RHS of an attribute, which is of the form + * LHS="RHS". The template path is computed from the specified `info` whereas + * the context is determined from the specified `htmlPath`. + * @param info Object that contains the template AST + * @param htmlPath Path to the HTML node + */ +function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.CompletionEntry[] { + // Find the corresponding Template AST path. + const templatePath = findTemplateAstAt(info.templateAst, htmlPath.position); + const visitor = new ExpressionVisitor(info, htmlPath.position, () => { + const dinfo = diagnosticInfoFromTemplateInfo(info); + return getExpressionScope(dinfo, templatePath); + }); + if (templatePath.tail instanceof AttrAst || + templatePath.tail instanceof BoundElementPropertyAst || + templatePath.tail instanceof BoundEventAst) { + templatePath.tail.visit(visitor, null); + return visitor.results; } - // HtmlAst contains the `Attribute` node, however the corresponding `AttrAst` - // node is missing from the TemplateAst. In this case, we have to manually - // append the `AttrAst` node to the path. - if (!(path.tail instanceof AttrAst)) { - // The sourceSpan of an AttrAst is the valueSpan of the HTML Attribute. - path.push(new AttrAst(attr.name, attr.value, attr.valueSpan !)); + // In order to provide accurate attribute value completion, we need to know + // what the LHS is, and construct the proper AST if it is missing. + const htmlAttr = htmlPath.tail as Attribute; + const bindParts = htmlAttr.name.match(BIND_NAME_REGEXP); + if (bindParts && bindParts[ATTR.KW_REF_IDX] !== undefined) { + let refAst: ReferenceAst|undefined; + let elemAst: ElementAst|undefined; + if (templatePath.tail instanceof ReferenceAst) { + refAst = templatePath.tail; + const parent = templatePath.parentOf(refAst); + if (parent instanceof ElementAst) { + elemAst = parent; + } + } else if (templatePath.tail instanceof ElementAst) { + refAst = new ReferenceAst(htmlAttr.name, null !, htmlAttr.value, htmlAttr.valueSpan !); + elemAst = templatePath.tail; + } + if (refAst && elemAst) { + refAst.visit(visitor, elemAst); + } + } else { + // HtmlAst contains the `Attribute` node, however the corresponding `AttrAst` + // node is missing from the TemplateAst. + const attrAst = new AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan !); + attrAst.visit(visitor, null); } - const dinfo = diagnosticInfoFromTemplateInfo(info); - const visitor = - new ExpressionVisitor(info, position, () => getExpressionScope(dinfo, path, false)); - path.tail.visit(visitor, null); - return visitor.results; -} - -function referenceAttributeValueCompletions( - info: AstResult, position: number, attr: Attribute): ng.CompletionEntry[] { - const path = findTemplateAstAt(info.templateAst, position); - if (!path.tail) { - return []; - } - - // When the template parser does not find a directive with matching "exportAs", - // the ReferenceAst will be ignored. - if (!(path.tail instanceof ReferenceAst)) { - // The sourceSpan of an ReferenceAst is the valueSpan of the HTML Attribute. - path.push(new ReferenceAst(attr.name, null !, attr.value, attr.valueSpan !)); - } - const dinfo = diagnosticInfoFromTemplateInfo(info); - const visitor = - new ExpressionVisitor(info, position, () => getExpressionScope(dinfo, path, false)); - path.tail.visit(visitor, path.parentOf(path.tail)); return visitor.results; } @@ -393,8 +398,7 @@ function interpolationCompletions(info: AstResult, position: number): ng.Complet return []; } const visitor = new ExpressionVisitor( - info, position, - () => getExpressionScope(diagnosticInfoFromTemplateInfo(info), templatePath, false)); + info, position, () => getExpressionScope(diagnosticInfoFromTemplateInfo(info), templatePath)); templatePath.tail.visit(visitor, null); return visitor.results; } @@ -441,36 +445,34 @@ class ExpressionVisitor extends NullTemplateVisitor { visitEvent(ast: BoundEventAst): void { this.processExpressionCompletions(ast.handler); } - visitElement(ast: ElementAst): void { + visitElement(): void { // no-op for now } visitAttr(ast: AttrAst) { - // First, verify the attribute consists of some binding we can give completions for. - const {templateBindings} = this.info.expressionParser.parseTemplateBindings( - ast.name, ast.value, ast.sourceSpan.toString(), ast.sourceSpan.start.offset); - // Find where the cursor is relative to the start of the attribute value. - const valueRelativePosition = this.position - ast.sourceSpan.start.offset; - // Find the template binding that contains the position - const binding = templateBindings.find(b => inSpan(valueRelativePosition, b.span)); - - if (!binding) { - return; - } - if (ast.name.startsWith('*')) { + // This a template binding given by micro syntax expression. + // First, verify the attribute consists of some binding we can give completions for. + const {templateBindings} = this.info.expressionParser.parseTemplateBindings( + ast.name, ast.value, ast.sourceSpan.toString(), ast.sourceSpan.start.offset); + // Find where the cursor is relative to the start of the attribute value. + const valueRelativePosition = this.position - ast.sourceSpan.start.offset; + // Find the template binding that contains the position. + const binding = templateBindings.find(b => inSpan(valueRelativePosition, b.span)); + + if (!binding) { + return; + } + this.microSyntaxInAttributeValue(ast, binding); } else { - // If the position is in the expression or after the key or there is no key, return the - // expression completions. - // The expression must be reparsed to get a valid AST rather than only template bindings. const expressionAst = this.info.expressionParser.parseBinding( ast.value, ast.sourceSpan.toString(), ast.sourceSpan.start.offset); this.processExpressionCompletions(expressionAst); } } - visitReference(ast: ReferenceAst, context: ElementAst) { + visitReference(_ast: ReferenceAst, context: ElementAst) { context.directives.forEach(dir => { const {exportAs} = dir.directive; if (exportAs) { diff --git a/packages/language-service/src/definitions.ts b/packages/language-service/src/definitions.ts index 1d12c7df89..17c14744d5 100644 --- a/packages/language-service/src/definitions.ts +++ b/packages/language-service/src/definitions.ts @@ -9,9 +9,9 @@ import * as path from 'path'; import * as ts from 'typescript'; // used as value and is provided at runtime import {AstResult} from './common'; -import {locateSymbol} from './locate_symbol'; +import {locateSymbols} from './locate_symbol'; import {getPropertyAssignmentFromValue, isClassDecoratorProperty} from './template'; -import {Span, TemplateSource} from './types'; +import {Span} from './types'; import {findTightestNode} from './utils'; /** @@ -34,32 +34,53 @@ function ngSpanToTsTextSpan(span: Span): ts.TextSpan { */ export function getDefinitionAndBoundSpan( info: AstResult, position: number): ts.DefinitionInfoAndBoundSpan|undefined { - const symbolInfo = locateSymbol(info, position); - if (!symbolInfo) { + const symbols = locateSymbols(info, position); + if (!symbols.length) { return; } - const textSpan = ngSpanToTsTextSpan(symbolInfo.span); - const {symbol} = symbolInfo; - const {container, definition: locations} = symbol; - if (!locations || !locations.length) { + + const seen = new Set(); + const definitions: ts.DefinitionInfo[] = []; + for (const symbolInfo of symbols) { + const {symbol} = symbolInfo; + // symbol.definition is really the locations of the symbol. There could be // more than one. No meaningful info could be provided without any location. - return {textSpan}; + const {kind, name, container, definition: locations} = symbol; + if (!locations || !locations.length) { + continue; + } + + const containerKind = + container ? container.kind as ts.ScriptElementKind : ts.ScriptElementKind.unknown; + const containerName = container ? container.name : ''; + + for (const {fileName, span} of locations) { + const textSpan = ngSpanToTsTextSpan(span); + // In cases like two-way bindings, a request for the definitions of an expression may return + // two of the same definition: + // [(ngModel)]="prop" + // ^^^^ -- one definition for the property binding, one for the event binding + // To prune duplicate definitions, tag definitions with unique location signatures and ignore + // definitions whose locations have already been seen. + const signature = `${textSpan.start}:${textSpan.length}@${fileName}`; + if (seen.has(signature)) continue; + + definitions.push({ + kind: kind as ts.ScriptElementKind, + name, + containerKind, + containerName, + textSpan: ngSpanToTsTextSpan(span), + fileName: fileName, + }); + seen.add(signature); + } } - const containerKind = container ? container.kind : ts.ScriptElementKind.unknown; - const containerName = container ? container.name : ''; - const definitions = locations.map((location) => { - return { - kind: symbol.kind as ts.ScriptElementKind, - name: symbol.name, - containerKind: containerKind as ts.ScriptElementKind, - containerName: containerName, - textSpan: ngSpanToTsTextSpan(location.span), - fileName: location.fileName, - }; - }); + return { - definitions, textSpan, + definitions, + textSpan: symbols[0].span, }; } diff --git a/packages/language-service/src/diagnostics.ts b/packages/language-service/src/diagnostics.ts index bf2e365b19..6b8bed9616 100644 --- a/packages/language-service/src/diagnostics.ts +++ b/packages/language-service/src/diagnostics.ts @@ -96,9 +96,6 @@ export function getDeclarationDiagnostics( span: error.span, }); } - if (!metadata) { - continue; // declaration is not an Angular directive - } if (metadata.isComponent) { if (!modules.ngModuleByPipeOrDirective.has(declaration.type)) { results.push({ @@ -231,25 +228,3 @@ export function ngDiagnosticToTsDiagnostic( source: 'ng', }; } - -/** - * Return elements filtered by unique span. - * @param elements - */ -export function uniqueBySpan(elements: T[]): T[] { - const result: T[] = []; - const map = new Map>(); - for (const element of elements) { - const {span} = element; - let set = map.get(span.start); - if (!set) { - set = new Set(); - map.set(span.start, set); - } - if (!set.has(span.end)) { - set.add(span.end); - result.push(element); - } - } - return result; -} diff --git a/packages/language-service/src/expression_diagnostics.ts b/packages/language-service/src/expression_diagnostics.ts index 2382fd85f0..72fec3f9c4 100644 --- a/packages/language-service/src/expression_diagnostics.ts +++ b/packages/language-service/src/expression_diagnostics.ts @@ -9,10 +9,10 @@ import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, VariableAst, identifierName, templateVisitAll, tokenReference} from '@angular/compiler'; import * as ts from 'typescript'; -import {AstType, ExpressionDiagnosticsContext, TypeDiagnostic} from './expression_type'; +import {AstType} from './expression_type'; import {BuiltinType, Definition, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; import {Diagnostic} from './types'; -import {getPathToNodeAtPosition} from './utils'; +import {findOutputBinding, getPathToNodeAtPosition} from './utils'; export interface DiagnosticTemplateInfo { fileName?: string; @@ -25,20 +25,11 @@ export interface DiagnosticTemplateInfo { export function getTemplateExpressionDiagnostics(info: DiagnosticTemplateInfo): Diagnostic[] { const visitor = new ExpressionDiagnosticsVisitor( - info, (path: TemplateAstPath, includeEvent: boolean) => - getExpressionScope(info, path, includeEvent)); + info, (path: TemplateAstPath) => getExpressionScope(info, path)); templateVisitAll(visitor, info.templateAst); return visitor.diagnostics; } -export function getExpressionDiagnostics( - scope: SymbolTable, ast: AST, query: SymbolQuery, - context: ExpressionDiagnosticsContext = {}): TypeDiagnostic[] { - const analyzer = new AstType(scope, query, context); - analyzer.getDiagnostics(ast); - return analyzer.diagnostics; -} - function getReferences(info: DiagnosticTemplateInfo): SymbolDeclaration[] { const result: SymbolDeclaration[] = []; @@ -194,26 +185,51 @@ function refinedVariableType( return query.getBuiltinType(BuiltinType.Any); } -function getEventDeclaration(info: DiagnosticTemplateInfo, includeEvent?: boolean) { - let result: SymbolDeclaration[] = []; - if (includeEvent) { - // TODO: Determine the type of the event parameter based on the Observable or EventEmitter - // of the event. - result = [{name: '$event', kind: 'variable', type: info.query.getBuiltinType(BuiltinType.Any)}]; +function getEventDeclaration( + info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration|undefined { + const event = path.tail; + if (!(event instanceof BoundEventAst)) { + // No event available in this context. + return; } - return result; + + const genericEvent: SymbolDeclaration = { + name: '$event', + kind: 'variable', + type: info.query.getBuiltinType(BuiltinType.Any), + }; + + const outputSymbol = findOutputBinding(event, path, info.query); + if (!outputSymbol) { + // The `$event` variable doesn't belong to an output, so its type can't be refined. + // TODO: type `$event` variables in bindings to DOM events. + return genericEvent; + } + + // The raw event type is wrapped in a generic, like EventEmitter or Observable. + const ta = outputSymbol.typeArguments(); + if (!ta || ta.length !== 1) return genericEvent; + const eventType = ta[0]; + + return {...genericEvent, type: eventType}; } +/** + * Returns the symbols available in a particular scope of a template. + * @param info parsed template information + * @param path path of template nodes narrowing to the context the expression scope should be + * derived for. + */ export function getExpressionScope( - info: DiagnosticTemplateInfo, path: TemplateAstPath, includeEvent: boolean): SymbolTable { + info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolTable { let result = info.members; const references = getReferences(info); const variables = getVarDeclarations(info, path); - const events = getEventDeclaration(info, includeEvent); - if (references.length || variables.length || events.length) { + const event = getEventDeclaration(info, path); + if (references.length || variables.length || event) { const referenceTable = info.query.createSymbolTable(references); const variableTable = info.query.createSymbolTable(variables); - const eventsTable = info.query.createSymbolTable(events); + const eventsTable = info.query.createSymbolTable(event ? [event] : []); result = info.query.mergeSymbolTable([result, referenceTable, variableTable, eventsTable]); } return result; @@ -221,8 +237,7 @@ export function getExpressionScope( class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { private path: TemplateAstPath; - // TODO(issue/24571): remove '!'. - private directiveSummary !: CompileDirectiveSummary; + private directiveSummary: CompileDirectiveSummary|undefined; diagnostics: Diagnostic[] = []; @@ -269,14 +284,12 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { if (directive && ast.value) { const context = this.info.query.getTemplateContext(directive.type.reference) !; if (context && !context.has(ast.value)) { - if (ast.value === '$implicit') { - this.reportError( - 'The template context does not have an implicit value', spanOf(ast.sourceSpan)); - } else { - this.reportError( - `The template context does not define a member called '${ast.value}'`, - spanOf(ast.sourceSpan)); - } + const missingMember = + ast.value === '$implicit' ? 'an implicit value' : `a member called '${ast.value}'`; + this.reportDiagnostic( + `The template context of '${directive.type.reference.name}' does not define ${missingMember}.\n` + + `If the context type is a base type or 'any', consider refining it to a more specific type.`, + spanOf(ast.sourceSpan), ts.DiagnosticCategory.Suggestion); } } } @@ -313,31 +326,25 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { return ast.sourceSpan.start.offset; } - private diagnoseExpression(ast: AST, offset: number, includeEvent: boolean) { - const scope = this.getExpressionScope(this.path, includeEvent); - this.diagnostics.push(...getExpressionDiagnostics(scope, ast, this.info.query, { - event: includeEvent - }).map(d => ({ - span: offsetSpan(d.ast.span, offset + this.info.offset), - kind: d.kind, - message: d.message - }))); + private diagnoseExpression(ast: AST, offset: number, event: boolean) { + const scope = this.getExpressionScope(this.path, event); + const analyzer = new AstType(scope, this.info.query, {event}); + for (const {message, span, kind} of analyzer.getDiagnostics(ast)) { + span.start += offset; + span.end += offset; + this.reportDiagnostic(message as string, span, kind); + } } private push(ast: TemplateAst) { this.path.push(ast); } private pop() { this.path.pop(); } - private reportError(message: string, span: Span|undefined) { - if (span) { - this.diagnostics.push( - {span: offsetSpan(span, this.info.offset), kind: ts.DiagnosticCategory.Error, message}); - } - } - - private reportWarning(message: string, span: Span) { - this.diagnostics.push( - {span: offsetSpan(span, this.info.offset), kind: ts.DiagnosticCategory.Warning, message}); + private reportDiagnostic( + message: string, span: Span, kind: ts.DiagnosticCategory = ts.DiagnosticCategory.Error) { + span.start += this.info.offset; + span.end += this.info.offset; + this.diagnostics.push({kind, span, message}); } } @@ -352,10 +359,6 @@ function hasTemplateReference(type: CompileTypeMetadata): boolean { return false; } -function offsetSpan(span: Span, amount: number): Span { - return {start: span.start + amount, end: span.end + amount}; -} - function spanOf(sourceSpan: ParseSourceSpan): Span { return {start: sourceSpan.start.offset, end: sourceSpan.end.offset}; } diff --git a/packages/language-service/src/expression_type.ts b/packages/language-service/src/expression_type.ts index fc47f6a875..3bdeec102b 100644 --- a/packages/language-service/src/expression_type.ts +++ b/packages/language-service/src/expression_type.ts @@ -10,17 +10,13 @@ import {AST, AstVisitor, Binary, BindingPipe, Chain, Conditional, FunctionCall, import * as ts from 'typescript'; import {BuiltinType, Signature, Symbol, SymbolQuery, SymbolTable} from './symbols'; +import * as ng from './types'; export interface ExpressionDiagnosticsContext { event?: boolean; } -export class TypeDiagnostic { - constructor(public kind: ts.DiagnosticCategory, public message: string, public ast: AST) {} -} - // AstType calculatetype of the ast given AST element. export class AstType implements AstVisitor { - // TODO(issue/24571): remove '!'. - public diagnostics !: TypeDiagnostic[]; + private readonly diagnostics: ng.Diagnostic[] = []; constructor( private scope: SymbolTable, private query: SymbolQuery, @@ -28,11 +24,12 @@ export class AstType implements AstVisitor { getType(ast: AST): Symbol { return ast.visit(this); } - getDiagnostics(ast: AST): TypeDiagnostic[] { - this.diagnostics = []; + getDiagnostics(ast: AST): ng.Diagnostic[] { const type: Symbol = ast.visit(this); if (this.context.event && type.callable) { - this.reportWarning('Unexpected callable expression. Expected a method call', ast); + this.reportDiagnostic( + 'Unexpected callable expression. Expected a method call', ast, + ts.DiagnosticCategory.Warning); } return this.diagnostics; } @@ -61,7 +58,7 @@ export class AstType implements AstVisitor { // Nullable allowed. break; default: - this.reportError(`The expression might be null`, ast); + this.reportDiagnostic(`The expression might be null`, ast); break; } return this.query.getNonNullableType(type); @@ -105,7 +102,8 @@ export class AstType implements AstVisitor { errorAst = ast.right; break; } - return this.reportError('Expected a numeric type', errorAst); + this.reportDiagnostic('Expected a numeric type', errorAst); + return this.anyType; } case '+': switch (operKind) { @@ -131,12 +129,15 @@ export class AstType implements AstVisitor { return this.query.getBuiltinType(BuiltinType.Number); case BuiltinType.Boolean << 8 | BuiltinType.Number: case BuiltinType.Other << 8 | BuiltinType.Number: - return this.reportError('Expected a number type', ast.left); + this.reportDiagnostic('Expected a number type', ast.left); + return this.anyType; case BuiltinType.Number << 8 | BuiltinType.Boolean: case BuiltinType.Number << 8 | BuiltinType.Other: - return this.reportError('Expected a number type', ast.right); + this.reportDiagnostic('Expected a number type', ast.right); + return this.anyType; default: - return this.reportError('Expected operands to be a string or number type', ast); + this.reportDiagnostic('Expected operands to be a string or number type', ast); + return this.anyType; } case '>': case '<': @@ -162,7 +163,8 @@ export class AstType implements AstVisitor { case BuiltinType.Other << 8 | BuiltinType.Other: return this.query.getBuiltinType(BuiltinType.Boolean); default: - return this.reportError('Expected the operants to be of similar type or any', ast); + this.reportDiagnostic('Expected the operants to be of similar type or any', ast); + return this.anyType; } case '&&': return rightType; @@ -170,23 +172,20 @@ export class AstType implements AstVisitor { return this.query.getTypeUnion(leftType, rightType); } - return this.reportError(`Unrecognized operator ${ast.operation}`, ast); + this.reportDiagnostic(`Unrecognized operator ${ast.operation}`, ast); + return this.anyType; } visitChain(ast: Chain) { - if (this.diagnostics) { - // If we are producing diagnostics, visit the children - visitAstChildren(ast, this); - } + // If we are producing diagnostics, visit the children + visitAstChildren(ast, this); // The type of a chain is always undefined. return this.query.getBuiltinType(BuiltinType.Undefined); } visitConditional(ast: Conditional) { // The type of a conditional is the union of the true and false conditions. - if (this.diagnostics) { - visitAstChildren(ast, this); - } + visitAstChildren(ast, this); return this.query.getTypeUnion(this.getType(ast.trueExp), this.getType(ast.falseExp)); } @@ -197,11 +196,17 @@ export class AstType implements AstVisitor { // version. const args = ast.args.map(arg => this.getType(arg)); const target = this.getType(ast.target !); - if (!target || !target.callable) return this.reportError('Call target is not callable', ast); + if (!target || !target.callable) { + this.reportDiagnostic('Call target is not callable', ast); + return this.anyType; + } const signature = target.selectSignature(args); - if (signature) return signature.result; + if (signature) { + return signature.result; + } // TODO: Consider a better error message here. - return this.reportError('Unable no compatible signature found for call', ast); + this.reportDiagnostic('Unable no compatible signature found for call', ast); + return this.anyType; } visitImplicitReceiver(ast: ImplicitReceiver): Symbol { @@ -223,15 +228,14 @@ export class AstType implements AstVisitor { members(): SymbolTable{return _this.scope;}, signatures(): Signature[]{return [];}, selectSignature(types): Signature | undefined{return undefined;}, - indexed(argument): Symbol | undefined{return undefined;} + indexed(argument): Symbol | undefined{return undefined;}, + typeArguments(): Symbol[] | undefined{return undefined;}, }; } visitInterpolation(ast: Interpolation): Symbol { // If we are producing diagnostics, visit the children. - if (this.diagnostics) { - visitAstChildren(ast, this); - } + visitAstChildren(ast, this); return this.undefinedType; } @@ -256,9 +260,7 @@ export class AstType implements AstVisitor { visitLiteralMap(ast: LiteralMap): Symbol { // If we are producing diagnostics, visit the children - if (this.diagnostics) { - visitAstChildren(ast, this); - } + visitAstChildren(ast, this); // TODO: Return a composite type. return this.anyType; } @@ -280,7 +282,8 @@ export class AstType implements AstVisitor { case 'number': return this.query.getBuiltinType(BuiltinType.Number); default: - return this.reportError('Unrecognized primitive', ast); + this.reportDiagnostic('Unrecognized primitive', ast); + return this.anyType; } } } @@ -293,19 +296,23 @@ export class AstType implements AstVisitor { // The type of a pipe node is the return type of the pipe's transform method. The table returned // by getPipes() is expected to contain symbols with the corresponding transform method type. const pipe = this.query.getPipes().get(ast.name); - if (!pipe) return this.reportError(`No pipe by the name ${ast.name} found`, ast); + if (!pipe) { + this.reportDiagnostic(`No pipe by the name ${ast.name} found`, ast); + return this.anyType; + } const expType = this.getType(ast.exp); const signature = pipe.selectSignature([expType].concat(ast.args.map(arg => this.getType(arg)))); - if (!signature) return this.reportError('Unable to resolve signature for pipe invocation', ast); + if (!signature) { + this.reportDiagnostic('Unable to resolve signature for pipe invocation', ast); + return this.anyType; + } return signature.result; } visitPrefixNot(ast: PrefixNot) { // If we are producing diagnostics, visit the children - if (this.diagnostics) { - visitAstChildren(ast, this); - } + visitAstChildren(ast, this); // The type of a prefix ! is always boolean. return this.query.getBuiltinType(BuiltinType.Boolean); } @@ -337,8 +344,7 @@ export class AstType implements AstVisitor { return this.resolvePropertyRead(this.query.getNonNullableType(this.getType(ast.receiver)), ast); } - // TODO(issue/24571): remove '!'. - private _anyType !: Symbol; + private _anyType: Symbol|undefined; private get anyType(): Symbol { let result = this._anyType; if (!result) { @@ -347,8 +353,7 @@ export class AstType implements AstVisitor { return result; } - // TODO(issue/24571): remove '!'. - private _undefinedType !: Symbol; + private _undefinedType: Symbol|undefined; private get undefinedType(): Symbol { let result = this._undefinedType; if (!result) { @@ -364,12 +369,23 @@ export class AstType implements AstVisitor { // The type of a method is the selected methods result type. const method = receiverType.members().get(ast.name); - if (!method) return this.reportError(`Unknown method '${ast.name}'`, ast); - if (!method.type) return this.reportError(`Could not find a type for '${ast.name}'`, ast); - if (!method.type.callable) return this.reportError(`Member '${ast.name}' is not callable`, ast); + if (!method) { + this.reportDiagnostic(`Unknown method '${ast.name}'`, ast); + return this.anyType; + } + if (!method.type) { + this.reportDiagnostic(`Could not find a type for '${ast.name}'`, ast); + return this.anyType; + } + if (!method.type.callable) { + this.reportDiagnostic(`Member '${ast.name}' is not callable`, ast); + return this.anyType; + } const signature = method.type.selectSignature(ast.args.map(arg => this.getType(arg))); - if (!signature) - return this.reportError(`Unable to resolve signature for call of method ${ast.name}`, ast); + if (!signature) { + this.reportDiagnostic(`Unable to resolve signature for call of method ${ast.name}`, ast); + return this.anyType; + } return signature.result; } @@ -386,13 +402,14 @@ export class AstType implements AstVisitor { receiverInfo = 'The component declaration, template variable declarations, and element references do'; } else if (receiverType.nullable) { - return this.reportError(`The expression might be null`, ast.receiver); + return this.reportDiagnostic(`The expression might be null`, ast.receiver); } else { receiverInfo = `'${receiverInfo}' does`; } - return this.reportError( + this.reportDiagnostic( `Identifier '${ast.name}' is not defined. ${receiverInfo} not contain such a member`, ast); + return this.anyType; } if (!member.public) { let receiverInfo = receiverType.name; @@ -401,24 +418,15 @@ export class AstType implements AstVisitor { } else { receiverInfo = `'${receiverInfo}'`; } - this.reportWarning( - `Identifier '${ast.name}' refers to a private member of ${receiverInfo}`, ast); + this.reportDiagnostic( + `Identifier '${ast.name}' refers to a private member of ${receiverInfo}`, ast, + ts.DiagnosticCategory.Warning); } return member.type; } - private reportError(message: string, ast: AST): Symbol { - if (this.diagnostics) { - this.diagnostics.push(new TypeDiagnostic(ts.DiagnosticCategory.Error, message, ast)); - } - return this.anyType; - } - - private reportWarning(message: string, ast: AST): Symbol { - if (this.diagnostics) { - this.diagnostics.push(new TypeDiagnostic(ts.DiagnosticCategory.Warning, message, ast)); - } - return this.anyType; + private reportDiagnostic(message: string, ast: AST, kind = ts.DiagnosticCategory.Error) { + this.diagnostics.push({kind, span: ast.span, message}); } private isAny(symbol: Symbol): boolean { diff --git a/packages/language-service/src/expressions.ts b/packages/language-service/src/expressions.ts index 26be536414..9d49448f93 100644 --- a/packages/language-service/src/expressions.ts +++ b/packages/language-service/src/expressions.ts @@ -148,8 +148,14 @@ export function getExpressionSymbol( }, visitPropertyWrite(ast) { const receiverType = getType(ast.receiver); + const {start} = ast.span; symbol = receiverType && receiverType.members().get(ast.name); - span = ast.span; + // A PropertyWrite span includes both the LHS (name) and the RHS (value) of the write. In this + // visit, only the name is relevant. + // prop=$event + // ^^^^ name + // ^^^^^^ value; visited separately as a nested AST + span = {start, end: start + ast.name.length}; }, visitQuote(ast) {}, visitSafeMethodCall(ast) { diff --git a/packages/language-service/src/global_symbols.ts b/packages/language-service/src/global_symbols.ts index 2f2c46aba0..4c0325ab62 100644 --- a/packages/language-service/src/global_symbols.ts +++ b/packages/language-service/src/global_symbols.ts @@ -59,6 +59,7 @@ export const createGlobalSymbolTable: (query: ng.SymbolQuery) => ng.SymbolTable }; }, indexed: () => undefined, + typeArguments: () => undefined, }, }, ]); diff --git a/packages/language-service/src/hover.ts b/packages/language-service/src/hover.ts index 9234377069..145fdfbc6b 100644 --- a/packages/language-service/src/hover.ts +++ b/packages/language-service/src/hover.ts @@ -6,20 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileSummaryKind, StaticSymbol} from '@angular/compiler'; +import {NgAnalyzedModules} from '@angular/compiler'; import * as ts from 'typescript'; - import {AstResult} from './common'; -import {locateSymbol} from './locate_symbol'; +import {locateSymbols} from './locate_symbol'; import * as ng from './types'; -import {TypeScriptServiceHost} from './typescript_host'; -import {findTightestNode} from './utils'; - +import {inSpan} from './utils'; // Reverse mappings of enum would generate strings const SYMBOL_SPACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.space]; const SYMBOL_PUNC = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.punctuation]; -const SYMBOL_CLASS = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.className]; const SYMBOL_TEXT = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.text]; const SYMBOL_INTERFACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.interfaceName]; @@ -28,123 +24,92 @@ const SYMBOL_INTERFACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.inter * return the corresponding quick info. * @param info template AST * @param position location of the symbol - * @param host Language Service host to query + * @param analyzedModules all NgModules in the program. */ -export function getHover(info: AstResult, position: number, host: Readonly): - ts.QuickInfo|undefined { - const symbolInfo = locateSymbol(info, position); +export function getTemplateHover( + info: AstResult, position: number, analyzedModules: NgAnalyzedModules): ts.QuickInfo|undefined { + const symbolInfo = locateSymbols(info, position)[0]; if (!symbolInfo) { return; } - const {symbol, span, compileTypeSummary} = symbolInfo; - const textSpan = {start: span.start, length: span.end - span.start}; + const {symbol, span, staticSymbol} = symbolInfo; - if (compileTypeSummary && compileTypeSummary.summaryKind === CompileSummaryKind.Directive) { - return getDirectiveModule(compileTypeSummary.type.reference, textSpan, host, symbol); + // The container is either the symbol's container (for example, 'AppComponent' + // is the container of the symbol 'title' in its template) or the NgModule + // that the directive belongs to (the container of AppComponent is AppModule). + let containerName: string|undefined = symbol.container ?.name; + if (!containerName && staticSymbol) { + // If there is a static symbol then the target is a directive. + const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol); + containerName = ngModule ?.type.reference.name; } - const containerDisplayParts: ts.SymbolDisplayPart[] = symbol.container ? - [ - {text: symbol.container.name, kind: symbol.container.kind}, - {text: '.', kind: SYMBOL_PUNC}, - ] : - []; - const typeDisplayParts: ts.SymbolDisplayPart[] = symbol.type ? - [ - {text: ':', kind: SYMBOL_PUNC}, - {text: ' ', kind: SYMBOL_SPACE}, - {text: symbol.type.name, kind: SYMBOL_INTERFACE}, - ] : - []; - return { - kind: symbol.kind as ts.ScriptElementKind, - kindModifiers: '', // kindModifier info not available on 'ng.Symbol' - textSpan, - documentation: symbol.documentation, - // this would generate a string like '(property) ClassX.propY: type' - // 'kind' in displayParts does not really matter because it's dropped when - // displayParts get converted to string. - displayParts: [ - {text: '(', kind: SYMBOL_PUNC}, - {text: symbol.kind, kind: symbol.kind}, - {text: ')', kind: SYMBOL_PUNC}, - {text: ' ', kind: SYMBOL_SPACE}, - ...containerDisplayParts, - {text: symbol.name, kind: symbol.kind}, - ...typeDisplayParts, - ], - }; + return createQuickInfo(symbol.name, symbol.kind, span, containerName, symbol.type?.name, symbol.documentation); } /** * Get quick info for Angular semantic entities in TypeScript files, like Directives. - * @param sf TypeScript source file an Angular symbol is in * @param position location of the symbol in the source file - * @param host Language Service host to query + * @param declarations All Directive-like declarations in the source file. + * @param analyzedModules all NgModules in the program. */ export function getTsHover( - sf: ts.SourceFile, position: number, host: Readonly): ts.QuickInfo| - undefined { - const node = findTightestNode(sf, position); - if (!node) return; - switch (node.kind) { - case ts.SyntaxKind.Identifier: - const directiveId = node as ts.Identifier; - if (ts.isClassDeclaration(directiveId.parent)) { - const directiveName = directiveId.text; - const directiveSymbol = host.getStaticSymbol(node.getSourceFile().fileName, directiveName); - if (!directiveSymbol) return; - return getDirectiveModule( - directiveSymbol, - {start: directiveId.getStart(), length: directiveId.end - directiveId.getStart()}, - host); - } - break; - default: - break; + position: number, declarations: ng.Declaration[], + analyzedModules: NgAnalyzedModules): ts.QuickInfo|undefined { + for (const {declarationSpan, metadata} of declarations) { + if (inSpan(position, declarationSpan)) { + const staticSymbol: ng.StaticSymbol = metadata.type.reference; + const directiveName = staticSymbol.name; + const kind = metadata.isComponent ? 'component' : 'directive'; + const textSpan = ts.createTextSpanFromBounds(declarationSpan.start, declarationSpan.end); + const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol); + const moduleName = ngModule ?.type.reference.name; + return createQuickInfo( + directiveName, kind, textSpan, moduleName, ts.ScriptElementKind.classElement); + } } - return undefined; } /** - * Attempts to get quick info for the NgModule a Directive is declared in. - * @param directive identifier on a potential Directive class declaration - * @param textSpan span of the symbol - * @param host Language Service host to query - * @param symbol the internal symbol that represents the directive + * Construct a QuickInfo object taking into account its container and type. + * @param name Name of the QuickInfo target + * @param kind component, directive, pipe, etc. + * @param textSpan span of the target + * @param containerName either the Symbol's container or the NgModule that contains the directive + * @param type user-friendly name of the type + * @param documentation docstring or comment */ -function getDirectiveModule( - directive: StaticSymbol, textSpan: ts.TextSpan, host: Readonly, - symbol?: ng.Symbol): ts.QuickInfo|undefined { - const analyzedModules = host.getAnalyzedModules(false); - const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(directive); - if (!ngModule) return; +function createQuickInfo( + name: string, kind: string, textSpan: ts.TextSpan, containerName?: string, type?: string, + documentation?: ts.SymbolDisplayPart[]): ts.QuickInfo { + const containerDisplayParts = containerName ? + [ + {text: containerName, kind: SYMBOL_INTERFACE}, + {text: '.', kind: SYMBOL_PUNC}, + ] : + []; - const isComponent = - host.getDeclarations(directive.filePath) - .find(decl => decl.type === directive && decl.metadata && decl.metadata.isComponent); + const typeDisplayParts = type ? + [ + {text: ':', kind: SYMBOL_PUNC}, + {text: ' ', kind: SYMBOL_SPACE}, + {text: type, kind: SYMBOL_INTERFACE}, + ] : + []; - const moduleName = ngModule.type.reference.name; return { - kind: ts.ScriptElementKind.classElement, - kindModifiers: - ts.ScriptElementKindModifier.none, // kindModifier info not available on 'ng.Symbol' - textSpan, - documentation: symbol ? symbol.documentation : undefined, - // This generates a string like '(directive) NgModule.Directive: class' - // 'kind' in displayParts does not really matter because it's dropped when - // displayParts get converted to string. + kind: kind as ts.ScriptElementKind, + kindModifiers: ts.ScriptElementKindModifier.none, + textSpan: textSpan, displayParts: [ {text: '(', kind: SYMBOL_PUNC}, - {text: isComponent ? 'component' : 'directive', kind: SYMBOL_TEXT}, + {text: kind, kind: SYMBOL_TEXT}, {text: ')', kind: SYMBOL_PUNC}, {text: ' ', kind: SYMBOL_SPACE}, - {text: moduleName, kind: SYMBOL_CLASS}, - {text: '.', kind: SYMBOL_PUNC}, - {text: directive.name, kind: SYMBOL_CLASS}, - {text: ':', kind: SYMBOL_PUNC}, - {text: ' ', kind: SYMBOL_SPACE}, - {text: ts.ScriptElementKind.classElement, kind: SYMBOL_TEXT}, + ...containerDisplayParts, + {text: name, kind: SYMBOL_INTERFACE}, + ...typeDisplayParts, ], + documentation, }; } diff --git a/packages/language-service/src/language_service.ts b/packages/language-service/src/language_service.ts index 37c66958e4..c6d1faacfe 100644 --- a/packages/language-service/src/language_service.ts +++ b/packages/language-service/src/language_service.ts @@ -10,9 +10,9 @@ import * as tss from 'typescript/lib/tsserverlibrary'; import {getTemplateCompletions} from './completions'; import {getDefinitionAndBoundSpan, getTsDefinitionAndBoundSpan} from './definitions'; -import {getDeclarationDiagnostics, getTemplateDiagnostics, ngDiagnosticToTsDiagnostic, uniqueBySpan} from './diagnostics'; -import {getHover, getTsHover} from './hover'; -import {Diagnostic, LanguageService} from './types'; +import {getDeclarationDiagnostics, getTemplateDiagnostics, ngDiagnosticToTsDiagnostic} from './diagnostics'; +import {getTemplateHover, getTsHover} from './hover'; +import * as ng from './types'; import {TypeScriptServiceHost} from './typescript_host'; /** @@ -20,35 +20,36 @@ import {TypeScriptServiceHost} from './typescript_host'; * * @publicApi */ -export function createLanguageService(host: TypeScriptServiceHost): LanguageService { +export function createLanguageService(host: TypeScriptServiceHost) { return new LanguageServiceImpl(host); } -class LanguageServiceImpl implements LanguageService { +class LanguageServiceImpl implements ng.LanguageService { constructor(private readonly host: TypeScriptServiceHost) {} - getDiagnostics(fileName: string): tss.Diagnostic[] { + getSemanticDiagnostics(fileName: string): tss.Diagnostic[] { const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData' - const results: Diagnostic[] = []; - const templates = this.host.getTemplates(fileName); + const ngDiagnostics: ng.Diagnostic[] = []; + const templates = this.host.getTemplates(fileName); for (const template of templates) { const ast = this.host.getTemplateAst(template); if (ast) { - results.push(...getTemplateDiagnostics(ast)); + ngDiagnostics.push(...getTemplateDiagnostics(ast)); } } const declarations = this.host.getDeclarations(fileName); - if (declarations && declarations.length) { - results.push(...getDeclarationDiagnostics(declarations, analyzedModules, this.host)); - } + ngDiagnostics.push(...getDeclarationDiagnostics(declarations, analyzedModules, this.host)); const sourceFile = fileName.endsWith('.ts') ? this.host.getSourceFile(fileName) : undefined; - return uniqueBySpan(results).map(d => ngDiagnosticToTsDiagnostic(d, sourceFile)); + const tsDiagnostics = ngDiagnostics.map(d => ngDiagnosticToTsDiagnostic(d, sourceFile)); + return [...tss.sortAndDeduplicateDiagnostics(tsDiagnostics)]; } - getCompletionsAt(fileName: string, position: number): tss.CompletionInfo|undefined { + getCompletionsAtPosition( + fileName: string, position: number, + options?: tss.GetCompletionsAtPositionOptions): tss.CompletionInfo|undefined { this.host.getAnalyzedModules(); // same role as 'synchronizeHostData' const ast = this.host.getTemplateAstAtPosition(fileName, position); if (!ast) { @@ -67,7 +68,8 @@ class LanguageServiceImpl implements LanguageService { }; } - getDefinitionAt(fileName: string, position: number): tss.DefinitionInfoAndBoundSpan|undefined { + getDefinitionAndBoundSpan(fileName: string, position: number): tss.DefinitionInfoAndBoundSpan + |undefined { this.host.getAnalyzedModules(); // same role as 'synchronizeHostData' const templateInfo = this.host.getTemplateAstAtPosition(fileName, position); if (templateInfo) { @@ -84,20 +86,16 @@ class LanguageServiceImpl implements LanguageService { } } - getHoverAt(fileName: string, position: number): tss.QuickInfo|undefined { - this.host.getAnalyzedModules(); // same role as 'synchronizeHostData' + getQuickInfoAtPosition(fileName: string, position: number): tss.QuickInfo|undefined { + const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData' const templateInfo = this.host.getTemplateAstAtPosition(fileName, position); if (templateInfo) { - return getHover(templateInfo, position, this.host); + return getTemplateHover(templateInfo, position, analyzedModules); } // Attempt to get Angular-specific hover information in a TypeScript file, the NgModule a // directive belongs to. - if (fileName.endsWith('.ts')) { - const sf = this.host.getSourceFile(fileName); - if (sf) { - return getTsHover(sf, position, this.host); - } - } + const declarations = this.host.getDeclarations(fileName); + return getTsHover(position, declarations, analyzedModules); } } diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index 20e66e4645..65591ea880 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -6,189 +6,285 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, Attribute, BoundDirectivePropertyAst, BoundEventAst, CompileTypeSummary, CssSelector, DirectiveAst, ElementAst, SelectorMatcher, TemplateAstPath, tokenReference} from '@angular/compiler'; +import {Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference} from '@angular/compiler'; +import * as tss from 'typescript/lib/tsserverlibrary'; import {AstResult} from './common'; import {getExpressionScope} from './expression_diagnostics'; import {getExpressionSymbol} from './expressions'; import {Definition, DirectiveKind, Span, Symbol} from './types'; -import {diagnosticInfoFromTemplateInfo, findTemplateAstAt, getPathToNodeAtPosition, inSpan, offsetSpan, spanOf} from './utils'; +import {diagnosticInfoFromTemplateInfo, findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils'; export interface SymbolInfo { symbol: Symbol; - span: Span; - compileTypeSummary: CompileTypeSummary|undefined; + span: tss.TextSpan; + staticSymbol?: StaticSymbol; } /** - * Traverse the template AST and locate the Symbol at the specified `position`. - * @param info Ast and Template Source - * @param position location to look for + * Traverses a template AST and locates symbol(s) at a specified position. + * @param info template AST information set + * @param position location to locate symbols at */ -export function locateSymbol(info: AstResult, position: number): SymbolInfo|undefined { +export function locateSymbols(info: AstResult, position: number): SymbolInfo[] { const templatePosition = position - info.template.span.start; + // TODO: update `findTemplateAstAt` to use absolute positions. const path = findTemplateAstAt(info.templateAst, templatePosition); - let compileTypeSummary: CompileTypeSummary|undefined = undefined; - if (path.tail) { - let symbol: Symbol|undefined = undefined; - let span: Span|undefined = undefined; - const attributeValueSymbol = (ast: AST, inEvent: boolean = false): boolean => { - const attribute = findAttribute(info, position); - if (attribute) { - if (inSpan(templatePosition, spanOf(attribute.valueSpan))) { - const dinfo = diagnosticInfoFromTemplateInfo(info); - const scope = getExpressionScope(dinfo, path, inEvent); - if (attribute.valueSpan) { - const result = getExpressionSymbol(scope, ast, templatePosition, info.template.query); - if (result) { - symbol = result.symbol; - const expressionOffset = attribute.valueSpan.start.offset; - span = offsetSpan(result.span, expressionOffset); - } - } - return true; - } - } - return false; - }; - path.tail.visit( - { - visitNgContent(ast) {}, - visitEmbeddedTemplate(ast) {}, - visitElement(ast) { - const component = ast.directives.find(d => d.directive.isComponent); - if (component) { - compileTypeSummary = component.directive; - symbol = info.template.query.getTypeSymbol(compileTypeSummary.type.reference); - symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.COMPONENT); - span = spanOf(ast); - } else { - // Find a directive that matches the element name - const directive = ast.directives.find( - d => d.directive.selector != null && d.directive.selector.indexOf(ast.name) >= 0); - if (directive) { - compileTypeSummary = directive.directive; - symbol = info.template.query.getTypeSymbol(compileTypeSummary.type.reference); - symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE); - span = spanOf(ast); - } - } - }, - visitReference(ast) { - symbol = ast.value && info.template.query.getTypeSymbol(tokenReference(ast.value)); - span = spanOf(ast); - }, - visitVariable(ast) {}, - visitEvent(ast) { - if (!attributeValueSymbol(ast.handler, /* inEvent */ true)) { - symbol = findOutputBinding(info, path, ast); - symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.EVENT); - span = spanOf(ast); - } - }, - visitElementProperty(ast) { attributeValueSymbol(ast.value); }, - visitAttr(ast) { - const element = path.head; - if (!element || !(element instanceof ElementAst)) return; - // Create a mapping of all directives applied to the element from their selectors. - const matcher = new SelectorMatcher(); - for (const dir of element.directives) { - if (!dir.directive.selector) continue; - matcher.addSelectables(CssSelector.parse(dir.directive.selector), dir); - } + const attribute = findAttribute(info, position); - // See if this attribute matches the selector of any directive on the element. - // TODO(ayazhafiz): Consider caching selector matches (at the expense of potentially - // very high memory usage). - const attributeSelector = `[${ast.name}=${ast.value}]`; - const parsedAttribute = CssSelector.parse(attributeSelector); - if (!parsedAttribute.length) return; - matcher.match(parsedAttribute[0], (_, directive) => { - symbol = info.template.query.getTypeSymbol(directive.directive.type.reference); - symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE); - span = spanOf(ast); - }); - }, - visitBoundText(ast) { - const expressionPosition = templatePosition - ast.sourceSpan.start.offset; - if (inSpan(expressionPosition, ast.value.span)) { - const dinfo = diagnosticInfoFromTemplateInfo(info); - const scope = getExpressionScope(dinfo, path, /* includeEvent */ false); - const result = - getExpressionSymbol(scope, ast.value, templatePosition, info.template.query); - if (result) { - symbol = result.symbol; - span = offsetSpan(result.span, ast.sourceSpan.start.offset); - } - } - }, - visitText(ast) {}, - visitDirective(ast) { - compileTypeSummary = ast.directive; - symbol = info.template.query.getTypeSymbol(compileTypeSummary.type.reference); + if (!path.tail) return []; + + const narrowest = spanOf(path.tail); + const toVisit: TemplateAst[] = []; + for (let node: TemplateAst|undefined = path.tail; + node && isNarrower(spanOf(node.sourceSpan), narrowest); node = path.parentOf(node)) { + toVisit.push(node); + } + + // For the structural directive, only care about the last template AST. + if (attribute?.name.startsWith('*')) { + toVisit.splice(0, toVisit.length - 1); + } + + return toVisit.map(ast => locateSymbol(ast, path, info)) + .filter((sym): sym is SymbolInfo => sym !== undefined); +} + +/** + * Visits a template node and locates the symbol in that node at a path position. + * @param ast template AST node to visit + * @param path non-empty set of narrowing AST nodes at a position + * @param info template AST information set + */ +function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): SymbolInfo| + undefined { + const templatePosition = path.position; + const position = templatePosition + info.template.span.start; + let symbol: Symbol|undefined; + let span: Span|undefined; + let staticSymbol: StaticSymbol|undefined; + const attributeValueSymbol = (): boolean => { + const attribute = findAttribute(info, position); + if (attribute) { + if (inSpan(templatePosition, spanOf(attribute.valueSpan))) { + const result = getSymbolInAttributeValue(info, path, attribute); + if (result) { + symbol = result.symbol; + span = offsetSpan(result.span, attribute.valueSpan !.start.offset); + } + return true; + } + } + return false; + }; + ast.visit( + { + visitNgContent(ast) {}, + visitEmbeddedTemplate(ast) {}, + visitElement(ast) { + const component = ast.directives.find(d => d.directive.isComponent); + if (component) { + // Need to cast because 'reference' is typed as any + staticSymbol = component.directive.type.reference as StaticSymbol; + symbol = info.template.query.getTypeSymbol(staticSymbol); + symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.COMPONENT); span = spanOf(ast); - }, - visitDirectiveProperty(ast) { - if (!attributeValueSymbol(ast.value)) { - symbol = findInputBinding(info, path, ast); + } else { + // Find a directive that matches the element name + const directive = ast.directives.find( + d => d.directive.selector != null && d.directive.selector.indexOf(ast.name) >= 0); + if (directive) { + // Need to cast because 'reference' is typed as any + staticSymbol = directive.directive.type.reference as StaticSymbol; + symbol = info.template.query.getTypeSymbol(staticSymbol); + symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE); span = spanOf(ast); } } }, - null); - if (symbol && span) { - return {symbol, span: offsetSpan(span, info.template.span.start), compileTypeSummary}; - } + visitReference(ast) { + symbol = ast.value && info.template.query.getTypeSymbol(tokenReference(ast.value)); + span = spanOf(ast); + }, + visitVariable(ast) {}, + visitEvent(ast) { + if (!attributeValueSymbol()) { + symbol = findOutputBinding(ast, path, info.template.query); + symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.EVENT); + span = spanOf(ast); + } + }, + visitElementProperty(ast) { attributeValueSymbol(); }, + visitAttr(ast) { + const element = path.head; + if (!element || !(element instanceof ElementAst)) return; + // Create a mapping of all directives applied to the element from their selectors. + const matcher = new SelectorMatcher(); + for (const dir of element.directives) { + if (!dir.directive.selector) continue; + matcher.addSelectables(CssSelector.parse(dir.directive.selector), dir); + } + + // See if this attribute matches the selector of any directive on the element. + const attributeSelector = `[${ast.name}=${ast.value}]`; + const parsedAttribute = CssSelector.parse(attributeSelector); + if (!parsedAttribute.length) return; + matcher.match(parsedAttribute[0], (_, {directive}) => { + // Need to cast because 'reference' is typed as any + staticSymbol = directive.type.reference as StaticSymbol; + symbol = info.template.query.getTypeSymbol(staticSymbol); + symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE); + span = spanOf(ast); + }); + }, + visitBoundText(ast) { + const expressionPosition = templatePosition - ast.sourceSpan.start.offset; + if (inSpan(expressionPosition, ast.value.span)) { + const dinfo = diagnosticInfoFromTemplateInfo(info); + const scope = getExpressionScope(dinfo, path); + const result = + getExpressionSymbol(scope, ast.value, templatePosition, info.template.query); + if (result) { + symbol = result.symbol; + span = offsetSpan(result.span, ast.sourceSpan.start.offset); + } + } + }, + visitText(ast) {}, + visitDirective(ast) { + // Need to cast because 'reference' is typed as any + staticSymbol = ast.directive.type.reference as StaticSymbol; + symbol = info.template.query.getTypeSymbol(staticSymbol); + span = spanOf(ast); + }, + visitDirectiveProperty(ast) { + if (!attributeValueSymbol()) { + const directive = findParentOfBinding(info.templateAst, ast, templatePosition); + const attribute = findAttribute(info, position); + if (directive && attribute) { + if (attribute.name.startsWith('*')) { + const compileTypeSummary = directive.directive; + symbol = info.template.query.getTypeSymbol(compileTypeSummary.type.reference); + symbol = symbol && new OverrideKindSymbol(symbol, DirectiveKind.DIRECTIVE); + // Use 'attribute.sourceSpan' instead of the directive's, + // because the span of the directive is the whole opening tag of an element. + span = spanOf(attribute.sourceSpan); + } else { + symbol = findInputBinding(info, ast.templateName, directive); + span = spanOf(ast); + } + } + } + } + }, + null); + if (symbol && span) { + const {start, end} = offsetSpan(span, info.template.span.start); + return { + symbol, + span: tss.createTextSpanFromBounds(start, end), staticSymbol, + }; } } +// Get the symbol in attribute value at template position. +function getSymbolInAttributeValue(info: AstResult, path: TemplateAstPath, attribute: Attribute): + {symbol: Symbol, span: Span}|undefined { + if (!attribute.valueSpan) { + return; + } + let result: {symbol: Symbol, span: Span}|undefined; + const {templateBindings} = info.expressionParser.parseTemplateBindings( + attribute.name, attribute.value, attribute.sourceSpan.toString(), + attribute.valueSpan.start.offset); + // Find where the cursor is relative to the start of the attribute value. + const valueRelativePosition = path.position - attribute.valueSpan.start.offset; + + // Find the symbol that contains the position. + templateBindings.filter(tb => !tb.keyIsVar).forEach(tb => { + if (inSpan(valueRelativePosition, tb.expression?.ast.span)) { + const dinfo = diagnosticInfoFromTemplateInfo(info); + const scope = getExpressionScope(dinfo, path); + result = getExpressionSymbol(scope, tb.expression !, path.position, info.template.query); + } else if (inSpan(valueRelativePosition, tb.span)) { + const template = path.first(EmbeddedTemplateAst); + if (template) { + // One element can only have one template binding. + const directiveAst = template.directives[0]; + if (directiveAst) { + const symbol = findInputBinding(info, tb.key.substring(1), directiveAst); + if (symbol) { + result = {symbol, span: tb.span}; + } + } + } + } + }); + return result; +} + function findAttribute(info: AstResult, position: number): Attribute|undefined { const templatePosition = position - info.template.span.start; const path = getPathToNodeAtPosition(info.htmlAst, templatePosition); return path.first(Attribute); } -function findInputBinding( - info: AstResult, path: TemplateAstPath, binding: BoundDirectivePropertyAst): Symbol|undefined { - const element = path.first(ElementAst); - if (element) { - for (const directive of element.directives) { - const invertedInput = invertMap(directive.directive.inputs); - const fieldName = invertedInput[binding.templateName]; - if (fieldName) { - const classSymbol = info.template.query.getTypeSymbol(directive.directive.type.reference); - if (classSymbol) { - return classSymbol.members().get(fieldName); - } - } - } - } -} - -function findOutputBinding(info: AstResult, path: TemplateAstPath, binding: BoundEventAst): Symbol| +// TODO: remove this function after the path includes 'DirectiveAst'. +// Find the directive that corresponds to the specified 'binding' +// at the specified 'position' in the 'ast'. +function findParentOfBinding( + ast: TemplateAst[], binding: BoundDirectivePropertyAst, position: number): DirectiveAst| undefined { - const element = path.first(ElementAst); - if (element) { - for (const directive of element.directives) { - const invertedOutputs = invertMap(directive.directive.outputs); - const fieldName = invertedOutputs[binding.name]; - if (fieldName) { - const classSymbol = info.template.query.getTypeSymbol(directive.directive.type.reference); - if (classSymbol) { - return classSymbol.members().get(fieldName); - } + let res: DirectiveAst|undefined; + const visitor = new class extends RecursiveTemplateAstVisitor { + visit(ast: TemplateAst): any { + const span = spanOf(ast); + if (!inSpan(position, span)) { + // Returning a value here will result in the children being skipped. + return true; } } - } + + visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { + return this.visitChildren(context, visit => { + visit(ast.directives); + visit(ast.children); + }); + } + + visitElement(ast: ElementAst, context: any): any { + return this.visitChildren(context, visit => { + visit(ast.directives); + visit(ast.children); + }); + } + + visitDirective(ast: DirectiveAst) { + const result = this.visitChildren(ast, visit => { visit(ast.inputs); }); + return result; + } + + visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: DirectiveAst) { + if (ast === binding) { + res = context; + } + } + }; + templateVisitAll(visitor, ast); + return res; } -function invertMap(obj: {[name: string]: string}): {[name: string]: string} { - const result: {[name: string]: string} = {}; - for (const name of Object.keys(obj)) { - const v = obj[name]; - result[v] = name; +// Find the symbol of input binding in 'directiveAst' by 'name'. +function findInputBinding(info: AstResult, name: string, directiveAst: DirectiveAst): Symbol| + undefined { + const invertedInput = invertMap(directiveAst.directive.inputs); + const fieldName = invertedInput[name]; + if (fieldName) { + const classSymbol = info.template.query.getTypeSymbol(directiveAst.directive.type.reference); + if (classSymbol) { + return classSymbol.members().get(fieldName); + } } - return result; } /** @@ -223,4 +319,6 @@ class OverrideKindSymbol implements Symbol { selectSignature(types: Symbol[]) { return this.sym.selectSignature(types); } indexed(argument: Symbol) { return this.sym.indexed(argument); } + + typeArguments(): Symbol[]|undefined { return this.sym.typeArguments(); } } diff --git a/packages/language-service/src/symbols.ts b/packages/language-service/src/symbols.ts index 2b88deab11..da3f851e24 100644 --- a/packages/language-service/src/symbols.ts +++ b/packages/language-service/src/symbols.ts @@ -129,6 +129,11 @@ export interface Symbol { * If the symbol cannot be indexed, this method should return `undefined`. */ indexed(argument: Symbol, key?: any): Symbol|undefined; + + /** + * Returns the type arguments of a Symbol, if any. + */ + typeArguments(): Symbol[]|undefined; } /** diff --git a/packages/language-service/src/template.ts b/packages/language-service/src/template.ts index afd13214e1..e882b1ca81 100644 --- a/packages/language-service/src/template.ts +++ b/packages/language-service/src/template.ts @@ -98,7 +98,9 @@ export class InlineTemplate extends BaseTemplate { throw new Error(`Inline template and component class should belong to the same source file`); } this.fileName = sourceFile.fileName; - this.source = templateNode.text; + // node.text returns the TS internal representation of the normalized text, + // and all CR characters are stripped. node.getText() returns the raw text. + this.source = templateNode.getText().slice(1, -1); // strip leading and trailing quotes this.span = { // TS string literal includes surrounding quotes in the start/end offsets. start: templateNode.getStart() + 1, diff --git a/packages/language-service/src/ts_plugin.ts b/packages/language-service/src/ts_plugin.ts index 71ac44c8f3..e2d4594cc9 100644 --- a/packages/language-service/src/ts_plugin.ts +++ b/packages/language-service/src/ts_plugin.ts @@ -36,7 +36,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { return results; } } - return ngLS.getCompletionsAt(fileName, position); + return ngLS.getCompletionsAtPosition(fileName, position, options); } function getQuickInfoAtPosition(fileName: string, position: number): tss.QuickInfo|undefined { @@ -47,7 +47,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { return result; } } - return ngLS.getHoverAt(fileName, position); + return ngLS.getQuickInfoAtPosition(fileName, position); } function getSemanticDiagnostics(fileName: string): tss.Diagnostic[] { @@ -56,7 +56,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { results.push(...tsLS.getSemanticDiagnostics(fileName)); } // For semantic diagnostics we need to combine both TS + Angular results - results.push(...ngLS.getDiagnostics(fileName)); + results.push(...ngLS.getSemanticDiagnostics(fileName)); return results; } @@ -69,7 +69,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { return results; } } - const result = ngLS.getDefinitionAt(fileName, position); + const result = ngLS.getDefinitionAndBoundSpan(fileName, position); if (!result || !result.definitions || !result.definitions.length) { return; } @@ -85,7 +85,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { return result; } } - return ngLS.getDefinitionAt(fileName, position); + return ngLS.getDefinitionAndBoundSpan(fileName, position); } const proxy: tss.LanguageService = Object.assign( diff --git a/packages/language-service/src/types.ts b/packages/language-service/src/types.ts index 63f3d21ae6..cb349eea4d 100644 --- a/packages/language-service/src/types.ts +++ b/packages/language-service/src/types.ts @@ -7,7 +7,7 @@ */ import {CompileDirectiveMetadata, NgAnalyzedModules, StaticSymbol} from '@angular/compiler'; - +import * as ts from 'typescript'; import {AstResult} from './common'; import {BuiltinType, DeclarationKind, Definition, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; @@ -124,7 +124,7 @@ export interface Declaration { /** * Reference to the compiler directive metadata for the declaration. */ - readonly metadata?: CompileDirectiveMetadata; + readonly metadata: CompileDirectiveMetadata; /** * Error reported trying to get the metadata. @@ -354,48 +354,12 @@ export interface Hover { /** * An instance of an Angular language service created by `createLanguageService()`. * - * The language service returns information about Angular templates that are included in a project - * as defined by the `LanguageServiceHost`. - * - * When a method expects a `fileName` this file can either be source file in the project that - * contains a template in a string literal or a template file referenced by the project returned - * by `getTemplateReference()`. All other files will cause the method to return `undefined`. - * - * If a method takes a `position`, it is the offset of the UTF-16 code-point relative to the - * beginning of the file reference by `fileName`. - * - * This interface and all interfaces and types marked as `LanguageService` types, describe a - * particular implementation of the Angular language service and is not intended to be - * implemented. Adding members to the interface will not be considered a breaking change as - * defined by SemVer. - * - * Removing a member or making a member optional, changing a method parameters, or changing a - * member's type will all be considered a breaking change. - * - * While an interface is marked as experimental breaking-changes will be allowed between minor - * releases. After an interface is marked as stable breaking-changes will only be allowed between - * major releases. No breaking changes are allowed between patch releases. + * The Angular language service implements a subset of methods defined in + * The Angular language service implements a subset of methods defined by + * the TypeScript language service. * * @publicApi */ -export interface LanguageService { - /** - * Returns a list of all error for all templates in the given file. - */ - getDiagnostics(fileName: string): ts.Diagnostic[]; - - /** - * Return the completions at the given position. - */ - getCompletionsAt(fileName: string, position: number): ts.CompletionInfo|undefined; - - /** - * Return the definition location for the symbol at position. - */ - getDefinitionAt(fileName: string, position: number): ts.DefinitionInfoAndBoundSpan|undefined; - - /** - * Return the hover information for the symbol at position. - */ - getHoverAt(fileName: string, position: number): ts.QuickInfo|undefined; -} +export type LanguageService = Pick< + ts.LanguageService, 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'| + 'getQuickInfoAtPosition'|'getSemanticDiagnostics'>; diff --git a/packages/language-service/src/typescript_host.ts b/packages/language-service/src/typescript_host.ts index a9576638b4..e7a6e8d9ef 100644 --- a/packages/language-service/src/typescript_host.ts +++ b/packages/language-service/src/typescript_host.ts @@ -148,13 +148,9 @@ export class TypeScriptServiceHost implements LanguageServiceHost { * and templateReferences. * In addition to returning information about NgModules, this method plays the * same role as 'synchronizeHostData' in tsserver. - * @param ensureSynchronized whether or not the Language Service should make sure analyzedModules - * are synced to the last update of the project. If false, returns the set of analyzedModules - * that is already cached. This is useful if the project must not be reanalyzed, even if its - * file watchers (which are disjoint from the TypeScriptServiceHost) detect an update. */ - getAnalyzedModules(ensureSynchronized = true): NgAnalyzedModules { - if (!ensureSynchronized || this.upToDate()) { + getAnalyzedModules(): NgAnalyzedModules { + if (this.upToDate()) { return this.analyzedModules; } @@ -288,9 +284,9 @@ export class TypeScriptServiceHost implements LanguageServiceHost { const visit = (child: tss.Node) => { const candidate = getDirectiveClassLike(child); if (candidate) { - const {decoratorId, classDecl} = candidate; - const declarationSpan = spanOf(decoratorId); - const className = classDecl.name !.text; + const {classId} = candidate; + const declarationSpan = spanOf(classId); + const className = classId.getText(); const classSymbol = this.reflector.getStaticSymbol(sourceFile.fileName, className); // Ask the resolver to check if candidate is actually Angular directive if (!this.resolver.isDirective(classSymbol)) { @@ -450,14 +446,6 @@ export class TypeScriptServiceHost implements LanguageServiceHost { return this.getTemplateAst(template); } - /** - * Gets a StaticSymbol from a file and symbol name. - * @return Angular StaticSymbol matching the file and name, if any - */ - getStaticSymbol(file: string, name: string): StaticSymbol|undefined { - return this.reflector.getStaticSymbol(file, name); - } - /** * Find the NgModule which the directive associated with the `classSymbol` * belongs to, then return its schema and transitive directives and pipes. diff --git a/packages/language-service/src/typescript_symbols.ts b/packages/language-service/src/typescript_symbols.ts index 834d242b7f..ba7d088c8c 100644 --- a/packages/language-service/src/typescript_symbols.ts +++ b/packages/language-service/src/typescript_symbols.ts @@ -82,14 +82,16 @@ export function getPipesTable( class TypeScriptSymbolQuery implements SymbolQuery { private typeCache = new Map(); - // TODO(issue/24571): remove '!'. - private pipesCache !: SymbolTable; + private pipesCache: SymbolTable|undefined; constructor( private program: ts.Program, private checker: ts.TypeChecker, private source: ts.SourceFile, private fetchPipes: () => SymbolTable) {} - getTypeKind(symbol: Symbol): BuiltinType { return typeKindOf(this.getTsTypeOf(symbol)); } + getTypeKind(symbol: Symbol): BuiltinType { + const type = symbol instanceof TypeWrapper ? symbol.tsType : undefined; + return typeKindOf(type); + } getBuiltinType(kind: BuiltinType): Symbol { let result = this.typeCache.get(kind); @@ -125,10 +127,10 @@ class TypeScriptSymbolQuery implements SymbolQuery { getElementType(type: Symbol): Symbol|undefined { if (type instanceof TypeWrapper) { - const elementType = getTypeParameterOf(type.tsType, 'Array'); - if (elementType) { - return new TypeWrapper(elementType, type.context); - } + const tSymbol = type.tsType.symbol; + const tArgs = type.typeArguments(); + if (!tSymbol || tSymbol.name !== 'Array' || !tArgs || tArgs.length != 1) return; + return tArgs[0]; } } @@ -157,8 +159,8 @@ class TypeScriptSymbolQuery implements SymbolQuery { const context: TypeContext = {node: this.source, program: this.program, checker: this.checker}; const typeSymbol = findClassSymbolInContext(type, context); if (typeSymbol) { - const contextType = this.getTemplateRefContextType(typeSymbol); - if (contextType) return new SymbolWrapper(contextType, context).members(); + const contextType = this.getTemplateRefContextType(typeSymbol, context); + if (contextType) return contextType.members(); } } @@ -186,7 +188,7 @@ class TypeScriptSymbolQuery implements SymbolQuery { return spanAt(this.source, line, column); } - private getTemplateRefContextType(typeSymbol: ts.Symbol): ts.Symbol|undefined { + private getTemplateRefContextType(typeSymbol: ts.Symbol, context: TypeContext): Symbol|undefined { const type = this.checker.getTypeOfSymbolAtLocation(typeSymbol, this.source); const constructor = type.symbol && type.symbol.members && getFromSymbolTable(type.symbol.members !, '__constructor'); @@ -196,29 +198,15 @@ class TypeScriptSymbolQuery implements SymbolQuery { for (const parameter of constructorDeclaration.parameters) { const type = this.checker.getTypeAtLocation(parameter.type !); if (type.symbol !.name == 'TemplateRef' && isReferenceType(type)) { - const typeReference = type as ts.TypeReference; - if (typeReference.typeArguments && typeReference.typeArguments.length === 1) { - return typeReference.typeArguments[0].symbol; + const typeWrapper = new TypeWrapper(type, context); + const typeArguments = typeWrapper.typeArguments(); + if (typeArguments && typeArguments.length === 1) { + return typeArguments[0]; } } } } } - - private getTsTypeOf(symbol: Symbol): ts.Type|undefined { - const type = this.getTypeWrapper(symbol); - return type && type.tsType; - } - - private getTypeWrapper(symbol: Symbol): TypeWrapper|undefined { - let type: TypeWrapper|undefined = undefined; - if (symbol instanceof TypeWrapper) { - type = symbol; - } else if (symbol.type instanceof TypeWrapper) { - type = symbol.type; - } - return type; - } } function typeCallable(type: ts.Type): boolean { @@ -289,8 +277,7 @@ class TypeWrapper implements Symbol { return selectSignature(this.tsType, this.context, types); } - indexed(argument: Symbol, value: any): Symbol|undefined { - const type = argument instanceof TypeWrapper ? argument : argument.type; + indexed(type: Symbol, value: any): Symbol|undefined { if (!(type instanceof TypeWrapper)) return; const typeKind = typeKindOf(type.tsType); @@ -311,6 +298,16 @@ class TypeWrapper implements Symbol { return sType && new TypeWrapper(sType, this.context); } } + + typeArguments(): Symbol[]|undefined { + if (!isReferenceType(this.tsType)) return; + + const typeReference = (this.tsType as ts.TypeReference); + let typeArguments: ReadonlyArray|undefined; + typeArguments = this.context.checker.getTypeArguments(typeReference); + if (!typeArguments) return undefined; + return typeArguments.map(ta => new TypeWrapper(ta, this.context)); + } } // If stringIndexType a primitive type(e.g. 'string'), the Symbol is undefined; @@ -342,7 +339,7 @@ class SymbolWrapper implements Symbol { get kind(): DeclarationKind { return this.callable ? 'method' : 'property'; } - get type(): Symbol|undefined { return new TypeWrapper(this.tsType, this.context); } + get type(): TypeWrapper { return new TypeWrapper(this.tsType, this.context); } get container(): Symbol|undefined { return getContainerOf(this.symbol, this.context); } @@ -380,6 +377,8 @@ class SymbolWrapper implements Symbol { indexed(argument: Symbol): Symbol|undefined { return undefined; } + typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + private get tsType(): ts.Type { let type = this._tsType; if (!type) { @@ -405,21 +404,21 @@ class DeclaredSymbol implements Symbol { get container(): Symbol|undefined { return undefined; } - get type() { return this.declaration.type; } + get type(): Symbol { return this.declaration.type; } - get callable(): boolean { return this.declaration.type.callable; } + get callable(): boolean { return this.type.callable; } get definition(): Definition { return this.declaration.definition; } get documentation(): ts.SymbolDisplayPart[] { return this.declaration.type.documentation; } - members(): SymbolTable { return this.declaration.type.members(); } + members(): SymbolTable { return this.type.members(); } - signatures(): Signature[] { return this.declaration.type.signatures(); } + signatures(): Signature[] { return this.type.signatures(); } - selectSignature(types: Symbol[]): Signature|undefined { - return this.declaration.type.selectSignature(types); - } + selectSignature(types: Symbol[]): Signature|undefined { return this.type.selectSignature(types); } + + typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } indexed(argument: Symbol): Symbol|undefined { return undefined; } } @@ -442,17 +441,14 @@ class SignatureResultOverride implements Signature { get result(): Symbol { return this.resultType; } } -export function toSymbolTableFactory(symbols: ts.Symbol[]) { +export function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { // ∀ Typescript version >= 2.2, `SymbolTable` is implemented as an ES6 `Map` const result = new Map(); for (const symbol of symbols) { result.set(symbol.name, symbol); } - // First, tell the compiler that `result` is of type `any`. Then, use a second type assertion - // to `ts.SymbolTable`. - // Otherwise, `Map` and `ts.SymbolTable` will be considered as incompatible - // types by the compiler - return (result); + + return result as ts.SymbolTable; } function toSymbols(symbolTable: ts.SymbolTable | undefined): ts.Symbol[] { @@ -589,8 +585,7 @@ class PipesTable implements SymbolTable { const INDEX_PATTERN = /[\\/]([^\\/]+)[\\/]\1\.d\.ts$/; class PipeSymbol implements Symbol { - // TODO(issue/24571): remove '!'. - private _tsType !: ts.Type; + private _tsType: ts.Type|undefined; public readonly kind: DeclarationKind = 'pipe'; public readonly language: string = 'typescript'; public readonly container: Symbol|undefined = undefined; @@ -602,7 +597,7 @@ class PipeSymbol implements Symbol { get name(): string { return this.pipe.name; } - get type(): Symbol|undefined { return new TypeWrapper(this.tsType, this.context); } + get type(): TypeWrapper { return new TypeWrapper(this.tsType, this.context); } get definition(): Definition|undefined { const symbol = this.tsType.getSymbol(); @@ -625,24 +620,21 @@ class PipeSymbol implements Symbol { let signature = selectSignature(this.tsType, this.context, types) !; if (types.length > 0) { const parameterType = types[0]; - if (parameterType instanceof TypeWrapper) { - let resultType: ts.Type|undefined = undefined; - switch (this.name) { - case 'async': - // Get symbol of 'Observable', 'Promise', or 'EventEmitter' type. - const symbol = parameterType.tsType.symbol; - if (symbol) { - resultType = getTypeParameterOf(parameterType.tsType, symbol.name); - } - break; - case 'slice': - resultType = parameterType.tsType; - break; - } - if (resultType) { - signature = new SignatureResultOverride( - signature, new TypeWrapper(resultType, parameterType.context)); - } + let resultType: Symbol|undefined = undefined; + switch (this.name) { + case 'async': + // Get type argument of 'Observable', 'Promise', or 'EventEmitter'. + const tArgs = parameterType.typeArguments(); + if (tArgs && tArgs.length === 1) { + resultType = tArgs[0]; + } + break; + case 'slice': + resultType = parameterType; + break; + } + if (resultType) { + signature = new SignatureResultOverride(signature, resultType); } } return signature; @@ -650,6 +642,8 @@ class PipeSymbol implements Symbol { indexed(argument: Symbol): Symbol|undefined { return undefined; } + typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + private get tsType(): ts.Type { let type = this._tsType; if (!type) { @@ -798,15 +792,6 @@ function getContainerOf(symbol: ts.Symbol, context: TypeContext): Symbol|undefin } } -function getTypeParameterOf(type: ts.Type, name: string): ts.Type|undefined { - if (type && type.symbol && type.symbol.name == name) { - const typeArguments: ts.Type[] = (type as any).typeArguments; - if (typeArguments && typeArguments.length <= 1) { - return typeArguments[0]; - } - } -} - function typeKindOf(type: ts.Type | undefined): BuiltinType { if (type) { if (type.flags & ts.TypeFlags.Any) { diff --git a/packages/language-service/src/utils.ts b/packages/language-service/src/utils.ts index 934457e9ce..4b8c062ee1 100644 --- a/packages/language-service/src/utils.ts +++ b/packages/language-service/src/utils.ts @@ -6,12 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {AstPath, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, identifierName, templateVisitAll, visitAll} from '@angular/compiler'; +import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, identifierName, templateVisitAll, visitAll} from '@angular/compiler'; import * as ts from 'typescript'; import {AstResult, SelectorInfo} from './common'; import {DiagnosticTemplateInfo} from './expression_diagnostics'; -import {Span} from './types'; +import {Span, Symbol, SymbolQuery} from './types'; export interface SpanHolder { sourceSpan: ParseSourceSpan; @@ -102,7 +102,7 @@ export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTempl export function findTemplateAstAt(ast: TemplateAst[], position: number): TemplateAstPath { const path: TemplateAst[] = []; const visitor = new class extends RecursiveTemplateAstVisitor { - visit(ast: TemplateAst, context: any): any { + visit(ast: TemplateAst): any { let span = spanOf(ast); if (inSpan(position, span)) { const len = path.length; @@ -164,8 +164,8 @@ export function findTightestNode(node: ts.Node, position: number): ts.Node|undef } interface DirectiveClassLike { - decoratorId: ts.Identifier; // decorator identifier - classDecl: ts.ClassDeclaration; + decoratorId: ts.Identifier; // decorator identifier, like @Component + classId: ts.Identifier; } /** @@ -178,11 +178,11 @@ interface DirectiveClassLike { * * For example, * v---------- `decoratorId` - * @NgModule({ - * declarations: [], - * }) - * class AppModule {} - * ^----- `classDecl` + * @NgModule({ < + * declarations: [], < classDecl + * }) < + * class AppModule {} < + * ^----- `classId` * * @param node Potential node that represents an Angular directive. */ @@ -200,7 +200,7 @@ export function getDirectiveClassLike(node: ts.Node): DirectiveClassLike|undefin if (ts.isObjectLiteralExpression(arg)) { return { decoratorId: expr.expression, - classDecl: node, + classId: node.name, }; } } @@ -247,3 +247,39 @@ export function getPathToNodeAtPosition(nodes: Node[], position: number): HtmlAs visitAll(visitor, nodes); return new AstPath(path, position); } + + +/** + * Inverts an object's key-value pairs. + */ +export function invertMap(obj: {[name: string]: string}): {[name: string]: string} { + const result: {[name: string]: string} = {}; + for (const name of Object.keys(obj)) { + const v = obj[name]; + result[v] = name; + } + return result; +} + + +/** + * Finds the directive member providing a template output binding, if one exists. + * @param info aggregate template AST information + * @param path narrowing + */ +export function findOutputBinding( + binding: BoundEventAst, path: TemplateAstPath, query: SymbolQuery): Symbol|undefined { + const element = path.first(ElementAst); + if (element) { + for (const directive of element.directives) { + const invertedOutputs = invertMap(directive.directive.outputs); + const fieldName = invertedOutputs[binding.name]; + if (fieldName) { + const classSymbol = query.getTypeSymbol(directive.directive.type.reference); + if (classSymbol) { + return classSymbol.members().get(fieldName); + } + } + } + } +} diff --git a/packages/language-service/test/BUILD.bazel b/packages/language-service/test/BUILD.bazel index f23e62bf27..00ccbd3407 100644 --- a/packages/language-service/test/BUILD.bazel +++ b/packages/language-service/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/language-service/index.js", + deps = ["//packages/language-service"], +) ts_library( name = "test_lib", diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts index e2795dab59..2d6967570c 100644 --- a/packages/language-service/test/completions_spec.ts +++ b/packages/language-service/test/completions_spec.ts @@ -29,7 +29,7 @@ describe('completions', () => { it('should be able to get entity completions', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'entity-amp'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.ENTITY, ['&', '>', '<', 'ι']); }); @@ -37,14 +37,14 @@ describe('completions', () => { const locations = ['empty', 'start-tag-h1', 'h1-content', 'start-tag', 'start-tag-after-h']; for (const location of locations) { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, location); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.HTML_ELEMENT, ['div', 'h1', 'h2', 'span']); } }); it('should be able to return component directives', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'empty'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.COMPONENT, [ 'ng-form', 'my-app', @@ -55,13 +55,13 @@ describe('completions', () => { it('should be able to return attribute directives', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h1-after-space'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.ATTRIBUTE, ['string-model', 'number-model']); }); it('should be able to return angular pseudo elements', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'empty'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.ANGULAR_ELEMENT, [ 'ng-container', 'ng-content', @@ -71,7 +71,7 @@ describe('completions', () => { it('should be able to return h1 attributes', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h1-after-space'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.HTML_ATTRIBUTE, [ 'class', 'id', @@ -82,7 +82,7 @@ describe('completions', () => { it('should be able to find common Angular attributes', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'div-attributes'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.ATTRIBUTE, [ 'ngClass', 'ngForm', @@ -94,13 +94,13 @@ describe('completions', () => { it('should be able to get the completions at the beginning of an interpolation', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h2-hero'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['title', 'hero']); }); it('should not include private members of a class', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h2-hero'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expect(completions).toBeDefined(); const internal = completions !.entries.find(e => e.name === 'internal'); expect(internal).toBeUndefined(); @@ -108,20 +108,20 @@ describe('completions', () => { it('should be able to get the completions at the end of an interpolation', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'sub-end'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['title', 'hero']); }); it('should be able to get the completions in a property', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h2-name'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); it('should suggest template references', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.ATTRIBUTE, [ 'ngFor', 'ngForOf', @@ -134,52 +134,52 @@ describe('completions', () => { it('should be able to return attribute names with an incomplete attribute', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'no-value-attribute'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.HTML_ATTRIBUTE, ['id', 'class', 'dir', 'lang']); }); it('should be able to return attributes of an incomplete element', () => { const m1 = mockHost.getLocationMarkerFor(PARSING_CASES, 'incomplete-open-lt'); - const c1 = ngLS.getCompletionsAt(PARSING_CASES, m1.start); + const c1 = ngLS.getCompletionsAtPosition(PARSING_CASES, m1.start); expectContain(c1, CompletionKind.HTML_ELEMENT, ['a', 'div', 'p', 'span']); const m2 = mockHost.getLocationMarkerFor(PARSING_CASES, 'incomplete-open-a'); - const c2 = ngLS.getCompletionsAt(PARSING_CASES, m2.start); + const c2 = ngLS.getCompletionsAtPosition(PARSING_CASES, m2.start); expectContain(c2, CompletionKind.HTML_ELEMENT, ['a', 'div', 'p', 'span']); const m3 = mockHost.getLocationMarkerFor(PARSING_CASES, 'incomplete-open-attr'); - const c3 = ngLS.getCompletionsAt(PARSING_CASES, m3.start); + const c3 = ngLS.getCompletionsAtPosition(PARSING_CASES, m3.start); expectContain(c3, CompletionKind.HTML_ATTRIBUTE, ['id', 'class', 'href', 'name']); }); it('should be able to return completions with a missing closing tag', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'missing-closing'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.HTML_ELEMENT, ['a', 'div', 'p', 'span', 'h1', 'h2']); }); it('should be able to return common attributes of an unknown tag', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'unknown-element'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.HTML_ATTRIBUTE, ['id', 'dir', 'lang']); }); it('should be able to get completions in an empty interpolation', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'empty-interpolation'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['title', 'subTitle']); }); it('should suggest $any() type cast function in an interpolation', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'sub-start'); - const completions = ngLS.getCompletionsAt(APP_COMPONENT, marker.start); + const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expectContain(completions, CompletionKind.METHOD, ['$any']); }); it('should suggest attribute values', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, [ 'title', 'hero', @@ -192,14 +192,14 @@ describe('completions', () => { it('should suggest event handlers', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.METHOD, ['myClick']); }); it('for methods should include parentheses', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); expect(completions !.entries).toContain(jasmine.objectContaining({ name: 'myClick', @@ -211,7 +211,7 @@ describe('completions', () => { it('for methods of pipe should not include parentheses', () => { mockHost.override(TEST_TEMPLATE, `

{{title | lowe~{pipe-method} }}`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'pipe-method'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); expect(completions !.entries).toContain(jasmine.objectContaining({ name: 'lowercase', @@ -223,7 +223,7 @@ describe('completions', () => { describe('in external template', () => { it('should be able to get entity completions in external template', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'entity-amp'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.ENTITY, ['&', '>', '<', 'ι']); }); @@ -231,7 +231,7 @@ describe('completions', () => { const locations = ['empty', 'start-tag-h1', 'h1-content', 'start-tag', 'start-tag-after-h']; for (const location of locations) { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, location); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); const {entries} = completions !; expect(entries).not.toContain(jasmine.objectContaining({name: 'div'})); @@ -243,7 +243,7 @@ describe('completions', () => { it('should be able to return element directives', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'empty'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.COMPONENT, [ 'ng-form', 'my-app', @@ -254,7 +254,7 @@ describe('completions', () => { it('should not return html attributes', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'h1-after-space'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); const {entries} = completions !; expect(entries).not.toContain(jasmine.objectContaining({name: 'class'})); @@ -266,7 +266,7 @@ describe('completions', () => { it('should be able to find common Angular attributes', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.ATTRIBUTE, [ 'ngClass', 'ngForm', @@ -280,7 +280,7 @@ describe('completions', () => { describe('with a *ngIf', () => { it('should be able to get completions for exported *ngIf variable', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'promised-person-name'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['name', 'age', 'street']); }); }); @@ -289,7 +289,7 @@ describe('completions', () => { it('should suggest NgForRow members for let initialization expression', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, [ '$implicit', 'ngForOf', @@ -305,14 +305,14 @@ describe('completions', () => { it('should not provide suggestion before the = sign', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeUndefined(); }); it('should include field reference', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['title', 'heroes', 'league']); // the symbol 'x' declared in *ngFor is also in scope. This asserts that // we are actually taking the AST into account and not just referring to @@ -323,7 +323,7 @@ describe('completions', () => { it('should include expression completions', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'expr-property-read'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['name']); }); @@ -334,7 +334,7 @@ describe('completions', () => {

`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.VARIABLE, ['h']); }); @@ -345,13 +345,13 @@ describe('completions', () => {
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); it('should be able to infer the type of a ngForOf with an async pipe', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'async-person-name'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['name', 'age', 'street']); }); @@ -364,7 +364,7 @@ describe('completions', () => {
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'position'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); // member variable of type Hero has properties 'id' and 'name'. expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); @@ -374,35 +374,35 @@ describe('completions', () => { it('should be able to complete property value', () => { mockHost.override(TEST_TEMPLATE, `

`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['title']); }); it('should be able to complete property read', () => { mockHost.override(TEST_TEMPLATE, `

`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'property-read'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); it('should be able to complete an event', () => { mockHost.override(TEST_TEMPLATE, `

`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.METHOD, ['myClick']); }); it('should be able to complete a the LHS of a two-way binding', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.ATTRIBUTE, ['ngModel']); }); it('should be able to complete a the RHS of a two-way binding', () => { mockHost.override(TEST_TEMPLATE, `

`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['title']); }); @@ -410,13 +410,13 @@ describe('completions', () => { // Property binding via [] mockHost.override(TEST_TEMPLATE, `
`); const m1 = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const c1 = ngLS.getCompletionsAt(TEST_TEMPLATE, m1.start); + const c1 = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, m1.start); expectContain(c1, CompletionKind.ATTRIBUTE, ['inputAlias']); // Property binding via bind- mockHost.override(TEST_TEMPLATE, `
`); const m2 = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const c2 = ngLS.getCompletionsAt(TEST_TEMPLATE, m2.start); + const c2 = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, m2.start); expectContain(c2, CompletionKind.ATTRIBUTE, ['inputAlias']); }); @@ -424,13 +424,13 @@ describe('completions', () => { // Event binding via () mockHost.override(TEST_TEMPLATE, `
`); const m1 = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const c1 = ngLS.getCompletionsAt(TEST_TEMPLATE, m1.start); + const c1 = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, m1.start); expectContain(c1, CompletionKind.ATTRIBUTE, ['outputAlias']); // Event binding via on- mockHost.override(TEST_TEMPLATE, `
`); const m2 = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const c2 = ngLS.getCompletionsAt(TEST_TEMPLATE, m2.start); + const c2 = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, m2.start); expectContain(c2, CompletionKind.ATTRIBUTE, ['outputAlias']); }); @@ -438,13 +438,13 @@ describe('completions', () => { // Banana-in-a-box via [()] mockHost.override(TEST_TEMPLATE, `
`); const m1 = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const c1 = ngLS.getCompletionsAt(TEST_TEMPLATE, m1.start); + const c1 = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, m1.start); expectContain(c1, CompletionKind.ATTRIBUTE, ['model']); // Banana-in-a-box via bindon- mockHost.override(TEST_TEMPLATE, `
`); const m2 = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const c2 = ngLS.getCompletionsAt(TEST_TEMPLATE, m2.start); + const c2 = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, m2.start); expectContain(c2, CompletionKind.ATTRIBUTE, ['model']); }); }); @@ -453,7 +453,7 @@ describe('completions', () => { it('should be able to get a list of pipe values', () => { for (const location of ['before-pipe', 'in-pipe', 'after-pipe']) { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, location); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.PIPE, [ 'async', 'uppercase', @@ -465,7 +465,7 @@ describe('completions', () => { it('should be able to resolve lowercase', () => { const marker = mockHost.getLocationMarkerFor(EXPRESSION_CASES, 'string-pipe'); - const completions = ngLS.getCompletionsAt(EXPRESSION_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(EXPRESSION_CASES, marker.start); expectContain(completions, CompletionKind.METHOD, [ 'charAt', 'replace', @@ -478,13 +478,13 @@ describe('completions', () => { describe('with references', () => { it('should list references', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'test-comp-content'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.REFERENCE, ['div', 'test1', 'test2']); }); it('should reference the component', () => { const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'test-comp-after-test'); - const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['name', 'testEvent']); }); @@ -494,14 +494,14 @@ describe('completions', () => {
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'property-read'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['name', 'testEvent']); }); // TODO: Enable when we have a flag that indicates the project targets the DOM // it('should reference the element if no component', () => { // const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'test-comp-after-div'); - // const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start); + // const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); // expectContain(completions, CompletionKind.PROPERTY, ['innerText']); // }); }); @@ -520,7 +520,7 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'key') !; expect(completion).toBeDefined(); @@ -537,7 +537,7 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'start'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'acronym') !; expect(completion).toBeDefined(); @@ -554,7 +554,7 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'end'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'acronym') !; expect(completion).toBeDefined(); @@ -575,7 +575,7 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'key') !; expect(completion).toBeDefined(); @@ -596,7 +596,7 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'field'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === '$title_1') !; expect(completion).toBeDefined(); @@ -615,7 +615,7 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'click'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'click') !; expect(completion).toBeDefined(); @@ -636,7 +636,7 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'handleClick'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'handleClick') !; expect(completion).toBeDefined(); @@ -655,7 +655,7 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'div'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'div') !; expect(completion).toBeDefined(); @@ -674,7 +674,7 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'model'); - const completions = ngLS.getCompletionsAt(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; expect(completions).toBeDefined(); const completion = completions.entries.find(entry => entry.name === 'ngModel') !; expect(completion).toBeDefined(); @@ -687,14 +687,14 @@ describe('completions', () => { it('should work with numeric index signatures (arrays)', () => { mockHost.override(TEST_TEMPLATE, `{{ heroes[0].~{heroes-number-index}}}`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'heroes-number-index'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); it('should work with numeric index signatures (tuple arrays)', () => { mockHost.override(TEST_TEMPLATE, `{{ tupleArray[1].~{tuple-array-number-index}}}`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'tuple-array-number-index'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); @@ -702,21 +702,21 @@ describe('completions', () => { it('should work with index notation', () => { mockHost.override(TEST_TEMPLATE, `{{ heroesByName['Jacky'].~{heroes-string-index}}}`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'heroes-string-index'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); it('should work with dot notation', () => { mockHost.override(TEST_TEMPLATE, `{{ heroesByName.jacky.~{heroes-string-index}}}`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'heroes-string-index'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); it('should work with dot notation if stringIndexType is a primitive type', () => { mockHost.override(TEST_TEMPLATE, `{{ primitiveIndexType.test.~{string-primitive-type}}}`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'string-primitive-type'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.METHOD, ['substring']); }); }); @@ -725,14 +725,14 @@ describe('completions', () => { it('should be able to get the completions (ref- prefix)', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start) !; + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !; expectContain(completions, CompletionKind.REFERENCE, ['ngForm']); }); it('should be able to get the completions (# prefix)', () => { mockHost.override(TEST_TEMPLATE, `
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start) !; + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !; expectContain(completions, CompletionKind.REFERENCE, ['ngForm']); }); }); @@ -741,9 +741,35 @@ describe('completions', () => { it('should not expand i18n templates', () => { mockHost.override(TEST_TEMPLATE, `
{{~{cursor}}}
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['title']); }); + + describe('$event completions', () => { + it('should suggest $event in event bindings', () => { + mockHost.override(TEST_TEMPLATE, `
`); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + expectContain(completions, CompletionKind.VARIABLE, ['$event']); + }); + }); + + describe('$event completions', () => { + it('should suggest $event in event bindings', () => { + mockHost.override(TEST_TEMPLATE, `
`); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + expectContain(completions, CompletionKind.VARIABLE, ['$event']); + }); + + it('should suggest $event completions in output bindings', () => { + mockHost.override(TEST_TEMPLATE, `
`); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + // Expect string properties + expectContain(completions, CompletionKind.METHOD, ['charAt', 'substring']); + }); + }); }); function expectContain( diff --git a/packages/language-service/test/definitions_spec.ts b/packages/language-service/test/definitions_spec.ts index 175a8ecfd3..6f989d03c9 100644 --- a/packages/language-service/test/definitions_spec.ts +++ b/packages/language-service/test/definitions_spec.ts @@ -13,6 +13,9 @@ import {TypeScriptServiceHost} from '../src/typescript_host'; import {MockTypescriptHost} from './test_utils'; +const TEST_TEMPLATE = '/app/test.ng'; +const PARSING_CASES = '/app/parsing-cases.ts'; + describe('definitions', () => { const mockHost = new MockTypescriptHost(['/app/main.ts']); const service = ts.createLanguageService(mockHost); @@ -31,7 +34,7 @@ describe('definitions', () => { }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -47,28 +50,26 @@ describe('definitions', () => { }); it('should be able to find a field in a attribute reference', () => { - const fileName = mockHost.addCode(` - @Component({ - template: '' - }) - export class MyComponent { - «ᐱnameᐱ: string;» - }`); + mockHost.override(TEST_TEMPLATE, ``); - const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); + const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); + expect(definitions !.length).toBe(1); const def = definitions ![0]; - expect(def.fileName).toBe(fileName); - expect(def.name).toBe('name'); + expect(def.fileName).toBe(PARSING_CASES); + expect(def.name).toBe('title'); expect(def.kind).toBe('property'); - expect(def.textSpan).toEqual(mockHost.getDefinitionMarkerFor(fileName, 'name')); + + const fileContent = mockHost.readFile(def.fileName); + expect(fileContent !.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) + .toEqual(`title = 'Some title';`); }); it('should be able to find a method from a call', () => { @@ -81,7 +82,7 @@ describe('definitions', () => { }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'myClick'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -106,7 +107,7 @@ describe('definitions', () => { }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'include'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -131,7 +132,7 @@ describe('definitions', () => { // Get the marker for «test-comp» in the code added above. const marker = mockHost.getReferenceMarkerFor(fileName, 'test-comp'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -168,7 +169,7 @@ describe('definitions', () => { // Get the marker for «test» in the code added above. const marker = mockHost.getReferenceMarkerFor(fileName, 'test'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -205,7 +206,7 @@ describe('definitions', () => { // Get the marker for «test» in the code added above. const marker = mockHost.getReferenceMarkerFor(fileName, 'tcName'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -242,7 +243,7 @@ describe('definitions', () => { // Get the marker for «test» in the code added above. const marker = mockHost.getReferenceMarkerFor(fileName, 'async'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -262,6 +263,123 @@ describe('definitions', () => { } }); + describe('in structural directive', () => { + it('should be able to find the directive', () => { + mockHost.override( + TEST_TEMPLATE, `
`); + + // Get the marker for ngFor in the code added above. + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'ngFor'); + + const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); + expect(result).toBeDefined(); + const {textSpan, definitions} = result !; + + // Get the marker for bounded text in the code added above + const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); + expect(textSpan).toEqual(boundedText); + + expect(definitions).toBeDefined(); + expect(definitions !.length).toBe(1); + + const refFileName = '/node_modules/@angular/common/common.d.ts'; + const def = definitions ![0]; + expect(def.fileName).toBe(refFileName); + expect(def.name).toBe('NgForOf'); + expect(def.kind).toBe('directive'); + // Not asserting the textSpan of definition because it's external file + }); + + it('should be able to find the directive property', () => { + mockHost.override( + TEST_TEMPLATE, + `
`); + + // Get the marker for trackBy in the code added above. + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'trackBy'); + + const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); + expect(result).toBeDefined(); + const {textSpan, definitions} = result !; + + // Get the marker for bounded text in the code added above + const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); + expect(textSpan).toEqual(boundedText); + + expect(definitions).toBeDefined(); + // The two definitions are setter and getter of 'ngForTrackBy'. + expect(definitions !.length).toBe(2); + + const refFileName = '/node_modules/@angular/common/common.d.ts'; + definitions !.forEach(def => { + expect(def.fileName).toBe(refFileName); + expect(def.name).toBe('ngForTrackBy'); + expect(def.kind).toBe('method'); + }); + // Not asserting the textSpan of definition because it's external file + }); + + it('should be able to find the property value', () => { + mockHost.override(TEST_TEMPLATE, `
`); + + // Get the marker for heroes in the code added above. + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'heroes'); + + const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); + expect(result).toBeDefined(); + const {textSpan, definitions} = result !; + + expect(textSpan).toEqual(marker); + + expect(definitions).toBeDefined(); + expect(definitions !.length).toBe(1); + + const refFileName = '/app/parsing-cases.ts'; + const def = definitions ![0]; + expect(def.fileName).toBe(refFileName); + expect(def.name).toBe('heroes'); + expect(def.kind).toBe('property'); + const content = mockHost.readFile(refFileName) !; + expect(content.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) + .toEqual(`heroes: Hero[] = [this.hero];`); + }); + }); + + it('should be able to find a two-way binding', () => { + mockHost.override( + TEST_TEMPLATE, + ``); + // Get the marker for «model» in the code added above. + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'model'); + + const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); + expect(result).toBeDefined(); + const {textSpan, definitions} = result !; + + // Get the marker for bounded text in the code added above + const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); + expect(textSpan).toEqual(boundedText); + + expect(definitions).toBeDefined(); + expect(definitions !.length).toBe(2); + const [def1, def2] = definitions !; + + const refFileName = '/app/parsing-cases.ts'; + expect(def1.fileName).toBe(refFileName); + expect(def1.name).toBe('model'); + expect(def1.kind).toBe('property'); + let content = mockHost.readFile(refFileName) !; + expect(content.substring(def1.textSpan.start, def1.textSpan.start + def1.textSpan.length)) + .toEqual(`@Input() model: string = 'model';`); + + expect(def2.fileName).toBe(refFileName); + expect(def2.name).toBe('modelChange'); + expect(def2.kind).toBe('event'); + content = mockHost.readFile(refFileName) !; + expect(content.substring(def2.textSpan.start, def2.textSpan.start + def2.textSpan.length)) + .toEqual(`@Output() modelChange: EventEmitter = new EventEmitter();`); + }); + it('should be able to find a template from a url', () => { const fileName = mockHost.addCode(` @Component({ @@ -270,7 +388,7 @@ describe('definitions', () => { export class MyComponent {}`); const marker = mockHost.getReferenceMarkerFor(fileName, 'test'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -293,7 +411,7 @@ describe('definitions', () => { export class MyComponent {}`); const marker = mockHost.getReferenceMarkerFor(fileName, 'test'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; @@ -317,7 +435,7 @@ describe('definitions', () => { }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); - const result = ngService.getDefinitionAt(fileName, marker.start); + const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); const {textSpan, definitions} = result !; diff --git a/packages/language-service/test/diagnostics_spec.ts b/packages/language-service/test/diagnostics_spec.ts index afff120cd1..3cccaa1f2b 100644 --- a/packages/language-service/test/diagnostics_spec.ts +++ b/packages/language-service/test/diagnostics_spec.ts @@ -25,7 +25,6 @@ import {MockTypescriptHost} from './test_utils'; const EXPRESSION_CASES = '/app/expression-cases.ts'; const NG_FOR_CASES = '/app/ng-for-cases.ts'; -const NG_IF_CASES = '/app/ng-if-cases.ts'; const TEST_TEMPLATE = '/app/test.ng'; const APP_COMPONENT = '/app/app.component.ts'; @@ -39,7 +38,7 @@ describe('diagnostics', () => { it('should produce no diagnostics for test.ng', () => { // there should not be any errors on existing external template - expect(ngLS.getDiagnostics('/app/test.ng')).toEqual([]); + expect(ngLS.getSemanticDiagnostics('/app/test.ng')).toEqual([]); }); it('should not return TS and NG errors for existing files', () => { @@ -52,14 +51,14 @@ describe('diagnostics', () => { expect(syntaxDiags).toEqual([]); const semanticDiags = tsLS.getSemanticDiagnostics(file); expect(semanticDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(file); + const ngDiags = ngLS.getSemanticDiagnostics(file); expect(ngDiags).toEqual([]); } }); it('should report error for unexpected end of expression', () => { const content = mockHost.override(TEST_TEMPLATE, `{{ 5 / }}`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); const {messageText, start, length} = diags[0]; expect(messageText) @@ -73,7 +72,7 @@ describe('diagnostics', () => { // https://github.com/angular/vscode-ng-language-service/issues/242 it('should support $any() type cast function', () => { mockHost.override(TEST_TEMPLATE, `
{{$any(title).xyz}}
`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags).toEqual([]); }); @@ -84,7 +83,7 @@ describe('diagnostics', () => { ]; for (const template of templates) { mockHost.override(TEST_TEMPLATE, template); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); expect(diags[0].messageText).toBe('Unable to resolve signature for call of method $any'); } @@ -95,7 +94,7 @@ describe('diagnostics', () => {
{{h.name}}
`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags).toEqual([]); }); @@ -104,7 +103,7 @@ describe('diagnostics', () => {
{{h.age}}
`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); expect(diags[0].messageText) .toBe(`Identifier 'age' is not defined. 'Hero' does not contain such a member`); @@ -116,7 +115,7 @@ describe('diagnostics', () => { `); - const diagnostics = ngLS.getDiagnostics(TEST_TEMPLATE); + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diagnostics).toEqual([]); }); @@ -128,7 +127,7 @@ describe('diagnostics', () => { {{ i === isFirst }}
`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); expect(diags[0].messageText).toBe(`Expected the operants to be of similar type or any`); }); @@ -140,7 +139,7 @@ describe('diagnostics', () => { {{ i < 2 }}
`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(0); }); }); @@ -149,7 +148,7 @@ describe('diagnostics', () => { it('should work with numeric index signatures (arrays)', () => { mockHost.override(TEST_TEMPLATE, ` {{heroes[0].badProperty}}`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); expect(diags[0].messageText) .toBe(`Identifier 'badProperty' is not defined. 'Hero' does not contain such a member`); @@ -159,7 +158,7 @@ describe('diagnostics', () => { it('should work with index notation', () => { mockHost.override(TEST_TEMPLATE, ` {{heroesByName['Jacky'].badProperty}}`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); expect(diags[0].messageText) .toBe(`Identifier 'badProperty' is not defined. 'Hero' does not contain such a member`); @@ -168,7 +167,7 @@ describe('diagnostics', () => { it('should work with dot notation', () => { mockHost.override(TEST_TEMPLATE, ` {{heroesByName.jacky.badProperty}}`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); expect(diags[0].messageText) .toBe(`Identifier 'badProperty' is not defined. 'Hero' does not contain such a member`); @@ -177,7 +176,7 @@ describe('diagnostics', () => { it('should not produce errors with dot notation if stringIndexType is a primitive type', () => { mockHost.override(TEST_TEMPLATE, `{{primitiveIndexType.test}}`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(0); }); }); @@ -186,7 +185,7 @@ describe('diagnostics', () => { it('should produce diagnostics for invalid tuple type property access', () => { mockHost.override(TEST_TEMPLATE, ` {{tupleArray[1].badProperty}}`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); expect(diags[0].messageText) .toBe(`Identifier 'badProperty' is not defined. 'Hero' does not contain such a member`); @@ -195,7 +194,7 @@ describe('diagnostics', () => { it('should not produce errors if tuple array index out of bound', () => { mockHost.override(TEST_TEMPLATE, ` {{tupleArray[2].badProperty}}`); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags).toEqual([]); }); @@ -203,13 +202,13 @@ describe('diagnostics', () => { mockHost.override(TEST_TEMPLATE, ` `); - const diags = ngLS.getDiagnostics(TEST_TEMPLATE); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags).toEqual([]); }); describe('in expression-cases.ts', () => { it('should report access to an unknown field', () => { - const diags = ngLS.getDiagnostics(EXPRESSION_CASES).map(d => d.messageText); + const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); expect(diags).toContain( `Identifier 'foo' is not defined. ` + `The component declaration, template variable declarations, ` + @@ -217,38 +216,33 @@ describe('diagnostics', () => { }); it('should report access to an unknown sub-field', () => { - const diags = ngLS.getDiagnostics(EXPRESSION_CASES).map(d => d.messageText); + const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); expect(diags).toContain( `Identifier 'nam' is not defined. 'Person' does not contain such a member`); }); it('should report access to a private member', () => { - const diags = ngLS.getDiagnostics(EXPRESSION_CASES).map(d => d.messageText); + const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); expect(diags).toContain(`Identifier 'myField' refers to a private member of the component`); }); it('should report numeric operator errors', () => { - const diags = ngLS.getDiagnostics(EXPRESSION_CASES).map(d => d.messageText); + const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); expect(diags).toContain('Expected a numeric type'); }); }); describe('in ng-for-cases.ts', () => { it('should report an unknown field', () => { - const diags = ngLS.getDiagnostics(NG_FOR_CASES).map(d => d.messageText); + const diags = ngLS.getSemanticDiagnostics(NG_FOR_CASES).map(d => d.messageText); expect(diags).toContain( `Identifier 'people_1' is not defined. ` + `The component declaration, template variable declarations, ` + `and element references do not contain such a member`); }); - it('should report an unknown context reference', () => { - const diags = ngLS.getDiagnostics(NG_FOR_CASES).map(d => d.messageText); - expect(diags).toContain(`The template context does not define a member called 'even_1'`); - }); - it('should report an unknown value in a key expression', () => { - const diags = ngLS.getDiagnostics(NG_FOR_CASES).map(d => d.messageText); + const diags = ngLS.getSemanticDiagnostics(NG_FOR_CASES).map(d => d.messageText); expect(diags).toContain( `Identifier 'trackBy_1' is not defined. ` + `The component declaration, template variable declarations, ` + @@ -256,10 +250,41 @@ describe('diagnostics', () => { }); }); - describe('in ng-if-cases.ts', () => { - it('should report an implicit context reference', () => { - const diags = ngLS.getDiagnostics(NG_IF_CASES).map(d => d.messageText); - expect(diags).toContain(`The template context does not define a member called 'unknown'`); + describe('embedded templates', () => { + it('should suggest refining a template context missing a property', () => { + mockHost.override( + TEST_TEMPLATE, + ``); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); + expect(diags.length).toBe(1); + const {messageText, start, length, category} = diags[0]; + expect(category).toBe(ts.DiagnosticCategory.Suggestion); + expect(messageText) + .toBe( + `The template context of 'CounterDirective' does not define an implicit value.\n` + + `If the context type is a base type or 'any', consider refining it to a more specific type.`, ); + + const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); + expect(start).toBe(span.start); + expect(length).toBe(span.length); + }); + + it('should report an unknown context reference', () => { + mockHost.override( + TEST_TEMPLATE, + `
`); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); + expect(diags.length).toBe(1); + const {messageText, start, length, category} = diags[0]; + expect(category).toBe(ts.DiagnosticCategory.Suggestion); + expect(messageText) + .toBe( + `The template context of 'NgForOf' does not define a member called 'even_1'.\n` + + `If the context type is a base type or 'any', consider refining it to a more specific type.`); + + const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); + expect(start).toBe(span.start); + expect(length).toBe(span.length); }); }); @@ -267,7 +292,7 @@ describe('diagnostics', () => { it('should not report diagnostic on iteration of any', () => { const fileName = '/app/test.ng'; mockHost.override(fileName, '
{{value.someField}}
'); - const diagnostics = ngLS.getDiagnostics(fileName); + const diagnostics = ngLS.getSemanticDiagnostics(fileName); expect(diagnostics).toEqual([]); }); @@ -279,7 +304,7 @@ describe('diagnostics', () => {
`); - const diagnostics = ngLS.getDiagnostics(TEST_TEMPLATE); + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) @@ -290,16 +315,14 @@ describe('diagnostics', () => { describe('with $event', () => { it('should accept an event', () => { - const fileName = '/app/test.ng'; - mockHost.override(fileName, '
Click me!
'); - const diagnostics = ngLS.getDiagnostics(fileName); + mockHost.override(TEST_TEMPLATE, '
Click me!
'); + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diagnostics).toEqual([]); }); it('should reject it when not in an event binding', () => { - const fileName = '/app/test.ng'; - const content = mockHost.override(fileName, '
'); - const diagnostics = ngLS.getDiagnostics(fileName) !; + const content = mockHost.override(TEST_TEMPLATE, '
'); + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) @@ -309,6 +332,17 @@ describe('diagnostics', () => { expect(start).toBe(content.lastIndexOf(keyword)); expect(length).toBe(keyword.length); }); + + it('should reject invalid properties on an event type', () => { + const content = mockHost.override( + TEST_TEMPLATE, '
'); + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !; + expect(diagnostics.length).toBe(1); + const {messageText, start, length} = diagnostics[0]; + expect(messageText).toBe(`Unknown method 'notSubstring'`); + expect(start).toBe(content.indexOf('$event')); + expect(length).toBe('$event.notSubstring()'.length); + }); }); it('should not crash with a incomplete *ngFor', () => { @@ -317,7 +351,7 @@ describe('diagnostics', () => { template: '
~{after-div}' }) export class MyComponent {}`); - expect(() => ngLS.getDiagnostics(fileName)).not.toThrow(); + expect(() => ngLS.getSemanticDiagnostics(fileName)).not.toThrow(); }); it('should report a component not in a module', () => { @@ -326,16 +360,14 @@ describe('diagnostics', () => { template: '
' }) export class MyComponent {}`); - const diagnostics = ngLS.getDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) .toBe( `Component 'MyComponent' is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration.`); const content = mockHost.readFile(fileName) !; - const keyword = '@Component'; - expect(start).toBe(content.lastIndexOf(keyword) + 1); // exclude leading '@' - expect(length).toBe(keyword.length - 1); // exclude leading '@' + expect(content.substring(start !, start ! + length !)).toBe('MyComponent'); }); @@ -348,7 +380,7 @@ describe('diagnostics', () => { export class AppComponent {}`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -358,7 +390,7 @@ describe('diagnostics', () => { template: '' }) export class MyComponent {}`); - expect(() => ngLS.getDiagnostics(fileName)).not.toThrow(); + expect(() => ngLS.getSemanticDiagnostics(fileName)).not.toThrow(); }); it('should not throw using a directive with no value', () => { @@ -369,7 +401,7 @@ describe('diagnostics', () => { export class MyComponent { name = 'some name'; }`); - expect(() => ngLS.getDiagnostics(fileName)).not.toThrow(); + expect(() => ngLS.getSemanticDiagnostics(fileName)).not.toThrow(); }); it('should report an error for invalid metadata', () => { @@ -387,7 +419,7 @@ describe('diagnostics', () => { }`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT) !; + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; expect(ngDiags.length).toBe(1); const {messageText, start, length} = ngDiags[0]; const keyword = `() => 'foo'`; @@ -409,7 +441,7 @@ describe('diagnostics', () => { @Component({ template: '' }) class`); - expect(() => ngLS.getDiagnostics(fileName)).not.toThrow(); + expect(() => ngLS.getSemanticDiagnostics(fileName)).not.toThrow(); }); it('should not report an error for sub-types of string in non-strict mode', () => { @@ -427,7 +459,7 @@ describe('diagnostics', () => { }); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -446,7 +478,7 @@ describe('diagnostics', () => { }); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -460,7 +492,7 @@ describe('diagnostics', () => { export class AppComponent { onClick() { } }`); - const diagnostics = ngLS.getDiagnostics(APP_COMPONENT) !; + const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; const {messageText, start, length} = diagnostics[0]; expect(messageText).toBe('Unexpected callable expression. Expected a method call'); const keyword = `"onClick"`; @@ -484,7 +516,7 @@ describe('diagnostics', () => { }); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -501,7 +533,7 @@ describe('diagnostics', () => { }`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags.length).toBe(1); const {messageText, start, length} = ngDiags[0]; expect(messageText).toBe(`The pipe 'dat' could not be found`); @@ -521,7 +553,7 @@ describe('diagnostics', () => { export class AppComponent {}`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -550,7 +582,7 @@ describe('diagnostics', () => { }`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -568,16 +600,14 @@ describe('diagnostics', () => { const msgText = ts.flattenDiagnosticMessageText(tsDiags[0].messageText, '\n'); expect(msgText).toBe( `Type 'null[]' is not assignable to type 'Provider[]'.\n Type 'null' is not assignable to type 'Provider'.`); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags.length).toBe(1); const {messageText, start, length} = ngDiags[0]; expect(messageText) .toBe( 'Invalid providers for "AppComponent in /app/app.component.ts" - only instances of Provider and Type are allowed, got: [?null?]'); // TODO: Looks like this is the wrong span. Should point to 'null' instead. - const keyword = '@Component'; - expect(start).toBe(content.lastIndexOf(keyword) + 1); // exclude leading '@' - expect(length).toBe(keyword.length - 1); // exclude leading '@ + expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); }); // Issue #15768 @@ -596,7 +626,7 @@ describe('diagnostics', () => { export class AppComponent {}`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -618,7 +648,7 @@ describe('diagnostics', () => { }`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(ngDiags).toEqual([]); }); @@ -642,7 +672,15 @@ describe('diagnostics', () => { }`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(APP_COMPONENT); + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT); + expect(ngDiags).toEqual([]); + }); + + // Issue https://github.com/angular/angular/issues/34874 + it('should recognize inputs and outputs listed inside directive decorators', () => { + mockHost.override( + TEST_TEMPLATE, `
`); + const ngDiags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(ngDiags).toEqual([]); }); @@ -666,7 +704,7 @@ describe('diagnostics', () => { }); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const diagnostic = ngLS.getDiagnostics(APP_COMPONENT); + const diagnostic = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(diagnostic).toEqual([]); }); @@ -702,7 +740,7 @@ describe('diagnostics', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile'); - const diagnostics = ngLS.getDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeDefined(); @@ -719,7 +757,7 @@ describe('diagnostics', () => { }) export class MyComponent {}`); - const diagnostics = ngLS.getDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeUndefined(); @@ -733,13 +771,12 @@ describe('diagnostics', () => { selector: 'app-example', }) export class AppComponent {}`); - const diags = ngLS.getDiagnostics(APP_COMPONENT); + const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(diags.length).toBe(1); const {file, messageText, start, length} = diags[0]; expect(file !.fileName).toBe(APP_COMPONENT); expect(messageText).toBe(`Component 'AppComponent' must have a template or templateUrl`); - expect(start).toBe(content.indexOf(`@Component`) + 1); - expect(length).toBe('Component'.length); + expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); }); it('should report diagnostic for both template and templateUrl', () => { @@ -752,14 +789,13 @@ describe('diagnostics', () => { templateUrl: './test.ng', }) export class AppComponent {}`); - const diags = ngLS.getDiagnostics(APP_COMPONENT); + const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(diags.length).toBe(1); const {file, messageText, start, length} = diags[0]; expect(file !.fileName).toBe(APP_COMPONENT); expect(messageText) .toBe(`Component 'AppComponent' must not have both template and templateUrl`); - expect(start).toBe(content.indexOf(`@Component`) + 1); - expect(length).toBe('Component'.length); + expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); }); it('should report errors for invalid styleUrls', () => { @@ -771,7 +807,7 @@ describe('diagnostics', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile'); - const diagnostics = ngLS.getDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeDefined(); @@ -791,21 +827,20 @@ describe('diagnostics', () => { }) export class AppComponent {}`); - const diagnostics = ngLS.getDiagnostics(APP_COMPONENT) !; + const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; expect(diagnostics.length).toBe(0); }); }); - it('should work correctly with CRLF endings', () => { + it('should work correctly with CRLF endings in external template', () => { // https://github.com/angular/vscode-ng-language-service/issues/235 // In the example below, the string // `\r\n{{line0}}\r\n{{line1}}\r\n{{line2}}` is tokenized as a whole, // and then CRLF characters are converted to LF. // Source span information is lost in the process. - const fileName = '/app/test.ng'; - const content = - mockHost.override(fileName, '\r\n
\r\n{{line0}}\r\n{{line1}}\r\n{{line2}}\r\n
'); - const ngDiags = ngLS.getDiagnostics(fileName); + const content = mockHost.override( + TEST_TEMPLATE, '\r\n
\r\n{{line0}}\r\n{{line1}}\r\n{{line2}}\r\n
'); + const ngDiags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(ngDiags.length).toBe(3); for (let i = 0; i < 3; ++i) { const {messageText, start, length} = ngDiags[i]; @@ -820,6 +855,21 @@ describe('diagnostics', () => { } }); + it('should work correctly with CRLF endings in inline template', () => { + const fileName = mockHost.addCode( + '\n@Component({template:`\r\n\r\n{{line}}`})export class ComponentCRLF {}'); + const content = mockHost.readFile(fileName) !; + const ngDiags = ngLS.getSemanticDiagnostics(fileName); + expect(ngDiags.length).toBeGreaterThan(0); + const {messageText, start, length} = ngDiags[0]; + expect(messageText) + .toBe( + `Identifier 'line' is not defined. ` + + `The component declaration, template variable declarations, and ` + + `element references do not contain such a member`); + expect(content.substring(start !, start ! + length !)).toBe('line'); + }); + it('should not produce diagnostics for non-exported directives', () => { const fileName = '/app/test.component.ts'; mockHost.addScript(fileName, ` @@ -832,7 +882,7 @@ describe('diagnostics', () => { `); const tsDiags = tsLS.getSemanticDiagnostics(fileName); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getDiagnostics(fileName); + const ngDiags = ngLS.getSemanticDiagnostics(fileName); expect(ngDiags).toEqual([]); }); }); diff --git a/packages/language-service/test/hover_spec.ts b/packages/language-service/test/hover_spec.ts index d94a94ff63..578f7fcc7e 100644 --- a/packages/language-service/test/hover_spec.ts +++ b/packages/language-service/test/hover_spec.ts @@ -32,7 +32,7 @@ describe('hover', () => { name: string; }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); @@ -48,7 +48,7 @@ describe('hover', () => { name: string; }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); @@ -64,7 +64,7 @@ describe('hover', () => { myClick() { } }`); const marker = mockHost.getDefinitionMarkerFor(fileName, 'myClick'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); @@ -81,7 +81,7 @@ describe('hover', () => { include = true; }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'include'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); @@ -89,31 +89,24 @@ describe('hover', () => { }); it('should be able to find a reference to a component', () => { - const fileName = mockHost.addCode(` - @Component({ - template: '«<ᐱtestᐱ-comp>»' - }) - export class MyComponent { }`); - const marker = mockHost.getDefinitionMarkerFor(fileName, 'test'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); - expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; - expect(textSpan).toEqual(marker); - expect(toText(displayParts)).toBe('(component) AppModule.TestComponent: class'); + mockHost.override(TEST_TEMPLATE, '<~{cursor}test-comp>'); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeDefined(); + const {displayParts, documentation} = quickInfo !; + expect(toText(displayParts)).toBe('(component) AppModule.TestComponent: typeof TestComponent'); + expect(toText(documentation)).toBe('This Component provides the `test-comp` selector.'); }); it('should be able to find a reference to a directive', () => { - const fileName = mockHost.addCode(` - @Component({ - template: '' - }) - export class MyComponent { }`); - const marker = mockHost.getReferenceMarkerFor(fileName, 'string-model'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); - expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; - expect(textSpan).toEqual(marker); - expect(toText(displayParts)).toBe('(directive) StringModel: typeof StringModel'); + const content = mockHost.override(TEST_TEMPLATE, `
`); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeDefined(); + const {displayParts, textSpan} = quickInfo !; + expect(toText(displayParts)).toBe('(directive) AppModule.StringModel: typeof StringModel'); + expect(content.substring(textSpan.start, textSpan.start + textSpan.length)) + .toBe('string-model'); }); it('should be able to find an event provider', () => { @@ -125,7 +118,7 @@ describe('hover', () => { myHandler() {} }`); const marker = mockHost.getDefinitionMarkerFor(fileName, 'test'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); @@ -141,13 +134,56 @@ describe('hover', () => { name = 'my name'; }`); const marker = mockHost.getDefinitionMarkerFor(fileName, 'tcName'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TestComponent.name: string'); }); + describe('over structural directive', () => { + it('should be able to find the directive', () => { + mockHost.override(TEST_TEMPLATE, `
`); + const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'ngFor'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(directive) NgForOf: typeof NgForOf'); + }); + + it('should be able to find the directive property', () => { + mockHost.override( + TEST_TEMPLATE, `
`); + const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'trackBy'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(method) NgForOf.ngForTrackBy: TrackByFunction'); + }); + + it('should be able to find the property value', () => { + mockHost.override(TEST_TEMPLATE, `
`); + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'heroes'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(property) TemplateReference.heroes: Hero[]'); + }); + }); + + it('should be able to find a reference to a two-way binding', () => { + mockHost.override(TEST_TEMPLATE, ``); + const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'model'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(property) StringModel.model: string'); + }); + it('should be able to ignore a reference declaration', () => { const fileName = mockHost.addCode(` @Component({ @@ -155,7 +191,7 @@ describe('hover', () => { }) export class MyComponent { }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'chart'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeUndefined(); }); @@ -171,7 +207,7 @@ describe('hover', () => { name: string; }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'AppComponent'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); @@ -183,7 +219,7 @@ describe('hover', () => { const content = mockHost.readFile(fileName) !; const position = content.indexOf('StringModel'); expect(position).toBeGreaterThan(0); - const quickInfo = ngLS.getHoverAt(fileName, position); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, position); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual({ @@ -196,7 +232,7 @@ describe('hover', () => { it('should be able to provide quick info for $any() cast function', () => { const content = mockHost.override(TEST_TEMPLATE, '
{{$any(title)}}
'); const position = content.indexOf('$any'); - const quickInfo = ngLS.getHoverAt(TEST_TEMPLATE, position); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, position); expect(quickInfo).toBeDefined(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual({ @@ -209,7 +245,7 @@ describe('hover', () => { it('should provide documentation for a property', () => { mockHost.override(TEST_TEMPLATE, `
{{~{cursor}title}}
`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const quickInfo = ngLS.getHoverAt(TEST_TEMPLATE, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); const documentation = toText(quickInfo !.documentation); expect(documentation).toBe('This is the title of the `TemplateReference` Component.'); @@ -218,7 +254,7 @@ describe('hover', () => { it('should provide documentation for a selector', () => { mockHost.override(TEST_TEMPLATE, `<~{cursor}test-comp>`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); - const quickInfo = ngLS.getHoverAt(TEST_TEMPLATE, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); const documentation = toText(quickInfo !.documentation); expect(documentation).toBe('This Component provides the `test-comp` selector.'); @@ -233,7 +269,7 @@ describe('hover', () => { name: string; }`); const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); - const quickInfo = ngLS.getHoverAt(fileName, marker.start); + const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start); expect(quickInfo).toBeTruthy(); const {textSpan, displayParts} = quickInfo !; expect(textSpan).toEqual(marker); diff --git a/packages/language-service/test/language_service_spec.ts b/packages/language-service/test/language_service_spec.ts index 2c7a87b3dc..a271928230 100644 --- a/packages/language-service/test/language_service_spec.ts +++ b/packages/language-service/test/language_service_spec.ts @@ -24,16 +24,17 @@ describe('service without angular', () => { beforeEach(() => { mockHost.reset(); }); it('should not crash a get diagnostics', - () => { expect(() => ngService.getDiagnostics(fileName)).not.toThrow(); }); + () => { expect(() => ngService.getSemanticDiagnostics(fileName)).not.toThrow(); }); it('should not crash a completion', - () => { expect(() => ngService.getCompletionsAt(fileName, position)).not.toThrow(); }); + () => { expect(() => ngService.getCompletionsAtPosition(fileName, position)).not.toThrow(); }); - it('should not crash a get definition', - () => { expect(() => ngService.getDefinitionAt(fileName, position)).not.toThrow(); }); + it('should not crash a get definition', () => { + expect(() => ngService.getDefinitionAndBoundSpan(fileName, position)).not.toThrow(); + }); it('should not crash a hover', - () => { expect(() => ngService.getHoverAt(fileName, position)).not.toThrow(); }); + () => { expect(() => ngService.getQuickInfoAtPosition(fileName, position)).not.toThrow(); }); it('should not crash with an incomplete class', () => { mockHost.addCode('\nexport class'); diff --git a/packages/language-service/test/mocks.ts b/packages/language-service/test/mocks.ts index e58327e1db..bab5996054 100644 --- a/packages/language-service/test/mocks.ts +++ b/packages/language-service/test/mocks.ts @@ -107,14 +107,11 @@ const summaryResolver = new AotSummaryResolver( staticSymbolCache); export class DiagnosticContext { - // tslint:disable - // TODO(issue/24571): remove '!'. - _analyzedModules !: NgAnalyzedModules; - _staticSymbolResolver: StaticSymbolResolver|undefined; - _reflector: StaticReflector|undefined; - _errors: {e: any, path?: string}[] = []; - _resolver: CompileMetadataResolver|undefined; - // tslint:enable + private _analyzedModules: NgAnalyzedModules|undefined; + private _staticSymbolResolver: StaticSymbolResolver|undefined; + private _reflector: StaticReflector|undefined; + private _errors: {e: any, path?: string}[] = []; + private _resolver: CompileMetadataResolver|undefined; constructor( public service: ts.LanguageService, public program: ts.Program, diff --git a/packages/language-service/test/project/app/main.ts b/packages/language-service/test/project/app/main.ts index defe0c4372..6de049e260 100644 --- a/packages/language-service/test/project/app/main.ts +++ b/packages/language-service/test/project/app/main.ts @@ -33,7 +33,9 @@ import * as ParsingCases from './parsing-cases'; ParsingCases.CaseIncompleteOpen, ParsingCases.CaseMissingClosing, ParsingCases.CaseUnknown, + ParsingCases.CounterDirective, ParsingCases.EmptyInterpolation, + ParsingCases.HintModel, ParsingCases.NoValueAttribute, ParsingCases.NumberModel, ParsingCases.Pipes, diff --git a/packages/language-service/test/project/app/parsing-cases.ts b/packages/language-service/test/project/app/parsing-cases.ts index 4ed8c4c787..90c90a9eaf 100644 --- a/packages/language-service/test/project/app/parsing-cases.ts +++ b/packages/language-service/test/project/app/parsing-cases.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Directive, EventEmitter, Input, Output} from '@angular/core'; +import {Component, Directive, EventEmitter, Input, OnChanges, Output, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core'; import {Hero} from './app.component'; @@ -60,6 +60,16 @@ export class NumberModel { @Output('outputAlias') modelChange: EventEmitter = new EventEmitter(); } +@Directive({ + selector: '[hint-model]', + inputs: ['hint'], + outputs: ['hintChange'], +}) +export class HintModel { + hint: string = 'hint'; + hintChange: EventEmitter = new EventEmitter(); +} + interface Person { name: string; age: number; @@ -99,6 +109,24 @@ export class AsyncForUsingComponent { export class References { } +class CounterDirectiveContext { + constructor(public $implicit: T) {} +} + +@Directive({selector: '[counterOf]'}) +export class CounterDirective implements OnChanges { + // Object does not have an "$implicit" property. + constructor(private container: ViewContainerRef, private template: TemplateRef) {} + + @Input('counterOf') counter: number = 0; + ngOnChanges(_changes: SimpleChanges) { + this.container.clear(); + for (let i = 0; i < this.counter; ++i) { + this.container.createEmbeddedView(this.template, new CounterDirectiveContext(i + 1)); + } + } +} + /** * This Component provides the `test-comp` selector. */ diff --git a/packages/language-service/test/typescript_host_spec.ts b/packages/language-service/test/typescript_host_spec.ts index 0352a19067..dadf9e9e7c 100644 --- a/packages/language-service/test/typescript_host_spec.ts +++ b/packages/language-service/test/typescript_host_spec.ts @@ -176,51 +176,4 @@ describe('TypeScriptServiceHost', () => { // files have changed. expect(newModules).toBe(oldModules); }); - - it('should get the correct StaticSymbol for a Directive', () => { - const tsLSHost = new MockTypescriptHost(['/app/app.component.ts', '/app/main.ts']); - const tsLS = ts.createLanguageService(tsLSHost); - const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS); - ngLSHost.getAnalyzedModules(); // modules are analyzed lazily - const sf = ngLSHost.getSourceFile('/app/app.component.ts'); - expect(sf).toBeDefined(); - const directiveDecl = sf !.forEachChild(n => { - if (ts.isClassDeclaration(n) && n.name && n.name.text === 'AppComponent') return n; - }); - - expect(directiveDecl).toBeDefined(); - expect(directiveDecl !.name).toBeDefined(); - const fileName = directiveDecl !.getSourceFile().fileName; - const symbolName = directiveDecl !.name !.getText(); - const directiveSymbol = ngLSHost.getStaticSymbol(fileName, symbolName); - expect(directiveSymbol).toBeDefined(); - expect(directiveSymbol !.name).toBe('AppComponent'); - }); - - it('should allow for retreiving analyzedModules in synchronized mode', () => { - const fileName = '/app/app.component.ts'; - const tsLSHost = new MockTypescriptHost([fileName]); - const tsLS = ts.createLanguageService(tsLSHost); - const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS); - - // Get initial state - const originalModules = ngLSHost.getAnalyzedModules(); - - // Override app.component.ts with a different component - tsLSHost.override(fileName, ` - import {Component} from '@angular/core'; - - @Component({ - template: '
Hello!
', - }) - export class HelloComponent {} - `); - // Make sure synchronized modules match the original state - const syncModules = ngLSHost.getAnalyzedModules(false); - expect(originalModules).toEqual(syncModules); - - // Now, get modules for the updated project, which should not be synchronized - const updatedModules = ngLSHost.getAnalyzedModules(); - expect(updatedModules).not.toEqual(syncModules); - }); }); diff --git a/packages/language-service/test/utils_spec.ts b/packages/language-service/test/utils_spec.ts index 8419924c2b..ee0670ea93 100644 --- a/packages/language-service/test/utils_spec.ts +++ b/packages/language-service/test/utils_spec.ts @@ -28,10 +28,10 @@ describe('getDirectiveClassLike()', () => { } }); expect(result).toBeTruthy(); - const {decoratorId, classDecl} = result !; + const {decoratorId, classId} = result !; expect(decoratorId.kind).toBe(ts.SyntaxKind.Identifier); - expect((decoratorId as ts.Identifier).text).toBe('NgModule'); - expect(classDecl.name !.text).toBe('AppModule'); + expect(decoratorId.text).toBe('NgModule'); + expect(classId.text).toBe('AppModule'); }); }); diff --git a/packages/license-banner.txt b/packages/license-banner.txt index f7aafb73f8..5c286d793c 100644 --- a/packages/license-banner.txt +++ b/packages/license-banner.txt @@ -1,5 +1,5 @@ /** * @license Angular v0.0.0-PLACEHOLDER - * (c) 2010-2019 Google LLC. https://angular.io/ + * (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */ diff --git a/packages/localize/BUILD.bazel b/packages/localize/BUILD.bazel index d086fb082f..b81d1ad48d 100644 --- a/packages/localize/BUILD.bazel +++ b/packages/localize/BUILD.bazel @@ -24,7 +24,7 @@ ng_package( "//packages/localize/init:package.json", ], entry_point = ":index.ts", - packages = [ + nested_packages = [ "//packages/localize/schematics:npm_package", "//packages/localize/src/tools:npm_package", ], diff --git a/packages/localize/package.json b/packages/localize/package.json index 0860362068..1d7203f85f 100644 --- a/packages/localize/package.json +++ b/packages/localize/package.json @@ -32,7 +32,7 @@ "node": ">=8.0" }, "dependencies": { - "@babel/core": "^7.5.5", + "@babel/core": "7.8.3", "glob": "7.1.2", "yargs": "13.1.0" }, diff --git a/packages/localize/schematics/BUILD.bazel b/packages/localize/schematics/BUILD.bazel index 2f41c3f8a3..30aed92bde 100644 --- a/packages/localize/schematics/BUILD.bazel +++ b/packages/localize/schematics/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "npm_package") +load("//tools:defaults.bzl", "pkg_npm") package(default_visibility = ["//visibility:public"]) @@ -10,7 +10,7 @@ filegroup( visibility = ["//packages/localize:__subpackages__"], ) -npm_package( +pkg_npm( name = "npm_package", srcs = [ "collection.json", diff --git a/packages/localize/schematics/ng-add/BUILD.bazel b/packages/localize/schematics/ng-add/BUILD.bazel index 20bce8ad46..280203d617 100644 --- a/packages/localize/schematics/ng-add/BUILD.bazel +++ b/packages/localize/schematics/ng-add/BUILD.bazel @@ -43,9 +43,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/localize/src/localize/test/BUILD.bazel b/packages/localize/src/localize/test/BUILD.bazel index 94cde285ef..4da7c93501 100644 --- a/packages/localize/src/localize/test/BUILD.bazel +++ b/packages/localize/src/localize/test/BUILD.bazel @@ -14,11 +14,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = [ - "angular/tools/testing/init_node_no_angular_spec.js", - ], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/localize/src/tools/BUILD.bazel b/packages/localize/src/tools/BUILD.bazel index 3fb61ab0ea..daf193f862 100644 --- a/packages/localize/src/tools/BUILD.bazel +++ b/packages/localize/src/tools/BUILD.bazel @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "npm_package", "ts_library") +load("//tools:defaults.bzl", "pkg_npm", "ts_library") load("@npm_bazel_typescript//:index.bzl", "ts_config") ts_config( @@ -30,7 +30,7 @@ ts_library( ], ) -npm_package( +pkg_npm( name = "npm_package", srcs = [ ], diff --git a/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts b/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts index 6f88e945a9..51d1e44f9a 100644 --- a/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts +++ b/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts @@ -9,7 +9,7 @@ import {ɵParsedTranslation} from '@angular/localize'; import {NodePath, PluginObj} from '@babel/core'; import {TaggedTemplateExpression} from '@babel/types'; import {Diagnostics} from '../../diagnostics'; -import {TranslatePluginOptions, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromTemplateLiteral} from './source_file_utils'; +import {TranslatePluginOptions, buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromTemplateLiteral} from './source_file_utils'; export function makeEs2015TranslatePlugin( diagnostics: Diagnostics, translations: Record, @@ -32,7 +32,7 @@ export function makeEs2015TranslatePlugin( // If we get a BabelParseError here then something went wrong with Babel itself // since there must be something wrong with the structure of the AST generated // by Babel parsing a TaggedTemplateExpression. - throw path.hub.file.buildCodeFrameError(e.node, e.message); + throw buildCodeFrameError(path, e); } } } diff --git a/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts b/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts index b96002b34a..30f87cfced 100644 --- a/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts +++ b/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts @@ -9,7 +9,7 @@ import {ɵParsedTranslation} from '@angular/localize'; import {NodePath, PluginObj} from '@babel/core'; import {CallExpression} from '@babel/types'; import {Diagnostics} from '../../diagnostics'; -import {TranslatePluginOptions, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromLocalizeCall, unwrapSubstitutionsFromLocalizeCall} from './source_file_utils'; +import {TranslatePluginOptions, buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromLocalizeCall, unwrapSubstitutionsFromLocalizeCall} from './source_file_utils'; export function makeEs5TranslatePlugin( diagnostics: Diagnostics, translations: Record, @@ -29,7 +29,7 @@ export function makeEs5TranslatePlugin( } } catch (e) { if (isBabelParseError(e)) { - diagnostics.error(callPath.hub.file.buildCodeFrameError(e.node, e.message).message); + diagnostics.error(buildCodeFrameError(callPath, e)); } } } diff --git a/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts b/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts index 1a6c81f275..266caa8b93 100644 --- a/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts +++ b/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts @@ -328,3 +328,9 @@ export class BabelParseError extends Error { export function isBabelParseError(e: any): e is BabelParseError { return e.type === 'BabelParseError'; } + +export function buildCodeFrameError(path: NodePath, e: BabelParseError): string { + const filename = path.hub.file.opts.filename || '(unknown file)'; + const message = path.hub.file.buildCodeFrameError(e.node, e.message).message; + return `${filename}: ${message}`; +} diff --git a/packages/localize/src/tools/test/BUILD.bazel b/packages/localize/src/tools/test/BUILD.bazel index dea2fea294..b828ba9ec8 100644 --- a/packages/localize/src/tools/test/BUILD.bazel +++ b/packages/localize/src/tools/test/BUILD.bazel @@ -11,6 +11,8 @@ ts_library( "//packages/compiler", "//packages/localize", "//packages/localize/src/tools", + "@npm//@babel/core", + "@npm//@babel/generator", "@npm//@babel/template", "@npm//@babel/types", "@npm//@types/babel__core", @@ -22,12 +24,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = [ - "angular/tools/testing/init_node_no_angular_spec.js", - ], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", "@npm//glob", ], ) diff --git a/packages/localize/src/tools/test/translate/integration/BUILD.bazel b/packages/localize/src/tools/test/translate/integration/BUILD.bazel index 9f2eeabf1a..d114c63fff 100644 --- a/packages/localize/src/tools/test/translate/integration/BUILD.bazel +++ b/packages/localize/src/tools/test/translate/integration/BUILD.bazel @@ -14,9 +14,7 @@ ts_library( jasmine_node_test( name = "integration", - bootstrap = [ - "angular/tools/testing/init_node_no_angular_spec.js", - ], + bootstrap = ["//tools/testing:node_no_angular_es5"], data = glob( [ "locales/**", @@ -25,7 +23,6 @@ jasmine_node_test( ), deps = [ ":test_lib", - "//tools/testing:node_no_angular", "@npm//glob", "@npm//yargs", ], diff --git a/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts b/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts index ff2a1b89d6..5a83eb6889 100644 --- a/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts +++ b/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts @@ -142,7 +142,7 @@ describe('makeEs5Plugin', () => { type: 'error', message: '/app/dist/test.js: `$localize` called without any arguments.\n' + '> 1 | $localize()\n' + - ' | ^', + ' | ^^^^^^^^^^^', }); }); @@ -158,7 +158,7 @@ describe('makeEs5Plugin', () => { type: 'error', message: '/app/dist/test.js: Unexpected argument to `$localize` (expected an array).\n' + '> 1 | $localize(...x)\n' + - ' | ^', + ' | ^^^^', }); }); @@ -175,7 +175,7 @@ describe('makeEs5Plugin', () => { message: '/app/dist/test.js: Unexpected messageParts for `$localize` (expected an array of strings).\n' + '> 1 | $localize(null, [])\n' + - ' | ^', + ' | ^^^^', }); }); @@ -192,7 +192,7 @@ describe('makeEs5Plugin', () => { message: '/app/dist/test.js: Unexpected `raw` argument to the "makeTemplateObject()" function (expected an expression).\n' + '> 1 | $localize(__makeTemplateObject([], ...[]))\n' + - ' | ^', + ' | ^^^^^', }); }); @@ -209,7 +209,7 @@ describe('makeEs5Plugin', () => { message: '/app/dist/test.js: Unexpected `cooked` argument to the "makeTemplateObject()" function (expected an expression).\n' + '> 1 | $localize(__makeTemplateObject(...[], []))\n' + - ' | ^', + ' | ^^^^^', }); }); @@ -226,7 +226,7 @@ describe('makeEs5Plugin', () => { message: '/app/dist/test.js: Unexpected messageParts for `$localize` (expected an array of strings).\n' + '> 1 | $localize(__makeTemplateObject(["a", 12, "b"], ["a", "12", "b"]))\n' + - ' | ^', + ' | ^^^^^^^^^^^^^^', }); }); @@ -243,7 +243,7 @@ describe('makeEs5Plugin', () => { message: '/app/dist/test.js: Unexpected messageParts for `$localize` (expected an array of strings).\n' + '> 1 | $localize(__makeTemplateObject(["a", "12", "b"], ["a", 12, "b"]))\n' + - ' | ^', + ' | ^^^^^^^^^^^^^^', }); }); @@ -260,7 +260,7 @@ describe('makeEs5Plugin', () => { message: '/app/dist/test.js: Invalid substitutions for `$localize` (expected all substitution arguments to be expressions).\n' + '> 1 | $localize(__makeTemplateObject(["a", "b"], ["a", "b"]), ...[])\n' + - ' | ^', + ' | ^^^^^', }); }); diff --git a/packages/localize/src/utils/test/BUILD.bazel b/packages/localize/src/utils/test/BUILD.bazel index aaf43dcf63..aa16ff7e83 100644 --- a/packages/localize/src/utils/test/BUILD.bazel +++ b/packages/localize/src/utils/test/BUILD.bazel @@ -14,11 +14,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = [ - "angular/tools/testing/init_node_no_angular_spec.js", - ], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/localize/test/BUILD.bazel b/packages/localize/test/BUILD.bazel index 13381b2dad..70622deefd 100644 --- a/packages/localize/test/BUILD.bazel +++ b/packages/localize/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/localize/index.js", + deps = ["//packages/localize"], +) ts_library( name = "test_lib", @@ -16,11 +23,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = [ - "angular/tools/testing/init_node_no_angular_spec.js", - ], + bootstrap = ["//tools/testing:node_no_angular_es5"], deps = [ ":test_lib", - "//tools/testing:node_no_angular", ], ) diff --git a/packages/platform-browser-dynamic/src/compiler_factory.ts b/packages/platform-browser-dynamic/src/compiler_factory.ts index bac7cfdfe4..ac0a1ed8d5 100644 --- a/packages/platform-browser-dynamic/src/compiler_factory.ts +++ b/packages/platform-browser-dynamic/src/compiler_factory.ts @@ -6,9 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -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, 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 {CompileMetadataResolver, CompileReflector, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, ElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitCompiler, JitEvaluator, JitSummaryResolver, Lexer, NgModuleCompiler, NgModuleResolver, Parser, PipeResolver, ProviderMeta, ResourceLoader, StaticSymbolCache, StyleCompiler, SummaryResolver, TemplateParser, UrlResolver, ViewCompiler} from '@angular/compiler'; +import {Compiler, CompilerFactory, CompilerOptions, ComponentFactory, Inject, InjectionToken, Injector, MissingTranslationStrategy, ModuleWithComponentFactories, NgModuleFactory, Optional, PACKAGE_ROOT_URL, StaticProvider, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, isDevMode, ɵConsole as Console} from '@angular/core'; import {JitReflector} from './compiler_reflector'; diff --git a/packages/platform-browser-dynamic/test/BUILD.bazel b/packages/platform-browser-dynamic/test/BUILD.bazel index 0d54237df5..c798c052e7 100644 --- a/packages/platform-browser-dynamic/test/BUILD.bazel +++ b/packages/platform-browser-dynamic/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/platform-browser-dynamic/index.js", + deps = ["//packages/platform-browser-dynamic"], +) ts_library( name = "test_lib", @@ -18,10 +25,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/platform-browser/animations/test/BUILD.bazel b/packages/platform-browser/animations/test/BUILD.bazel index 4af17f10ba..f14e31e55a 100644 --- a/packages/platform-browser/animations/test/BUILD.bazel +++ b/packages/platform-browser/animations/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/platform-browser/animations/index.js", + deps = ["//packages/platform-browser/animations"], +) ts_library( name = "test_lib", @@ -24,10 +31,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/platform-browser/src/browser.ts b/packages/platform-browser/src/browser.ts index f730f0419b..032bdc0ca3 100644 --- a/packages/platform-browser/src/browser.ts +++ b/packages/platform-browser/src/browser.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CommonModule, DOCUMENT, PlatformLocation, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; +import {CommonModule, DOCUMENT, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; import {APP_ID, ApplicationModule, ErrorHandler, Inject, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, PlatformRef, RendererFactory2, Sanitizer, SkipSelf, StaticProvider, Testability, createPlatformFactory, platformCore, ɵConsole as Console, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵsetDocument} from '@angular/core'; import {BrowserDomAdapter} from './browser/browser_adapter'; import {SERVER_TRANSITION_PROVIDERS, TRANSITION_ID} from './browser/server-transition'; diff --git a/packages/platform-browser/src/dom/debug/ng_probe.ts b/packages/platform-browser/src/dom/debug/ng_probe.ts index 2ed9656c3b..e6d4942d0a 100644 --- a/packages/platform-browser/src/dom/debug/ng_probe.ts +++ b/packages/platform-browser/src/dom/debug/ng_probe.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {APP_INITIALIZER, ApplicationRef, DebugNode, NgProbeToken, NgZone, Optional, Provider, getDebugNode} from '@angular/core'; +import {APP_INITIALIZER, ApplicationRef, DebugNode, NgProbeToken, NgZone, Optional, Provider, ɵgetDebugNodeR2} from '@angular/core'; import {exportNgVar} from '../util'; @@ -23,14 +23,14 @@ const CORE_TOKENS_GLOBAL_NAME = 'coreTokens'; * null if the given native element does not have an Angular view associated * with it. */ -export function inspectNativeElement(element: any): DebugNode|null { - return getDebugNode(element); +export function inspectNativeElementR2(element: any): DebugNode|null { + return ɵgetDebugNodeR2(element); } -export function _createNgProbe(coreTokens: NgProbeToken[]): any { - exportNgVar(INSPECT_GLOBAL_NAME, inspectNativeElement); +export function _createNgProbeR2(coreTokens: NgProbeToken[]): any { + exportNgVar(INSPECT_GLOBAL_NAME, inspectNativeElementR2); exportNgVar(CORE_TOKENS_GLOBAL_NAME, {...CORE_TOKENS, ..._ngProbeTokensToMap(coreTokens || [])}); - return () => inspectNativeElement; + return () => inspectNativeElementR2; } function _ngProbeTokensToMap(tokens: NgProbeToken[]): {[name: string]: any} { @@ -52,7 +52,7 @@ export const ELEMENT_PROBE_PROVIDERS__POST_R3__ = []; export const ELEMENT_PROBE_PROVIDERS__PRE_R3__: Provider[] = [ { provide: APP_INITIALIZER, - useFactory: _createNgProbe, + useFactory: _createNgProbeR2, deps: [ [NgProbeToken, new Optional()], ], diff --git a/packages/platform-browser/src/dom/dom_renderer.ts b/packages/platform-browser/src/dom/dom_renderer.ts index c25a18bfb3..2ac41a4521 100644 --- a/packages/platform-browser/src/dom/dom_renderer.ts +++ b/packages/platform-browser/src/dom/dom_renderer.ts @@ -50,10 +50,16 @@ export function flattenStyles( } function decoratePreventDefault(eventHandler: Function): Function { + // `DebugNode.triggerEventHandler` needs to know if the listener was created with + // decoratePreventDefault or is a listener added outside the Angular context so it can handle the + // two differently. In the first case, the special '__ngUnwrap__' token is passed to the unwrap + // the listener (see below). return (event: any) => { - // Ivy uses `Function` as a special token that allows us to unwrap the function - // so that it can be invoked programmatically by `DebugNode.triggerEventHandler`. - if (event === Function) { + // Ivy uses '__ngUnwrap__' as a special token that allows us to unwrap the function + // so that it can be invoked programmatically by `DebugNode.triggerEventHandler`. The debug_node + // can inspect the listener toString contents for the existence of this special token. Because + // the token is a string literal, it is ensured to not be modified by compiled code. + if (event === '__ngUnwrap__') { return eventHandler; } diff --git a/packages/platform-browser/test/BUILD.bazel b/packages/platform-browser/test/BUILD.bazel index 150d014521..901e3f6c94 100644 --- a/packages/platform-browser/test/BUILD.bazel +++ b/packages/platform-browser/test/BUILD.bazel @@ -1,10 +1,23 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") exports_files([ "browser/static_assets/200.html", "static_assets/test.html", ]) +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/platform-browser/index.js", + deps = ["//packages/platform-browser"], +) + +circular_dependency_test( + name = "testing_circular_deps_test", + entry_point = "angular/packages/platform-browser/testing/index.js", + deps = ["//packages/platform-browser/testing"], +) + ts_library( name = "test_lib", testonly = True, @@ -29,10 +42,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/platform-server/src/server_renderer.ts b/packages/platform-server/src/server_renderer.ts index 7767196f52..83f2f830dc 100644 --- a/packages/platform-server/src/server_renderer.ts +++ b/packages/platform-server/src/server_renderer.ts @@ -145,7 +145,7 @@ class DefaultServerRenderer2 implements Renderer2 { setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void { style = style.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); const styleMap = _readStyleAttribute(el); - styleMap[style] = value || ''; + styleMap[style] = value == null ? '' : value; _writeStyleAttribute(el, styleMap); } @@ -276,7 +276,7 @@ function _writeStyleAttribute(element: any, styleMap: {[name: string]: string}) let styleAttrValue = ''; for (const key in styleMap) { const newValue = styleMap[key]; - if (newValue) { + if (newValue != null) { styleAttrValue += key + ':' + styleMap[key] + ';'; } } diff --git a/packages/platform-server/src/tokens.ts b/packages/platform-server/src/tokens.ts index 870b900f9c..ebb0bf23ee 100644 --- a/packages/platform-server/src/tokens.ts +++ b/packages/platform-server/src/tokens.ts @@ -32,4 +32,4 @@ export const INITIAL_CONFIG = new InjectionToken('Server.INITIAL * @publicApi */ export const BEFORE_APP_SERIALIZED = - new InjectionToken void>>('Server.RENDER_MODULE_HOOK'); + new InjectionToken void | Promise>>('Server.RENDER_MODULE_HOOK'); diff --git a/packages/platform-server/test/BUILD.bazel b/packages/platform-server/test/BUILD.bazel index 187430ed56..b51853d191 100644 --- a/packages/platform-server/test/BUILD.bazel +++ b/packages/platform-server/test/BUILD.bazel @@ -1,4 +1,17 @@ load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/platform-server/index.js", + deps = ["//packages/platform-server"], +) + +circular_dependency_test( + name = "testing_circular_deps_test", + entry_point = "angular/packages/platform-server/testing/index.js", + deps = ["//packages/platform-server/testing"], +) ts_library( name = "test_lib", @@ -22,11 +35,10 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], tags = [ ], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/platform-webworker/test/BUILD.bazel b/packages/platform-webworker/test/BUILD.bazel index f4c2211f22..21b87b2f08 100644 --- a/packages/platform-webworker/test/BUILD.bazel +++ b/packages/platform-webworker/test/BUILD.bazel @@ -21,10 +21,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/router/test/BUILD.bazel b/packages/router/test/BUILD.bazel index 30e62191e2..bbadc0ccba 100644 --- a/packages/router/test/BUILD.bazel +++ b/packages/router/test/BUILD.bazel @@ -1,4 +1,17 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/router/index.js", + deps = ["//packages/router"], +) + +circular_dependency_test( + name = "testing_circular_deps_test", + entry_point = "angular/packages/router/testing/index.js", + deps = ["//packages/router/testing"], +) ts_library( name = "test_lib", @@ -23,10 +36,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/router/test/aot_ngsummary_test/BUILD.bazel b/packages/router/test/aot_ngsummary_test/BUILD.bazel index fc804c6b82..f21ff91914 100644 --- a/packages/router/test/aot_ngsummary_test/BUILD.bazel +++ b/packages/router/test/aot_ngsummary_test/BUILD.bazel @@ -27,9 +27,8 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":aot_test_lib", - "//tools/testing:node", ], ) diff --git a/packages/router/upgrade/test/BUILD.bazel b/packages/router/upgrade/test/BUILD.bazel index 56154ab969..f6ccbd1045 100644 --- a/packages/router/upgrade/test/BUILD.bazel +++ b/packages/router/upgrade/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/router/upgrade/index.js", + deps = ["//packages/router/upgrade"], +) ts_library( name = "test_lib", diff --git a/packages/service-worker/config/test/BUILD.bazel b/packages/service-worker/config/test/BUILD.bazel index f133a418b5..6d0a35c3a8 100644 --- a/packages/service-worker/config/test/BUILD.bazel +++ b/packages/service-worker/config/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/service-worker/config/index.js", + deps = ["//packages/service-worker/config"], +) ts_library( name = "test_lib", @@ -14,11 +21,10 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", "//packages/service-worker/config", "//packages/service-worker/config/testing", - "//tools/testing:node", ], ) diff --git a/packages/service-worker/test/BUILD.bazel b/packages/service-worker/test/BUILD.bazel index ad498fde3d..16956f533a 100644 --- a/packages/service-worker/test/BUILD.bazel +++ b/packages/service-worker/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/service-worker/index.js", + deps = ["//packages/service-worker"], +) ts_library( name = "test_lib", @@ -18,10 +25,9 @@ ts_library( jasmine_node_test( name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], + bootstrap = ["//tools/testing:node_es5"], deps = [ ":test_lib", - "//tools/testing:node", ], ) diff --git a/packages/service-worker/worker/test/BUILD.bazel b/packages/service-worker/worker/test/BUILD.bazel index 5cbb07b681..4ef4b2b910 100644 --- a/packages/service-worker/worker/test/BUILD.bazel +++ b/packages/service-worker/worker/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/service-worker/worker/main.js", + deps = ["//packages/service-worker/worker:main"], +) ts_library( name = "test_lib", diff --git a/packages/upgrade/src/common/src/downgrade_component.ts b/packages/upgrade/src/common/src/downgrade_component.ts index 1fd75a06d8..139bfdb59e 100644 --- a/packages/upgrade/src/common/src/downgrade_component.ts +++ b/packages/upgrade/src/common/src/downgrade_component.ts @@ -21,7 +21,7 @@ import {LazyModuleRef, UpgradeAppType, controllerKey, getDowngradedModuleCount, * A helper function that allows an Angular component to be used from AngularJS. * * *Part of the [upgrade/static](api?query=upgrade%2Fstatic) - * library for hybrid upgrade apps that support AoT compilation* + * library for hybrid upgrade apps that support AOT compilation* * * This helper function returns a factory function to be used for registering * an AngularJS wrapper directive for "downgrading" an Angular component. diff --git a/packages/upgrade/src/common/src/downgrade_injectable.ts b/packages/upgrade/src/common/src/downgrade_injectable.ts index be5d517aca..a92ef8e086 100644 --- a/packages/upgrade/src/common/src/downgrade_injectable.ts +++ b/packages/upgrade/src/common/src/downgrade_injectable.ts @@ -17,7 +17,7 @@ import {getTypeName, isFunction, validateInjectionKey} from './util'; * A helper function to allow an Angular service to be accessible from AngularJS. * * *Part of the [upgrade/static](api?query=upgrade%2Fstatic) - * library for hybrid upgrade apps that support AoT compilation* + * library for hybrid upgrade apps that support AOT compilation* * * This helper function returns a factory function that provides access to the Angular * service identified by the `token` parameter. diff --git a/packages/upgrade/src/common/test/BUILD.bazel b/packages/upgrade/src/common/test/BUILD.bazel index dc8abe07b8..97506c93d2 100644 --- a/packages/upgrade/src/common/test/BUILD.bazel +++ b/packages/upgrade/src/common/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/upgrade/index.js", + deps = ["//packages/upgrade"], +) ts_library( name = "test_lib", diff --git a/packages/upgrade/static/src/downgrade_module.ts b/packages/upgrade/static/src/downgrade_module.ts index 8397a415b8..71e87c671c 100644 --- a/packages/upgrade/static/src/downgrade_module.ts +++ b/packages/upgrade/static/src/downgrade_module.ts @@ -27,7 +27,7 @@ let moduleUid = 0; * instantiated. * * *Part of the [upgrade/static](api?query=upgrade/static) library for hybrid upgrade apps that - * support AoT compilation.* + * support AOT compilation.* * * It allows loading/bootstrapping the Angular part of a hybrid application lazily and not having to * pay the cost up-front. For example, you can have an AngularJS application that uses Angular for diff --git a/packages/upgrade/static/src/upgrade_component.ts b/packages/upgrade/static/src/upgrade_component.ts index 6a75b2ce1c..81fda98163 100644 --- a/packages/upgrade/static/src/upgrade_component.ts +++ b/packages/upgrade/static/src/upgrade_component.ts @@ -33,7 +33,7 @@ class Bindings { * A helper class that allows an AngularJS component to be used from Angular. * * *Part of the [upgrade/static](api?query=upgrade%2Fstatic) - * library for hybrid upgrade apps that support AoT compilation.* + * library for hybrid upgrade apps that support AOT compilation.* * * This helper class should be used as a base class for creating Angular directives * that wrap AngularJS components that need to be "upgraded". @@ -53,7 +53,7 @@ class Bindings { * * In this example you can see that we must derive from the `UpgradeComponent` * base class but also provide an {@link Directive `@Directive`} decorator. This is - * because the AoT compiler requires that this information is statically available at + * because the AOT compiler requires that this information is statically available at * compile time. * * Note that we must do the following: diff --git a/packages/upgrade/static/src/upgrade_module.ts b/packages/upgrade/static/src/upgrade_module.ts index 5301f8748d..fed0a5eb11 100644 --- a/packages/upgrade/static/src/upgrade_module.ts +++ b/packages/upgrade/static/src/upgrade_module.ts @@ -24,10 +24,10 @@ import {NgAdapterInjector} from './util'; * and has an instance method used to bootstrap the hybrid upgrade application. * * *Part of the [upgrade/static](api?query=upgrade/static) - * library for hybrid upgrade apps that support AoT compilation* + * library for hybrid upgrade apps that support AOT compilation* * * The `upgrade/static` package contains helpers that allow AngularJS and Angular components - * to be used together inside a hybrid upgrade application, which supports AoT compilation. + * to be used together inside a hybrid upgrade application, which supports AOT compilation. * * Specifically, the classes and functions in the `upgrade/static` module allow the following: * diff --git a/packages/upgrade/static/test/BUILD.bazel b/packages/upgrade/static/test/BUILD.bazel index 5c1a710315..a1efce37db 100644 --- a/packages/upgrade/static/test/BUILD.bazel +++ b/packages/upgrade/static/test/BUILD.bazel @@ -1,4 +1,11 @@ load("//tools:defaults.bzl", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/upgrade/static/index.js", + deps = ["//packages/upgrade/static"], +) ts_library( name = "test_lib", diff --git a/packages/upgrade/static/testing/test/BUILD.bazel b/packages/upgrade/static/testing/test/BUILD.bazel index 554d922c89..8a9c4f3ba6 100644 --- a/packages/upgrade/static/testing/test/BUILD.bazel +++ b/packages/upgrade/static/testing/test/BUILD.bazel @@ -1,6 +1,13 @@ package(default_visibility = ["//visibility:public"]) load("//tools:defaults.bzl", "karma_web_test_suite", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/upgrade/static/testing/index.js", + deps = ["//packages/upgrade/static/testing"], +) ts_library( name = "test_lib", diff --git a/packages/zone.js/BUILD.bazel b/packages/zone.js/BUILD.bazel index f683bc1480..379bab62ed 100644 --- a/packages/zone.js/BUILD.bazel +++ b/packages/zone.js/BUILD.bazel @@ -1,4 +1,4 @@ -load("@build_bazel_rules_nodejs//:index.bzl", "npm_package") +load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm") load("//packages/zone.js:bundles.bzl", "ES2015_BUNDLES", "ES5_BUNDLES", "ES5_GLOBAL_BUNDLES") exports_files([ @@ -21,7 +21,7 @@ genrule( cmd = "(echo '/**\n @license' && cat $< && echo '*/') > $@", ) -npm_package( +pkg_npm( name = "npm_package", srcs = [ "CHANGELOG.md", diff --git a/packages/zone.js/NON-STANDARD-APIS.md b/packages/zone.js/NON-STANDARD-APIS.md index 8cca25bdd3..36dbd1fc0d 100644 --- a/packages/zone.js/NON-STANDARD-APIS.md +++ b/packages/zone.js/NON-STANDARD-APIS.md @@ -1,14 +1,13 @@ # Zone.js's support for non standard apis Zone.js patched most standard APIs such as DOM event listeners, XMLHttpRequest in Browser, EventEmitter and fs API in Node.js so they can be in zone. - -But there are still a lot of non standard APIs that are not patched by default, such as MediaQuery, Notification, - WebAudio and so on. We are adding support to those APIs, and our progress is updated here. - -## Currently supported non standard Web APIs + +But there are still a lot of non-standard APIs that are not patched by default, such as MediaQuery, Notification, WebAudio and so on. This page provides updates on the current state of zone support for Angular APIs. + +## Currently supported non-standard Web APIs * MediaQuery -* Notification +* Notification ## Currently supported polyfills @@ -26,9 +25,9 @@ Usage: ## Currently supported non standard common APIs -* bluebird promise +* [Bluebird](http://bluebirdjs.com/docs/getting-started.html] Promise -Browser Usage: +Browser Usage: ``` @@ -39,7 +38,29 @@ Browser Usage: ``` -After those steps, window.Promise will become a ZoneAware Bluebird Promise. +After those steps, window.Promise becomes Bluebird Promise and will also be zone awareness. + +Angular Usage: + +in polyfills.ts, import the `zone-bluebird` package. + +``` +import 'zone.js/dist/zone'; // Included with Angular CLI. +import 'zone.js/dist/zone-bluebird'; +``` + +in main.ts, patch bluebird. + +``` +platformBrowserDynamic() + .bootstrapModule(AppModule) + .then(_ => { +import('bluebird').then(Bluebird => {const Zone = (window as any)['Zone']; Zone[Zone['__symbol__']('bluebird')](Bluebird.default);}); + }) + .catch(err => console.error(err)); +``` + +After this step, the `window.Promise` will be the Bluebird `Promise`, and the callback of `Bluebird.then` will be executed in the Angular zone. Node Sample Usage: @@ -75,11 +96,11 @@ remove the comment of the following line ## Others -* Cordova +* Cordova patch `cordova.exec` API -`cordova.exec(success, error, service, action, args);` +`cordova.exec(success, error, service, action, args);` `success` and `error` will be patched with `Zone.wrap`. @@ -96,12 +117,12 @@ to load the patch, you should load in the following order. By default, those APIs' support will not be loaded in zone.js or zone-node.js, so if you want to load those API's support, you should load those files by yourself. -For example, if you want to add MediaQuery patch, you should do like this: +For example, if you want to add MediaQuery patch, you should do like this: ``` - - -``` + + +``` * rxjs @@ -127,17 +148,17 @@ constructorZone.run(() => { subscriptionZone.run(() => { observable.subscribe(() => { - console.log('current zone when subscription next', Zone.current.name); // will output subscription. + console.log('current zone when subscription next', Zone.current.name); // will output subscription. }, () => { - console.log('current zone when subscription error', Zone.current.name); // will output subscription. + console.log('current zone when subscription error', Zone.current.name); // will output subscription. }, () => { - console.log('current zone when subscription complete', Zone.current.name); // will output subscription. + console.log('current zone when subscription complete', Zone.current.name); // will output subscription. }); }); operatorZone.run(() => { observable.map(() => { - console.log('current zone when map operator', Zone.current.name); // will output operator. + console.log('current zone when map operator', Zone.current.name); // will output operator. }); }); ``` @@ -147,8 +168,8 @@ Currently basically everything the `rxjs` API includes - Observable - Subscription - Subscriber -- Operators -- Scheduler +- Operators +- Scheduler is patched, so each asynchronous call will run in the correct zone. @@ -194,7 +215,7 @@ user need to patch `io` themselves just like following code. ``` -please reference the sample repo [zone-socketio](https://github.com/JiaLiPassion/zone-socketio) about +please reference the sample repo [zone-socketio](https://github.com/JiaLiPassion/zone-socketio) about detail usage. * jsonp @@ -212,7 +233,7 @@ import 'zone.js/dist/zone-patch-jsonp'; Zone['__zone_symbol__jsonp']({ jsonp: getJSONP, sendFuncName: 'send', - successFuncName: 'jsonpSuccessCallback', + successFuncName: 'jsonpSuccessCallback', failedFuncName: 'jsonpFailedCallback' }); ``` diff --git a/packages/zone.js/lib/common/events.ts b/packages/zone.js/lib/common/events.ts index 084f126457..85818b4d12 100644 --- a/packages/zone.js/lib/common/events.ts +++ b/packages/zone.js/lib/common/events.ts @@ -44,6 +44,16 @@ export const globalSources: any = {}; const EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); const IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); +function prepareEventNames(eventName: string, eventNameToString?: (eventName: string) => string) { + const falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; + const trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; + const symbol = ZONE_SYMBOL_PREFIX + falseEventName; + const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; +} + export interface PatchEventTargetOptions { // validateHandler vh?: (nativeDelegate: any, delegate: any, target: any, args: any) => boolean; @@ -387,23 +397,12 @@ export function patchEventTarget( } const zone = Zone.current; - const symbolEventNames = zoneSymbolEventNames[eventName]; - let symbolEventName; + let symbolEventNames = zoneSymbolEventNames[eventName]; if (!symbolEventNames) { - // the code is duplicate, but I just want to get some better performance - const falseEventName = - (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; - const trueEventName = - (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; - const symbol = ZONE_SYMBOL_PREFIX + falseEventName; - const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; - zoneSymbolEventNames[eventName] = {}; - zoneSymbolEventNames[eventName][FALSE_STR] = symbol; - zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; - symbolEventName = capture ? symbolCapture : symbol; - } else { - symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + prepareEventNames(eventName, eventNameToString); + symbolEventNames = zoneSymbolEventNames[eventName]; } + const symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; let existingTasks = target[symbolEventName]; let isExisting = false; if (existingTasks) { @@ -668,20 +667,35 @@ export function patchEventTarget( } export function findEventTasks(target: any, eventName: string): Task[] { - const foundTasks: any[] = []; - for (let prop in target) { - const match = EVENT_NAME_SYMBOL_REGX.exec(prop); - let evtName = match && match[1]; - if (evtName && (!eventName || evtName === eventName)) { - const tasks: any = target[prop]; - if (tasks) { - for (let i = 0; i < tasks.length; i++) { - foundTasks.push(tasks[i]); + if (!eventName) { + const foundTasks: any[] = []; + for (let prop in target) { + const match = EVENT_NAME_SYMBOL_REGX.exec(prop); + let evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + const tasks: any = target[prop]; + if (tasks) { + for (let i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } } } } + return foundTasks; + } + let symbolEventName = zoneSymbolEventNames[eventName]; + if (!symbolEventName) { + prepareEventNames(eventName); + symbolEventName = zoneSymbolEventNames[eventName]; + } + const captureFalseTasks = target[symbolEventName[FALSE_STR]]; + const captureTrueTasks = target[symbolEventName[TRUE_STR]]; + if (!captureFalseTasks) { + return captureTrueTasks ? captureTrueTasks.slice() : []; + } else { + return captureTrueTasks ? captureFalseTasks.concat(captureTrueTasks) : + captureFalseTasks.slice(); } - return foundTasks; } export function patchEventPrototype(global: any, api: _ZonePrivate) { diff --git a/packages/zone.js/lib/common/promise.ts b/packages/zone.js/lib/common/promise.ts index 44fb652c58..2e12b15c53 100644 --- a/packages/zone.js/lib/common/promise.ts +++ b/packages/zone.js/lib/common/promise.ts @@ -384,7 +384,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr null): Promise { let C = (this.constructor as any)[Symbol.species]; if (!C || typeof C !== 'function') { - C = ZoneAwarePromise; + C = this.constructor || ZoneAwarePromise; } const chainPromise: Promise = new (C as typeof ZoneAwarePromise)(noop); const zone = Zone.current; diff --git a/packages/zone.js/rollup-es5.config.js b/packages/zone.js/rollup-es5.config.js index 8e86e499f5..049523e5b0 100644 --- a/packages/zone.js/rollup-es5.config.js +++ b/packages/zone.js/rollup-es5.config.js @@ -16,7 +16,7 @@ if (bazel_stamp_file) { const banner = `/** * @license Angular v${version} -* (c) 2010-2019 Google LLC. https://angular.io/ +* (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */`; diff --git a/packages/zone.js/rollup-es5_global-es2015.config.js b/packages/zone.js/rollup-es5_global-es2015.config.js index 729415f95d..37bdfd1edd 100644 --- a/packages/zone.js/rollup-es5_global-es2015.config.js +++ b/packages/zone.js/rollup-es5_global-es2015.config.js @@ -16,7 +16,7 @@ if (bazel_stamp_file) { const banner = `/** * @license Angular v${version} -* (c) 2010-2019 Google LLC. https://angular.io/ +* (c) 2010-2020 Google LLC. https://angular.io/ * License: MIT */`; diff --git a/packages/zone.js/test/BUILD.bazel b/packages/zone.js/test/BUILD.bazel index 6c30bd4810..b9da4f9466 100644 --- a/packages/zone.js/test/BUILD.bazel +++ b/packages/zone.js/test/BUILD.bazel @@ -68,8 +68,6 @@ ts_library( testonly = True, srcs = glob(["node/*.ts"]) + [ "node-env-setup.ts", - "node_entry_point.ts", - "node_entry_point_no_patch_clock.ts", "test-env-setup-jasmine-no-patch-clock.ts", ], deps = [ @@ -85,12 +83,45 @@ ts_library( ], ) +ts_library( + name = "node_entry_point", + testonly = True, + srcs = ["node_entry_point.ts"], + deps = [ + ":common_spec_env", + ":common_spec_srcs", + ":common_spec_util", + "//packages/zone.js/lib", + "@npm//@types/shelljs", + "@npm//@types/systemjs", + "@npm//rxjs", + "@npm//shelljs", + "@npm//systemjs", + ], +) + +ts_library( + name = "node_entry_point_no_patch_clock", + testonly = True, + srcs = ["node_entry_point_no_patch_clock.ts"], + deps = [ + ":common_spec_env", + ":common_spec_srcs", + ":common_spec_util", + "//packages/zone.js/lib", + "@npm//@types/shelljs", + "@npm//@types/systemjs", + "@npm//rxjs", + "@npm//shelljs", + "@npm//systemjs", + ], +) + ts_library( name = "bluebird_spec", testonly = True, srcs = [ "extra/bluebird.spec.ts", - "node_bluebird_entry_point.ts", ], deps = [ ":common_spec_env", @@ -100,13 +131,33 @@ ts_library( ) ts_library( - name = "error_spec", + name = "node_bluebird_entry_point", testonly = True, - srcs = [ - "node_error_disable_policy_entry_point.ts", - "node_error_entry_point.ts", - "node_error_lazy_policy_entry_point.ts", + srcs = ["node_bluebird_entry_point.ts"], + deps = [ + ":common_spec_env", + "//packages/zone.js/lib", + "@npm//bluebird", ], +) + +ts_library( + name = "node_error_disable_policy_entry_point", + testonly = True, + srcs = ["node_error_disable_policy_entry_point.ts"], + deps = [ + ":common_spec_env", + ":common_spec_util", + ":error_spec_srcs", + ":node_error_entry_point", + "//packages/zone.js/lib", + ], +) + +ts_library( + name = "node_error_entry_point", + testonly = True, + srcs = ["node_error_entry_point.ts"], deps = [ ":common_spec_env", ":common_spec_util", @@ -115,11 +166,22 @@ ts_library( ], ) +ts_library( + name = "node_error_lazy_policy_entry_point", + testonly = True, + srcs = ["node_error_lazy_policy_entry_point.ts"], + deps = [ + ":common_spec_env", + ":common_spec_util", + ":error_spec_srcs", + ":node_error_entry_point", + "//packages/zone.js/lib", + ], +) + jasmine_node_test( name = "test_node", - bootstrap = [ - "angular/packages/zone.js/test/node_entry_point.js", - ], + bootstrap = [":node_entry_point_es5"], deps = [ ":test_node_lib", ], @@ -127,9 +189,7 @@ jasmine_node_test( jasmine_node_test( name = "test_node_no_jasmine_clock", - bootstrap = [ - "angular/packages/zone.js/test/node_entry_point_no_patch_clock.js", - ], + bootstrap = [":node_entry_point_no_patch_clock_es5"], deps = [ ":test_node_lib", ], @@ -137,9 +197,7 @@ jasmine_node_test( jasmine_node_test( name = "test_node_bluebird", - bootstrap = [ - "angular/packages/zone.js/test/node_bluebird_entry_point.js", - ], + bootstrap = [":node_bluebird_entry_point_es5"], deps = [ ":bluebird_spec", ], @@ -147,22 +205,12 @@ jasmine_node_test( jasmine_node_test( name = "test_node_error_disable_policy", - bootstrap = [ - "angular/packages/zone.js/test/node_error_disable_policy_entry_point.js", - ], - deps = [ - ":error_spec", - ], + bootstrap = [":node_error_disable_policy_entry_point_es5"], ) jasmine_node_test( name = "test_node_error_lazy_policy", - bootstrap = [ - "angular/packages/zone.js/test/node_error_lazy_policy_entry_point.js", - ], - deps = [ - ":error_spec", - ], + bootstrap = [":node_error_lazy_policy_entry_point_es5"], ) ts_library( diff --git a/packages/zone.js/test/common/Promise.spec.ts b/packages/zone.js/test/common/Promise.spec.ts index f5038b83f0..e277902da5 100644 --- a/packages/zone.js/test/common/Promise.spec.ts +++ b/packages/zone.js/test/common/Promise.spec.ts @@ -103,7 +103,14 @@ describe( }).toThrowError('Must be an instanceof Promise.'); }); - it('should allow subclassing with Promise.specices', () => { + it('should allow subclassing without Symbol.species', () => { + class MyPromise extends Promise { + constructor(fn: any) { super(fn); } + } + expect(new MyPromise(() => {}).then(() => null) instanceof MyPromise).toBe(true); + }); + + it('should allow subclassing with Symbol.species', () => { class MyPromise extends Promise { constructor(fn: any) { super(fn); } @@ -112,7 +119,7 @@ describe( expect(new MyPromise(() => {}).then(() => null) instanceof MyPromise).toBe(true); }); - it('Promise.specices should return ZoneAwarePromise', () => { + it('Symbol.species should return ZoneAwarePromise', () => { const empty = function() {}; const promise = Promise.resolve(1); const FakePromise = ((promise.constructor = {} as any) as any)[Symbol.species] = function( diff --git a/packages/zone.js/test/common/fetch.spec.ts b/packages/zone.js/test/common/fetch.spec.ts index 8df75786cd..2fe72e2ce2 100644 --- a/packages/zone.js/test/common/fetch.spec.ts +++ b/packages/zone.js/test/common/fetch.spec.ts @@ -150,7 +150,7 @@ describe( it('cancel fetch should invoke onCancelTask', ifEnvSupportsWithDone('AbortController', (done: DoneFn) => { - if (isSafari) { + if (isSafari()) { // safari not work with AbortController done(); return; @@ -177,7 +177,7 @@ describe( it('cancel fetchTask should trigger abort', ifEnvSupportsWithDone('AbortController', (done: DoneFn) => { - if (isSafari) { + if (isSafari()) { // safari not work with AbortController done(); return; diff --git a/protractor-perf.conf.js b/protractor-perf.conf.js index 748ea12c2b..6bbd427185 100644 --- a/protractor-perf.conf.js +++ b/protractor-perf.conf.js @@ -6,10 +6,6 @@ * 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('angular/modules/e2e_util/perf_util').readCommandLine(); - const CHROME_OPTIONS = { 'args': ['--js-flags=--expose-gc', '--no-sandbox', '--headless', '--disable-dev-shm-usage'], 'perfLoggingPrefs': { diff --git a/scripts/ci/clone_angular_components_repo.sh b/scripts/ci/clone_angular_components_repo.sh new file mode 100755 index 0000000000..4607a386c8 --- /dev/null +++ b/scripts/ci/clone_angular_components_repo.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -u -e -o pipefail + +# Clones the `angular/components` repository if the repository has not been cloned before. +# If the repository has been already cloned, the script refreshes the repository by syncing +# with the upstream remote, and resetting to the commit specified in the `COMPONENTS_REPO_COMMIT` +# environment variable. + +if [[ ! -d "${COMPONENTS_REPO_TMP_DIR}" ]]; then + # Clone the repository if not present through restored cache. + git clone --branch ${COMPONENTS_REPO_BRANCH} ${COMPONENTS_REPO_URL} ${COMPONENTS_REPO_TMP_DIR} + + # Switch into the cloned repository. + cd ${COMPONENTS_REPO_TMP_DIR} + + # Reset branch to the desired commit. + git reset --hard ${COMPONENTS_REPO_COMMIT} +else + # Switch into the cached repository. + cd ${COMPONENTS_REPO_TMP_DIR} + + # Only refresh the repository if the current branch HEAD is not + # matching the desired commit. + if [[ "$(git rev-parse HEAD)" != "${COMPONENTS_REPO_COMMIT}" ]]; then + # Pull the latest changes of the specified branch. + git fetch origin ${COMPONENTS_REPO_BRANCH} + + # Reset the current branch to the desired commit. + git reset --hard ${COMPONENTS_REPO_COMMIT} + fi +fi diff --git a/scripts/ci/clone_angular_material_repo.sh b/scripts/ci/clone_angular_material_repo.sh deleted file mode 100755 index 56969cc2f2..0000000000 --- a/scripts/ci/clone_angular_material_repo.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Clones the Angular Material repository if the repository has not been cloned before. If -# the repository is already cloned, the script refreshes the repository by syncing with -# upstream and resetting to the desired Material commit (see "MATERIAL_REPO_COMMIT" variable). - -if [[ ! -d "${MATERIAL_REPO_TMP_DIR}" ]]; then - # Clone the Material repository if not present through restored cache. - git clone --branch ${MATERIAL_REPO_BRANCH} ${MATERIAL_REPO_URL} ${MATERIAL_REPO_TMP_DIR} - - # Switch into the cloned repository. - cd ${MATERIAL_REPO_TMP_DIR} - - # Reset branch to the desired commit. - git reset --hard ${MATERIAL_REPO_COMMIT} -else - # Switch into the cached repository. - cd ${MATERIAL_REPO_TMP_DIR} - - # Only refresh the repository if the current branch HEAD is not - # matching the desired commit. - if [[ "$(git rev-parse HEAD)" != "${MATERIAL_REPO_COMMIT}" ]]; then - # Pull the latest changes of the specified branch. - git fetch origin ${MATERIAL_REPO_BRANCH} - - # Reset the current branch to the desired commit. - git reset --hard ${MATERIAL_REPO_COMMIT} - fi -fi diff --git a/scripts/ci/run_angular_components_unit_tests.sh b/scripts/ci/run_angular_components_unit_tests.sh new file mode 100755 index 0000000000..8c2691acc6 --- /dev/null +++ b/scripts/ci/run_angular_components_unit_tests.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -u -e -o pipefail + +# Script that runs all unit tests of the `angular/components` repository. The script also +# sets up the test blocklist from `tools/components-repo-ci`. + +# Path to the Angular project. +angular_dir=$(pwd) + +# Switch into the temporary directory where the `angular/components` +# repository has been cloned into. +cd ${COMPONENTS_REPO_TMP_DIR} + +# Copy the test blocklist into the `angular/components` repository. The unit tests will +# automatically pick up the blocklist and disable the specified tests. +cp ${angular_dir}/tools/components-repo-ci/test-blocklist.ts ${COMPONENTS_REPO_TMP_DIR}/test/ + +# Create a symlink for the Bazel binary installed through NPM, as running through Yarn introduces OOM errors. +./scripts/circleci/setup_bazel_binary.sh + +# Now actually run the tests. The dev-app and all its subpackages are excluded as they fail +# to compile due to limitations in Ivy's type checker (see FW-1352 and FW-1433) +bazel test --build_tag_filters=-docs-package,-e2e,-browser:firefox-local --test_tag_filters=-e2e,-browser:firefox-local --config=ivy -- src/... -src/dev-app/... diff --git a/scripts/ci/run_angular_material_unit_tests.sh b/scripts/ci/run_angular_material_unit_tests.sh deleted file mode 100755 index 2be584a55d..0000000000 --- a/scripts/ci/run_angular_material_unit_tests.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/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) - -# Switch into Material directory. -cd ${MATERIAL_REPO_TMP_DIR} - -# Updates Material's package.json to refer to the packages-dist directory. -# Note that it's not necessary to perform a yarn install, as Bazel performs its own yarn install. -node ${angular_dir}/scripts/ci/update-deps-to-dist-packages.js ${MATERIAL_REPO_TMP_DIR}/package.json ${angular_dir}/dist/packages-dist/ - -# Copy the test blocklist into the "angular/components" repository. The components -# repository automatically picks up the blocklist and disables the specified tests. -cp ${angular_dir}/tools/material-ci/test-blocklist.ts ${MATERIAL_REPO_TMP_DIR}/test/ - -# Create a symlink for the Bazel binary installed through NPM, as running through Yarn introduces OOM errors. -./scripts/circleci/setup_bazel_binary.sh - -# Now actually run the tests. The dev-app and all its subpackages are excluded as they fail -# to compile due to limitations in Ivy's type checker (see FW-1352 and FW-1433) -bazel test --build_tag_filters=-docs-package,-e2e,-browser:firefox-local --test_tag_filters=-e2e,-browser:firefox-local --config=ivy -- src/... -src/dev-app/... diff --git a/scripts/github/merge-pr b/scripts/github/merge-pr index 4ad7a09aa1..5d81c093bf 100755 --- a/scripts/github/merge-pr +++ b/scripts/github/merge-pr @@ -131,8 +131,8 @@ CHERRY_PICK_PR="git cherry-pick merge_pr_base..merge_pr" # # 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="a03a9236f2aed5d00012d25f032aa43a046d91da" # pullapprove => CODEOWNERS migration -REQUIRED_BASE_SHA_PATCH="a03a9236f2aed5d00012d25f032aa43a046d91da" # pullapprove => CODEOWNERS migration +REQUIRED_BASE_SHA_MASTER="296dc0622f0e8c4e803ff4f19a5c6fe02a2ae66e" # CODEOWNERS => PullApprove migration +REQUIRED_BASE_SHA_PATCH="110f6c91b904819cab639861b54b6a989e176942" # CODEOWNERS => PullApprove migration if [[ $MERGE_MASTER == 1 ]]; then REQUIRED_BASE_SHA="$REQUIRED_BASE_SHA_MASTER" # check patch only if patch-only PR diff --git a/scripts/package-builder.js b/scripts/package-builder.js index da8a58167d..4451d3e427 100755 --- a/scripts/package-builder.js +++ b/scripts/package-builder.js @@ -61,7 +61,7 @@ function buildTargetPackages(destPath, enableIvy, description) { // all carriage return (`\r`) characters form the query output, because otherwise the carriage // return is part of the bazel target name and bazel will complain. const getTargetsCmd = - `${bazelCmd} query --output=label "attr('tags', '\\[.*release-with-framework.*\\]', //packages/...) intersect kind('.*_package', //packages/...)"`; + `${bazelCmd} query --output=label "attr('tags', '\\[.*release-with-framework.*\\]', //packages/...) intersect kind('ng_package|pkg_npm', //packages/...)"`; const targets = exec(getTargetsCmd, true).split(/\r?\n/); // Use `--config=release` so that snapshot builds get published with embedded version info. diff --git a/scripts/release/publish-latest b/scripts/release/publish-latest index d811b4c165..54c142cfdc 100755 --- a/scripts/release/publish-latest +++ b/scripts/release/publish-latest @@ -14,7 +14,7 @@ BAZEL_OUTPUT_BASE=$(mktemp -d -t angular-release-latest.XXXXXXX) BAZEL="$BAZEL_BIN --output_base=$BAZEL_OUTPUT_BASE" # query for all npm packages to be released as part of the framework release -NPM_PACKAGE_LABELS=`${BAZEL_BIN} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind(".*_package", //packages/...)'` +NPM_PACKAGE_LABELS=`${BAZEL_BIN} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind("ng_package|pkg_npm", //packages/...)'` # build all npm packages in parallel $BAZEL build --config=release $NPM_PACKAGE_LABELS # publish all packages in sequence to make it easier to spot any errors or warnings diff --git a/scripts/release/publish-next b/scripts/release/publish-next index c0c611a67d..e616498139 100755 --- a/scripts/release/publish-next +++ b/scripts/release/publish-next @@ -14,7 +14,7 @@ BAZEL_OUTPUT_BASE=$(mktemp -d -t angular-release-next.XXXXXXX) BAZEL="$BAZEL_BIN --output_base=$BAZEL_OUTPUT_BASE" # query for all npm packages to be released as part of the framework release -NPM_PACKAGE_LABELS=`${BAZEL_BIN} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind(".*_package", //packages/...)'` +NPM_PACKAGE_LABELS=`${BAZEL_BIN} query --output=label 'attr("tags", "\[.*release-with-framework.*\]", //packages/...) intersect kind("ng_package|pkg_npm", //packages/...)'` # build all npm packages in parallel $BAZEL build --config=release $NPM_PACKAGE_LABELS # publish all packages in sequence to make it easier to spot any errors or warnings diff --git a/scripts/saucelabs/run-bazel-via-tunnel.sh b/scripts/saucelabs/run-bazel-via-tunnel.sh deleted file mode 100755 index 1d359a3443..0000000000 --- a/scripts/saucelabs/run-bazel-via-tunnel.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env bash - -set -u -e -o pipefail - -# Prints out usage information for the script. -function printUsage { - echo -e "\e[1mrun-bazel-via-tunnel.sh\e[0m - Runs a bazel command using a saucelabs tunnel - - \e[1mUsage:\e[0m $0 --tunnel-id= \\ - --username= --key= - - \e[1mExample:\e[0m ./run-bazel-via-tunnel.sh --tunnel-id= \\ - --username= --key= \\ - yarn bazel test //src:everything - - Flags: - --username: The saucelabs username - --key: The saucelabs access key - --tunnel-id: An identifier for the saucelabs tunnel"; -} - -# Ensures a file is created, creating directories for the full path as needed. -function touch-safe { - for f in "$@"; do - [ -d $f:h ] || mkdir -p $f:h && command touch $f - done -} - -# The root directory of the git project the script is running in. -readonly GIT_ROOT_DIR=$(git rev-parse --show-toplevel 2> /dev/null) -# Location for the saucelabs log file. -readonly SAUCE_LOG_FILE=/tmp/angular/sauce-connect.log -# Location for the saucelabs ready to connect lock file. -readonly SAUCE_READY_FILE=/tmp/angular/sauce-connect-ready-file.lock -# Location for the saucelabs ready to connection process id lock file. -readonly SAUCE_PID_FILE=/tmp/angular/sauce-connect-pid-file.lock -# 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. -readonly SAUCE_READY_FILE_TIMEOUT=120 - -# Create saucelabs log file if it doesn't already exist. -touch-safe $SAUCE_LOG_FILE; - -# Handle configuration of script from command line flags and arguments -OPTIONS=$(getopt -u -l tunnel-id:,username:,key:,help --options "" -- "$@") -# Exit if flag parsing fails. -if [ $? != 0 ] ; then echo "Failed to parse flags, exiting" && printUsage >&2 ; exit 1 ; fi -set -- $OPTIONS -while true; do - case "$1" in - --tunnel-id) - shift - SAUCE_TUNNEL_IDENTIFIER=$1 - ;; - --username) - shift - SAUCE_USERNAME=$1 - ;; - --key) - shift - SAUCE_ACCESS_KEY=$1 - ;; - --help) - printUsage - exit 2 - ;; - --) - shift - USER_COMMAND=$@ - break - ;; - *) - shift - ;; - esac -done - -# Check each required flag and parameter -if [[ -z ${SAUCE_TUNNEL_IDENTIFIER+x} ]]; then - echo "Missing required flag: --tunnel-id" - badCommandSyntax=1 -fi -if [[ -z ${SAUCE_USERNAME+x} ]]; then - echo "Missing required flag: --username" - badCommandSyntax=1 -fi -if [[ -z ${SAUCE_ACCESS_KEY+x} ]]; then - echo "Missing required flag: --key" - badCommandSyntax=1 -fi -if [[ "${USER_COMMAND}" == "" ]]; then - echo "Missing required bazel command: Bazel command for running in saucelabs tunnel" - badCommandSyntax=1 -elif [[ ! $USER_COMMAND =~ ^(yarn bazel) ]]; then - echo "The command provided must be a bazel command run via yarn, beginning with \"yarn bazel\"" - badCommandSyntax=1 -fi - -# If any required flag or parameter were found to be missing or incorrect, exit the script. -if [[ ${badCommandSyntax+x} ]]; then - echo - printUsage - exit 1 -fi - - -# Command arguments that will be passed to sauce-connect. -# By default we disable SSL bumping for all requests. This is because SSL bumping is -# not needed for our test setup and in order to perform the SSL bumping, Saucelabs -# intercepts all HTTP requests in the tunnel VM and modifies them. This can cause -# flakiness as it makes all requests dependent on the SSL bumping middleware. -# See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping -sauceArgs="--no-ssl-bump-domains all" -sauceArgs="${sauceArgs} --logfile ${SAUCE_LOG_FILE}" -sauceArgs="${sauceArgs} --readyfile ${SAUCE_READY_FILE}" -sauceArgs="${sauceArgs} --pidfile ${SAUCE_PID_FILE}" -sauceArgs="${sauceArgs} --tunnel-identifier ${SAUCE_TUNNEL_IDENTIFIER}" -sauceArgs="${sauceArgs} -u ${SAUCE_USERNAME}" - -######################### -# Open saucelabs tunnel # -######################### - - -${GIT_ROOT_DIR}/node_modules/sauce-connect/bin/sc -k $SAUCE_ACCESS_KEY ${sauceArgs} & - - -######################################## -# Wait for saucelabs tunnel to connect # -######################################## -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 "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file." - echo "Printing logfile output:" - echo "" - cat ${SAUCE_LOG_FILE} - exit 5 - fi - - printf "." - sleep 0.5 -done - -######################### -# Execute Bazel command # -######################### - -# Prevent immediate exit for Bazel test failures -set +e - -( - cd $GIT_ROOT_DIR && \ - # Run bazel command with saucelabs specific environment variables passed to the action - # The KARMA_WEB_TEST_MODE and SAUCE_TUNNEL_IDENTIFIER environment variables provide - # environment variables to be read in the karma configuration file to set correct - # configurations for karma saucelabs and browser configs. - # Usage of these environment variables can be seen in this repo in - # /karma-js.conf.js and /browser-providers.conf.js - eval "$USER_COMMAND --define=KARMA_WEB_TEST_MODE=SL_REQUIRED \ - --action_env=SAUCE_USERNAME=$SAUCE_USERNAME \ - --action_env=SAUCE_ACCESS_KEY=$SAUCE_ACCESS_KEY \ - --action_env=SAUCE_READY_FILE=$SAUCE_READY_FILE \ - --action_env=SAUCE_PID_FILE=$SAUCE_PID_FILE \ - --action_env=SAUCE_TUNNEL_IDENTIFIER=$SAUCE_TUNNEL_IDENTIFIER" -) -BAZEL_EXIT_CODE=$? -echo "Exit code for bazel command was: $BAZEL_EXIT_CODE" - -# Reenable immediate exit for failure exit code -set -e - -############################## -# Close the saucelabs tunnel # -############################## - -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" - -exit $BAZEL_EXIT_CODE diff --git a/scripts/saucelabs/start-tunnel.sh b/scripts/saucelabs/start-tunnel.sh deleted file mode 100755 index 34bf0a7b5b..0000000000 --- a/scripts/saucelabs/start-tunnel.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/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. By default we disable SSL bumping for -# all requests. This is because SSL bumping is not needed for our test setup and in order -# to perform the SSL bumping, Saucelabs intercepts all HTTP requests in the tunnel VM and modifies -# them. This can cause flakiness as it makes all requests dependent on the SSL bumping middleware. -# See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping -sauceArgs="--no-ssl-bump-domains all" - -if [[ ! -z "${SAUCE_LOG_FILE:-}" ]]; then - mkdir -p $(dirname ${SAUCE_LOG_FILE}) - sauceArgs="${sauceArgs} --logfile ${SAUCE_LOG_FILE}" -fi - -if [[ ! -z "${SAUCE_READY_FILE:-}" ]]; then - mkdir -p $(dirname ${SAUCE_READY_FILE}) - 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 deleted file mode 100755 index c53a7e31ca..0000000000 --- a/scripts/saucelabs/stop-tunnel.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/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 deleted file mode 100755 index feda9a85b6..0000000000 --- a/scripts/saucelabs/wait-for-tunnel.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/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 "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file." - echo "Printing logfile output:" - echo "" - cat ${SAUCE_LOG_FILE} - exit 5 - fi - - printf "." - sleep 0.5 -done - -echo "" -echo "Connected to Saucelabs" diff --git a/tools/circular_dependency_test/BUILD.bazel b/tools/circular_dependency_test/BUILD.bazel new file mode 100644 index 0000000000..2fbfcdf237 --- /dev/null +++ b/tools/circular_dependency_test/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["madge-resolve.config.js"]) diff --git a/tools/circular_dependency_test/index.bzl b/tools/circular_dependency_test/index.bzl new file mode 100644 index 0000000000..1eb66b2669 --- /dev/null +++ b/tools/circular_dependency_test/index.bzl @@ -0,0 +1,37 @@ +# 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 + +load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test") + +MADGE_CONFIG_LABEL = "//tools/circular_dependency_test:madge-resolve.config.js" + +""" + Creates a test target that ensures that no circular dependencies can + be found in the given entry point file. +""" + +def circular_dependency_test(name, deps, entry_point, **kwargs): + nodejs_test( + name = name, + data = ["@npm//madge", MADGE_CONFIG_LABEL] + deps, + entry_point = "@npm//:node_modules/madge/bin/cli.js", + templated_args = [ + "--circular", + "--no-spinner", + # NOTE: We cannot use `$(location)` to resolve labels. This is because `ts_library` + # does not pre-declare outputs in the rule. Hence, the outputs cannot be referenced + # through labels (i.e. `//packages/core:index.js`). Read more here: + # https://docs.bazel.build/versions/2.0.0/skylark/rules.html#outputs + # TODO: revisit once https://github.com/bazelbuild/rules_nodejs/issues/1563 is solved. + "$(rlocation %s)" % entry_point, + # Madge supports custom module resolution, but expects a configuration file + # similar to a Webpack configuration file setting the `resolve` option. + "--webpack-config", + "$(rlocation $(location %s))" % MADGE_CONFIG_LABEL, + ], + testonly = 1, + expected_exit_code = 0, + **kwargs + ) diff --git a/tools/circular_dependency_test/madge-resolve.config.js b/tools/circular_dependency_test/madge-resolve.config.js new file mode 100644 index 0000000000..1788191079 --- /dev/null +++ b/tools/circular_dependency_test/madge-resolve.config.js @@ -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 + */ + +/** + * Custom resolution plugin for Webpack's `resolve-enhanced` package that is used by + * Madge for resolving imports. The plugin extends the resolution by leveraging the + * runfile resolution and module mappings handled in the module info aspect. + */ +class BazelRunfileResolutionPlugin { + apply(resolver) { + resolver.plugin('module', (request, callback) => { + try { + // Resolve the module through the `require.resolve` method which has been patched + // in the Bazel NodeJS loader to respect runfiles and module mappings. This allows + // Madge to handle module mappings specified in `ts_library` and `ng_module` targets. + const resolvedPath = require.resolve(request.request); + // Update the request to refer to the runfile resolved file path. + resolver.doResolve('resolve', {...request, request: resolvedPath}, null, callback, true); + return; + } catch { + } + // If the file could not be resolved through Bazel's runfile resolution, proceed + // with the default module resolvers. + callback(); + }); + } +} + +// Configures a plugin which ensures that Madge can properly resolve specified +// dependencies through their configured module names. +module.exports = { + resolve: {plugins: [new BazelRunfileResolutionPlugin()]} +}; diff --git a/tools/material-ci/instructions.md b/tools/components-repo-ci/instructions.md similarity index 84% rename from tools/material-ci/instructions.md rename to tools/components-repo-ci/instructions.md index a000c32809..0f04f096d5 100644 --- a/tools/material-ci/instructions.md +++ b/tools/components-repo-ci/instructions.md @@ -1,8 +1,8 @@ -### Unit tests for Angular CDK/Material +### Unit tests for `angular/components` Currently, all changes to Ivy are validated against the test suite of the `angular/components` repository. Known failing tests are skipped based on -the blocklist in `tools/material-ci/test-blocklist.ts`. +the blocklist in `tools/components-repo-ci/test-blocklist.ts`. Whenever the root cause of a known failure is identified, the `notes` field for the corresponding tests should be updated. Whenever a failure is resolved, @@ -10,7 +10,7 @@ the corresponding tests should be removed from the blocklist. ### Debugging -Information on debugging can be found [here](../../docs/DEBUG_MATERIAL_IVY.md). +Information on debugging can be found [here](../../docs/DEBUG_COMPONENTS_REPO_IVY.md). ### Excluding new tests diff --git a/tools/material-ci/test-blocklist.ts b/tools/components-repo-ci/test-blocklist.ts similarity index 100% rename from tools/material-ci/test-blocklist.ts rename to tools/components-repo-ci/test-blocklist.ts diff --git a/tools/defaults.bzl b/tools/defaults.bzl index 231c52c856..170233b267 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -1,6 +1,6 @@ """Re-export of some bazel rules with repository-wide defaults.""" -load("@build_bazel_rules_nodejs//:index.bzl", _nodejs_binary = "nodejs_binary", _npm_package = "npm_package") +load("@build_bazel_rules_nodejs//:index.bzl", _nodejs_binary = "nodejs_binary", _pkg_npm = "pkg_npm") load("@npm_bazel_jasmine//:index.bzl", _jasmine_node_test = "jasmine_node_test") load("@npm_bazel_karma//:index.bzl", _karma_web_test = "karma_web_test", _karma_web_test_suite = "karma_web_test_suite") load("@npm_bazel_typescript//:index.bzl", _ts_devserver = "ts_devserver", _ts_library = "ts_library") @@ -93,7 +93,7 @@ def ts_devserver(**kwargs): **kwargs ) -def ts_library(tsconfig = None, testonly = False, deps = [], module_name = None, **kwargs): +def ts_library(name, tsconfig = None, testonly = False, deps = [], module_name = None, **kwargs): """Default values for ts_library""" deps = deps + ["@npm//tslib"] if testonly: @@ -108,6 +108,7 @@ def ts_library(tsconfig = None, testonly = False, deps = [], module_name = None, module_name = _default_module_name(testonly) _ts_library( + name = name, tsconfig = tsconfig, testonly = testonly, deps = deps, @@ -115,6 +116,17 @@ def ts_library(tsconfig = None, testonly = False, deps = [], module_name = None, **kwargs ) + # Select the es5 .js output of the ts_library for use in downstream boostrap targets + # with `output_group = "es5_sources"`. This exposes an internal detail of ts_library + # that is not ideal. + # TODO(gregmagolan): clean this up by using tsc() in these cases rather than ts_library + native.filegroup( + name = "%s_es5" % name, + srcs = [":%s" % name], + testonly = testonly, + output_group = "es5_sources", + ) + def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps = [], module_name = None, bundle_dts = True, **kwargs): """Default values for ng_module""" deps = deps + ["@npm//tslib"] @@ -160,7 +172,7 @@ def ng_package(name, readme_md = None, license_banner = None, deps = [], **kwarg deps = deps, readme_md = readme_md, license_banner = license_banner, - replacements = PKG_GROUP_REPLACEMENTS, + substitutions = PKG_GROUP_REPLACEMENTS, ng_packager = _INTERNAL_NG_PACKAGE_PACKAGER, terser_config_file = _INTERNAL_NG_PACKAGE_DEFALUT_TERSER_CONFIG_FILE, rollup_config_tmpl = _INTERNAL_NG_PACKAGE_DEFAULT_ROLLUP_CONFIG_TMPL, @@ -168,11 +180,11 @@ def ng_package(name, readme_md = None, license_banner = None, deps = [], **kwarg **kwargs ) -def npm_package(name, replacements = {}, **kwargs): +def pkg_npm(name, substitutions = {}, **kwargs): """Default values for npm_package""" - _npm_package( + _pkg_npm( name = name, - replacements = dict(replacements, **PKG_GROUP_REPLACEMENTS), + substitutions = dict(substitutions, **PKG_GROUP_REPLACEMENTS), **kwargs ) @@ -244,10 +256,34 @@ def nodejs_binary(data = [], **kwargs): **kwargs ) -def jasmine_node_test(deps = [], **kwargs): - """Default values for jasmine_node_test""" - deps = deps + [ - # Very common dependencies for tests +def jasmine_node_test(bootstrap = [], **kwargs): + """Default values for jasmine_node_test + + Args: + bootstrap: A list of labels of scripts to run before the entry_point. + + The labels can either be individual files or a filegroup that contain a single + file. + + The label is automatically added to the deps of jasmine_node_test. + If the label ends in `_es5` which by convention selects the es5 outputs + of a ts_library rule, then corresponding ts_library target sans `_es5` + is also added to the deps of jasmine_node_test. + + For example with, + + jasmine_node_test( + name = "test", + bootstrap = ["//tools/testing:node_es5"], + deps = [":test_lib"], + ) + + the `//tools/testing:node` target will automatically get added to deps + by this macro. This removes the need for duplicate deps on the + target and makes the usage of this rule less verbose.""" + + # Very common dependencies for tests + deps = kwargs.pop("deps", []) + [ "@npm//chokidar", "@npm//domino", "@npm//jasmine-core", @@ -256,9 +292,24 @@ def jasmine_node_test(deps = [], **kwargs): "@npm//tslib", "@npm//xhr2", ] + configuration_env_vars = kwargs.pop("configuration_env_vars", []) + [ + "angular_ivy_enabled", + ] + templated_args = kwargs.pop("templated_args", []) + for label in bootstrap: + deps += [label] + templated_args += ["--node_options=--require=$(rlocation $(location %s))" % label] + if label.endswith("_es5"): + # If this label is a filegroup derived from a ts_library then automatically + # add the ts_library target (which is the label sans `_es5`) to deps so we pull + # in all of its transitive deps. This removes the need for duplicate deps on the + # target and makes the usage of this rule less verbose. + deps += [label[:-4]] + _jasmine_node_test( deps = deps, - configuration_env_vars = ["angular_ivy_enabled"], + configuration_env_vars = configuration_env_vars, + templated_args = templated_args, **kwargs ) @@ -319,7 +370,7 @@ def rollup_bundle(name, testonly = False, **kwargs): name + ".js", ], args = [ - "$(location :%s.es2015.js)" % name, + "$(execpath :%s.es2015.js)" % name, "--types", "--skipLibCheck", "--target", @@ -328,7 +379,7 @@ def rollup_bundle(name, testonly = False, **kwargs): "es2015,dom", "--allowJS", "--outFile", - "$(location :%s.js)" % name, + "$(execpath :%s.js)" % name, ], data = [ name + ".es2015.js", @@ -350,7 +401,7 @@ def rollup_bundle(name, testonly = False, **kwargs): name + ".es5umd.js", ], args = [ - "$(location :%s.umd.js)" % name, + "$(execpath :%s.umd.js)" % name, "--types", "--skipLibCheck", "--target", @@ -359,7 +410,7 @@ def rollup_bundle(name, testonly = False, **kwargs): "es2015,dom", "--allowJS", "--outFile", - "$(location :%s.es5umd.js)" % name, + "$(execpath :%s.es5umd.js)" % name, ], data = [ name + ".umd.js", diff --git a/tools/gulp-tasks/check-cycle.js b/tools/gulp-tasks/check-cycle.js deleted file mode 100644 index 62315c5bc6..0000000000 --- a/tools/gulp-tasks/check-cycle.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 - */ - -// tslint:disable:no-console -module.exports = (gulp) => (done) => { - const madge = require('madge'); - - // 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, '//'); } - }); - const circularDependencies = dependencyObject.circular().getArray(); - if (circularDependencies.length > 0) { - console.log('Found circular dependencies!'); - console.log(circularDependencies); - process.exit(1); - } - done(); -}; diff --git a/tools/gulp-tasks/cldr/extract.js b/tools/gulp-tasks/cldr/extract.js index 81c89e795f..084c50e21c 100644 --- a/tools/gulp-tasks/cldr/extract.js +++ b/tools/gulp-tasks/cldr/extract.js @@ -97,8 +97,8 @@ module.exports = (gulp, done) => { console.log(`All i18n cldr files have been generated, formatting files..."`); shelljs.exec( - `yarn clang-format -i ${I18N_DATA_FOLDER}/**/*.ts ${I18N_DATA_FOLDER}/*.ts ${I18N_FOLDER}/currencies.ts ${I18N_CORE_FOLDER}/locale_en.ts ${I18N_GLOBAL_FOLDER}/*.js`, - {silent: true}); + `yarn clang-format -i ${I18N_DATA_FOLDER}/**/*.ts ${I18N_DATA_FOLDER}/*.ts ${I18N_FOLDER}/currencies.ts ${I18N_CORE_FOLDER}/locale_en.ts ${I18N_GLOBAL_FOLDER}/*.js`, + {silent: true}); done(); }; @@ -149,16 +149,19 @@ function generateGlobalLocale(locale, localeData, baseCurrencies) { * Collect up the basic locale data [ localeId, dateTime, number, currency, pluralCase ]. */ function generateBasicLocaleString(locale, localeData, baseCurrencies) { - let data = - stringify( - [ - locale, ...getDateTimeTranslations(localeData), ...getDateTimeSettings(localeData), - ...getNumberSettings(localeData), ...getCurrencySettings(locale, localeData), - generateLocaleCurrencies(localeData, baseCurrencies), getDirectionality(localeData), - ], - true) - // We remove "undefined" added by spreading arrays when there is no value - .replace(/undefined/g, 'u'); + let data = stringify( + [ + locale, + ...getDateTimeTranslations(localeData), + ...getDateTimeSettings(localeData), + ...getNumberSettings(localeData), + ...getCurrencySettings(locale, localeData), + generateLocaleCurrencies(localeData, baseCurrencies), + getDirectionality(localeData), + ], + true) + // We remove "undefined" added by spreading arrays when there is no value + .replace(/undefined/g, 'u'); // adding plural function after, because we don't want it as a string data = data.replace(/\]$/, ', plural]'); @@ -495,8 +498,8 @@ function getNumberSettings(localeData) { } /** - * Returns the currency symbol and name for a locale - * @returns [ symbol, name ] + * Returns the currency code, symbol and name for a locale + * @returns [ code, symbol, name ] */ function getCurrencySettings(locale, localeData) { const currencyInfo = localeData.main(`numbers/currencies`); @@ -523,11 +526,13 @@ function getCurrencySettings(locale, localeData) { } } - let currencySettings = [undefined, undefined]; + let currencySettings = [undefined, undefined, undefined]; if (currentCurrency) { - currencySettings = - [currencyInfo[currentCurrency].symbol, currencyInfo[currentCurrency].displayName]; + currencySettings = [ + currentCurrency, currencyInfo[currentCurrency].symbol, + currencyInfo[currentCurrency].displayName + ]; } return currencySettings; diff --git a/tools/gulp-tasks/validate-commit-message.js b/tools/gulp-tasks/validate-commit-message.js index 6dc192e7a8..5761856c0c 100644 --- a/tools/gulp-tasks/validate-commit-message.js +++ b/tools/gulp-tasks/validate-commit-message.js @@ -8,30 +8,56 @@ // tslint:disable:no-console -module.exports = (gulp) => () => { +module.exports = (gulp) => async() => { try { const validateCommitMessage = require('../validate-commit-message'); const shelljs = require('shelljs'); + const getRefsAndShasForTarget = require('../utils/get-refs-and-shas-for-target'); - shelljs.set('-e'); // Break on error. + // Break on error. + shelljs.set('-e'); - let baseBranch = 'master'; - const currentVersion = require('semver').parse(require('../../package.json').version); - const baseHead = - shelljs - .exec(`git ls-remote --heads origin ${currentVersion.major}.${currentVersion.minor}.*`) - .trim() - .split('\n') - .pop(); - if (baseHead) { - const match = /refs\/heads\/(.+)/.exec(baseHead); - baseBranch = match && match[1] || baseBranch; + + let target = {}; + if (process.env['CI'] === 'true') { + // Validation of commit messages on CI + if (process.env['CI_PULL_REQUEST'] === 'false') { + // Skip commit message validation on CI for non-PR branches as we are not testing new + // unreviewed commits. By enforcing correctness on the incoming changes in the PR + // branches, we are able to render this check unnecessary on non-PR branches. + console.info( + `Since valid commit messages are enforced by PR linting on CI,\n` + + `we do not need to validate commit messages on CI runs on upstream branches.\n\n` + + `Skipping validate-commit-message check`); + process.exit(); + } + target = await getRefsAndShasForTarget(process.env['CI_PULL_REQUEST']); + } else { + // Validation of commit messages locally + const baseRef = 'master'; + const headRef = shelljs.exec('git symbolic-ref --short HEAD', {silent: true}).trim(); + const baseSha = shelljs.exec(`git rev-parse origin/master`, {silent: true}).trim(); + const headSha = shelljs.exec(`git rev-parse HEAD`, {silent: true}).trim(); + const commonAncestorSha = + shelljs.exec(`git merge-base origin/master ${headSha}`, {silent: true}).trim(); + target = { + base: { + ref: baseRef, + sha: baseSha, + }, + head: { + ref: headRef, + sha: headSha, + }, + commonAncestorSha: commonAncestorSha, + latestShaOfTargetBranch: baseSha, + latestShaOfPrBranch: headSha, + }; } - // We need to fetch origin explicitly because it might be stale. - // I couldn't find a reliable way to do this without fetch. const result = shelljs.exec( - `git fetch origin ${baseBranch} && git log --reverse --format=%s origin/${baseBranch}..HEAD`); + `git log --reverse --format=%s ${target.commonAncestorSha}..${target.latestShaOfPrBranch}`, + {silent: true}); if (result.code) { throw new Error(`Failed to fetch commits: ${result.stderr}`); @@ -39,10 +65,10 @@ module.exports = (gulp) => () => { const commitsByLine = result.trim().split(/\n/).filter(line => line != ''); - console.log(`Examining ${commitsByLine.length} commit(s) between ${baseBranch} and HEAD`); + console.log(`Examining ${commitsByLine.length} commit(s) between ${target.base.ref} and HEAD`); if (commitsByLine.length == 0) { - console.log(`There are zero new commits between ${baseBranch} and HEAD`); + console.log(`There are zero new commits between ${target.base.ref} and HEAD`); } const disallowSquashCommits = true; diff --git a/tools/ng_rollup_bundle/BUILD.bazel b/tools/ng_rollup_bundle/BUILD.bazel index a1e47c5f05..9c7960d932 100644 --- a/tools/ng_rollup_bundle/BUILD.bazel +++ b/tools/ng_rollup_bundle/BUILD.bazel @@ -17,5 +17,4 @@ nodejs_binary( "@npm//rollup-plugin-sourcemaps", ], entry_point = "@npm//:node_modules/rollup/dist/bin/rollup", - install_source_map_support = False, ) diff --git a/tools/ng_rollup_bundle/ng_rollup_bundle.bzl b/tools/ng_rollup_bundle/ng_rollup_bundle.bzl index 93f468dd7f..30ecc22054 100644 --- a/tools/ng_rollup_bundle/ng_rollup_bundle.bzl +++ b/tools/ng_rollup_bundle/ng_rollup_bundle.bzl @@ -416,8 +416,8 @@ def ng_rollup_bundle(name, **kwargs): data = [name + ".min.js"], outs = [name + ".min.js.br"], args = [ - "--output=$(location %s.min.js.br)" % name, - "$(location %s.min.js)" % name, + "--output=$(execpath %s.min.js.br)" % name, + "$(execpath %s.min.js)" % name, ], visibility = visibility, ) @@ -439,8 +439,8 @@ def ng_rollup_bundle(name, **kwargs): data = [name + ".min.es2015.js"], outs = [name + ".min.es2015.js.br"], args = [ - "--output=$(location %s.min.es2015.js.br)" % name, - "$(location %s.min.es2015.js)" % name, + "--output=$(execpath %s.min.es2015.js.br)" % name, + "$(execpath %s.min.es2015.js)" % name, ], visibility = visibility, ) diff --git a/tools/public_api_guard/BUILD.bazel b/tools/public_api_guard/BUILD.bazel index 57d7066617..922324ebc7 100644 --- a/tools/public_api_guard/BUILD.bazel +++ b/tools/public_api_guard/BUILD.bazel @@ -65,3 +65,14 @@ ts_api_guardian_test( ], golden = "angular/tools/public_api_guard/global_utils.d.ts", ) + +# explicit target because the d.ts file is nested in the core and not part of typical public d.ts api +ts_api_guardian_test( + name = "error_code_api", + actual = "angular/packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.d.ts", + data = [ + ":error_code.d.ts", + "//packages/compiler-cli/src/ngtsc/diagnostics", + ], + golden = "angular/tools/public_api_guard/error_code.d.ts", +) diff --git a/tools/public_api_guard/common/common.d.ts b/tools/public_api_guard/common/common.d.ts index 8abc8bf99b..84ade8d7aa 100644 --- a/tools/public_api_guard/common/common.d.ts +++ b/tools/public_api_guard/common/common.d.ts @@ -3,17 +3,17 @@ export declare const APP_BASE_HREF: InjectionToken; export declare class AsyncPipe implements OnDestroy, PipeTransform { constructor(_ref: ChangeDetectorRef); ngOnDestroy(): void; + transform(obj: null): null; + transform(obj: undefined): undefined; transform(obj: Observable | null | undefined): T | null; transform(obj: Promise | null | undefined): T | null; - transform(obj: undefined): undefined; - transform(obj: null): null; } export declare class CommonModule { } export declare class CurrencyPipe implements PipeTransform { - constructor(_locale: string); + constructor(_locale: string, _defaultCurrencyCode?: string); transform(value: any, currencyCode?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean, digitsInfo?: string, locale?: string): string | null; } @@ -51,6 +51,8 @@ export declare enum FormStyle { export declare function getCurrencySymbol(code: string, format: 'wide' | 'narrow', locale?: string): string; +export declare function getLocaleCurrencyCode(locale: string): string | null; + export declare function getLocaleCurrencyName(locale: string): string | null; export declare function getLocaleCurrencySymbol(locale: string): string | null; @@ -187,25 +189,15 @@ export declare class LowerCasePipe implements PipeTransform { transform(value: string): string; } -export declare class NgClass extends NgClassBase implements DoCheck { - klass: string; - ngClass: string | string[] | Set | { +export declare class NgClass implements DoCheck { + set klass(value: string); + set ngClass(value: string | string[] | Set | { [klass: string]: any; - }; - constructor(delegate: NgClassImpl); + }); + constructor(_iterableDiffers: IterableDiffers, _keyValueDiffers: KeyValueDiffers, _ngEl: ElementRef, _renderer: Renderer2); ngDoCheck(): void; } -export declare class NgClassBase { - protected _delegate: NgClassImpl; - constructor(_delegate: NgClassImpl); - getValue(): { - [key: string]: any; - } | null; - static ɵdir: any; - static ɵfac: any; -} - export declare class NgComponentOutlet implements OnChanges, OnDestroy { ngComponentOutlet: Type; ngComponentOutletContent: any[][]; @@ -217,9 +209,10 @@ export declare class NgComponentOutlet implements OnChanges, OnDestroy { } export declare class NgForOf = NgIterable> implements DoCheck { - ngForOf: (U & NgIterable) | undefined | null; - ngForTemplate: TemplateRef>; - ngForTrackBy: TrackByFunction; + set ngForOf(ngForOf: (U & NgIterable) | undefined | null); + set ngForTemplate(value: TemplateRef>); + set ngForTrackBy(fn: TrackByFunction); + get ngForTrackBy(): TrackByFunction; constructor(_viewContainer: ViewContainerRef, _template: TemplateRef>, _differs: IterableDiffers); ngDoCheck(): void; static ngTemplateContextGuard>(dir: NgForOf, ctx: any): ctx is NgForOfContext; @@ -228,19 +221,19 @@ export declare class NgForOf = NgIterable> impleme export declare class NgForOfContext = NgIterable> { $implicit: T; count: number; - readonly even: boolean; - readonly first: boolean; + get even(): boolean; + get first(): boolean; index: number; - readonly last: boolean; + get last(): boolean; ngForOf: U; - readonly odd: boolean; + get odd(): boolean; constructor($implicit: T, ngForOf: U, index: number, count: number); } export declare class NgIf { - ngIf: T; - ngIfElse: TemplateRef> | null; - ngIfThen: TemplateRef> | null; + set ngIf(condition: T); + set ngIfElse(templateRef: TemplateRef> | null); + set ngIfThen(templateRef: TemplateRef> | null); constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef>); static ngTemplateGuard_ngIf: 'binding'; static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext; @@ -262,7 +255,7 @@ export declare abstract class NgLocalization { } export declare class NgPlural { - ngPlural: number; + set ngPlural(value: number); constructor(_localization: NgLocalization); addCase(value: string, switchView: SwitchView): void; } @@ -272,26 +265,16 @@ export declare class NgPluralCase { constructor(value: string, template: TemplateRef, viewContainer: ViewContainerRef, ngPlural: NgPlural); } -export declare class NgStyle extends NgStyleBase implements DoCheck { - ngStyle: { +export declare class NgStyle implements DoCheck { + set ngStyle(values: { [klass: string]: any; - } | null; - constructor(delegate: NgStyleImpl); + } | null); + constructor(_ngEl: ElementRef, _differs: KeyValueDiffers, _renderer: Renderer2); ngDoCheck(): void; } -export declare class NgStyleBase { - protected _delegate: NgStyleImpl; - constructor(_delegate: NgStyleImpl); - getValue(): { - [key: string]: any; - } | null; - static ɵdir: any; - static ɵfac: any; -} - export declare class NgSwitch { - ngSwitch: any; + set ngSwitch(newValue: any); } export declare class NgSwitchCase implements DoCheck { @@ -353,13 +336,13 @@ export declare class PercentPipe implements PipeTransform { } export declare abstract class PlatformLocation { - abstract readonly hash: string; - abstract readonly hostname: string; - abstract readonly href: string; - abstract readonly pathname: string; - abstract readonly port: string; - abstract readonly protocol: string; - abstract readonly search: string; + abstract get hash(): string; + abstract get hostname(): string; + abstract get href(): string; + abstract get pathname(): string; + abstract get port(): string; + abstract get protocol(): string; + abstract get search(): string; abstract back(): void; abstract forward(): void; abstract getBaseHrefFromDOM(): string; diff --git a/tools/public_api_guard/common/http.d.ts b/tools/public_api_guard/common/http.d.ts index b82636b302..0f2fa899aa 100644 --- a/tools/public_api_guard/common/http.d.ts +++ b/tools/public_api_guard/common/http.d.ts @@ -6,7 +6,7 @@ export declare abstract class HttpBackend implements HttpHandler { export declare class HttpClient { constructor(handler: HttpHandler); - delete(url: string, options?: { + delete(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -15,9 +15,153 @@ export declare class HttpClient { [param: string]: string | string[]; }; reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; responseType?: 'json'; withCredentials?: boolean; - }): Observable; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + delete(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; delete(url: string, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -30,7 +174,19 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; - delete(url: string, options: { + delete(url: string, options?: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable; + get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -42,7 +198,7 @@ export declare class HttpClient { responseType: 'arraybuffer'; withCredentials?: boolean; }): Observable; - delete(url: string, options: { + get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -54,7 +210,7 @@ export declare class HttpClient { responseType: 'blob'; withCredentials?: boolean; }): Observable; - delete(url: string, options: { + get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -66,7 +222,7 @@ export declare class HttpClient { responseType: 'text'; withCredentials?: boolean; }): Observable; - delete(url: string, options: { + get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -78,7 +234,7 @@ export declare class HttpClient { responseType: 'arraybuffer'; withCredentials?: boolean; }): Observable>; - delete(url: string, options: { + get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -90,102 +246,6 @@ export declare class HttpClient { responseType: 'blob'; withCredentials?: boolean; }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - delete(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; get(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -198,6 +258,90 @@ export declare class HttpClient { responseType: 'text'; withCredentials?: boolean; }): Observable>; + get(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + get(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + get(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + get(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + get(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; + get(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + get(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; get(url: string, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -210,66 +354,6 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; - get(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable; - get(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable; - get(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable; - get(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - get(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; get(url: string, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -282,7 +366,79 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; - get(url: string, options: { + head(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable; + head(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable; + head(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable; + head(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + head(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + head(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; + head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -294,7 +450,7 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable>; - get(url: string, options: { + head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -306,7 +462,7 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable>; - get(url: string, options: { + head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -318,7 +474,7 @@ export declare class HttpClient { responseType: 'arraybuffer'; withCredentials?: boolean; }): Observable>; - get(url: string, options: { + head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -330,7 +486,7 @@ export declare class HttpClient { responseType: 'blob'; withCredentials?: boolean; }): Observable>; - get(url: string, options: { + head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -342,7 +498,7 @@ export declare class HttpClient { responseType: 'text'; withCredentials?: boolean; }): Observable>; - get(url: string, options: { + head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -354,7 +510,7 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable>; - get(url: string, options: { + head(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -366,18 +522,6 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable>; - head(url: string, options?: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable; head(url: string, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -390,249 +534,7 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable; - head(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable; - jsonp(url: string, callbackParam: string): Observable; - jsonp(url: string, callbackParam: string): Observable; - options(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - options(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable; - options(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable; - options(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable; - options(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - options(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; - options(url: string, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - options(url: string, options?: { + head(url: string, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -644,6 +546,92 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; + jsonp(url: string, callbackParam: string): Observable; + jsonp(url: string, callbackParam: string): Observable; + options(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable; + options(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable; + options(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable; + options(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + options(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + options(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; + options(url: string, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; options(url: string, options: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -728,30 +716,18 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; - patch(url: string, body: any | null, options: { + options(url: string, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; }; - observe: 'events'; + observe?: 'body'; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; - responseType: 'blob'; + responseType?: 'json'; withCredentials?: boolean; - }): Observable>; - patch(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; + }): Observable; patch(url: string, body: any | null, options: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -800,30 +776,30 @@ export declare class HttpClient { responseType: 'arraybuffer'; withCredentials?: boolean; }): Observable>; - patch(url: string, body: any | null, options?: { + patch(url: string, body: any | null, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; - observe?: 'body'; + observe: 'events'; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; - responseType?: 'json'; + responseType: 'blob'; withCredentials?: boolean; - }): Observable; - patch(url: string, body: any | null, options?: { + }): Observable>; + patch(url: string, body: any | null, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; - observe?: 'body'; + observe: 'events'; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; - responseType?: 'json'; + responseType: 'text'; withCredentials?: boolean; - }): Observable; + }): Observable>; patch(url: string, body: any | null, options: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -908,19 +884,7 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable>; - post(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - post(url: string, body: any | null, options?: { + patch(url: string, body: any | null, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; }; @@ -932,6 +896,18 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; + patch(url: string, body: any | null, options?: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable; post(url: string, body: any | null, options: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -992,18 +968,18 @@ export declare class HttpClient { responseType: 'blob'; withCredentials?: boolean; }): Observable>; - post(url: string, body: any | null, options?: { + post(url: string, body: any | null, options: { headers?: HttpHeaders | { [header: string]: string | string[]; }; - observe?: 'body'; + observe: 'events'; params?: HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; - responseType?: 'json'; + responseType: 'text'; withCredentials?: boolean; - }): Observable; + }): Observable>; post(url: string, body: any | null, options: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -1088,6 +1064,182 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable>; + post(url: string, body: any | null, options?: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable; + post(url: string, body: any | null, options?: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; + put(url: string, body: any | null, options: { + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'response'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType?: 'json'; + withCredentials?: boolean; + }): Observable>; put(url: string, body: any | null, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -1100,158 +1252,6 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'response'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType?: 'json'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable; - put(url: string, body: any | null, options: { - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable; put(url: string, body: any | null, options?: { headers?: HttpHeaders | { [header: string]: string | string[]; @@ -1264,6 +1264,85 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable; + request(req: HttpRequest): Observable>; + request(method: string, url: string, options: { + body?: any; + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable; + request(method: string, url: string, options: { + body?: any; + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable; + request(method: string, url: string, options: { + body?: any; + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable; + request(method: string, url: string, options: { + body?: any; + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + params?: HttpParams | { + [param: string]: string | string[]; + }; + observe: 'events'; + reportProgress?: boolean; + responseType: 'arraybuffer'; + withCredentials?: boolean; + }): Observable>; + request(method: string, url: string, options: { + body?: any; + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'blob'; + withCredentials?: boolean; + }): Observable>; + request(method: string, url: string, options: { + body?: any; + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe: 'events'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + reportProgress?: boolean; + responseType: 'text'; + withCredentials?: boolean; + }): Observable>; request(method: string, url: string, options: { body?: any; headers?: HttpHeaders | { @@ -1277,98 +1356,6 @@ export declare class HttpClient { responseType?: 'json'; withCredentials?: boolean; }): Observable>; - request(method: string, url: string, options?: { - body?: any; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - responseType?: 'json'; - reportProgress?: boolean; - withCredentials?: boolean; - }): Observable; - request(method: string, url: string, options: { - body?: any; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable; - request(method: string, url: string, options: { - body?: any; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable; - request(method: string, url: string, options: { - body?: any; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe?: 'body'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable; - request(method: string, url: string, options: { - body?: any; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - params?: HttpParams | { - [param: string]: string | string[]; - }; - observe: 'events'; - reportProgress?: boolean; - responseType: 'arraybuffer'; - withCredentials?: boolean; - }): Observable>; - request(method: string, url: string, options: { - body?: any; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'blob'; - withCredentials?: boolean; - }): Observable>; - request(method: string, url: string, options: { - body?: any; - headers?: HttpHeaders | { - [header: string]: string | string[]; - }; - observe: 'events'; - params?: HttpParams | { - [param: string]: string | string[]; - }; - reportProgress?: boolean; - responseType: 'text'; - withCredentials?: boolean; - }): Observable>; - request(req: HttpRequest): Observable>; request(method: string, url: string, options: { body?: any; headers?: HttpHeaders | { @@ -1460,6 +1447,19 @@ export declare class HttpClient { reportProgress?: boolean; withCredentials?: boolean; }): Observable; + request(method: string, url: string, options?: { + body?: any; + headers?: HttpHeaders | { + [header: string]: string | string[]; + }; + observe?: 'body'; + params?: HttpParams | { + [param: string]: string | string[]; + }; + responseType?: 'json'; + reportProgress?: boolean; + withCredentials?: boolean; + }): Observable; request(method: string, url: string, options?: { body?: any; headers?: HttpHeaders | { diff --git a/tools/public_api_guard/common/http/testing.d.ts b/tools/public_api_guard/common/http/testing.d.ts index 7387dc1486..72b5c10bb4 100644 --- a/tools/public_api_guard/common/http/testing.d.ts +++ b/tools/public_api_guard/common/http/testing.d.ts @@ -22,7 +22,7 @@ export interface RequestMatch { } export declare class TestRequest { - readonly cancelled: boolean; + get cancelled(): boolean; request: HttpRequest; constructor(request: HttpRequest, observer: Observer>); error(error: ErrorEvent, opts?: { diff --git a/tools/public_api_guard/common/testing.d.ts b/tools/public_api_guard/common/testing.d.ts index 11002fcd55..4b3f845e47 100644 --- a/tools/public_api_guard/common/testing.d.ts +++ b/tools/public_api_guard/common/testing.d.ts @@ -19,15 +19,15 @@ export declare class MockLocationStrategy extends LocationStrategy { } export declare class MockPlatformLocation implements PlatformLocation { - readonly hash: string; - readonly hostname: string; - readonly href: string; - readonly pathname: string; - readonly port: string; - readonly protocol: string; - readonly search: string; - readonly state: unknown; - readonly url: string; + get hash(): string; + get hostname(): string; + get href(): string; + get pathname(): string; + get port(): string; + get protocol(): string; + get search(): string; + get state(): unknown; + get url(): string; constructor(config?: MockPlatformLocationConfig); back(): void; forward(): void; diff --git a/tools/public_api_guard/common/upgrade.d.ts b/tools/public_api_guard/common/upgrade.d.ts index 4ea123fffa..db9f0782de 100644 --- a/tools/public_api_guard/common/upgrade.d.ts +++ b/tools/public_api_guard/common/upgrade.d.ts @@ -3,8 +3,8 @@ export declare class $locationShim { $$parse(url: string): void; $$parseLinkUrl(url: string, relHref?: string | null): boolean; absUrl(): string; - hash(hash: string | number | null): this; hash(): string; + hash(hash: string | number | null): this; host(): string; onChange(fn: (url: string, state: unknown, oldUrl: string, oldState: unknown) => void, err?: (e: Error) => void): void; path(): string; @@ -21,8 +21,8 @@ export declare class $locationShim { search(search: string | number | { [key: string]: unknown; }, paramValue: null | undefined | string | number | boolean | string[]): this; - state(state: unknown): this; state(): unknown; + state(state: unknown): this; url(): string; url(url: string): this; } diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index 7d0e7e2417..1b3220ba04 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -41,7 +41,7 @@ export declare class ApplicationRef { readonly componentTypes: Type[]; readonly components: ComponentRef[]; readonly isStable: Observable; - readonly viewCount: number; + get viewCount(): number; attachView(viewRef: ViewRef): void; bootstrap(componentOrFactory: ComponentFactory | Type, rootSelectorOrNode?: string | any): ComponentRef; detachView(viewRef: ViewRef): void; @@ -136,17 +136,17 @@ export interface ComponentDecorator { } export declare abstract class ComponentFactory { - abstract readonly componentType: Type; - abstract readonly inputs: { + abstract get componentType(): Type; + abstract get inputs(): { propName: string; templateName: string; }[]; - abstract readonly ngContentSelectors: string[]; - abstract readonly outputs: { + abstract get ngContentSelectors(): string[]; + abstract get outputs(): { propName: string; templateName: string; }[]; - abstract readonly selector: string; + abstract get selector(): string; abstract create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string | any, ngModule?: NgModuleRef): ComponentRef; } @@ -156,12 +156,12 @@ export declare abstract class ComponentFactoryResolver { } export declare abstract class ComponentRef { - abstract readonly changeDetectorRef: ChangeDetectorRef; - abstract readonly componentType: Type; - abstract readonly hostView: ViewRef; - abstract readonly injector: Injector; - abstract readonly instance: C; - abstract readonly location: ElementRef; + abstract get changeDetectorRef(): ChangeDetectorRef; + abstract get componentType(): Type; + abstract get hostView(): ViewRef; + abstract get injector(): Injector; + abstract get instance(): C; + abstract get location(): ElementRef; abstract destroy(): void; abstract onDestroy(callback: Function): void; } @@ -257,10 +257,12 @@ export declare const DebugNode: { new (...args: any[]): DebugNode; }; +export declare const DEFAULT_CURRENCY_CODE: InjectionToken; + /** @deprecated */ export declare class DefaultIterableDiffer implements IterableDiffer, IterableChanges { readonly collection: V[] | Iterable | null; - readonly isDirty: boolean; + get isDirty(): boolean; readonly length: number; constructor(trackByFn?: TrackByFunction); check(collection: NgIterable): boolean; @@ -316,8 +318,8 @@ export declare class ElementRef { } export declare abstract class EmbeddedViewRef extends ViewRef { - abstract readonly context: C; - abstract readonly rootNodes: any[]; + abstract get context(): C; + abstract get rootNodes(): any[]; } export declare function enableProdMode(): void; @@ -599,7 +601,7 @@ export interface NgModuleDecorator { } export declare abstract class NgModuleFactory { - abstract readonly moduleType: Type; + abstract get moduleType(): Type; abstract create(parentInjector: Injector | null): NgModuleRef; } @@ -609,9 +611,9 @@ export declare abstract class NgModuleFactoryLoader { } export declare abstract class NgModuleRef { - abstract readonly componentFactoryResolver: ComponentFactoryResolver; - abstract readonly injector: Injector; - abstract readonly instance: T; + abstract get componentFactoryResolver(): ComponentFactoryResolver; + abstract get injector(): Injector; + abstract get instance(): T; abstract destroy(): void; abstract onDestroy(callback: () => void): void; } @@ -680,8 +682,6 @@ export interface OutputDecorator { export declare function ɵɵadvance(delta: number): void; -export declare function ɵɵallocHostVars(count: number): void; - export declare function ɵɵattribute(name: string, value: any, sanitizer?: SanitizerFn | null, namespace?: string): typeof ɵɵattribute; export declare function ɵɵattributeInterpolate1(attrName: string, prefix: string, v0: any, suffix: string, sanitizer?: SanitizerFn, namespace?: string): typeof ɵɵattributeInterpolate1; @@ -703,8 +703,8 @@ export declare function ɵɵattributeInterpolate8(attrName: string, prefix: stri export declare function ɵɵattributeInterpolateV(attrName: string, values: any[], sanitizer?: SanitizerFn, namespace?: string): typeof ɵɵattributeInterpolateV; export declare function ɵɵclassMap(classes: { - [className: string]: any; -} | NO_CHANGE | string | null): void; + [className: string]: boolean | undefined | null; +} | Map | Set | string[] | string | undefined | null): void; export declare function ɵɵclassMapInterpolate1(prefix: string, v0: any, suffix: string): void; @@ -724,7 +724,7 @@ export declare function ɵɵclassMapInterpolate8(prefix: string, v0: any, i0: st export declare function ɵɵclassMapInterpolateV(values: any[]): void; -export declare function ɵɵclassProp(className: string, value: boolean | null): typeof ɵɵclassProp; +export declare function ɵɵclassProp(className: string, value: boolean | undefined | null): typeof ɵɵclassProp; export declare type ɵɵComponentDefWithMeta(componentDefinition: { [P in keyof T]?: string; }; hostBindings?: HostBindingsFunction; + hostVars?: number; + hostAttrs?: TAttributes; contentQueries?: ContentQueriesFunction; exportAs?: string[]; template: ComponentTemplate; @@ -778,11 +780,13 @@ export declare function ɵɵdefineComponent(componentDefinition: { export declare const ɵɵdefineDirective: (directiveDefinition: { type: Type; - selectors?: (string | SelectorFlags)[][] | undefined; + selectors?: CssSelectorList | undefined; inputs?: { [P in keyof T]?: string | [string, string] | undefined; } | undefined; outputs?: { [P_1 in keyof T]?: string | undefined; } | undefined; features?: DirectiveDefFeature[] | undefined; hostBindings?: HostBindingsFunction | undefined; + hostVars?: number | undefined; + hostAttrs?: TAttributes | undefined; contentQueries?: ContentQueriesFunction | undefined; viewQuery?: ViewQueriesFunction | null | undefined; exportAs?: string[] | undefined; @@ -837,8 +841,6 @@ export declare function ɵɵelementContainerStart(index: number, attrsIndex?: nu export declare function ɵɵelementEnd(): void; -export declare function ɵɵelementHostAttrs(attrs: TAttributes): void; - export declare function ɵɵelementStart(index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void; export declare function ɵɵembeddedViewEnd(): void; @@ -1033,9 +1035,9 @@ export declare function ɵɵstaticViewQuery(predicate: Type | string[], export declare function ɵɵstyleMap(styles: { [styleName: string]: any; -} | NO_CHANGE | null): void; +} | Map | string | undefined | null): void; -export declare function ɵɵstyleProp(prop: string, value: string | number | SafeValue | null, suffix?: string | null): typeof ɵɵstyleProp; +export declare function ɵɵstyleProp(prop: string, value: string | number | SafeValue | undefined | null, suffix?: string | null): typeof ɵɵstyleProp; export declare function ɵɵstylePropInterpolate1(prop: string, prefix: string, v0: any, suffix: string, valueSuffix?: string | null): typeof ɵɵstylePropInterpolate1; @@ -1112,8 +1114,8 @@ export declare const PLATFORM_INITIALIZER: InjectionToken<(() => void)[]>; export declare const platformCore: (extraProviders?: StaticProvider[] | undefined) => PlatformRef; export declare class PlatformRef { - readonly destroyed: boolean; - readonly injector: Injector; + get destroyed(): boolean; + get injector(): Injector; bootstrapModule(moduleType: Type, compilerOptions?: (CompilerOptions & BootstrapOptions) | Array): Promise>; bootstrapModuleFactory(moduleFactory: NgModuleFactory, options?: BootstrapOptions): Promise>; destroy(): void; @@ -1162,7 +1164,7 @@ export declare class QueryList implements Iterable { /** @deprecated */ export declare abstract class ReflectiveInjector implements Injector { - abstract readonly parent: Injector | null; + abstract get parent(): Injector | null; abstract createChildFromResolved(providers: ResolvedReflectiveProvider[]): ReflectiveInjector; abstract get(token: any, notFoundValue?: any): any; abstract instantiateResolved(provider: ResolvedReflectiveProvider): any; @@ -1179,12 +1181,12 @@ export declare class ReflectiveKey { id: number; token: Object; constructor(token: Object, id: number); - static readonly numberOfKeys: number; + static get numberOfKeys(): number; static get(token: Object): ReflectiveKey; } export declare abstract class Renderer2 { - abstract readonly data: { + abstract get data(): { [key: string]: any; }; destroyNode: ((node: any) => void) | null; @@ -1323,7 +1325,7 @@ export declare abstract class SystemJsNgModuleLoaderConfig { } export declare abstract class TemplateRef { - abstract readonly elementRef: ElementRef; + abstract get elementRef(): ElementRef; abstract createEmbeddedView(context: C): EmbeddedViewRef; } @@ -1410,10 +1412,10 @@ export interface ViewChildrenDecorator { } export declare abstract class ViewContainerRef { - abstract readonly element: ElementRef; - abstract readonly injector: Injector; - abstract readonly length: number; - /** @deprecated */ abstract readonly parentInjector: Injector; + abstract get element(): ElementRef; + abstract get injector(): Injector; + abstract get length(): number; + /** @deprecated */ abstract get parentInjector(): Injector; abstract clear(): void; abstract createComponent(componentFactory: ComponentFactory, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef): ComponentRef; abstract createEmbeddedView(templateRef: TemplateRef, context?: C, index?: number): EmbeddedViewRef; @@ -1433,7 +1435,7 @@ export declare enum ViewEncapsulation { } export declare abstract class ViewRef extends ChangeDetectorRef { - abstract readonly destroyed: boolean; + abstract get destroyed(): boolean; abstract destroy(): void; abstract onDestroy(callback: Function): any /** TODO #9100 */; } diff --git a/tools/public_api_guard/core/testing.d.ts b/tools/public_api_guard/core/testing.d.ts index e502c94f0d..111156ec83 100644 --- a/tools/public_api_guard/core/testing.d.ts +++ b/tools/public_api_guard/core/testing.d.ts @@ -58,8 +58,8 @@ export interface TestBed { configureTestingModule(moduleDef: TestModuleMetadata): void; createComponent(component: Type): ComponentFixture; execute(tokens: any[], fn: Function, context?: any): any; - /** @deprecated */ get(token: any, notFoundValue?: any): any; /** @deprecated */ get(token: Type | InjectionToken, notFoundValue?: T, flags?: InjectFlags): any; + /** @deprecated */ get(token: any, notFoundValue?: any): any; initTestEnvironment(ngModule: Type | Type[], platform: PlatformRef, aotSummaries?: () => any[]): void; inject(token: Type | InjectionToken | AbstractType, notFoundValue?: T, flags?: InjectFlags): T; inject(token: Type | InjectionToken | AbstractType, notFoundValue: null, flags?: InjectFlags): T | null; @@ -95,15 +95,19 @@ export interface TestBedStatic { }): TestBedStatic; configureTestingModule(moduleDef: TestModuleMetadata): TestBedStatic; createComponent(component: Type): ComponentFixture; - /** @deprecated */ get(token: any, notFoundValue?: any): any; /** @deprecated */ get(token: Type | InjectionToken, notFoundValue?: T, flags?: InjectFlags): any; + /** @deprecated */ get(token: any, notFoundValue?: any): any; initTestEnvironment(ngModule: Type | Type[], platform: PlatformRef, aotSummaries?: () => any[]): TestBed; - inject(token: Type | InjectionToken | AbstractType, notFoundValue: null, flags?: InjectFlags): T | null; inject(token: Type | InjectionToken | AbstractType, notFoundValue?: T, flags?: InjectFlags): T; + inject(token: Type | InjectionToken | AbstractType, notFoundValue: null, flags?: InjectFlags): T | null; overrideComponent(component: Type, override: MetadataOverride): TestBedStatic; overrideDirective(directive: Type, override: MetadataOverride): TestBedStatic; overrideModule(ngModule: Type, override: MetadataOverride): TestBedStatic; overridePipe(pipe: Type, override: MetadataOverride): TestBedStatic; + overrideProvider(token: any, provider: { + useFactory: Function; + deps: any[]; + }): TestBedStatic; overrideProvider(token: any, provider: { useValue: any; }): TestBedStatic; @@ -112,10 +116,6 @@ export interface TestBedStatic { useValue?: any; deps?: any[]; }): TestBedStatic; - overrideProvider(token: any, provider: { - useFactory: Function; - deps: any[]; - }): TestBedStatic; overrideTemplate(component: Type, template: string): TestBedStatic; overrideTemplateUsingTestingModule(component: Type, template: string): TestBedStatic; resetTestEnvironment(): void; diff --git a/tools/public_api_guard/error_code.d.ts b/tools/public_api_guard/error_code.d.ts new file mode 100644 index 0000000000..738dbaea60 --- /dev/null +++ b/tools/public_api_guard/error_code.d.ts @@ -0,0 +1,34 @@ +export declare enum ErrorCode { + DECORATOR_ARG_NOT_LITERAL = 1001, + DECORATOR_ARITY_WRONG = 1002, + DECORATOR_NOT_CALLED = 1003, + DECORATOR_ON_ANONYMOUS_CLASS = 1004, + DECORATOR_UNEXPECTED = 1005, + DECORATOR_COLLISION = 1006, + VALUE_HAS_WRONG_TYPE = 1010, + VALUE_NOT_LITERAL = 1011, + COMPONENT_MISSING_TEMPLATE = 2001, + PIPE_MISSING_NAME = 2002, + PARAM_MISSING_TOKEN = 2003, + DIRECTIVE_MISSING_SELECTOR = 2004, + UNDECORATED_PROVIDER = 2005, + DIRECTIVE_INHERITS_UNDECORATED_CTOR = 2006, + SYMBOL_NOT_EXPORTED = 3001, + SYMBOL_EXPORTED_UNDER_DIFFERENT_NAME = 3002, + CONFIG_FLAT_MODULE_NO_INDEX = 4001, + CONFIG_STRICT_TEMPLATES_IMPLIES_FULL_TEMPLATE_TYPECHECK = 4002, + HOST_BINDING_PARSE_ERROR = 5001, + NGMODULE_INVALID_DECLARATION = 6001, + NGMODULE_INVALID_IMPORT = 6002, + NGMODULE_INVALID_EXPORT = 6003, + NGMODULE_INVALID_REEXPORT = 6004, + NGMODULE_MODULE_WITH_PROVIDERS_MISSING_GENERIC = 6005, + NGMODULE_REEXPORT_NAME_COLLISION = 6006, + NGMODULE_DECLARATION_NOT_UNIQUE = 6007, + SCHEMA_INVALID_ELEMENT = 8001, + SCHEMA_INVALID_ATTRIBUTE = 8002, + MISSING_REFERENCE_TARGET = 8003, + MISSING_PIPE = 8004, + WRITE_TO_READ_ONLY_VARIABLE = 8005, + INJECTABLE_DUPLICATE_PROV = 9001 +} diff --git a/tools/public_api_guard/forms/forms.d.ts b/tools/public_api_guard/forms/forms.d.ts index 685841ba05..fa6a25659d 100644 --- a/tools/public_api_guard/forms/forms.d.ts +++ b/tools/public_api_guard/forms/forms.d.ts @@ -1,20 +1,20 @@ export declare abstract class AbstractControl { asyncValidator: AsyncValidatorFn | null; - readonly dirty: boolean; - readonly disabled: boolean; - readonly enabled: boolean; + get dirty(): boolean; + get disabled(): boolean; + get enabled(): boolean; readonly errors: ValidationErrors | null; - readonly invalid: boolean; - readonly parent: FormGroup | FormArray; - readonly pending: boolean; + get invalid(): boolean; + get parent(): FormGroup | FormArray; + get pending(): boolean; readonly pristine: boolean; - readonly root: AbstractControl; + get root(): AbstractControl; readonly status: string; readonly statusChanges: Observable; readonly touched: boolean; - readonly untouched: boolean; - readonly updateOn: FormHooks; - readonly valid: boolean; + get untouched(): boolean; + get updateOn(): FormHooks; + get valid(): boolean; validator: ValidatorFn | null; readonly value: any; readonly valueChanges: Observable; @@ -65,22 +65,22 @@ export declare abstract class AbstractControl { } export declare abstract class AbstractControlDirective { - abstract readonly control: AbstractControl | null; - readonly dirty: boolean | null; - readonly disabled: boolean | null; - readonly enabled: boolean | null; - readonly errors: ValidationErrors | null; - readonly invalid: boolean | null; - readonly path: string[] | null; - readonly pending: boolean | null; - readonly pristine: boolean | null; - readonly status: string | null; - readonly statusChanges: Observable | null; - readonly touched: boolean | null; - readonly untouched: boolean | null; - readonly valid: boolean | null; - readonly value: any; - readonly valueChanges: Observable | null; + abstract get control(): AbstractControl | null; + get dirty(): boolean | null; + get disabled(): boolean | null; + get enabled(): boolean | null; + get errors(): ValidationErrors | null; + get invalid(): boolean | null; + get path(): string[] | null; + get pending(): boolean | null; + get pristine(): boolean | null; + get status(): string | null; + get statusChanges(): Observable | null; + get touched(): boolean | null; + get untouched(): boolean | null; + get valid(): boolean | null; + get value(): any; + get valueChanges(): Observable | null; getError(errorCode: string, path?: Array | string): any; hasError(errorCode: string, path?: Array | string): boolean; reset(value?: any): void; @@ -93,11 +93,11 @@ export interface AbstractControlOptions { } export declare class AbstractFormGroupDirective extends ControlContainer implements OnInit, OnDestroy { - readonly asyncValidator: AsyncValidatorFn | null; - readonly control: FormGroup; - readonly formDirective: Form | null; - readonly path: string[]; - readonly validator: ValidatorFn | null; + get asyncValidator(): AsyncValidatorFn | null; + get control(): FormGroup; + get formDirective(): Form | null; + get path(): string[]; + get validator(): ValidatorFn | null; ngOnDestroy(): void; ngOnInit(): void; } @@ -127,9 +127,9 @@ export declare class CheckboxRequiredValidator extends RequiredValidator { export declare const COMPOSITION_BUFFER_MODE: InjectionToken; export declare abstract class ControlContainer extends AbstractControlDirective { - readonly formDirective: Form | null; + get formDirective(): Form | null; name: string | number | null; - readonly path: string[] | null; + get path(): string[] | null; } export interface ControlValueAccessor { @@ -150,7 +150,7 @@ export declare class DefaultValueAccessor implements ControlValueAccessor { } export declare class EmailValidator implements Validator { - email: boolean | string; + set email(value: boolean | string); registerOnValidatorChange(fn: () => void): void; validate(control: AbstractControl): ValidationErrors | null; } @@ -167,7 +167,7 @@ export interface Form { export declare class FormArray extends AbstractControl { controls: AbstractControl[]; - readonly length: number; + get length(): number; constructor(controls: AbstractControl[], validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null); at(index: number): AbstractControl; clear(): void; @@ -191,12 +191,12 @@ export declare class FormArray extends AbstractControl { } export declare class FormArrayName extends ControlContainer implements OnInit, OnDestroy { - readonly asyncValidator: AsyncValidatorFn | null; - readonly control: FormArray; - readonly formDirective: FormGroupDirective | null; + get asyncValidator(): AsyncValidatorFn | null; + get control(): FormArray; + get formDirective(): FormGroupDirective | null; name: string | number | null; - readonly path: string[]; - readonly validator: ValidatorFn | null; + get path(): string[]; + get validator(): ValidatorFn | null; constructor(parent: ControlContainer, validators: any[], asyncValidators: any[]); ngOnDestroy(): void; ngOnInit(): void; @@ -235,14 +235,14 @@ export declare class FormControl extends AbstractControl { } export declare class FormControlDirective extends NgControl implements OnChanges { - readonly asyncValidator: AsyncValidatorFn | null; - readonly control: FormControl; + get asyncValidator(): AsyncValidatorFn | null; + get control(): FormControl; form: FormControl; - isDisabled: boolean; + set isDisabled(isDisabled: boolean); /** @deprecated */ model: any; - readonly path: string[]; + get path(): string[]; /** @deprecated */ update: EventEmitter; - readonly validator: ValidatorFn | null; + get validator(): ValidatorFn | null; viewModel: any; constructor(validators: Array, asyncValidators: Array, valueAccessors: ControlValueAccessor[], _ngModelWarningConfig: string | null); ngOnChanges(changes: SimpleChanges): void; @@ -250,15 +250,15 @@ export declare class FormControlDirective extends NgControl implements OnChanges } export declare class FormControlName extends NgControl implements OnChanges, OnDestroy { - readonly asyncValidator: AsyncValidatorFn; + get asyncValidator(): AsyncValidatorFn; readonly control: FormControl; - readonly formDirective: any; - isDisabled: boolean; + get formDirective(): any; + set isDisabled(isDisabled: boolean); /** @deprecated */ model: any; name: string | number | null; - readonly path: string[]; + get path(): string[]; /** @deprecated */ update: EventEmitter; - readonly validator: ValidatorFn | null; + get validator(): ValidatorFn | null; constructor(parent: ControlContainer, validators: Array, asyncValidators: Array, valueAccessors: ControlValueAccessor[], _ngModelWarningConfig: string | null); ngOnChanges(changes: SimpleChanges): void; ngOnDestroy(): void; @@ -297,12 +297,12 @@ export declare class FormGroup extends AbstractControl { } export declare class FormGroupDirective extends ControlContainer implements Form, OnChanges { - readonly control: FormGroup; + get control(): FormGroup; directives: FormControlName[]; form: FormGroup; - readonly formDirective: Form; + get formDirective(): Form; ngSubmit: EventEmitter; - readonly path: string[]; + get path(): string[]; readonly submitted: boolean; constructor(_validators: any[], _asyncValidators: any[]); addControl(dir: FormControlName): FormControl; @@ -330,14 +330,14 @@ export declare class FormsModule { } export declare class MaxLengthValidator implements Validator, OnChanges { - maxlength: string; + maxlength: string | number; ngOnChanges(changes: SimpleChanges): void; registerOnValidatorChange(fn: () => void): void; validate(control: AbstractControl): ValidationErrors | null; } export declare class MinLengthValidator implements Validator, OnChanges { - minlength: string; + minlength: string | number; ngOnChanges(changes: SimpleChanges): void; registerOnValidatorChange(fn: () => void): void; validate(control: AbstractControl): ValidationErrors | null; @@ -350,9 +350,9 @@ export declare const NG_VALIDATORS: InjectionToken<(Function | Validator)[]>; export declare const NG_VALUE_ACCESSOR: InjectionToken; export declare abstract class NgControl extends AbstractControlDirective { - readonly asyncValidator: AsyncValidatorFn | null; + get asyncValidator(): AsyncValidatorFn | null; name: string | number | null; - readonly validator: ValidatorFn | null; + get validator(): ValidatorFn | null; valueAccessor: ControlValueAccessor | null; abstract viewToModelUpdate(newValue: any): void; } @@ -366,17 +366,17 @@ export declare class NgControlStatusGroup extends AbstractControlStatus { } export declare class NgForm extends ControlContainer implements Form, AfterViewInit { - readonly control: FormGroup; - readonly controls: { + get control(): FormGroup; + get controls(): { [key: string]: AbstractControl; }; form: FormGroup; - readonly formDirective: Form; + get formDirective(): Form; ngSubmit: EventEmitter; options: { updateOn?: FormHooks; }; - readonly path: string[]; + get path(): string[]; readonly submitted: boolean; constructor(validators: any[], asyncValidators: any[]); addControl(dir: NgModel): void; @@ -396,9 +396,9 @@ export declare class NgForm extends ControlContainer implements Form, AfterViewI } export declare class NgModel extends NgControl implements OnChanges, OnDestroy { - readonly asyncValidator: AsyncValidatorFn | null; + get asyncValidator(): AsyncValidatorFn | null; readonly control: FormControl; - readonly formDirective: any; + get formDirective(): any; isDisabled: boolean; model: any; name: string; @@ -407,9 +407,9 @@ export declare class NgModel extends NgControl implements OnChanges, OnDestroy { standalone?: boolean; updateOn?: FormHooks; }; - readonly path: string[]; + get path(): string[]; update: EventEmitter; - readonly validator: ValidatorFn | null; + get validator(): ValidatorFn | null; viewModel: any; constructor(parent: ControlContainer, validators: Array, asyncValidators: Array, valueAccessors: ControlValueAccessor[]); ngOnChanges(changes: SimpleChanges): void; @@ -425,8 +425,8 @@ export declare class NgModelGroup extends AbstractFormGroupDirective implements export declare class NgSelectOption implements OnDestroy { id: string; - ngValue: any; - value: any; + set ngValue(value: any); + set value(value: any); constructor(_element: ElementRef, _renderer: Renderer2, _select: SelectControlValueAccessor); ngOnDestroy(): void; } @@ -480,13 +480,14 @@ export declare class ReactiveFormsModule { } export declare class RequiredValidator implements Validator { - required: boolean | string; + get required(): boolean | string; + set required(value: boolean | string); registerOnValidatorChange(fn: () => void): void; validate(control: AbstractControl): ValidationErrors | null; } export declare class SelectControlValueAccessor implements ControlValueAccessor { - compareWith: (o1: any, o2: any) => boolean; + set compareWith(fn: (o1: any, o2: any) => boolean); onChange: (_: any) => void; onTouched: () => void; value: any; @@ -498,7 +499,7 @@ export declare class SelectControlValueAccessor implements ControlValueAccessor } export declare class SelectMultipleControlValueAccessor implements ControlValueAccessor { - compareWith: (o1: any, o2: any) => boolean; + set compareWith(fn: (o1: any, o2: any) => boolean); onChange: (_: any) => void; onTouched: () => void; value: any; @@ -523,8 +524,8 @@ export interface ValidatorFn { } export declare class Validators { - static compose(validators: (ValidatorFn | null | undefined)[]): ValidatorFn | null; static compose(validators: null): null; + static compose(validators: (ValidatorFn | null | undefined)[]): ValidatorFn | null; static composeAsync(validators: (AsyncValidatorFn | null)[]): AsyncValidatorFn | null; static email(control: AbstractControl): ValidationErrors | null; static max(max: number): ValidatorFn; diff --git a/tools/public_api_guard/global_utils.d.ts b/tools/public_api_guard/global_utils.d.ts index a20f47d92d..11f3023690 100644 --- a/tools/public_api_guard/global_utils.d.ts +++ b/tools/public_api_guard/global_utils.d.ts @@ -1,19 +1,25 @@ -export declare function getComponent(element: Element): T | null; +export declare function applyChanges(component: {}): void; -export declare function getContext(element: Element): T | null; +export declare function getComponent(element: Element): T | null; -export declare function getDebugNode(element: Node): DebugNode | null; +export declare function getContext(element: Element): T | null; -export declare function getDirectives(target: {}): Array<{}>; +export declare function getDirectives(element: Element): {}[]; -export declare function getHostElement(directive: T): Element; +export declare function getHostElement(componentOrDirective: {}): Element; -export declare function getInjector(target: {}): Injector; +export declare function getInjector(elementOrDir: Element | {}): Injector; export declare function getListeners(element: Element): Listener[]; -export declare function getRootComponents(target: {}): any[]; +export declare function getOwningComponent(elementOrDir: Element | {}): T | null; -export declare function getViewComponent(element: Element | {}): T | null; +export declare function getRootComponents(elementOrDir: Element | {}): {}[]; -export declare function markDirty(component: T): void; +export interface Listener { + callback: (value: any) => any; + element: Element; + name: string; + type: 'dom' | 'output'; + useCapture: boolean; +} diff --git a/tools/public_api_guard/http/http.d.ts b/tools/public_api_guard/http/http.d.ts index e34b4aa541..5651e7289a 100644 --- a/tools/public_api_guard/http/http.d.ts +++ b/tools/public_api_guard/http/http.d.ts @@ -142,7 +142,8 @@ export declare class RequestOptions { method: RequestMethod | string | null; params: URLSearchParams; responseType: ResponseContentType | null; - /** @deprecated */ search: URLSearchParams; + /** @deprecated */ get search(): URLSearchParams; + /** @deprecated */ set search(params: URLSearchParams); url: string | null; withCredentials: boolean | null; constructor(opts?: RequestOptionsArgs); diff --git a/tools/public_api_guard/platform-server/platform-server.d.ts b/tools/public_api_guard/platform-server/platform-server.d.ts index d81559ba50..479c315e9c 100644 --- a/tools/public_api_guard/platform-server/platform-server.d.ts +++ b/tools/public_api_guard/platform-server/platform-server.d.ts @@ -1,4 +1,4 @@ -export declare const BEFORE_APP_SERIALIZED: InjectionToken<(() => void)[]>; +export declare const BEFORE_APP_SERIALIZED: InjectionToken<(() => void | Promise)[]>; export declare const INITIAL_CONFIG: InjectionToken; diff --git a/tools/public_api_guard/router/router.d.ts b/tools/public_api_guard/router/router.d.ts index 48bd09e57d..cb6db66157 100644 --- a/tools/public_api_guard/router/router.d.ts +++ b/tools/public_api_guard/router/router.d.ts @@ -1,37 +1,37 @@ export declare class ActivatedRoute { - readonly children: ActivatedRoute[]; + get children(): ActivatedRoute[]; component: Type | string | null; data: Observable; - readonly firstChild: ActivatedRoute | null; + get firstChild(): ActivatedRoute | null; fragment: Observable; outlet: string; - readonly paramMap: Observable; + get paramMap(): Observable; params: Observable; - readonly parent: ActivatedRoute | null; - readonly pathFromRoot: ActivatedRoute[]; - readonly queryParamMap: Observable; + get parent(): ActivatedRoute | null; + get pathFromRoot(): ActivatedRoute[]; + get queryParamMap(): Observable; queryParams: Observable; - readonly root: ActivatedRoute; - readonly routeConfig: Route | null; + get root(): ActivatedRoute; + get routeConfig(): Route | null; snapshot: ActivatedRouteSnapshot; url: Observable; toString(): string; } export declare class ActivatedRouteSnapshot { - readonly children: ActivatedRouteSnapshot[]; + get children(): ActivatedRouteSnapshot[]; component: Type | string | null; data: Data; - readonly firstChild: ActivatedRouteSnapshot | null; + get firstChild(): ActivatedRouteSnapshot | null; fragment: string; outlet: string; - readonly paramMap: ParamMap; + get paramMap(): ParamMap; params: Params; - readonly parent: ActivatedRouteSnapshot | null; - readonly pathFromRoot: ActivatedRouteSnapshot[]; - readonly queryParamMap: ParamMap; + get parent(): ActivatedRouteSnapshot | null; + get pathFromRoot(): ActivatedRouteSnapshot[]; + get queryParamMap(): ParamMap; queryParams: Params; - readonly root: ActivatedRouteSnapshot; + get root(): ActivatedRouteSnapshot; readonly routeConfig: Route | null; url: UrlSegment[]; toString(): string; @@ -333,7 +333,7 @@ export declare class Router { relativeLinkResolution: 'legacy' | 'corrected'; routeReuseStrategy: RouteReuseStrategy; readonly routerState: RouterState; - readonly url: string; + get url(): string; urlHandlingStrategy: UrlHandlingStrategy; urlUpdateStrategy: 'deferred' | 'eager'; constructor(rootComponentType: Type | null, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes); @@ -374,18 +374,18 @@ export declare class RouterEvent { export declare class RouterLink { fragment: string; preserveFragment: boolean; - /** @deprecated */ preserveQueryParams: boolean; + /** @deprecated */ set preserveQueryParams(value: boolean); queryParams: { [k: string]: any; }; queryParamsHandling: QueryParamsHandling; replaceUrl: boolean; - routerLink: any[] | string; + set routerLink(commands: any[] | string); skipLocationChange: boolean; state?: { [k: string]: any; }; - readonly urlTree: UrlTree; + get urlTree(): UrlTree; constructor(router: Router, route: ActivatedRoute, tabIndex: string, renderer: Renderer2, el: ElementRef); onClick(): boolean; } @@ -394,7 +394,7 @@ export declare class RouterLinkActive implements OnChanges, OnDestroy, AfterCont readonly isActive: boolean; links: QueryList; linksWithHrefs: QueryList; - routerLinkActive: string[] | string; + set routerLinkActive(data: string[] | string); routerLinkActiveOptions: { exact: boolean; }; @@ -408,19 +408,19 @@ export declare class RouterLinkWithHref implements OnChanges, OnDestroy { fragment: string; href: string; preserveFragment: boolean; - preserveQueryParams: boolean; + set preserveQueryParams(value: boolean); queryParams: { [k: string]: any; }; queryParamsHandling: QueryParamsHandling; replaceUrl: boolean; - routerLink: any[] | string; + set routerLink(commands: any[] | string); skipLocationChange: boolean; state?: { [k: string]: any; }; target: string; - readonly urlTree: UrlTree; + get urlTree(): UrlTree; constructor(router: Router, route: ActivatedRoute, locationStrategy: LocationStrategy); ngOnChanges(changes: {}): any; ngOnDestroy(): any; @@ -435,11 +435,11 @@ export declare class RouterModule { export declare class RouterOutlet implements OnDestroy, OnInit { activateEvents: EventEmitter; - readonly activatedRoute: ActivatedRoute; - readonly activatedRouteData: Data; - readonly component: Object; + get activatedRoute(): ActivatedRoute; + get activatedRouteData(): Data; + get component(): Object; deactivateEvents: EventEmitter; - readonly isActivated: boolean; + get isActivated(): boolean; constructor(parentContexts: ChildrenOutletContexts, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string, changeDetector: ChangeDetectorRef); activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null): void; attach(ref: ComponentRef, activatedRoute: ActivatedRoute): void; @@ -510,7 +510,7 @@ export declare type UrlMatchResult = { }; export declare class UrlSegment { - readonly parameterMap: ParamMap; + get parameterMap(): ParamMap; parameters: { [name: string]: string; }; @@ -527,7 +527,7 @@ export declare class UrlSegmentGroup { children: { [key: string]: UrlSegmentGroup; }; - readonly numberOfChildren: number; + get numberOfChildren(): number; parent: UrlSegmentGroup | null; segments: UrlSegment[]; constructor( @@ -546,7 +546,7 @@ export declare abstract class UrlSerializer { export declare class UrlTree { fragment: string | null; - readonly queryParamMap: ParamMap; + get queryParamMap(): ParamMap; queryParams: Params; root: UrlSegmentGroup; toString(): string; diff --git a/tools/public_api_guard/router/testing.d.ts b/tools/public_api_guard/router/testing.d.ts index a6396352c0..39a5574924 100644 --- a/tools/public_api_guard/router/testing.d.ts +++ b/tools/public_api_guard/router/testing.d.ts @@ -6,7 +6,10 @@ export declare function setupTestingRouter(urlSerializer: UrlSerializer, context export declare function setupTestingRouter(urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location, loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][], urlHandlingStrategy?: UrlHandlingStrategy): Router; export declare class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader { - stubbedModules: { + set stubbedModules(modules: { + [path: string]: any; + }); + get stubbedModules(): { [path: string]: any; }; constructor(compiler: Compiler); diff --git a/tools/public_api_guard/service-worker/service-worker.d.ts b/tools/public_api_guard/service-worker/service-worker.d.ts index 06a389a790..975f331604 100644 --- a/tools/public_api_guard/service-worker/service-worker.d.ts +++ b/tools/public_api_guard/service-worker/service-worker.d.ts @@ -3,7 +3,7 @@ export declare class ServiceWorkerModule { } export declare class SwPush { - readonly isEnabled: boolean; + get isEnabled(): boolean; readonly messages: Observable; readonly notificationClicks: Observable<{ action: string; @@ -28,7 +28,7 @@ export declare abstract class SwRegistrationOptions { export declare class SwUpdate { readonly activated: Observable; readonly available: Observable; - readonly isEnabled: boolean; + get isEnabled(): boolean; constructor(sw: NgswCommChannel); activateUpdate(): Promise; checkForUpdate(): Promise; diff --git a/tools/rebase-pr.js b/tools/rebase-pr.js index c11e80547a..53d4280c71 100644 --- a/tools/rebase-pr.js +++ b/tools/rebase-pr.js @@ -38,9 +38,9 @@ // Imports const util = require('util'); -const https = require('https'); const child_process = require('child_process'); const exec = util.promisify(child_process.exec); +const getRefsAndShasForTarget = require('./utils/get-refs-and-shas-for-target'); // CLI validation if (process.argv.length != 4) { @@ -59,51 +59,42 @@ _main(...process.argv.slice(2)).catch(err => { // Helpers async function _main(repository, prNumber) { - console.log(`Getting refs and SHAs for PR ${prNumber} on ${repository}.`); - const target = await determineTargetRefAndSha(repository, prNumber); - console.log(`Fetching target branch: ${target.baseRef}.`); - await exec(`git fetch origin ${target.baseRef}`); - // The sha of the latest commit on the target branch. - const {stdout: shaOfTargetBranchLatest} = await exec(`git rev-parse origin/${target.baseRef}`); - // The sha of the latest commit on the PR. - const {stdout: shaOfPRLatest} = await exec(`git rev-parse HEAD`); - // The first common SHA in the history of the target branch and the latest commit in the PR. - const {stdout: commonAncestorSha} = - await exec(`git merge-base origin/${target.baseRef} ${shaOfPRLatest}`); + const target = await getRefsAndShasForTarget(prNumber); // Log known refs and shas console.log(`--------------------------------`); - console.log(` Target Branch: ${target.baseRef}`); - console.log(` Latest Commit for Target Branch: ${shaOfTargetBranchLatest.trim()}`); - console.log(` Latest Commit for PR: ${shaOfPRLatest.trim()}`); - console.log(` First Common Ancestor SHA: ${commonAncestorSha.trim()}`); + console.log(` Target Branch: ${target.base.ref}`); + console.log(` Latest Commit for Target Branch: ${target.latestShaOfTargetBranch}`); + console.log(` Latest Commit for PR: ${target.latestShaOfPrBranch}`); + console.log(` First Common Ancestor SHA: ${target.commonAncestorSha}`); console.log(`--------------------------------`); console.log(); + // Get the count of commits between the latest commit from origin and the common ancestor SHA. const {stdout: commitCount} = - await exec(`git rev-list --count origin/${target.baseRef}...${commonAncestorSha.trim()}`); + await exec(`git rev-list --count origin/${target.base.ref}...${target.commonAncestorSha}`); console.log(`Checking ${commitCount.trim()} commits for changes in the CircleCI config file.`); // Check if the files changed between the latest commit from origin and the common ancestor SHA // includes the CircleCI config. const {stdout: circleCIConfigChanged} = await exec( - `git diff --name-only origin/${target.baseRef} ${commonAncestorSha.trim()} -- .circleci/config.yml`); + `git diff --name-only origin/${target.base.ref} ${target.commonAncestorSha} -- .circleci/config.yml`); if (!!circleCIConfigChanged) { throw Error(` - CircleCI config on ${target.baseRef} has been modified since commit ${commonAncestorSha.slice(0, 7)}, + CircleCI config on ${target.base.ref} has been modified since commit ${target.commonAncestorSha.slice(0, 7)}, which this PR is based on. - Please rebase the PR on ${target.baseRef} after fetching from upstream. + Please rebase the PR on ${target.base.ref} after fetching from upstream. Rebase instructions for PR Author, please run the following commands: - git fetch upstream ${target.baseRef}; - git checkout ${target.headRef}; - git rebase upstream/${target.baseRef}; + git fetch upstream ${target.base.ref}; + git checkout ${target.head.ref}; + git rebase upstream/${target.base.ref}; git push --force-with-lease; `); } else { @@ -112,61 +103,7 @@ async function _main(repository, prNumber) { console.log(); // Rebase the PR. - console.log(`Rebasing current branch on ${target.baseRef}.`); - await exec(`git rebase origin/${target.baseRef}`); + console.log(`Rebasing current branch on ${target.base.ref}.`); + await exec(`git rebase origin/${target.base.ref}`); console.log('Rebase successful.'); - -} - -async function requestDataFromGithub(url) { - // GitHub requires a user agent: https://developer.github.com/v3/#user-agent-required - const options = {headers: {'User-Agent': 'angular'}}; - - return new Promise((resolve, reject) => { - https - .get( - url, options, - (res) => { - const {statusCode} = res; - const contentType = res.headers['content-type']; - let rawData = ''; - - res.on('data', (chunk) => { rawData += chunk; }); - res.on('end', () => { - let error; - if (statusCode !== 200) { - error = new Error( - `Request Failed.\nStatus Code: ${statusCode}.\nResponse: ${rawData}`); - } else if (!/^application\/json/.test(contentType)) { - error = new Error( - 'Invalid content-type.\n' + - `Expected application/json but received ${contentType}`); - } - - if (error) { - reject(error); - return; - } - - try { - resolve(JSON.parse(rawData)); - } catch (e) { - reject(e); - } - }); - }) - .on('error', (e) => { reject(e); }); - }); -} - -async function determineTargetRefAndSha(repository, prNumber) { - const pullsUrl = `https://api.github.com/repos/${repository}/pulls/${prNumber}`; - - const result = await requestDataFromGithub(pullsUrl); - return { - baseRef: result.base.ref, - baseSha: result.base.sha, - headRef: result.head.ref, - headSha: result.head.sha, - }; } diff --git a/tools/saucelabs/BUILD.bazel b/tools/saucelabs/BUILD.bazel new file mode 100644 index 0000000000..5cfca5be42 --- /dev/null +++ b/tools/saucelabs/BUILD.bazel @@ -0,0 +1,50 @@ +load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary") + +package(default_visibility = ["//visibility:public"]) + +sh_binary( + name = "sauce_service_setup", + srcs = ["sauce-service.sh"], + args = ["setup"], + data = ["@npm//sauce-connect"], +) + +sh_binary( + name = "sauce_service_start", + srcs = ["sauce-service.sh"], + args = ["start"], + data = ["@npm//sauce-connect"], +) + +sh_binary( + name = "sauce_service_start_ready_wait", + srcs = ["sauce-service.sh"], + args = ["start-ready-wait"], + data = ["@npm//sauce-connect"], +) + +sh_binary( + name = "sauce_service_ready_wait", + srcs = ["sauce-service.sh"], + args = ["ready-wait"], + data = ["@npm//sauce-connect"], +) + +sh_binary( + name = "sauce_service_stop", + srcs = ["sauce-service.sh"], + args = ["stop"], + data = ["@npm//sauce-connect"], +) + +nodejs_binary( + name = "karma-saucelabs", + data = [ + "sauce-service.sh", + "@npm//karma", + "@npm//sauce-connect", + "@npm//shelljs", + ], + entry_point = "karma-saucelabs.js", + templated_args = ["$(location sauce-service.sh)"], +) diff --git a/tools/saucelabs/README.md b/tools/saucelabs/README.md new file mode 100644 index 0000000000..be7b463ca3 --- /dev/null +++ b/tools/saucelabs/README.md @@ -0,0 +1,51 @@ +# Saucelabs testing with Bazel + +## Local testing + +Setup your `SAUCE_USERNAME`, `SAUCE_ACCESS_KEY` & `SAUCE_TUNNEL_IDENTIFIER` environment variables. These are required. On OSX, also set `SAUCE_CONNECT` to the path of your `sc` binary. + +To run tests use: + +``` +yarn bazel run //tools/saucelabs:sauce_service_setup +yarn bazel test //path/to:saucelabs_test_target_1 --config=saucelabs [--config=ivy] +yarn bazel test //path/to:saucelabs_test_target_2 --config=saucelabs [--config=ivy] +``` + +or if the tests are combined into a test suite: + +``` +yarn bazel run //tools/saucelabs:sauce_service_setup +yarn bazel test //path/to:saucelabs_test_suite --config=saucelabs [--config=ivy] +``` + +To see the test output while the tests are running as these are long tests, add the `--test_output=streamed` option. Note, this option will also prevent bazel from using the test cache and will force the test to run. + +The `//tools/saucelabs:sauce_service_setup` target does not start the Sauce Connect proxy but it does start process which will that then listens for the start signal from the service manager script. This signal is sent by the karma wrapper script `//tools/saucelabs:karma-saucelabs` which calls `./tools/saucelabs/sauce-service.sh start`. This is necessary as the Sauce Connect Proxy process must be started outside of `bazel test` as Bazel will automatically kill any processes spwaned during a test when that tests completes, which would prevent the tunnel from being shared by multiple tests. + +# Under the hood + +The karma_web_test rule is to test with saucelabs with a modified `karma` attribute set to +`//tools/saucelabs:karma-saucelabs`. This runs the `/tools/saucelabs/karma-saucelabs.js` wrapper +script which configures the saucelabs environment and starts Sauce Connect before running karma. + +For example, + +``` +karma_web_test( + name = "saucelabs_core_acceptance_tests", + timeout = "long", + karma = "//tools/saucelabs:karma-saucelabs", + tags = [ + "manual", + "no-remote-exec", + ], + deps = [ + "//packages/core/test/acceptance:acceptance_lib", + ], +) +``` + +These saucelabs targets must be tagged `no-remote-exec` as they cannot be executed remotely since +they require a local Sauce Connect process. They should also be tagged `manual` so they are not +automatically tested with `//...`. diff --git a/tools/saucelabs/karma-saucelabs.js b/tools/saucelabs/karma-saucelabs.js new file mode 100644 index 0000000000..dd0f623ce7 --- /dev/null +++ b/tools/saucelabs/karma-saucelabs.js @@ -0,0 +1,62 @@ +/** + * @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 + */ +'use strict'; + +const shell = require('shelljs'); +const karmaBin = require.resolve('karma/bin/karma'); +const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']); +const sauceService = runfiles.resolve(process.argv[2]); +process.argv = [ + process.argv[0], + karmaBin, + ...process.argv.splice(3), +]; +try { + console.error(`Setting up environment for SauceLabs karma tests...`); + // KARMA_WEB_TEST_MODE is set which informs /karma-js.conf.js that it should + // run the test with the karma saucelabs launcher + process.env['KARMA_WEB_TEST_MODE'] = 'SL_REQUIRED'; + // Setup required SAUCE_* env if they are not already set + if (!process.env['SAUCE_USERNAME'] || !process.env['SAUCE_ACCESS_KEY'] || + !process.env['SAUCE_TUNNEL_IDENTIFIER']) { + try { + // The following path comes from /tools/saucelabs/sauce-service.sh. + // We setup the required saucelabs environment variables here for the karma test + // from a json file under /tmp/angular/sauce-service so that we don't break the + // test cache with a changing SAUCE_TUNNEL_IDENTIFIER provided through --test_env + const scParams = require('/tmp/angular/sauce-service/sauce-connect-params.json'); + process.env['SAUCE_USERNAME'] = scParams.SAUCE_USERNAME; + process.env['SAUCE_ACCESS_KEY'] = scParams.SAUCE_ACCESS_KEY; + process.env['SAUCE_TUNNEL_IDENTIFIER'] = scParams.SAUCE_TUNNEL_IDENTIFIER; + } catch (e) { + console.error(e.stack || e); + console.error( + `!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!! Make sure that you have run "yarn bazel run //tools/saucelabs:sauce_service_setup" +!!! (or "./tools/saucelabs/sauce-service.sh setup") before the test target. Alternately +!!! you can provide the required SAUCE_* environment variables (SAUCE_USERNAME, SAUCE_ACCESS_KEY & +!!! SAUCE_TUNNEL_IDENTIFIER) to the test with --test_env or --define but this may prevent bazel from +!!! using cached test results. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`); + process.exit(1); + } + } + + const scStart = `${sauceService} start-ready-wait`; + console.error(`Starting SauceConnect (${scStart})...`); + const result = shell.exec(scStart).code; + if (result !== 0) { + throw new Error(`Starting SauceConnect failed with code ${result}`); + } + + console.error(`Launching karma ${karmaBin}...`); + module.constructor._load(karmaBin, this, /*isMain=*/true); +} catch (e) { + console.error(e.stack || e); + process.exit(1); +} diff --git a/tools/saucelabs/sauce-service.sh b/tools/saucelabs/sauce-service.sh new file mode 100755 index 0000000000..124d399572 --- /dev/null +++ b/tools/saucelabs/sauce-service.sh @@ -0,0 +1,419 @@ +#!/usr/bin/env bash + +set -u -e -o pipefail + +#################################################################################################### +# Some helper funtions + +@echo() { + echo "# $*" +} + +@warn() { + @echo "Warning: $*" >&2 +} + +@fail() { + @echo "Error! $*" >&2 + exit 1 +} + +@remove() { + local f="$1" + if [[ -f ${f} ]]; then + @echo "Removing ${f}" + rm -f "${f}" || @fail "Can not delete ${f} file" + fi +} + +@kill() { + for p in $1; do + if kill -0 ${p} >/dev/null 2>&1; then + kill ${p} + sleep 2 + if kill -0 ${p} >/dev/null 2>&1; then + kill -9 ${p} + sleep 2 + fi + fi + done +} + +@wait_for() { + local m="$1" + local f="$2" + if [[ ! -f "${f}" ]]; then + printf "# ${m} (${f})" + while [[ ! -f "${f}" ]]; do + printf "." + sleep 0.5 + done + printf "\n" + fi +} + +#################################################################################################### +# Sauce service functions + +readonly SCRIPT_DIR=$(cd $(dirname $0); pwd) +readonly TMP_DIR="/tmp/angular/sauce-service" +mkdir -p ${TMP_DIR} + +# Location for the saucelabs log file. +readonly SAUCE_LOG_FILE="${TMP_DIR}/sauce-connect.log" + +# Location for the saucelabs ready to connection process id lock file. +readonly SAUCE_PID_FILE="${TMP_DIR}/sauce-connect.pid" + +# Location for the saucelabs ready to connect lock file. +readonly SAUCE_READY_FILE="${TMP_DIR}/sauce-connect.lock" + +# Location for the saucelabs params file for use by test runner. +readonly SAUCE_PARAMS_JSON_FILE="${TMP_DIR}/sauce-connect-params.json" + +# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not +# acquire CircleCI instances for too long if sauceconnect fails, we need a connect timeout. +readonly SAUCE_READY_FILE_TIMEOUT=120 + +readonly SERVICE_LOCK_FILE="${TMP_DIR}/service.lock" +readonly SERVICE_START_FILE="${TMP_DIR}/service.start" +readonly SERVICE_PID_FILE="${TMP_DIR}/service.pid" +readonly SERVICE_LOG_FILE="${TMP_DIR}/service.log" + +service-setup-command() { + if [[ -z "${SAUCE_USERNAME:-}" ]]; then + @fail "SAUCE_USERNAME environment variable required" + fi + + if [[ -z "${SAUCE_ACCESS_KEY:-}" ]]; then + @fail "SAUCE_ACCESS_KEY environment variable required" + fi + + if [[ -z "${SAUCE_TUNNEL_IDENTIFIER:-}" ]]; then + @fail "SAUCE_TUNNEL_IDENTIFIER environment variable required" + fi + + local unameOut="$(uname -s)" + case "${unameOut}" in + Linux*) local machine=linux ;; + Darwin*) local machine=darwin ;; + CYGWIN*) local machine=windows ;; + MINGW*) local machine=windows ;; + MSYS_NT*) local machine=windows ;; + *) local machine=linux + printf "\nUnrecongized uname '${unameOut}'; defaulting to use node for linux.\n" >&2 + printf "Please file an issue to https://github.com/bazelbuild/rules_nodejs/issues if \n" >&2 + printf "you would like to add your platform to the supported rules_nodejs node platforms.\n\n" >&2 + ;; + esac + + case "${machine}" in + # Path to sauce connect executable + linux) + if [[ -z "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then + # Started manually + SAUCE_CONNECT="${SCRIPT_DIR}/../../node_modules/sauce-connect/bin/sc" + else + # Started via `bazel run` + SAUCE_CONNECT="${BUILD_WORKSPACE_DIRECTORY}/node_modules/sauce-connect/bin/sc" + fi + ;; + *) + if [[ -z "${SAUCE_CONNECT:-}" ]]; then + @fail "SAUCE_CONNECT environment variable is required on non-linux environments" + exit 1 + fi + ;; + esac + + if [[ ! -f ${SAUCE_CONNECT} ]]; then + @fail "sc binary not found at ${SAUCE_CONNECT}" + fi + + echo "{ \"SAUCE_USERNAME\": \"${SAUCE_USERNAME}\", \"SAUCE_ACCESS_KEY\": \"${SAUCE_ACCESS_KEY}\", \"SAUCE_TUNNEL_IDENTIFIER\": \"${SAUCE_TUNNEL_IDENTIFIER}\" }" > ${SAUCE_PARAMS_JSON_FILE} + + # Command arguments that will be passed to sauce-connect. + # By default we disable SSL bumping for all requests. This is because SSL bumping is + # not needed for our test setup and in order to perform the SSL bumping, Saucelabs + # intercepts all HTTP requests in the tunnel VM and modifies them. This can cause + # flakiness as it makes all requests dependent on the SSL bumping middleware. + # See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping + local sauce_args=( + "--no-ssl-bump-domains all" + "--logfile ${SAUCE_LOG_FILE}" + "--pidfile ${SAUCE_PID_FILE}" + "--readyfile ${SAUCE_READY_FILE}" + "--tunnel-identifier ${SAUCE_TUNNEL_IDENTIFIER}" + "--user ${SAUCE_USERNAME}" + # Don't add the --api-key here so we don't echo it out in service-pre-start + ) + @echo "Sauce connect will be started with:" + echo " ${SAUCE_CONNECT} ${sauce_args[@]}" + SERVICE_COMMAND="${SAUCE_CONNECT} ${sauce_args[@]} --api-key ${SAUCE_ACCESS_KEY}" +} + +# Called by pre-start & post-stop +service-cleanup() { + if [[ -f "${SAUCE_PID_FILE}" ]]; then + local p=$(cat "${SAUCE_PID_FILE}") + @echo "Stopping Sauce Connect (pid $p)..." + @kill $p + fi + @remove "${SAUCE_PID_FILE}" + @remove "${SAUCE_READY_FILE}" + @remove "${SAUCE_PARAMS_JSON_FILE}" +} + +# Called before service is setup +service-pre-setup() { + service-cleanup +} + +# Called after service is setup +service-post-setup() { + @echo " sauce params : ${SAUCE_PARAMS_JSON_FILE}" +} + +# Called before service is started +service-pre-start() { + return +} + +# Called after service is started +service-post-start() { + @wait_for "Waiting for Sauce Connect Proxy process" "${SAUCE_PID_FILE}" + @echo "Sauce Connect Proxy started (pid $(cat "${SAUCE_PID_FILE}"))" +} + +# Called if service fails to start +service-failed-setup() { + if [[ -f "${SERVICE_LOG_FILE}" ]]; then + echo "================================================================================" + echo "${SERVICE_LOG_FILE}:" + echo $(cat "${SERVICE_LOG_FILE}") + fi +} + +# Called by ready-wait action +service-ready-wait() { + if [[ ! -f "${SAUCE_PID_FILE}" ]]; then + @fail "Sauce Connect not running" + fi + if [[ ! -f "${SAUCE_READY_FILE}" ]]; then + # Wait for saucelabs tunnel to connect + printf "# Waiting for saucelabs tunnel to connect (${SAUCE_READY_FILE})" + 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 "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file." + if [[ -f "${SAUCE_LOG_FILE}" ]]; then + echo "================================================================================" + echo "${SAUCE_LOG_FILE}:" + cat "${SAUCE_LOG_FILE}" + fi + exit 5 + fi + + printf "." + sleep 0.5 + done + printf "\n" + @echo "Saucelabs tunnel connected" + else + @echo "Saucelabs tunnel already connected" + fi +} + +# Called before service is stopped +service-pre-stop() { + return +} + +# Called after service is stopped +service-post-stop() { + service-cleanup +} + +#################################################################################################### +# Generic service functions +# This uses functions setup above but nothing below should be specific to saucelabs + +@serviceLock() { + # Check is Lock File exists, if not create it and set trap on exit + printf "# Waiting for service action lock (${SERVICE_LOCK_FILE})" + while true; do + if { set -C; 2>/dev/null >"${SERVICE_LOCK_FILE}"; }; then + trap "rm -f \"${SERVICE_LOCK_FILE}\"" EXIT + printf "\n" + break + fi + printf "." + sleep 0.5 + done + @echo "Acquired service action lock" +} + +@serviceStatus() { + if [ -f "${SERVICE_PID_FILE}" ] && [ ! -z "$(cat "${SERVICE_PID_FILE}")" ]; then + local p=$(cat "${SERVICE_PID_FILE}") + + if kill -0 $p >/dev/null 2>&1; then + @echo "Service is running (pid $p)" + return 0 + else + @echo "Service is not running (process PID $p not exists)" + return 1 + fi + else + @echo "Service is not running" + return 2 + fi +} + +@serviceSetup() { + if @serviceStatus >/dev/null 2>&1; then + @echo "Service already running (pid $(cat "${SERVICE_PID_FILE}"))" + return 0 + fi + + @echo "Setting up service..." + @remove "${SERVICE_PID_FILE}" + @remove "${SERVICE_START_FILE}" + touch "${SERVICE_LOG_FILE}" >/dev/null 2>&1 || @fail "Can not create ${SERVICE_LOG_FILE} file" + @echo " service pid : ${SERVICE_PID_FILE}" + @echo " service logs : ${SERVICE_LOG_FILE}" + service-pre-setup + service-setup-command + + ( + ( + if [[ -z "${SERVICE_COMMAND:-}" ]]; then + @fail "No SERVICE_COMMAND is set" + fi + @wait_for "Waiting for start file" "${SERVICE_START_FILE}" + ${SERVICE_COMMAND} + ) >>"${SERVICE_LOG_FILE}" 2>&1 + ) & + echo $! >"${SERVICE_PID_FILE}" + + if @serviceStatus >/dev/null 2>&1; then + @echo "Service setup (pid $(cat "${SERVICE_PID_FILE}"))" + service-post-setup + else + @echo "Error setting up Service!" + service-failed-setup + exit 1 + fi + + return $? +} + +@serviceStart() { + if @serviceStatus >/dev/null 2>&1; then + @echo "Service already setup (pid $(cat "${SERVICE_PID_FILE}"))" + else + @serviceSetup + fi + if [[ -f "${SERVICE_START_FILE}" ]]; then + @echo "Service already started" + else + @echo "Starting service..." + service-pre-start + touch "${SERVICE_START_FILE}" >/dev/null 2>&1 || @err "Can not create ${SERVICE_START_FILE} file" + service-post-start + @echo "Service started" + fi +} + +@serviceStop() { + if @serviceStatus >/dev/null 2>&1; then + touch "${SERVICE_PID_FILE}" >/dev/null 2>&1 || @fail "Can not touch ${SERVICE_PID_FILE} file" + + service-pre-stop + @echo "Stopping sevice (pid $(cat "${SERVICE_PID_FILE}"))..." + @kill $(cat "${SERVICE_PID_FILE}") + + if @serviceStatus >/dev/null 2>&1; then + @fail "Error stopping Service! Service already running with PID $(cat "${SERVICE_PID_FILE}")" + else + @echo "Service stopped" + @remove "${SERVICE_PID_FILE}" + @remove "${SERVICE_START_FILE}" + service-post-stop + fi + + return 0 + else + @warn "Service is not running" + service-post-stop + fi +} + +@serviceStartReadyWait() { + @serviceStart + @serviceReadyWait +} + +@serviceReadyWait() { + service-ready-wait +} + +@serviceRestart() { + @serviceStop + @serviceStart +} + +@serviceTail() { + tail -f "${SERVICE_LOG_FILE}" +} + +case "${1:-}" in + setup) + @serviceLock + @serviceSetup + ;; + start) + @serviceLock + @serviceStart + ;; + start-ready-wait) + @serviceLock + @serviceStartReadyWait + ;; + ready-wait) + @serviceLock + @serviceReadyWait + ;; + stop) + @serviceLock + @serviceStop + ;; + restart) + @serviceLock + @serviceRestart + ;; + status) + @serviceLock + @serviceStatus + ;; + run) + ( + service-setup-command + if [[ -z "${SERVICE_COMMAND:-}" ]]; then + @fail "No SERVICE_COMMAND is set" + fi + ${SERVICE_COMMAND} + ) + ;; + tail) + @serviceTail + ;; + *) + @echo "Actions: [setup|start|start-read-wait|ready-wait|stop|restart|status|run|tail]" + exit 1 + ;; +esac diff --git a/tools/testing/BUILD.bazel b/tools/testing/BUILD.bazel index 705e4d562b..1344c895ed 100644 --- a/tools/testing/BUILD.bazel +++ b/tools/testing/BUILD.bazel @@ -1,4 +1,4 @@ -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") package(default_visibility = ["//visibility:public"]) @@ -36,3 +36,27 @@ ts_library( "//packages:types", ], ) + +# A test to verify that jasmine_node_test targets fail as expected. +# This is to catch any future regressions to jasmine_node_test where +# tests pass silently without executing. +# See https://github.com/bazelbuild/rules_nodejs/pull/1540 for an example +# of a potential regression. +jasmine_node_test( + name = "fail_test", + srcs = ["fail.spec.js"], + expected_exit_code = 55, +) + +# A test to verify that jasmine_node_test targets fail as expected +# when there is a bootstrap script set. +# This is to catch any future regressions to jasmine_node_test where +# tests pass silently without executing. +# See https://github.com/bazelbuild/rules_nodejs/pull/1540 for an example +# of a potential regression. +jasmine_node_test( + name = "fail_bootstrap_test", + srcs = ["fail.spec.js"], + bootstrap = ["//tools/testing:node_es5"], + expected_exit_code = 55, +) diff --git a/packages/core/global.ts b/tools/testing/fail.spec.js similarity index 92% rename from packages/core/global.ts rename to tools/testing/fail.spec.js index c91a05e544..051229b33e 100644 --- a/packages/core/global.ts +++ b/tools/testing/fail.spec.js @@ -5,3 +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 */ +process.exit(55); \ No newline at end of file diff --git a/tools/ts-api-guardian/BUILD.bazel b/tools/ts-api-guardian/BUILD.bazel index 746712514b..e27f2a55cf 100644 --- a/tools/ts-api-guardian/BUILD.bazel +++ b/tools/ts-api-guardian/BUILD.bazel @@ -1,7 +1,7 @@ # BEGIN-INTERNAL -load("@build_bazel_rules_nodejs//:index.bzl", "npm_package") -load("@npm_bazel_jasmine//:index.bzl", "jasmine_node_test") +load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm") load("@npm_bazel_typescript//:index.bzl", "ts_library") +load("//tools:defaults.bzl", "jasmine_node_test") ts_library( name = "lib", @@ -29,7 +29,7 @@ genrule( cmd = "cp $< $@", ) -npm_package( +pkg_npm( name = "ts-api-guardian", srcs = [ "BUILD.bazel", @@ -38,7 +38,7 @@ npm_package( "index.bzl", "package.json", ], - replacements = { + substitutions = { "@angular//tools/ts-api-guardian:bin": "@npm_ts_api_guardian//:bin", "@angular//tools/ts-api-guardian:lib": "@npm//ts-api-guardian", "angular/tools/ts-api-guardian/": "npm_ts_api_guardian/", @@ -55,7 +55,10 @@ npm_package( ts_library( name = "test_lib", testonly = True, - srcs = glob(["test/*.ts"]), + srcs = glob( + ["test/*.ts"], + exclude = ["test/bootstrap.ts"], + ), tsconfig = "//tools:tsconfig-test", deps = [ ":lib", @@ -68,17 +71,36 @@ ts_library( ], ) +ts_library( + name = "bootstrap", + testonly = True, + srcs = ["test/bootstrap.ts"], + tsconfig = "//tools:tsconfig-test", + deps = ["@npm//@types/node"], +) + +# Select the es5 .js output of the ts_library :boostrap target +# with `output_group = "es5_sources"` for use in the jasmine_node_test +# below. This exposes an internal detail of ts_library that is not ideal. +# TODO(gregmagolan): clean this up by using tsc() in this case rather than ts_library +filegroup( + name = "bootstrap_es5", + testonly = True, + srcs = [":bootstrap"], + output_group = "es5_sources", +) + jasmine_node_test( name = "tests", - srcs = [":test_lib"], - bootstrap = ["angular/tools/ts-api-guardian/test/bootstrap.js"], + srcs = [ + ":test_lib", + ], + bootstrap = [":bootstrap_es5"], data = glob([ "test/fixtures/*.ts", "test/fixtures/*.patch", ]) + [ ":ts-api-guardian", - # TODO: remove this once the boostrap.js workaround has been removed. - ":package.json", ], ) # END-INTERNAL diff --git a/tools/ts-api-guardian/lib/cli.ts b/tools/ts-api-guardian/lib/cli.ts index 1c2db1491e..745e224a2e 100644 --- a/tools/ts-api-guardian/lib/cli.ts +++ b/tools/ts-api-guardian/lib/cli.ts @@ -80,16 +80,19 @@ export function startCli() { } if (hasDiff) { + const bazelTarget = process.env['BAZEL_TARGET']; // Under bazel, give instructions how to use bazel run to accept the golden file. - if (!!process.env['BAZEL_TARGET']) { + if (bazelTarget) { console.error('\n\nIf you modify a public API, you must accept the new golden file.'); console.error('\n\nTo do so, execute the following Bazel target:'); - console.error( - ` yarn bazel run ${process.env['BAZEL_TARGET'].replace(/_bin$/, "")}.accept`); - console.error('\n\nFor more information, see'); - console.error( - '\n https://github.com/angular/angular/blob/master/docs/PUBLIC_API.md#golden-files'); + console.error(` yarn bazel run ${bazelTarget.replace(/_bin$/, "")}.accept`); + if (process.env['TEST_WORKSPACE'] === 'angular') { + console.error('\n\nFor more information, see'); + console.error( + '\n https://github.com/angular/angular/blob/master/docs/PUBLIC_API.md#golden-files'); + } } + process.exit(1); } } diff --git a/tools/ts-api-guardian/package.json b/tools/ts-api-guardian/package.json index 37609adb61..8f1c9c8778 100644 --- a/tools/ts-api-guardian/package.json +++ b/tools/ts-api-guardian/package.json @@ -1,12 +1,12 @@ { "name": "ts-api-guardian", - "version": "0.4.4", + "version": "0.5.0", "description": "Guards the API of TypeScript libraries!", "main": "lib/main.js", "typings": "lib/main.d.ts", "bazelWorkspaces": { "npm_ts_api_guardian": { - "version": "0.4.4", + "version": "0.5.0", "rootPath": "." } }, @@ -17,7 +17,7 @@ "test": "test" }, "peerDependencies": { - "typescript": "~3.6.4" + "typescript": "~3.7.4" }, "dependencies": { "chalk": "^2.3.1", @@ -33,7 +33,7 @@ "chai": "^4.1.2", "jasmine": "^3.1.0", "source-map-support": "^0.5.9", - "typescript": "~3.6.4" + "typescript": "~3.7.4" }, "repository": {}, "keywords": [ diff --git a/tools/ts-api-guardian/test/bootstrap.ts b/tools/ts-api-guardian/test/bootstrap.ts index 6b57f8f54c..e29dd1fbdf 100644 --- a/tools/ts-api-guardian/test/bootstrap.ts +++ b/tools/ts-api-guardian/test/bootstrap.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import * as path from 'path'; +const path = require('path'); +const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']); -// Resolve the path to the package.json of the ts-api-guardian. We need to resolve an actual -// path of a runfile because we want to determine the path to the directory that includes all +// Change directories to the path of the ts-api-guardian source tree. We need to resolve an actual +// path of a tree because we want to determine the path to the directory that includes all // test fixture runfiles. On Windows this is usually the original non-sandboxed disk location, // otherwise this just refers to the runfile directory with all the proper symlinked files. // TODO: remove the whole bootstrap file once the tests are Bazel and Windows compatible. -const runfilesDirectory = path.dirname(require.resolve('../package.json')); - -process.chdir(runfilesDirectory); +process.chdir(path.dirname(path.dirname( + path.dirname(runfiles.resolve('angular/tools/ts-api-guardian/test/fixtures/empty.ts'))))); diff --git a/tools/utils/get-refs-and-shas-for-target.js b/tools/utils/get-refs-and-shas-for-target.js new file mode 100644 index 0000000000..42a8989069 --- /dev/null +++ b/tools/utils/get-refs-and-shas-for-target.js @@ -0,0 +1,89 @@ +/** + * @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 + */ + +// This script uses `console` to print messages to the user. +// tslint:disable:no-console + +const https = require('https'); +const util = require('util'); +const child_process = require('child_process'); +const exec = util.promisify(child_process.exec); + +async function requestDataFromGithub(url) { + // GitHub requires a user agent: https://developer.github.com/v3/#user-agent-required + const options = {headers: {'User-Agent': 'angular'}}; + + return new Promise((resolve, reject) => { + https + .get( + url, options, + (res) => { + const {statusCode} = res; + const contentType = res.headers['content-type']; + let rawData = ''; + + res.on('data', (chunk) => { rawData += chunk; }); + res.on('end', () => { + let error; + if (statusCode !== 200) { + error = new Error( + `Request Failed.\nStatus Code: ${statusCode}.\nResponse: ${rawData}`); + } else if (!/^application\/json/.test(contentType)) { + error = new Error( + 'Invalid content-type.\n' + + `Expected application/json but received ${contentType}`); + } + + if (error) { + reject(error); + return; + } + + try { + resolve(JSON.parse(rawData)); + } catch (e) { + reject(e); + } + }); + }) + .on('error', (e) => { reject(e); }); + }); +} + +module.exports = async function getRefsAndShasForTarget(prNumber) { + console.log(`Getting refs and SHAs for PR ${prNumber} on angular/angular.`); + const pullsUrl = `https://api.github.com/repos/angular/angular/pulls/${prNumber}`; + const result = await requestDataFromGithub(pullsUrl); + + // Ensure the base ref is up to date + await exec(`git fetch origin ${result.base.ref}`); + + // The sha of the latest commit on the target branch. + const {stdout: latestShaOfTargetBranch} = await exec(`git rev-parse origin/${result.base.ref}`); + // The sha of the latest commit on the PR. + const {stdout: latestShaOfPrBranch} = await exec(`git rev-parse HEAD`); + // The first common SHA in the history of the target branch and the latest commit in the PR. + const {stdout: commonAncestorSha} = + await exec(`git merge-base origin/${result.base.ref} ${latestShaOfPrBranch}`); + + const output = { + base: { + ref: result.base.ref, + sha: result.base.sha, + }, + head: { + ref: result.head.ref, + sha: result.head.sha, + }, + commonAncestorSha: commonAncestorSha.trim(), + latestShaOfTargetBranch: latestShaOfTargetBranch.trim(), + latestShaOfPrBranch: latestShaOfPrBranch.trim(), + }; + + return output; +}; diff --git a/tools/validate-commit-message/commit-message.json b/tools/validate-commit-message/commit-message.json index 0f5c372d3f..ebe2cca1b1 100644 --- a/tools/validate-commit-message/commit-message.json +++ b/tools/validate-commit-message/commit-message.json @@ -26,6 +26,7 @@ "http", "ivy", "language-service", + "localize", "ngcc", "platform-browser", "platform-browser-dynamic", diff --git a/tools/verify-codeownership.js b/tools/verify-codeownership.js deleted file mode 100644 index 00d5b46142..0000000000 --- a/tools/verify-codeownership.js +++ /dev/null @@ -1,199 +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 - */ - -/** - * **Usage:** - * ``` - * node tools/verify-codeownership - * ``` - * - * Verify whether there are directories in the codebase that don't have a codeowner (in - * `.github/CODEOWNERS`) and vice versa (that there are no patterns in `CODEOWNERS` that do not - * correspond to actual directories). - * - * The script does not aim to be exhaustive and highly accurate, checking all files and directories - * (since that would be too complicated). Instead, it does a coarse check on some important (or - * frequently changing) directories. - * - * Currently, it checks the following: - * - **Packages**: Top-level directories in `packages/`. - * - **API docs examples**: Top-level directories in `packages/examples/`. - * - **Guides**: Top-level files in `aio/content/guide/`. - * - **Guide images**: Top-level directories in `aio/content/images/guide/`. - * - **Guide examples**: Top-level directories in `aio/content/examples/`. - */ -'use strict'; - -// Imports -const chalk = require('chalk'); -const fs = require('fs'); -const path = require('path'); - -// Constants -const PROJECT_ROOT_DIR = path.resolve(__dirname, '..'); -const CODEOWNERS_PATH = path.resolve(PROJECT_ROOT_DIR, '.github/CODEOWNERS'); -const PKG_DIR = path.resolve(PROJECT_ROOT_DIR, 'packages'); -const PKG_EXAMPLES_DIR = path.resolve(PKG_DIR, 'examples'); -const AIO_CONTENT_DIR = path.resolve(PROJECT_ROOT_DIR, 'aio/content'); -const AIO_GUIDES_DIR = path.resolve(AIO_CONTENT_DIR, 'guide'); -const AIO_GUIDE_IMAGES_DIR = path.resolve(AIO_CONTENT_DIR, 'images/guide'); -const AIO_GUIDE_EXAMPLES_DIR = path.resolve(AIO_CONTENT_DIR, 'examples'); -const IGNORED_PKG_DIRS = new Set([ - // Examples are checked separately. - 'examples', -]); - -// Run -_main(); - -// Functions - Definitions -function _main() { - const {packages: pkgPackagePaths, examples: pkgExamplePaths} = getPathsFromPkg(); - const { - guides: aioGuidePaths, - images: aioGuideImagesPaths, - examples: aioExamplePaths, - } = getPathsFromAioContent(); - const { - pkgPackages: coPkgPackagePaths, - pkgExamples: coPkgExamplePaths, - aioGuides: coAioGuidePaths, - aioImages: coAioGuideImagesPaths, - aioExamples: coAioExamplePaths, - } = getPathsFromCodeowners(); - - const pkgPackagesDiff = arrayDiff(pkgPackagePaths, coPkgPackagePaths); - const pkgExamplesDiff = arrayDiff(pkgExamplePaths, coPkgExamplePaths); - const aioGuidesDiff = arrayDiff(aioGuidePaths, coAioGuidePaths); - const aioImagesDiff = arrayDiff(aioGuideImagesPaths, coAioGuideImagesPaths); - const aioExamplesDiff = arrayDiff(aioExamplePaths, coAioExamplePaths); - const hasDiff = (pkgPackagesDiff.diffCount > 0) || (pkgExamplesDiff.diffCount > 0) || - (aioGuidesDiff.diffCount > 0) || (aioImagesDiff.diffCount > 0) || - (aioExamplesDiff.diffCount > 0); - - if (hasDiff) { - const expectedPkgPackagesSrc = path.relative(PROJECT_ROOT_DIR, PKG_DIR); - const expectedPkgExamplesSrc = path.relative(PROJECT_ROOT_DIR, PKG_EXAMPLES_DIR); - const expectedAioGuidesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDES_DIR); - const expectedAioImagesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDE_IMAGES_DIR); - const expectedAioExamplesSrc = path.relative(PROJECT_ROOT_DIR, AIO_GUIDE_EXAMPLES_DIR); - const actualSrc = path.relative(PROJECT_ROOT_DIR, CODEOWNERS_PATH); - - reportDiff(pkgPackagesDiff, expectedPkgPackagesSrc, actualSrc); - reportDiff(pkgExamplesDiff, expectedPkgExamplesSrc, actualSrc); - reportDiff(aioGuidesDiff, expectedAioGuidesSrc, actualSrc); - reportDiff(aioImagesDiff, expectedAioImagesSrc, actualSrc); - reportDiff(aioExamplesDiff, expectedAioExamplesSrc, actualSrc); - - // tslint:disable-next-line: no-console - console.log(chalk.red( - '\nCode-ownership verification failed.\n' + - 'Please update \'.github/CODEOWNERS\' to ensure that all necessary files/directories ' + - 'have code-owners and all patterns that appear in the file correspond to actual ' + - 'files/directories in the repo.')); - } else { - // tslint:disable-next-line: no-console - console.log(chalk.green('\nCode-ownership verification succeeded!')); - } - - process.exit(hasDiff ? 1 : 0); -} - -function arrayDiff(expected, actual) { - const missing = expected.filter(x => !actual.includes(x)).sort(); - const extra = actual.filter(x => !expected.includes(x)).sort(); - - return {missing, extra, diffCount: missing.length + extra.length}; -} - -function findDirectories(parentDir) { - return fs.readdirSync(parentDir).filter( - name => fs.statSync(`${parentDir}/${name}`).isDirectory()); -} - -function getPathsFromAioContent() { - return { - guides: fs.readdirSync(AIO_GUIDES_DIR), - images: fs.readdirSync(AIO_GUIDE_IMAGES_DIR), - examples: fs.readdirSync(AIO_GUIDE_EXAMPLES_DIR) - .filter(name => fs.statSync(`${AIO_GUIDE_EXAMPLES_DIR}/${name}`).isDirectory()), - }; -} - -function getPathsFromCodeowners() { - const pkgPackagesPathRe = /^\/packages\/([^\s\*/]+)\/\*?\*\s/; - const pkgExamplesPathRe = /^\/packages\/examples\/([^\s\*/]+)/; - // Use capturing groups for `images/` and `examples` to be able to differentiate between the - // different kinds of matches (guide, image, example) later (see `isImage`/`isExample` below). - const aioGuidesImagesExamplesPathRe = - /^\/aio\/content\/(?:(images\/)?guide|(examples))\/([^\s\*/]+)/; - const manualGlobExpansions = { - // `CODEOWNERS` has a glob to match all `testing/` directories, so no specific glob for - // `packages/examples/testing/` is necessary. - 'testing/**': ['/packages/examples/testing/**'], - }; - - const pkgPackages = []; - const pkgExamples = []; - const aioGuides = []; - const aioImages = []; - const aioExamples = []; - - // Read `CODEOWNERS` and split into lines. - const lines = fs.readFileSync(CODEOWNERS_PATH, 'utf8').split('\n').map(l => l.trim()); - - // Manually expand globs to known matching patterns. - for (const [glob, expansions] of Object.entries(manualGlobExpansions)) { - const matchingLine = lines.find(l => l.startsWith(`${glob} `)); - if (matchingLine !== undefined) { - lines.push(...expansions); - } - } - - // Collect packages (`packages/`). - lines.map(l => l.match(pkgPackagesPathRe)).filter(m => m).forEach(([ - , path - ]) => pkgPackages.push(path)); - - // Collect API docs examples (`packages/examples/`). - lines.map(l => l.match(pkgExamplesPathRe)).filter(m => m).forEach(([ - , path - ]) => pkgExamples.push(path)); - - // Collect `aio/` guides/images/examples. - lines.map(l => l.match(aioGuidesImagesExamplesPathRe)) - .filter(m => m) - .forEach(([, isImage, isExample, path]) => { - const list = isExample ? aioExamples : isImage ? aioImages : aioGuides; - list.push(path); - }); - - return {pkgPackages, pkgExamples, aioGuides, aioImages, aioExamples}; -} - -function getPathsFromPkg() { - return { - packages: findDirectories(PKG_DIR).filter(name => !IGNORED_PKG_DIRS.has(name)), - examples: findDirectories(PKG_EXAMPLES_DIR), - }; -} - - -function reportDiff(diff, expectedSrc, actualSrc) { - if (diff.missing.length) { - console.error( - `\nEntries in '${expectedSrc}' but not in '${actualSrc}':\n` + - diff.missing.map(x => ` - ${x}`).join('\n')); - } - - if (diff.extra.length) { - console.error( - `\nEntries in '${actualSrc}' but not in '${expectedSrc}':\n` + - diff.extra.map(x => ` - ${x}`).join('\n')); - } -} diff --git a/yarn.lock b/yarn.lock index b40a5c8f62..23b7e7b67f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,41 +2,49 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.900.0-rc.3", "@angular-devkit/architect@^0.900.0-rc.3": - version "0.900.0-rc.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.900.0-rc.3.tgz#e01d0296153624d6ef073650484d0d8063bb2a42" - integrity sha512-QVD/iL3CxG6nNFveYN7NhsNLir/SmgVGrsPt7FtKJq2tWxmBEsU3d3zYGYNtFNv/WshHZ7K6UFg+VsRpqnQTtQ== +"@angular-devkit/architect@0.900.0-rc.10": + version "0.900.0-rc.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.900.0-rc.10.tgz#5fee2dd12de787d02c4c78d6d5dd53364bcaae25" + integrity sha512-85bHmwBOJ9nkQ4Ict4rPNF6ON/zHkxGWNST9gy3BgwBcNUO3Y/udywxO0j2/UE/dQ8wtIvqKZfUD7GgVEnLXdQ== dependencies: - "@angular-devkit/core" "9.0.0-rc.3" + "@angular-devkit/core" "9.0.0-rc.10" rxjs "6.5.3" -"@angular-devkit/build-angular@^0.900.0-rc.3": - version "0.900.0-rc.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.900.0-rc.3.tgz#44c963f10a90e47d6b666adc351d9ddd872dfd9c" - integrity sha512-Ioz9sHHI+5Q3XrMLrPEeo7RLYGqJs+KuGE+IyFT1CUCiNH8/YZhx0x4+Z++oTpPiN/by27QjWfE61AHTRloAtA== +"@angular-devkit/architect@0.900.0-rc.11": + version "0.900.0-rc.11" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.900.0-rc.11.tgz#e9f3e5e372d467a220027cf53231b88e8e857fbc" + integrity sha512-rRbq4ipppnY4FvVo89Cv+yC7rlt1/VFE/jaB77Ra2tI6zVlFWCTjnMzuc9TYz/3jK1ssThzgEA2sebPDmjH47w== dependencies: - "@angular-devkit/architect" "0.900.0-rc.3" - "@angular-devkit/build-optimizer" "0.900.0-rc.3" - "@angular-devkit/build-webpack" "0.900.0-rc.3" - "@angular-devkit/core" "9.0.0-rc.3" - "@babel/core" "7.7.2" - "@babel/generator" "7.7.2" - "@babel/preset-env" "7.7.1" - "@ngtools/webpack" "9.0.0-rc.3" + "@angular-devkit/core" "9.0.0-rc.11" + rxjs "6.5.3" + +"@angular-devkit/build-angular@0.900.0-rc.11": + version "0.900.0-rc.11" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.900.0-rc.11.tgz#0bdec73d3ba631b3550527c54a35cf4145b0ed6d" + integrity sha512-lp0f5lRsiTYSPjIgiWtX2N0NgV7dUZ/ifXYqqAEURKZ5O0jFF2gt2x9R29TmyFzTQ3ZP8O5AojO7POh1OfJ6iA== + dependencies: + "@angular-devkit/architect" "0.900.0-rc.11" + "@angular-devkit/build-optimizer" "0.900.0-rc.11" + "@angular-devkit/build-webpack" "0.900.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.11" + "@babel/core" "7.7.7" + "@babel/generator" "7.7.7" + "@babel/preset-env" "7.7.7" + "@ngtools/webpack" "9.0.0-rc.11" ajv "6.10.2" autoprefixer "9.7.1" babel-loader "8.0.6" - browserslist "4.7.2" + browserslist "4.8.3" cacache "13.0.1" - caniuse-lite "1.0.30001006" + caniuse-lite "1.0.30001020" circular-dependency-plugin "5.2.0" - clean-css "4.2.1" - copy-webpack-plugin "5.0.4" - core-js "3.3.6" + copy-webpack-plugin "5.1.1" + core-js "3.6.0" + coverage-istanbul-loader "2.0.3" + cssnano "4.1.10" file-loader "4.2.0" find-cache-dir "3.0.0" glob "7.1.5" - istanbul-instrumenter-loader "3.0.1" jest-worker "24.9.0" karma-source-map-support "1.4.0" less "3.10.3" @@ -66,9 +74,9 @@ style-loader "1.0.0" stylus "0.54.7" stylus-loader "3.0.2" - terser "4.4.0" - terser-webpack-plugin "2.2.1" - tree-kill "1.2.1" + terser "4.5.1" + terser-webpack-plugin "2.3.3" + tree-kill "1.2.2" webpack "4.41.2" webpack-dev-middleware "3.7.2" webpack-dev-server "3.9.0" @@ -87,10 +95,10 @@ typescript "3.2.4" webpack-sources "1.3.0" -"@angular-devkit/build-optimizer@0.900.0-rc.3", "@angular-devkit/build-optimizer@^0.900.0-rc.3": - version "0.900.0-rc.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.900.0-rc.3.tgz#9a658cb6d7ade410058d31f26f5dfbf7e16ba6d3" - integrity sha512-Ldfqg1ZrX6ToARc5Sne+lL3oo8KH163ixfDsFYjN5xkYjpLB4b6uY7nSSibeVquj+6hnZwfpDEXuil8zXVYD9g== +"@angular-devkit/build-optimizer@0.900.0-rc.10": + version "0.900.0-rc.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.900.0-rc.10.tgz#e2351297689185ed71b07d0537fc1d3c73e9b2b7" + integrity sha512-cQkOLwzIdhZgAzkpea2Pi1oS8C8BDo+aB06JchMpdRudi1+ArbTbsaH/2FYhHMD4jkK2XCfKT8yFx20J8t2lVg== dependencies: loader-utils "1.2.3" source-map "0.7.3" @@ -98,19 +106,30 @@ typescript "3.6.4" webpack-sources "1.4.3" -"@angular-devkit/build-webpack@0.900.0-rc.3": - version "0.900.0-rc.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.900.0-rc.3.tgz#220e9ee38b60e94e423afba2bbad2e84124c7e69" - integrity sha512-oOIKo3A2A0aCU/9Pq1OUxzYct6KcWK5UyjRig7Unw/MMOcKuDVk61cC0pM9w2h9gCero1y9M2ofW5tCPwcIfoA== +"@angular-devkit/build-optimizer@0.900.0-rc.11": + version "0.900.0-rc.11" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.900.0-rc.11.tgz#96c2446fa9cd2e90700ab8a68312b28b3907f6d9" + integrity sha512-GJC+7H7ER6bxDC2UdAGwW357EYHpv8ISKKmS19wdJV5gZPMPANcpbg9FIpl27SDhUyZX9C2DOrcATvYYFoYgDQ== dependencies: - "@angular-devkit/architect" "0.900.0-rc.3" - "@angular-devkit/core" "9.0.0-rc.3" + loader-utils "1.2.3" + source-map "0.7.3" + tslib "1.10.0" + typescript "3.6.4" + webpack-sources "1.4.3" + +"@angular-devkit/build-webpack@0.900.0-rc.11": + version "0.900.0-rc.11" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.900.0-rc.11.tgz#d9a91c2b67a629f6adfe87980d26e495f2e30e0a" + integrity sha512-utBAnkO6WLi323Rto1s7TJpaDRqDNR8jkD0C0PG5Zm3y1U9ARbAjTkugkrB/7bc4gEIqWZD+1dLYaaJCidye2Q== + dependencies: + "@angular-devkit/architect" "0.900.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.11" rxjs "6.5.3" -"@angular-devkit/core@9.0.0-rc.3", "@angular-devkit/core@^9.0.0-rc.3": - version "9.0.0-rc.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.0.0-rc.3.tgz#42703073d0f83eee9b319d59d5f61ef407f0ff13" - integrity sha512-x9x4yj0HMzg8rAIgxEPrefjMXB0GOlgzzbHxgcB+qxIP/feASzhnB28OyXSCa4Sgv3er3Jd5wzV/P3QYHKLeoQ== +"@angular-devkit/core@9.0.0-rc.10": + version "9.0.0-rc.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.0.0-rc.10.tgz#e751cedf6483026bbb3f9a5a6ab9c6e9833e1c3a" + integrity sha512-aEdHb9M1rwAsyJSkmQ8J4BRiRLK4zWQL/CXxK15c056H04ncwU8OntBChpnSIf5iGsBM9UQRtiFbRubLfrpxgQ== dependencies: ajv "6.10.2" fast-json-stable-stringify "2.0.0" @@ -118,28 +137,68 @@ rxjs "6.5.3" source-map "0.7.3" -"@angular-devkit/schematics@9.0.0-rc.3", "@angular-devkit/schematics@^9.0.0-rc.3": - version "9.0.0-rc.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.0.0-rc.3.tgz#3c3177098251a003a9e1c0ab4f65e055fea7d941" - integrity sha512-fxwhzE8i1zNs+f4wjpFJfwLE9FIJGYvmDCdXjh5eBA4rPBx8tIrGYXaCZgOrVVkrpO+1bNgrqCaC/lFm4jY8oA== +"@angular-devkit/core@9.0.0-rc.11": + version "9.0.0-rc.11" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.0.0-rc.11.tgz#9e69545eb21284a573ad78e4c33003f2ea25afd5" + integrity sha512-ki7Sln+mQdCctJNBalzy70tiFn2hOCY2Yyte8B0xKWVHnofZySvG+ANzoLgodnKFOBH18AQy35FhgzZM++N9tQ== dependencies: - "@angular-devkit/core" "9.0.0-rc.3" + ajv "6.10.2" + fast-json-stable-stringify "2.0.0" + magic-string "0.25.4" + rxjs "6.5.3" + source-map "0.7.3" + +"@angular-devkit/core@9.0.0-rc.8": + version "9.0.0-rc.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.0.0-rc.8.tgz#e667940cddcf51673032174f52ea2991f05d31b9" + integrity sha512-VxqlKeNh0dgCYdy2mn+yw3wymQCMKrWbaMqDxdlrA1jQ7fFq9bHATVTOc67iqZhigPpOI1tPO3GSQ27MmwAbXw== + dependencies: + ajv "6.10.2" + fast-json-stable-stringify "2.0.0" + magic-string "0.25.4" + rxjs "6.5.3" + source-map "0.7.3" + +"@angular-devkit/schematics@9.0.0-rc.10": + version "9.0.0-rc.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.0.0-rc.10.tgz#65d5e3fbf6a0c7c0689f3ac27cc1b629ca6c8570" + integrity sha512-cuy+gDOhzf04vhJHsR21HnkEcOZqyfFabNs90Q5H77iGWl7GUO/RhwV7tXADdKZ4ee14rfFQi3TA0SrcOMXQlA== + dependencies: + "@angular-devkit/core" "9.0.0-rc.10" + ora "4.0.2" + rxjs "6.5.3" + +"@angular-devkit/schematics@9.0.0-rc.11": + version "9.0.0-rc.11" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.0.0-rc.11.tgz#e0d4d271d8d783ebf05eced576262f20e6c3562c" + integrity sha512-aJqOLzsoAkVj3AVTf1ehH2hA9wHHz1+7TTtfqI+Yx+S3jFyvGmnKrNBCKtMuIV5JdEHiXmhhuGbNBHwRFWpOow== + dependencies: + "@angular-devkit/core" "9.0.0-rc.11" + ora "4.0.2" + rxjs "6.5.3" + +"@angular-devkit/schematics@9.0.0-rc.8": + version "9.0.0-rc.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.0.0-rc.8.tgz#546568a6186499045289e134d329b2867a0353ff" + integrity sha512-YvFqpdluy9nNsKfcTG1x1W2AXV6m+CkavVSws4KJx1hRua+n9vO3jRYGKep4+GwpUg36oQTMXyW37XufUuGGyQ== + dependencies: + "@angular-devkit/core" "9.0.0-rc.8" ora "4.0.2" rxjs "6.5.3" "@angular/bazel@file:./tools/npm/@angular_bazel": version "0.0.0" -"@angular/cli@^9.0.0-rc.3": - version "9.0.0-rc.3" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-9.0.0-rc.3.tgz#f9fe26d479cfc957ed9c76fb23d8b631cb83a8c3" - integrity sha512-C5rDWxW9Rl+Ew+nmQ1ZftXljxxrbdQVhxuEqtFuSn4plJIq0Z4YPkF7tJerX80PMk4BJdJ/1ZvCGCCSoQIfhRQ== +"@angular/cli@9.0.0-rc.11": + version "9.0.0-rc.11" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-9.0.0-rc.11.tgz#5d830045bb95f4a38a1d0df02212207731061a57" + integrity sha512-Du0y6rpOfGkH7h6ukZf5SKgpTv0uAZ5McNFrPAH2KFs7PgM4fyj9VmJ1lSns9WsVcEHdPlIPh8WGResUzvePdA== dependencies: - "@angular-devkit/architect" "0.900.0-rc.3" - "@angular-devkit/core" "9.0.0-rc.3" - "@angular-devkit/schematics" "9.0.0-rc.3" - "@schematics/angular" "9.0.0-rc.3" - "@schematics/update" "0.900.0-rc.3" + "@angular-devkit/architect" "0.900.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/schematics" "9.0.0-rc.11" + "@schematics/angular" "9.0.0-rc.11" + "@schematics/update" "0.900.0-rc.11" "@yarnpkg/lockfile" "1.1.0" ansi-colors "4.1.1" debug "^4.1.1" @@ -170,18 +229,25 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@7.7.2": - version "7.7.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.2.tgz#ea5b99693bcfc058116f42fa1dd54da412b29d91" - integrity sha512-eeD7VEZKfhK1KUXGiyPFettgF3m513f8FoBSWiQ1xTvl1RAopLs42Wp9+Ze911I6H0N9lNqJMDgoZT7gHsipeQ== +"@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + +"@babel/core@7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.7.tgz#ee155d2e12300bcc0cff6a8ad46f2af5063803e9" + integrity sha512-jlSjuj/7z138NLZALxVgrx13AOtqip42ATZP7+kYl53GvDV6+4dCek1mVUo8z8c8Xnw/mx2q3d9HWh3griuesQ== dependencies: "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.2" - "@babel/helpers" "^7.7.0" - "@babel/parser" "^7.7.2" - "@babel/template" "^7.7.0" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.7.2" + "@babel/generator" "^7.7.7" + "@babel/helpers" "^7.7.4" + "@babel/parser" "^7.7.7" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@babel/types" "^7.7.4" convert-source-map "^1.7.0" debug "^4.1.0" json5 "^2.1.0" @@ -190,47 +256,48 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.6.4": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.4.tgz#6ebd9fe00925f6c3e177bb726a188b5f578088ff" - integrity sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ== +"@babel/core@7.8.3", "@babel/core@^7.7.5": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941" + integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA== dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.4" - "@babel/helpers" "^7.6.2" - "@babel/parser" "^7.6.4" - "@babel/template" "^7.6.0" - "@babel/traverse" "^7.6.3" - "@babel/types" "^7.6.3" - convert-source-map "^1.1.0" + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.3" + "@babel/helpers" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" debug "^4.1.0" + gensync "^1.0.0-beta.1" json5 "^2.1.0" lodash "^4.17.13" resolve "^1.3.2" semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@7.7.2": - version "7.7.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.2.tgz#2f4852d04131a5e17ea4f6645488b5da66ebf3af" - integrity sha512-WthSArvAjYLz4TcbKOi88me+KmDJdKSlfwwN8CnUYn9jBkzhq0ZEPuBfkAWIvjJ3AdEV1Cf/+eSQTnp3IDJKlQ== +"@babel/generator@7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.7.tgz#859ac733c44c74148e1a72980a64ec84b85f4f45" + integrity sha512-/AOIBpHh/JU1l0ZFS4kiRCBnLi6OTHzh0RPk3h9isBxkkqELtQNFi1Vr/tiG9p1yfoUdKVwISuXWQR+hwwM4VQ== dependencies: - "@babel/types" "^7.7.2" + "@babel/types" "^7.7.4" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" -"@babel/generator@^7.6.3", "@babel/generator@^7.6.4": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.4.tgz#a4f8437287bf9671b07f483b76e3bb731bc97671" - integrity sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w== +"@babel/generator@7.8.3", "@babel/generator@^7.7.7", "@babel/generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" + integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug== dependencies: - "@babel/types" "^7.6.3" + "@babel/types" "^7.8.3" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" -"@babel/generator@^7.7.2", "@babel/generator@^7.7.4": +"@babel/generator@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg== @@ -240,63 +307,54 @@ lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz#bb3faf1e74b74bd547e867e48f551fa6b098b6ce" - integrity sha512-2BQmQgECKzYKFPpiycoF9tlb5HA4lrVyAmLLVK177EcQAqjVLciUb2/R+n1boQ9y5ENV3uz2ZqiNw7QMBBw1Og== +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.7.4.tgz#5f73f2b28580e224b5b9bd03146a4015d6217f5f" - integrity sha512-Biq/d/WtvfftWZ9Uf39hbPBYDUo986m5Bb4zhkeYDGUllF43D+nUe5M6Vuo6/8JDK/0YX/uBdeoQpyaNhNugZQ== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== dependencies: - "@babel/helper-explode-assignable-expression" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-call-delegate@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.7.4.tgz#621b83e596722b50c0066f9dc37d3232e461b801" - integrity sha512-8JH9/B7J7tCYJ2PpWVpw9JhPuEVHztagNVuQAFBVFYluRMlpG7F1CgKEgGeL6KFqcsIa92ZYVj6DSc0XwmN1ZA== +"@babel/helper-call-delegate@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" + integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== dependencies: - "@babel/helper-hoist-variables" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-create-regexp-features-plugin@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz#6d5762359fd34f4da1500e4cff9955b5299aaf59" - integrity sha512-Mt+jBKaxL0zfOIWrfQpnfYCN7/rS6GKx6CCCfuoqVVd+17R8zNDlzVYmIi9qyb2wOk002NsmSTDymkIygDUH7A== +"@babel/helper-create-regexp-features-plugin@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79" + integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q== dependencies: - "@babel/helper-regex" "^7.4.4" + "@babel/helper-regex" "^7.8.3" regexpu-core "^4.6.0" -"@babel/helper-define-map@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.7.4.tgz#2841bf92eb8bd9c906851546fe6b9d45e162f176" - integrity sha512-v5LorqOa0nVQUvAUTUF3KPastvUt/HzByXNamKQ6RdJRTV7j8rLL+WB5C/MzzWAwOomxDhYFb1wLLxHqox86lg== +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" lodash "^4.17.13" -"@babel/helper-explode-assignable-expression@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.7.4.tgz#fa700878e008d85dc51ba43e9fb835cddfe05c84" - integrity sha512-2/SicuFrNSXsZNBxe5UGdLr+HZg+raWBLE9vC98bdYOKX/U6PY0mdGlYUJdtTDPSU0Lw0PNbKKDpwYHJLn2jLg== +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== dependencies: - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" - -"@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/traverse" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helper-function-name@^7.7.4": version "7.7.4" @@ -307,12 +365,14 @@ "@babel/template" "^7.7.4" "@babel/types" "^7.7.4" -"@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== +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== dependencies: - "@babel/types" "^7.0.0" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helper-get-function-arity@^7.7.4": version "7.7.4" @@ -321,93 +381,105 @@ dependencies: "@babel/types" "^7.7.4" -"@babel/helper-hoist-variables@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz#612384e3d823fdfaaf9fce31550fe5d4db0f3d12" - integrity sha512-wQC4xyvc1Jo/FnLirL6CEgPgPCa8M74tOdjWpRhQYapz5JC7u3NYU1zCVoVAGCE3EaIP9T1A3iW0WLJ+reZlpQ== +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-member-expression-to-functions@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.4.tgz#356438e2569df7321a8326644d4b790d2122cb74" - integrity sha512-9KcA1X2E3OjXl/ykfMMInBK+uVdfIVakVe7W7Lg3wfXUNyS3Q1HWLFRwZIjhqiCGbslummPDnmb7vIekS0C1vw== +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helper-module-imports@^7.7.0", "@babel/helper-module-imports@^7.7.4": +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-imports@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz#e5a92529f8888bf319a6376abfbd1cebc491ad91" integrity sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ== dependencies: "@babel/types" "^7.7.4" -"@babel/helper-module-transforms@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz#8d7cdb1e1f8ea3d8c38b067345924ac4f8e0879a" - integrity sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA== +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-simple-access" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" + +"@babel/helper-module-transforms@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" + integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" lodash "^4.17.13" -"@babel/helper-optimise-call-expression@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.4.tgz#034af31370d2995242aa4df402c3b7794b2dcdf2" - integrity sha512-VB7gWZ2fDkSuqW6b1AKXkJWO5NyNI3bFL/kK79/30moK57blr6NbH8xcl2XcKCwOmJosftWunZqfO84IGq3ZZg== +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== dependencies: - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== -"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.5.5.tgz#0aa6824f7100a2e0e89c1527c23936c152cab351" - integrity sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw== +"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== dependencies: lodash "^4.17.13" -"@babel/helper-remap-async-to-generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.4.tgz#c68c2407350d9af0e061ed6726afb4fff16d0234" - integrity sha512-Sk4xmtVdM9sA/jCI80f+KS+Md+ZHIpjuqmYPk1M7F/upHou5e4ReYmExAiu6PVe65BhJPZA2CY9x9k4BqE5klw== +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-wrap-function" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-replace-supers@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.4.tgz#3c881a6a6a7571275a72d82e6107126ec9e2cdd2" - integrity sha512-pP0tfgg9hsZWo5ZboYGuBn/bbYT/hdLPVSS4NMmiRJdwWhP0IznPwN9AE1JwyGsjSPLC364I0Qh5p+EPkGPNpg== +"@babel/helper-replace-supers@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" + integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.7.4" - "@babel/helper-optimise-call-expression" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helper-simple-access@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz#a169a0adb1b5f418cfc19f22586b2ebf58a9a294" - integrity sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A== +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== dependencies: - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" - -"@babel/helper-split-export-declaration@^7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" - integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== - dependencies: - "@babel/types" "^7.4.4" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/helper-split-export-declaration@^7.7.4": version "7.7.4" @@ -416,33 +488,31 @@ dependencies: "@babel/types" "^7.7.4" -"@babel/helper-wrap-function@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" - integrity sha512-VsfzZt6wmsocOaVU0OokwrIytHND55yvyT4BPB9AIIgwr8+x7617hetdJTsuGwygN5RC6mxA9EJztTjuwm2ofg== +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/types" "^7.8.3" -"@babel/helpers@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.6.2.tgz#681ffe489ea4dcc55f23ce469e58e59c1c045153" - integrity sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA== +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== dependencies: - "@babel/template" "^7.6.0" - "@babel/traverse" "^7.6.2" - "@babel/types" "^7.6.0" + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/helpers@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.4.tgz#62c215b9e6c712dadc15a9a0dcab76c92a940302" - integrity sha512-ak5NGZGJ6LV85Q1Zc9gn2n+ayXOizryhjSUBTdu5ih1tlVCJeuQENzc4ItyCVhINVXvIT/ZQ4mheGIsfBkpskg== +"@babel/helpers@^7.7.4", "@babel/helpers@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85" + integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ== dependencies: - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@babel/types" "^7.7.4" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" "@babel/highlight@^7.0.0": version "7.0.0" @@ -453,418 +523,459 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.6.0", "@babel/parser@^7.6.3", "@babel/parser@^7.6.4": +"@babel/highlight@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" + integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.7.5", "@babel/parser@^7.7.7", "@babel/parser@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" + integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== + +"@babel/parser@^7.1.0": version "7.6.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81" integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A== -"@babel/parser@^7.7.2", "@babel/parser@^7.7.4": +"@babel/parser@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== -"@babel/plugin-proposal-async-generator-functions@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz#0351c5ac0a9e927845fffd5b82af476947b7ce6d" - integrity sha512-1ypyZvGRXriY/QP668+s8sFr2mqinhkRDMPSQLNghCQE+GAkFtp+wkHVvg2+Hdki8gwP+NFzJBJ/N1BfzCCDEw== +"@babel/plugin-proposal-async-generator-functions@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" - "@babel/plugin-syntax-async-generators" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-dynamic-import@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz#dde64a7f127691758cbfed6cf70de0fa5879d52d" - integrity sha512-StH+nGAdO6qDB1l8sZ5UBV8AC3F2VW2I8Vfld73TMKyptMU9DY5YsJAS8U81+vEtxcH3Y/La0wG0btDrhpnhjQ== +"@babel/plugin-proposal-dynamic-import@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@babel/plugin-proposal-json-strings@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.7.4.tgz#7700a6bfda771d8dc81973249eac416c6b4c697d" - integrity sha512-wQvt3akcBTfLU/wYoqm/ws7YOAQKu8EVJEvHip/mzkNtjaclQoCCIqKXFP5/eyfnfbQCDV3OLRIK3mIVyXuZlw== +"@babel/plugin-proposal-json-strings@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" -"@babel/plugin-proposal-object-rest-spread@^7.6.2": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.7.4.tgz#cc57849894a5c774214178c8ab64f6334ec8af71" - integrity sha512-rnpnZR3/iWKmiQyJ3LKJpSwLDcX/nSXhdLk4Aq/tXOApIvyu7qoabrige0ylsAJffaUC51WiBu209Q0U+86OWQ== +"@babel/plugin-proposal-object-rest-spread@^7.7.7": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" + integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" -"@babel/plugin-proposal-optional-catch-binding@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.7.4.tgz#ec21e8aeb09ec6711bc0a39ca49520abee1de379" - integrity sha512-DyM7U2bnsQerCQ+sejcTNZh8KQEUuC3ufzdnVnSiUv/qoGJp2Z3hanKL18KDhsBT5Wj6a7CMT5mdyCNJsEaA9w== +"@babel/plugin-proposal-optional-catch-binding@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-unicode-property-regex@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.4.tgz#7c239ccaf09470dbe1d453d50057460e84517ebb" - integrity sha512-cHgqHgYvffluZk85dJ02vloErm3Y6xtH+2noOBOJ2kXOJH3aVCDnj5eR/lVNlTnYu4hndAPJD3rTFjW3qee0PA== +"@babel/plugin-proposal-unicode-property-regex@^7.7.7": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f" + integrity sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-async-generators@^7.2.0", "@babel/plugin-syntax-async-generators@^7.7.4": +"@babel/plugin-syntax-async-generators@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz#331aaf310a10c80c44a66b238b6e49132bd3c889" integrity sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-dynamic-import@^7.2.0", "@babel/plugin-syntax-dynamic-import@^7.7.4": +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-dynamic-import@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec" integrity sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-json-strings@^7.2.0", "@babel/plugin-syntax-json-strings@^7.7.4": +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-json-strings@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-object-rest-spread@^7.2.0", "@babel/plugin-syntax-object-rest-spread@^7.7.4": +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-object-rest-spread@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-optional-catch-binding@^7.2.0", "@babel/plugin-syntax-optional-catch-binding@^7.7.4": +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz#a3e38f59f4b6233867b4a92dcb0ee05b2c334aa6" integrity sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-top-level-await@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.4.tgz#bd7d8fa7b9fee793a36e4027fd6dd1aa32f946da" - integrity sha512-wdsOw0MvkL1UIgiQ/IFr3ETcfv1xb8RMM0H9wbiDyLaJFyiDg5oZvDLCXosIXmFeIlweML5iOBXAkqddkYNizg== +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-transform-arrow-functions@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" - integrity sha512-zUXy3e8jBNPiffmqkHRNDdZM2r8DWhCB7HhcoyZjiK1TxYEluLHAvQuYnTT+ARqRpabWqy/NHkO6e3MsYB5YfA== +"@babel/plugin-syntax-top-level-await@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-async-to-generator@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.4.tgz#694cbeae6d613a34ef0292713fa42fb45c4470ba" - integrity sha512-zpUTZphp5nHokuy8yLlyafxCJ0rSlFoSHypTUWgpdwoDXWQcseaect7cJ8Ppk6nunOM6+5rPMkod4OYKPR5MUg== +"@babel/plugin-transform-arrow-functions@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== dependencies: - "@babel/helper-module-imports" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-remap-async-to-generator" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-block-scoped-functions@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.7.4.tgz#d0d9d5c269c78eaea76227ace214b8d01e4d837b" - integrity sha512-kqtQzwtKcpPclHYjLK//3lH8OFsCDuDJBaFhVwf8kqdnF6MN4l618UDlcA7TfRs3FayrHj+svYnSX8MC9zmUyQ== +"@babel/plugin-transform-async-to-generator@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" -"@babel/plugin-transform-block-scoping@^7.6.3": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.7.4.tgz#200aad0dcd6bb80372f94d9e628ea062c58bf224" - integrity sha512-2VBe9u0G+fDt9B5OV5DQH4KBf5DoiNkwFKOz0TCvBWvdAN2rOykCTkrL+jTLxfCAm76l9Qo5OqL7HBOx2dWggg== +"@babel/plugin-transform-block-scoped-functions@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" lodash "^4.17.13" -"@babel/plugin-transform-classes@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.4.tgz#c92c14be0a1399e15df72667067a8f510c9400ec" - integrity sha512-sK1mjWat7K+buWRuImEzjNf68qrKcrddtpQo3swi9j7dUcG6y6R6+Di039QN2bD1dykeswlagupEmpOatFHHUg== +"@babel/plugin-transform-classes@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" + integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-define-map" "^7.7.4" - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-optimise-call-expression" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.7.4.tgz#e856c1628d3238ffe12d668eb42559f79a81910d" - integrity sha512-bSNsOsZnlpLLyQew35rl4Fma3yKWqK3ImWMSC/Nc+6nGjC9s5NFWAer1YQ899/6s9HxO2zQC1WoFNfkOqRkqRQ== +"@babel/plugin-transform-computed-properties@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-destructuring@^7.6.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.7.4.tgz#2b713729e5054a1135097b6a67da1b6fe8789267" - integrity sha512-4jFMXI1Cu2aXbcXXl8Lr6YubCn6Oc7k9lLsu8v61TZh+1jny2BWmdtvY9zSUlLdGUvcy9DMAWyZEOqjsbeg/wA== +"@babel/plugin-transform-destructuring@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b" + integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-dotall-regex@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.4.tgz#f7ccda61118c5b7a2599a72d5e3210884a021e96" - integrity sha512-mk0cH1zyMa/XHeb6LOTXTbG7uIJ8Rrjlzu91pUx/KS3JpcgaTDwMS8kM+ar8SLOvlL2Lofi4CGBAjCo3a2x+lw== +"@babel/plugin-transform-dotall-regex@^7.7.7": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-duplicate-keys@^7.5.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.7.4.tgz#3d21731a42e3f598a73835299dd0169c3b90ac91" - integrity sha512-g1y4/G6xGWMD85Tlft5XedGaZBCIVN+/P0bs6eabmcPP9egFleMAo65OOjlhcz1njpwagyY3t0nsQC9oTFegJA== +"@babel/plugin-transform-duplicate-keys@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.7.4.tgz#dd30c0191e3a1ba19bcc7e389bdfddc0729d5db9" - integrity sha512-MCqiLfCKm6KEA1dglf6Uqq1ElDIZwFuzz1WH5mTf8k2uQSxEJMbOIEh7IZv7uichr7PMfi5YVSrr1vz+ipp7AQ== +"@babel/plugin-transform-exponentiation-operator@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-for-of@^7.4.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" - integrity sha512-zZ1fD1B8keYtEcKF+M1TROfeHTKnijcVQm0yO/Yu1f7qoDoxEIc/+GX6Go430Bg84eM/xwPFp0+h4EbZg7epAA== +"@babel/plugin-transform-for-of@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz#15f17bce2fc95c7d59a24b299e83e81cedc22e18" + integrity sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-function-name@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.4.tgz#75a6d3303d50db638ff8b5385d12451c865025b1" - integrity sha512-E/x09TvjHNhsULs2IusN+aJNRV5zKwxu1cpirZyRPw+FyyIKEHPXTsadj48bVpc1R5Qq1B5ZkzumuFLytnbT6g== +"@babel/plugin-transform-function-name@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== dependencies: - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-literals@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.7.4.tgz#27fe87d2b5017a2a5a34d1c41a6b9f6a6262643e" - integrity sha512-X2MSV7LfJFm4aZfxd0yLVFrEXAgPqYoDG53Br/tCKiKYfX0MjVjQeWPIhPHHsCqzwQANq+FLN786fF5rgLS+gw== +"@babel/plugin-transform-literals@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-member-expression-literals@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.7.4.tgz#aee127f2f3339fc34ce5e3055d7ffbf7aa26f19a" - integrity sha512-9VMwMO7i69LHTesL0RdGy93JU6a+qOPuvB4F4d0kR0zyVjJRVJRaoaGjhtki6SzQUu8yen/vxPKN6CWnCUw6bA== +"@babel/plugin-transform-member-expression-literals@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-modules-amd@^7.5.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.4.tgz#276b3845ca2b228f2995e453adc2e6f54d72fb71" - integrity sha512-/542/5LNA18YDtg1F+QHvvUSlxdvjZoD/aldQwkq+E3WCkbEjNSN9zdrOXaSlfg3IfGi22ijzecklF/A7kVZFQ== +"@babel/plugin-transform-modules-amd@^7.7.5": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" + integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== dependencies: - "@babel/helper-module-transforms" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-commonjs@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.4.tgz#bee4386e550446343dd52a571eda47851ff857a3" - integrity sha512-k8iVS7Jhc367IcNF53KCwIXtKAH7czev866ThsTgy8CwlXjnKZna2VHwChglzLleYrcHz1eQEIJlGRQxB53nqA== +"@babel/plugin-transform-modules-commonjs@^7.7.5": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" + integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg== dependencies: - "@babel/helper-module-transforms" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-simple-access" "^7.7.4" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-systemjs@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.4.tgz#cd98152339d3e763dfe838b7d4273edaf520bb30" - integrity sha512-y2c96hmcsUi6LrMqvmNDPBBiGCiQu0aYqpHatVVu6kD4mFEXKjyNxd/drc18XXAf9dv7UXjrZwBVmTTGaGP8iw== +"@babel/plugin-transform-modules-systemjs@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" + integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg== dependencies: - "@babel/helper-hoist-variables" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" -"@babel/plugin-transform-modules-umd@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.4.tgz#1027c355a118de0aae9fee00ad7813c584d9061f" - integrity sha512-u2B8TIi0qZI4j8q4C51ktfO7E3cQ0qnaXFI1/OXITordD40tt17g/sXqgNNCcMTcBFKrUPcGDx+TBJuZxLx7tw== +"@babel/plugin-transform-modules-umd@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" + integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw== dependencies: - "@babel/helper-module-transforms" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-named-capturing-groups-regex@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.4.tgz#fb3bcc4ee4198e7385805007373d6b6f42c98220" - integrity sha512-jBUkiqLKvUWpv9GLSuHUFYdmHg0ujC1JEYoZUfeOOfNydZXp1sXObgyPatpcwjWgsdBGsagWW0cdJpX/DO2jMw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" -"@babel/plugin-transform-new-target@^7.4.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.7.4.tgz#4a0753d2d60639437be07b592a9e58ee00720167" - integrity sha512-CnPRiNtOG1vRodnsyGX37bHQleHE14B9dnnlgSeEs3ek3fHN1A1SScglTCg1sfbe7sRQ2BUcpgpTpWSfMKz3gg== +"@babel/plugin-transform-new-target@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-object-super@^7.5.5": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.7.4.tgz#48488937a2d586c0148451bf51af9d7dda567262" - integrity sha512-ho+dAEhC2aRnff2JCA0SAK7V2R62zJd/7dmtoe7MHcso4C2mS+vZjn1Pb1pCVZvJs1mgsvv5+7sT+m3Bysb6eg== +"@babel/plugin-transform-object-super@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.7.4" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" -"@babel/plugin-transform-parameters@^7.4.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.7.4.tgz#da4555c97f39b51ac089d31c7380f03bca4075ce" - integrity sha512-VJwhVePWPa0DqE9vcfptaJSzNDKrWU/4FbYCjZERtmqEs05g3UMXnYMZoXja7JAJ7Y7sPZipwm/pGApZt7wHlw== +"@babel/plugin-transform-parameters@^7.7.7": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz#7890576a13b17325d8b7d44cb37f21dc3bbdda59" + integrity sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q== dependencies: - "@babel/helper-call-delegate" "^7.7.4" - "@babel/helper-get-function-arity" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-call-delegate" "^7.8.3" + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-property-literals@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.7.4.tgz#2388d6505ef89b266103f450f9167e6bd73f98c2" - integrity sha512-MatJhlC4iHsIskWYyawl53KuHrt+kALSADLQQ/HkhTjX954fkxIEh4q5slL4oRAnsm/eDoZ4q0CIZpcqBuxhJQ== +"@babel/plugin-transform-property-literals@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-regenerator@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.4.tgz#d18eac0312a70152d7d914cbed2dc3999601cfc0" - integrity sha512-e7MWl5UJvmPEwFJTwkBlPmqixCtr9yAASBqff4ggXTNicZiwbF8Eefzm6NVgfiBp7JdAGItecnctKTgH44q2Jw== +"@babel/plugin-transform-regenerator@^7.7.5": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" + integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== dependencies: regenerator-transform "^0.14.0" -"@babel/plugin-transform-reserved-words@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.7.4.tgz#6a7cf123ad175bb5c69aec8f6f0770387ed3f1eb" - integrity sha512-OrPiUB5s5XvkCO1lS7D8ZtHcswIC57j62acAnJZKqGGnHP+TIc/ljQSrgdX/QyOTdEK5COAhuc820Hi1q2UgLQ== +"@babel/plugin-transform-reserved-words@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-shorthand-properties@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.7.4.tgz#74a0a9b2f6d67a684c6fbfd5f0458eb7ba99891e" - integrity sha512-q+suddWRfIcnyG5YiDP58sT65AJDZSUhXQDZE3r04AuqD6d/XLaQPPXSBzP2zGerkgBivqtQm9XKGLuHqBID6Q== +"@babel/plugin-transform-shorthand-properties@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-spread@^7.6.2": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.7.4.tgz#aa673b356fe6b7e70d69b6e33a17fef641008578" - integrity sha512-8OSs0FLe5/80cndziPlg4R0K6HcWSM0zyNhHhLsmw/Nc5MaA49cAsnoJ/t/YZf8qkG7fD+UjTRaApVDB526d7Q== +"@babel/plugin-transform-spread@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-sticky-regex@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.7.4.tgz#ffb68c05090c30732076b1285dc1401b404a123c" - integrity sha512-Ls2NASyL6qtVe1H1hXts9yuEeONV2TJZmplLONkMPUG158CtmnrzW5Q5teibM5UVOFjG0D3IC5mzXR6pPpUY7A== +"@babel/plugin-transform-sticky-regex@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-regex" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" -"@babel/plugin-transform-template-literals@^7.4.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.7.4.tgz#1eb6411736dd3fe87dbd20cc6668e5121c17d604" - integrity sha512-sA+KxLwF3QwGj5abMHkHgshp9+rRz+oY9uoRil4CyLtgEuE/88dpkeWgNk5qKVsJE9iSfly3nvHapdRiIS2wnQ== +"@babel/plugin-transform-template-literals@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-typeof-symbol@^7.2.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.7.4.tgz#3174626214f2d6de322882e498a38e8371b2140e" - integrity sha512-KQPUQ/7mqe2m0B8VecdyaW5XcQYaePyl9R7IsKd+irzj6jvbhoGnRE+M0aNkyAzI07VfUQ9266L5xMARitV3wg== +"@babel/plugin-transform-typeof-symbol@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz#5cffb216fb25c8c64ba6bf5f76ce49d3ab079f4d" + integrity sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g== dependencies: - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-unicode-regex@^7.7.0": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz#a3c0f65b117c4c81c5b6484f2a5e7b95346b83ae" - integrity sha512-N77UUIV+WCvE+5yHw+oks3m18/umd7y392Zv7mYTpFqHtkpcc+QUz+gLJNTWVlWROIWeLqY0f3OjZxV5TcXnRw== +"@babel/plugin-transform-unicode-regex@^7.7.4": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.7.4" - "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" -"@babel/preset-env@7.7.1": - version "7.7.1" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.1.tgz#04a2ff53552c5885cf1083e291c8dd5490f744bb" - integrity sha512-/93SWhi3PxcVTDpSqC+Dp4YxUu3qZ4m7I76k0w73wYfn7bGVuRIO4QUz95aJksbS+AD1/mT1Ie7rbkT0wSplaA== +"@babel/preset-env@7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.7.tgz#c294167b91e53e7e36d820e943ece8d0c7fe46ac" + integrity sha512-pCu0hrSSDVI7kCVUOdcMNQEbOPJ52E+LrQ14sN8uL2ALfSqePZQlKrOy+tM4uhEdYlCHi4imr8Zz2cZe9oSdIg== dependencies: - "@babel/helper-module-imports" "^7.7.0" + "@babel/helper-module-imports" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.7.0" - "@babel/plugin-proposal-dynamic-import" "^7.7.0" - "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.6.2" - "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.7.0" - "@babel/plugin-syntax-async-generators" "^7.2.0" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-syntax-json-strings" "^7.2.0" - "@babel/plugin-syntax-object-rest-spread" "^7.2.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" - "@babel/plugin-syntax-top-level-await" "^7.7.0" - "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.7.0" - "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.6.3" - "@babel/plugin-transform-classes" "^7.7.0" - "@babel/plugin-transform-computed-properties" "^7.2.0" - "@babel/plugin-transform-destructuring" "^7.6.0" - "@babel/plugin-transform-dotall-regex" "^7.7.0" - "@babel/plugin-transform-duplicate-keys" "^7.5.0" - "@babel/plugin-transform-exponentiation-operator" "^7.2.0" - "@babel/plugin-transform-for-of" "^7.4.4" - "@babel/plugin-transform-function-name" "^7.7.0" - "@babel/plugin-transform-literals" "^7.2.0" - "@babel/plugin-transform-member-expression-literals" "^7.2.0" - "@babel/plugin-transform-modules-amd" "^7.5.0" - "@babel/plugin-transform-modules-commonjs" "^7.7.0" - "@babel/plugin-transform-modules-systemjs" "^7.7.0" - "@babel/plugin-transform-modules-umd" "^7.7.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.0" - "@babel/plugin-transform-new-target" "^7.4.4" - "@babel/plugin-transform-object-super" "^7.5.5" - "@babel/plugin-transform-parameters" "^7.4.4" - "@babel/plugin-transform-property-literals" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.7.0" - "@babel/plugin-transform-reserved-words" "^7.2.0" - "@babel/plugin-transform-shorthand-properties" "^7.2.0" - "@babel/plugin-transform-spread" "^7.6.2" - "@babel/plugin-transform-sticky-regex" "^7.2.0" - "@babel/plugin-transform-template-literals" "^7.4.4" - "@babel/plugin-transform-typeof-symbol" "^7.2.0" - "@babel/plugin-transform-unicode-regex" "^7.7.0" - "@babel/types" "^7.7.1" + "@babel/plugin-proposal-async-generator-functions" "^7.7.4" + "@babel/plugin-proposal-dynamic-import" "^7.7.4" + "@babel/plugin-proposal-json-strings" "^7.7.4" + "@babel/plugin-proposal-object-rest-spread" "^7.7.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.7.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.7.7" + "@babel/plugin-syntax-async-generators" "^7.7.4" + "@babel/plugin-syntax-dynamic-import" "^7.7.4" + "@babel/plugin-syntax-json-strings" "^7.7.4" + "@babel/plugin-syntax-object-rest-spread" "^7.7.4" + "@babel/plugin-syntax-optional-catch-binding" "^7.7.4" + "@babel/plugin-syntax-top-level-await" "^7.7.4" + "@babel/plugin-transform-arrow-functions" "^7.7.4" + "@babel/plugin-transform-async-to-generator" "^7.7.4" + "@babel/plugin-transform-block-scoped-functions" "^7.7.4" + "@babel/plugin-transform-block-scoping" "^7.7.4" + "@babel/plugin-transform-classes" "^7.7.4" + "@babel/plugin-transform-computed-properties" "^7.7.4" + "@babel/plugin-transform-destructuring" "^7.7.4" + "@babel/plugin-transform-dotall-regex" "^7.7.7" + "@babel/plugin-transform-duplicate-keys" "^7.7.4" + "@babel/plugin-transform-exponentiation-operator" "^7.7.4" + "@babel/plugin-transform-for-of" "^7.7.4" + "@babel/plugin-transform-function-name" "^7.7.4" + "@babel/plugin-transform-literals" "^7.7.4" + "@babel/plugin-transform-member-expression-literals" "^7.7.4" + "@babel/plugin-transform-modules-amd" "^7.7.5" + "@babel/plugin-transform-modules-commonjs" "^7.7.5" + "@babel/plugin-transform-modules-systemjs" "^7.7.4" + "@babel/plugin-transform-modules-umd" "^7.7.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.4" + "@babel/plugin-transform-new-target" "^7.7.4" + "@babel/plugin-transform-object-super" "^7.7.4" + "@babel/plugin-transform-parameters" "^7.7.7" + "@babel/plugin-transform-property-literals" "^7.7.4" + "@babel/plugin-transform-regenerator" "^7.7.5" + "@babel/plugin-transform-reserved-words" "^7.7.4" + "@babel/plugin-transform-shorthand-properties" "^7.7.4" + "@babel/plugin-transform-spread" "^7.7.4" + "@babel/plugin-transform-sticky-regex" "^7.7.4" + "@babel/plugin-transform-template-literals" "^7.7.4" + "@babel/plugin-transform-typeof-symbol" "^7.7.4" + "@babel/plugin-transform-unicode-regex" "^7.7.4" + "@babel/types" "^7.7.4" browserslist "^4.6.0" - core-js-compat "^3.1.1" + core-js-compat "^3.6.0" invariant "^2.2.2" js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/template@^7.1.0", "@babel/template@^7.6.0": - version "7.6.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6" - integrity sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.6.0" - "@babel/types" "^7.6.0" - -"@babel/template@^7.7.0", "@babel/template@^7.7.4": +"@babel/template@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== @@ -873,22 +984,16 @@ "@babel/parser" "^7.7.4" "@babel/types" "^7.7.4" -"@babel/traverse@^7.6.2", "@babel/traverse@^7.6.3": - version "7.6.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.3.tgz#66d7dba146b086703c0fb10dd588b7364cec47f9" - integrity sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw== +"@babel/template@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" + integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.6.3" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.4.4" - "@babel/parser" "^7.6.3" - "@babel/types" "^7.6.3" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" -"@babel/traverse@^7.7.2", "@babel/traverse@^7.7.4": +"@babel/traverse@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== @@ -903,7 +1008,22 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.6.0", "@babel/types@^7.6.3": +"@babel/traverse@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" + integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.3" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.0.0", "@babel/types@^7.3.0": version "7.6.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.3.tgz#3f07d96f854f98e2fbd45c64b0cb942d11e8ba09" integrity sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA== @@ -912,7 +1032,7 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@babel/types@^7.7.1", "@babel/types@^7.7.2", "@babel/types@^7.7.4": +"@babel/types@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" integrity sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA== @@ -921,31 +1041,40 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@bazel/bazel-darwin_x64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-1.1.0.tgz#9402ecadfaf0383bc366ef5b37b933e0d0e804fc" - integrity sha512-/dnpkjqnl2Qrcy+qFerOe+lV9QZ2HoUHtTplQgRxa+OH8AtQ7mcopdJ9/3Y10GqgT2Kp+AR6G99R59/Si+BOMg== +"@babel/types@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" -"@bazel/bazel-linux_x64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-1.1.0.tgz#98d75240e3e9ff5ba14fa48d6241d5d741e89926" - integrity sha512-yDR1URphRQTkXYjl4U2NLmbGR8ar8imhytK3txZZqlPf5pfWI/7wa7gSg0H4VbRRLIGAy/nD2eXZpgSj1eUiqA== +"@bazel/bazel-darwin_x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-darwin_x64/-/bazel-darwin_x64-2.0.0.tgz#bd678069216dd470c6816a22c405f21e7f048038" + integrity sha512-I/pP+B+2xfY0g+OEpEcVnk8rizuC761pAzBOQjP3b+gz3AzeRgm05CpcSY7tfPIppMSYoy3uTZJ1XlwgUg7IQQ== -"@bazel/bazel-win32_x64@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-1.1.0.tgz#e9c80a8c6495834ee7fc6184c425284d1151ac38" - integrity sha512-mj3ujcifKO+hjAjHvLoutYxzs90YWuc/fYJuVaEQrk4YFrRW5g70OpjN74zzBHRstObOjSZ3cOj+HDB19SIFKw== +"@bazel/bazel-linux_x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-linux_x64/-/bazel-linux_x64-2.0.0.tgz#2c76e3301e9178a90ec3ad00649e89b953eda0b7" + integrity sha512-iOr45G+511IbP7e+ISriG97WpfCAVXekTrTgL5mGg3NDBFCVNs350VquHAvmlXAoP5+IEug2pCOlkdEl4bLl8g== -"@bazel/bazel@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@bazel/bazel/-/bazel-1.1.0.tgz#9ce8308e44d76132812e908fcbc9e9051c7c2e1a" - integrity sha512-3NOWRHG1i/tAVQWuStIUuliFLVfjcKMbqIlc2Q206VWQ5pjlKgo0qa+qrWb0G6BYq+N3hxT4IwBz+Z17A8dbbg== +"@bazel/bazel-win32_x64@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel-win32_x64/-/bazel-win32_x64-2.0.0.tgz#f12ac0738d2eac0fd255f099776194807cedfe50" + integrity sha512-5qs2qoa/paG/YYEM0yvrwuJIShoPVK2FX+Oz9jEWAQJsmU4drHA9Aq+gbBOirEFLmvYhleZ9XORCwu/5uAo8vA== + +"@bazel/bazel@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@bazel/bazel/-/bazel-2.0.0.tgz#feb8cf5a40ea6437ef69cac2a92072118b11c230" + integrity sha512-KQbv5dHNSfutbhXCc3KVMuBXPpUh6Af/hT9IRIaMTuiB6Nq2gEW9Z3aNqncopdZqV848V/qYxnqPnQ+S37fMyQ== dependencies: "@bazel/hide-bazel-files" latest optionalDependencies: - "@bazel/bazel-darwin_x64" "1.1.0" - "@bazel/bazel-linux_x64" "1.1.0" - "@bazel/bazel-win32_x64" "1.1.0" + "@bazel/bazel-darwin_x64" "2.0.0" + "@bazel/bazel-linux_x64" "2.0.0" + "@bazel/bazel-win32_x64" "2.0.0" "@bazel/buildifier-darwin_x64@0.29.0": version "0.29.0" @@ -976,46 +1105,46 @@ resolved "https://registry.yarnpkg.com/@bazel/hide-bazel-files/-/hide-bazel-files-0.34.0.tgz#368ea84db2756ff80ead23bb9eb179e9ed24b462" integrity sha512-suyO6cZf8iV6W2LkM1X1spWBt7CsRRXH7gU1wYNuAuHYkkfI0A6qj84yPiIXiOt/2G44kbioGyC1bUsI3fKv7A== -"@bazel/ibazel@^0.10.3": - version "0.10.3" - resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.10.3.tgz#2e2b8a1d3e885946eac41db2b1aa6801fb319887" - integrity sha512-v1nXbMTHVlMM4z4uWp6XiRoHAyUlYggF1SOboLLWRp0+D22kWixqArWqnozLw2mOtnxr97BdLjluWiho6A8Hjg== +"@bazel/ibazel@^0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.11.1.tgz#c07ceaded388f1e39d6aa732953e0dd04f3dbdf0" + integrity sha512-qAdEquFAudYyN+CYfLzvuRWNubdsh6C8+o5CiViUEfchq1HQM5Rs8xAOE3fzGsTZ1EUsvgca/PY0kn0VIxckBA== -"@bazel/jasmine@0.42.2": - version "0.42.2" - resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-0.42.2.tgz#38e0d715e519e7ce4bce7d55b3e8accb2aad8217" - integrity sha512-OgxX84wPeWlHi4O2m0ezH9gTGx+wp3MR7QcC46PIIjWKL4W4L0Buss0R9AJeNTtxpjfv+8hfrDUI0bf2ZEIIjQ== +"@bazel/jasmine@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-1.2.2.tgz#0fc9b0084b38311cf59c825a7dda8c6421351379" + integrity sha512-fFTWtxj8KWBPC1Gcl+uD641dEQwkVCclGCtpqIhogq+cZQDJk3/pc3qfVDGXjLKIRr7BId+Tnu5Y2sc+zdKeSg== dependencies: jasmine "~3.4.0" jasmine-core "~3.4.0" v8-coverage "1.0.9" -"@bazel/karma@0.42.2": - version "0.42.2" - resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-0.42.2.tgz#24e2cf150a5da1fbdeb9382822b0ba7e662455a1" - integrity sha512-fNrZ8fIHTFwr7DGKtZLFLZxV/7+txZfiHH6bDN73qOId91RY7rr82BHgZx/iDQqnaKCW0+o9i2gPqu7lutVc8g== +"@bazel/karma@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.2.2.tgz#545c0f86f921229879511a9a0b2edba1329a1fb8" + integrity sha512-jUTv6DKoLkU3VUIFHCTnRU94qbOBPRZYbg7//2AnzHAS77SQyIAEUG5xU/W26+kle+sj7nBMavlMOxLjsrpMFA== dependencies: tmp "0.1.0" -"@bazel/protractor@0.42.2": - version "0.42.2" - resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-0.42.2.tgz#f20acd64e9456434cdc56903186fa31144a462a6" - integrity sha512-0LpRnaeL6/QHnNTK561aKFxAh4nECUNxrouC15XGWb57emj1q4a/IScAGwPrnb5dBQl1ZlgDXzyz/bqG928L1g== +"@bazel/protractor@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.2.2.tgz#33bd58dfbfa33f1ec4b037ef5d4edc5de130aa2b" + integrity sha512-PgE/VAwgvtlFPKdCR1o2ofZyc4khLeEu+nztzuohZ1MqD5Yn5tx6QGhOAhLDLNCim1DRqRXct7LerAy1VNm5iA== -"@bazel/rollup@0.42.2": - version "0.42.2" - resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-0.42.2.tgz#b7a6495e1c506e3684448140395be80c45420271" - integrity sha512-SiXxuydxC3+jZIfS8oib3YyXBXeoA816bYdnIdVJX0WNgIMStdvGm7a/UU20KlbOWBx7qKB+mCSjSQa6C2FBnQ== +"@bazel/rollup@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.2.2.tgz#f5522ac308c41c6e11cbbdf3f0300a1db885410d" + integrity sha512-TGdL06eO8ARHEGVYdwA4MXoVM/V8EeFhi2DAMK+VrN609B7/CvtukdlT9KnuAONo5W7mttPzyuCgsvkaADrNOA== -"@bazel/terser@0.42.2": - version "0.42.2" - resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-0.42.2.tgz#392e150af530d1eaf56ba388161e6f7f107e6be3" - integrity sha512-DlsmZyTWQFKiQbCKK/CDcRism1xrV1f7fLU166cXUIokXfkCaVCbN2ViaB5fDFcRpBQaNKowdM37Y5O7282Low== +"@bazel/terser@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.2.2.tgz#a245e345028fd0e15b76b67da1a60c0d9635c76f" + integrity sha512-IsHxbSjbNesSjIQDRpm1tDPwiHadTQIIIOUgtQQN1hDlzmDufTNvqGpB+34MeSLNzn2KVHObqYbYs6LVpW1a8A== -"@bazel/typescript@0.42.2": - version "0.42.2" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-0.42.2.tgz#6c8e2187e9f7f937650c8b4e2350dc7d46284cb1" - integrity sha512-9HS8W6Wv74zhjvyP2rwym05TwzB8/c3Pxxi4gfjwjwxaDAIZCQfC8UGSRxeCm5t0JNz485W1/0WScoACjcASCQ== +"@bazel/typescript@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.2.2.tgz#9acb8e07d1bd2b5d9c7afd01b434687b277f9dcb" + integrity sha512-qEkkkLOsKvcTvyToiMLVTU67iEHTOzVUIJGDo3+7g8vRL4OqG9EWk0ooNzVLWZ129Caz9TyVyleh1RhuReJWOw== dependencies: protobufjs "6.8.8" semver "5.6.0" @@ -1082,6 +1211,11 @@ lodash.camelcase "^4.3.0" protobufjs "^6.8.6" +"@istanbuljs/schema@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + "@microsoft/api-extractor-model@7.3.2": version "7.3.2" resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.3.2.tgz#71229ba80f8aafc56afe4d3ee83f19b1ce72eb24" @@ -1135,12 +1269,12 @@ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.12.tgz#6692f1cbca664f68abbc62f9a26459fba8b9ff28" integrity sha512-5EzH1gHIonvvgA/xWRmVAJmRkTQj/yayUXyr66hFwNZiFE4j7lP8is9YQeXhwxGZEjO1PVMblAmFF0CyjNtPGw== -"@ngtools/webpack@9.0.0-rc.3": - version "9.0.0-rc.3" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-9.0.0-rc.3.tgz#54988e1414ec4ca25fc38d5fd2f38798ab75ab6f" - integrity sha512-gtfcdqah+4pHsClliEUFr5OZS36IkHLDjU69CNW81/BQ1NhRRMMmVVlpTl74pnOtGzFU0DjqeMK/zdx/UD88UA== +"@ngtools/webpack@9.0.0-rc.11": + version "9.0.0-rc.11" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-9.0.0-rc.11.tgz#10b5997bec7cf48d1b144c8b4d46ffd0039c522a" + integrity sha512-qeW81ISiO8GVEndOaCYv0k6fzRIxzZs6jrXGl1pcLH1H6qv2mxhA5DA0vC/9TN6wenrS43RGjDIQpp+RvkiLwA== dependencies: - "@angular-devkit/core" "9.0.0-rc.3" + "@angular-devkit/core" "9.0.0-rc.11" enhanced-resolve "4.1.1" rxjs "6.5.3" webpack-sources "1.4.3" @@ -1198,21 +1332,29 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= -"@schematics/angular@9.0.0-rc.3", "@schematics/angular@^9.0.0-rc.3": - version "9.0.0-rc.3" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.0.0-rc.3.tgz#804fc0a360109298ec694d77bdaadcd3652cf094" - integrity sha512-HIOlaReZFGQpjoLxGqDpNbw0UDg306KrPTDZ8eI0lSEAz6KKY3CsMWSGZ57cKRfw5PJYIybbpWeIvGsXq6i7uQ== +"@schematics/angular@9.0.0-rc.11": + version "9.0.0-rc.11" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.0.0-rc.11.tgz#d544c0d4e7b3dd59ed56be5183e038ebe06a165e" + integrity sha512-9InC+F71KiPXE0jl7Ow4iPFJ2AZZDbfTM6yWZoYLk3hzTCohAZZciBl00Tfyu2uerGshx8akbJMLySjXtf+q0g== dependencies: - "@angular-devkit/core" "9.0.0-rc.3" - "@angular-devkit/schematics" "9.0.0-rc.3" + "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/schematics" "9.0.0-rc.11" -"@schematics/update@0.900.0-rc.3": - version "0.900.0-rc.3" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.900.0-rc.3.tgz#b33b1d006fd76b6fc7a19ab3c84251d6ffc7fb9b" - integrity sha512-+CFVwY3hLE54ZOjf1Big+49XW92Aiu7+wgU/kXnKhAGx7HtM4jflfMMtMJq2IjmBfr3+ObjwETSBQkWv4RtGYw== +"@schematics/angular@9.0.0-rc.8": + version "9.0.0-rc.8" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.0.0-rc.8.tgz#5fb7458d242efacf33a442b1b4fc156a5ec71999" + integrity sha512-1c7Sv74B2Fh3hr+80Yc0DVYIRYvbV8Z9k7hiqbXMT35+vulG6nZfHt88QSePChReY+TKreuPVdvBMjUQR/Zm/w== dependencies: - "@angular-devkit/core" "9.0.0-rc.3" - "@angular-devkit/schematics" "9.0.0-rc.3" + "@angular-devkit/core" "9.0.0-rc.8" + "@angular-devkit/schematics" "9.0.0-rc.8" + +"@schematics/update@0.900.0-rc.11": + version "0.900.0-rc.11" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.900.0-rc.11.tgz#d22df30f13a6f38970b759db61ad84d3f9b03a78" + integrity sha512-nV0oCPzzd0vi2Exo1910rWXwz/RnMc4zF9FxSOCZzsIv+AkwIehhL815OKyjUSCzU9+IM0/o1LKkPPrSWK7QEA== + dependencies: + "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/schematics" "9.0.0-rc.11" "@yarnpkg/lockfile" "1.1.0" ini "1.3.5" npm-package-arg "^7.0.0" @@ -1254,6 +1396,13 @@ dependencies: "@babel/types" "^7.0.0" +"@types/babel__generator@^7.6.1": + version "7.6.1" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" + integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== + dependencies: + "@babel/types" "^7.0.0" + "@types/babel__template@*": version "7.0.2" resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" @@ -1292,6 +1441,11 @@ "@types/events" "*" "@types/node" "*" +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + "@types/convert-source-map@^1.5.1": version "1.5.1" resolved "https://registry.yarnpkg.com/@types/convert-source-map/-/convert-source-map-1.5.1.tgz#d4d180dd6adc5cb68ad99bd56e03d637881f4616" @@ -1438,6 +1592,11 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" integrity sha1-vShOV8hPEyXacCur/IKlMoGQwMU= +"@types/q@^1.5.1": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" + integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== + "@types/resolve@0.0.8": version "0.0.8" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" @@ -1552,9 +1711,9 @@ integrity sha512-tHdDdGUBKTbiLLwf5mF78EP35F31UZekG+GRNowl8G5rMQoupAT4qWn/7AaGOvmaqvROdqC3Io/hP1ZyO58QkA== "@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== + version "3.0.16" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a" + integrity sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA== "@types/semver@^6.0.2": version "6.0.2" @@ -1605,6 +1764,19 @@ resolved "https://registry.yarnpkg.com/@types/z-schema/-/z-schema-3.16.31.tgz#2eb1d00a5e4ec3fa58c76afde12e182b66dc5c1c" integrity sha1-LrHQCl5Ow/pYx2r94S4YK2bcXBw= +"@typescript-eslint/typescript-estree@^2.4.0": + version "2.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.16.0.tgz#b444943a76c716ed32abd08cbe96172d2ca0ab75" + integrity sha512-hyrCYjFHISos68Bk5KjUAXw0pP/455qq9nxqB1KkT67Pxjcfw+r6Yhcmqnp8etFL45UexCHUMrADHH7dI/m2WQ== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^6.3.0" + tsutils "^3.17.1" + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -1815,16 +1987,6 @@ accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn@^1.0.3: - version "1.2.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014" - integrity sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ= - -acorn@^5.2.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" - integrity sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ== - acorn@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" @@ -1845,11 +2007,16 @@ add-stream@^1.0.0: resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= -adm-zip@0.4.11, adm-zip@^0.4.9, adm-zip@~0.4.3, adm-zip@~0.4.x: +adm-zip@0.4.11, adm-zip@~0.4.3, adm-zip@~0.4.x: version "0.4.11" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.11.tgz#2aa54c84c4b01a9d0fb89bb11982a51f13e3d62a" integrity sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA== +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" @@ -1917,7 +2084,7 @@ ajv@6.10.2, ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^5.0.0, ajv@^5.1.0: +ajv@^5.1.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= @@ -1927,17 +2094,10 @@ ajv@^5.0.0, ajv@^5.1.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= - -amdetective@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/amdetective/-/amdetective-0.0.2.tgz#260777ab35a6b9ba6edd1b8d7280d3a8ef4859b0" - integrity sha1-Jgd3qzWmubpu3RuNcoDTqO9IWbA= - dependencies: - esprima "~1.2.2" +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= "angular-1.5@npm:angular@1.5": version "1.5.11" @@ -2046,6 +2206,11 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -2058,6 +2223,14 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + ansi-wrap@0.1.0, ansi-wrap@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -2099,6 +2272,11 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +app-module-path@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" + integrity sha1-ZBqlXft9am8KgUHEucCqULbCTdU= + aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -2388,10 +2566,10 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-types@0.9.6: - version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" - integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk= +ast-module-types@^2.3.1, ast-module-types@^2.3.2, ast-module-types@^2.4.0, ast-module-types@^2.5.0, ast-module-types@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/ast-module-types/-/ast-module-types-2.6.0.tgz#f9f367fd273bbe01e52f2c51b5f46b65801d5d7f" + integrity sha512-zXSoVaMrf2R+r+ISid5/9a8SXm1LLdkhHzh6pSRhj9jklzruOOl1hva1YmFT33wAstg/f9ZndJAlq1BSrFLSGA== async-each@^1.0.1: version "1.0.1" @@ -2475,7 +2653,7 @@ aws4@^1.6.0, aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.22.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= @@ -2484,20 +2662,6 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: 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-loader@8.0.6: version "8.0.6" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" @@ -2508,13 +2672,6 @@ babel-loader@8.0.6: mkdirp "^0.5.1" pify "^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-dynamic-import-node@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" @@ -2531,7 +2688,7 @@ babel-polyfill@6.16.0: core-js "^2.4.0" regenerator-runtime "^0.9.5" -babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.1: +babel-runtime@^6.9.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -2539,47 +2696,6 @@ babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.1: 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" @@ -2590,11 +2706,6 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base62@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/base62/-/base62-0.1.1.tgz#7b4174c2f94449753b11c2651c083da841a7b084" - integrity sha1-e0F0wvlESXU7EcJlHAg9qEGnsIQ= - base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" @@ -2805,6 +2916,11 @@ bonjour@^3.5.0: multicast-dns "^6.0.1" multicast-dns-service-types "^1.1.0" +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + boom@2.x.x: version "2.10.1" resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" @@ -2936,16 +3052,25 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@4.7.2: - version "4.7.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.2.tgz#1bb984531a476b5d389cedecb195b2cd69fb1348" - integrity sha512-uZavT/gZXJd2UTi9Ov7/Z340WOSQ3+m1iBVRUknf+okKxonL9P83S3ctiBDtuRmRu8PiCHjqyueqQ9HYlJhxiw== +browserslist@4.8.3, browserslist@^4.8.3: + version "4.8.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.3.tgz#65802fcd77177c878e015f0e3189f2c4f627ba44" + integrity sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg== dependencies: - caniuse-lite "^1.0.30001004" - electron-to-chromium "^1.3.295" - node-releases "^1.1.38" + caniuse-lite "^1.0.30001017" + electron-to-chromium "^1.3.322" + node-releases "^1.1.44" -browserslist@^4.6.0, browserslist@^4.7.2, browserslist@^4.7.3: +browserslist@^4.0.0: + version "4.8.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.5.tgz#691af4e327ac877b25e7a3f7ee869c4ef36cdea3" + integrity sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg== + dependencies: + caniuse-lite "^1.0.30001022" + electron-to-chromium "^1.3.338" + node-releases "^1.1.46" + +browserslist@^4.6.0, browserslist@^4.7.2: version "4.7.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.3.tgz#02341f162b6bcc1e1028e30624815d4924442dc3" integrity sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ== @@ -3108,27 +3233,7 @@ cacache@13.0.1, cacache@^13.0.1: ssri "^7.0.0" unique-filename "^1.1.1" -cacache@^11.3.3: - version "11.3.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc" - integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - 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.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^12.0.0, cacache@^12.0.2: +cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: version "12.0.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== @@ -3220,16 +3325,36 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@1.0.30001006: - version "1.0.30001006" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001006.tgz#5b6e8288792cfa275f007b2819a00ccad7112655" - integrity sha512-MXnUVX27aGs/QINz+QG1sWSLDr3P1A3Hq5EUWoIt0T7K24DuvMxZEnh3Y5aHlJW6Bz2aApJdSewdYLd8zQnUuw== +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" -caniuse-lite@^1.0.30001004, caniuse-lite@^1.0.30001006, caniuse-lite@^1.0.30001010: +caniuse-lite@1.0.30001020: + version "1.0.30001020" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001020.tgz#3f04c1737500ffda78be9beb0b5c1e2070e15926" + integrity sha512-yWIvwA68wRHKanAVS1GjN8vajAv7MBFshullKCeq/eKpK7pJBVDgFFEqvgWTkcP2+wIDeQGYFRXECjKZnLkUjA== + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001022: + version "1.0.30001022" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz#9eeffe580c3a8f110b7b1742dcf06a395885e4c6" + integrity sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A== + +caniuse-lite@^1.0.30001006, caniuse-lite@^1.0.30001010: version "1.0.30001011" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001011.tgz#0d6c4549c78c4a800bb043a83ca0cbe0aee6c6e1" integrity sha512-h+Eqyn/YA6o6ZTqpS86PyRmNWOs1r54EBDcd2NTwwfsXQ8re1B38SnB+p2RKF8OUsyEIjeDU8XGec1RGO/wYCg== +caniuse-lite@^1.0.30001017: + version "1.0.30001021" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001021.tgz#e75ed1ef6dbadd580ac7e7720bb16f07b083f254" + integrity sha512-wuMhT7/hwkgd8gldgp2jcrUjOU9RXJ4XxGumQeOsUr91l3WwmM68Cpa/ymCnWEDqakwFXhuDQbaKNHXBPgeE9g== + canonical-path@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d" @@ -3304,6 +3429,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-spinner@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/char-spinner/-/char-spinner-1.0.1.tgz#e6ea67bd247e107112983b7ab0479ed362800081" @@ -3365,26 +3498,7 @@ chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.1.tgz#adc39ad55a2adf26548bd2afa048f611091f9184" - integrity sha512-gfw3p2oQV2wEt+8VuMlNsPjCxDxvvgnm/kz+uATu805mWVF8IJN7uz9DN7iBz+RMJISmiVbCOBFs9qBGMjtPfQ== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.0" - optionalDependencies: - fsevents "^1.2.7" - -chokidar@^3.0.2: +chokidar@^3.0.0, chokidar@^3.0.2: version "3.3.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== @@ -3505,13 +3619,6 @@ cldrjs@0.5.0: resolved "https://registry.yarnpkg.com/cldrjs/-/cldrjs-0.5.0.tgz#37be92d8d1a8e66c8ee12f1303ed316d85d8eb37" integrity sha1-N76S2NGo5myO4S8TA+0xbYXY6zc= -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" - clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -3639,16 +3746,20 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + 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= -coffee-script@1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.3.3.tgz#150d6b4cb522894369efed6a2101c20bc7f4a4f4" - integrity sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ= - collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -3657,27 +3768,50 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.1: 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-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + 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= +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -colors@0.6.0-1: - version "0.6.0-1" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.0-1.tgz#6dbb68ceb8bc60f2b313dcc5ce1599f06d19e67a" - integrity sha1-bbtozri8YPKzE9zFzhWZ8G0Z5no= +color@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" + integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" colors@1.0.3, colors@1.0.x: version "1.0.3" @@ -3713,11 +3847,6 @@ combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-1.0.0.tgz#5e6a88e7070ff5908836ead19169548c30f90bcd" - integrity sha1-XmqI5wcP9ZCINurRkWlUjDD5C80= - commander@2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" @@ -3725,56 +3854,36 @@ commander@2.9.0: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.19.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== - -commander@^2.20.0, commander@~2.20.3: +commander@^2.13.0, commander@^2.16.0, commander@^2.20.0, commander@^2.8.1, commander@~2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^2.5.0, commander@^2.9.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" - integrity sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew== +commander@^2.19.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== 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== +commander@^2.9.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" + integrity sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew== + commander@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83" integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw== -commondir@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-0.0.1.tgz#89f00fdcd51b519c578733fec563e6a6da7f5be2" - integrity sha1-ifAP3NUbUZxXhzP+xWPmptp/W+I= - commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -commoner@^0.10.0: - version "0.10.8" - resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" - integrity sha1-NPw2cs0kOT6LtH5wyqApOBH08sU= - dependencies: - commander "^2.5.0" - detective "^4.3.1" - glob "^5.0.15" - graceful-fs "^4.1.2" - iconv-lite "^0.4.5" - mkdirp "^0.5.0" - private "^0.1.6" - q "^1.1.2" - recast "^0.11.17" - compare-func@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.2.tgz#99dd0ba457e1f9bc722b12c08ec33eeab31fa648" @@ -4090,25 +4199,18 @@ conventional-commits-parser@^3.0.0: through2 "^2.0.0" trim-off-newlines "^1.0.0" -convert-source-map@^1.1.0: - 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.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= -convert-source-map@^1.5.0, convert-source-map@^1.7.0: +convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== dependencies: safe-buffer "~5.1.1" -convert-source-map@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= - cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -4141,12 +4243,12 @@ 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@5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.0.4.tgz#c78126f604e24f194c6ec2f43a64e232b5d43655" - integrity sha512-YBuYGpSzoCHSSDGyHy6VJ7SHojKp6WHT4D7ItcQFNAYx2hrwkMe56e97xfVR0/ovDuMTrMffXUiltvQljtAGeg== +copy-webpack-plugin@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88" + integrity sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg== dependencies: - cacache "^11.3.3" + cacache "^12.0.3" find-cache-dir "^2.1.0" glob-parent "^3.1.0" globby "^7.1.1" @@ -4154,23 +4256,23 @@ copy-webpack-plugin@5.0.4: loader-utils "^1.2.3" minimatch "^3.0.4" normalize-path "^3.0.0" - p-limit "^2.2.0" + p-limit "^2.2.1" schema-utils "^1.0.0" - serialize-javascript "^1.7.0" + serialize-javascript "^2.1.2" webpack-log "^2.0.0" -core-js-compat@^3.1.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.4.2.tgz#652fa7c54652b7f6586a893e37001df55ea2ac37" - integrity sha512-W0Aj+LM3EAxxjD0Kp2o4be8UlnxIZHNupBv2znqrheR4aY2nOn91794k/xoSp+SxqqriiZpTsSwBtZr60cbkwQ== +core-js-compat@^3.6.0: + version "3.6.4" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" + integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== dependencies: - browserslist "^4.7.3" - semver "^6.3.0" + browserslist "^4.8.3" + semver "7.0.0" -core-js@3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.3.6.tgz#6ad1650323c441f45379e176ed175c0d021eac92" - integrity sha512-u4oM8SHwmDuh5mWZdDg9UwNVq5s1uqq6ZDLLIs07VY+VJU91i3h4f3K/pgFvtUQPGdeStrZ+odKyfyt4EnKHfA== +core-js@3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.0.tgz#2b854e451de1967d1e29896025cdc13a2518d9ea" + integrity sha512-AHPTNKzyB+YwgDWoSOCaid9PUSEF6781vsfiK8qUz62zRR448/XgK2NtCbpiUGizbep8Lrpt0Du19PpGGZvw3Q== core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: version "2.5.7" @@ -4202,6 +4304,17 @@ cosmiconfig@^5.0.0: js-yaml "^3.13.1" parse-json "^4.0.0" +coverage-istanbul-loader@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz#87d42f03fa0fd3fa8743ec76945d9d67f105722a" + integrity sha512-LiGRvyIuzVYs3M1ZYK1tF0HekjH0DJ8zFdUwAZq378EJzqOgToyb1690dp3TAUlP6Y+82uu42LRjuROVeJ54CA== + dependencies: + convert-source-map "^1.7.0" + istanbul-lib-instrument "^4.0.0" + loader-utils "^1.2.3" + merge-source-map "^1.1.0" + schema-utils "^2.6.1" + crc32-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" @@ -4327,6 +4440,19 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + css-parse@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" @@ -4334,6 +4460,39 @@ css-parse@~2.0.0: dependencies: css "^2.0.0" +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-unit-converter@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" + integrity sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY= + +css-what@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1" + integrity sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw== + css@^2.0.0: version "2.2.4" resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" @@ -4344,6 +4503,86 @@ css@^2.0.0: source-map-resolve "^0.5.2" urix "^0.1.0" +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + +cssnano-preset-default@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" + integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== + dependencies: + css-declaration-sorter "^4.0.1" + cssnano-util-raw-cache "^4.0.1" + postcss "^7.0.0" + postcss-calc "^7.0.1" + postcss-colormin "^4.0.3" + postcss-convert-values "^4.0.1" + postcss-discard-comments "^4.0.2" + postcss-discard-duplicates "^4.0.2" + postcss-discard-empty "^4.0.1" + postcss-discard-overridden "^4.0.1" + postcss-merge-longhand "^4.0.11" + postcss-merge-rules "^4.0.3" + postcss-minify-font-values "^4.0.2" + postcss-minify-gradients "^4.0.2" + postcss-minify-params "^4.0.2" + postcss-minify-selectors "^4.0.2" + postcss-normalize-charset "^4.0.1" + postcss-normalize-display-values "^4.0.2" + postcss-normalize-positions "^4.0.2" + postcss-normalize-repeat-style "^4.0.2" + postcss-normalize-string "^4.0.2" + postcss-normalize-timing-functions "^4.0.2" + postcss-normalize-unicode "^4.0.1" + postcss-normalize-url "^4.0.1" + postcss-normalize-whitespace "^4.0.2" + postcss-ordered-values "^4.1.2" + postcss-reduce-initial "^4.0.3" + postcss-reduce-transforms "^4.0.2" + postcss-svgo "^4.0.2" + postcss-unique-selectors "^4.0.1" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@4.1.10: + version "4.1.10" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" + integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.7" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d" + integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg== + dependencies: + css-tree "1.0.0-alpha.37" + csv-streamify@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/csv-streamify/-/csv-streamify-3.0.4.tgz#4cb614c57e3f299cca17b63fdcb4ad167777f47a" @@ -4415,7 +4654,7 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: +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== @@ -4429,7 +4668,7 @@ debug@3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1: +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -4473,6 +4712,13 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +decomment@^0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/decomment/-/decomment-0.9.2.tgz#4dffdfbe96a32b0fdf301f758b7f92f7fbe82ab4" + integrity sha512-sblyUmOJZxiL7oJ2ogJS6jtl/67+CTOW87SrYE/96u3PhDYikYoLCdLzcnceToiQejOLlqNnLCkaxx/+nE/ehg== + dependencies: + esprima "4.0.1" + decompress-zip@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/decompress-zip/-/decompress-zip-0.3.0.tgz#ae3bcb7e34c65879adfe77e19c30f86602b4bdb0" @@ -4510,7 +4756,7 @@ 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: +deep-is@^0.1.3, 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= @@ -4564,11 +4810,6 @@ define-property@^2.0.2: 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" - integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= - del@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -4615,6 +4856,16 @@ dependency-graph@^0.7.2: resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== +dependency-tree@^7.0.2: + version "7.2.0" + resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-7.2.0.tgz#1dc8ea13c5623f5eab99b28a4fd4f4eca0809168" + integrity sha512-41LepYuMZNfd/wk7ppfhaOp8dzzd37t9hLP8XKg9WDQZ3u2WmNCR3eZOF/6jDatV+3OL4ChOON9a/UIeC75bYw== + dependencies: + commander "^2.19.0" + debug "^4.1.1" + filing-cabinet "^2.5.1" + precinct "^6.2.0" + deprecated@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" @@ -4638,13 +4889,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -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" @@ -4655,27 +4899,82 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== -detective-es6@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/detective-es6/-/detective-es6-1.1.0.tgz#7c036e1f9469a848a527201edf6ec5a2eef3adab" - integrity sha1-fANuH5RpqEilJyAe327Fou7zras= +detective-amd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/detective-amd/-/detective-amd-3.0.0.tgz#40c8e21e229df8bca1ee2d4b952a7b67b01e2a5a" + integrity sha512-kOpKHyabdSKF9kj7PqYHLeHPw+TJT8q2u48tZYMkIcas28el1CYeLEJ42Nm+563/Fq060T5WknfwDhdX9+kkBQ== dependencies: - node-source-walk "~1.4.0" + ast-module-types "^2.3.1" + escodegen "^1.8.0" + get-amd-module-type "^3.0.0" + node-source-walk "^4.0.0" -detective@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/detective/-/detective-0.1.1.tgz#f1e04fe973754c8907ae51edd3e230e380d76fe9" - integrity sha1-8eBP6XN1TIkHrlHt0+Iw44DXb+k= +detective-cjs@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/detective-cjs/-/detective-cjs-3.1.1.tgz#18da3e39a002d2098a1123d45ce1de1b0d9045a0" + integrity sha512-JQtNTBgFY6h8uT6pgph5QpV3IyxDv+z3qPk/FZRDT9TlFfm5dnRtpH39WtQEr1khqsUxVqXzKjZHpdoQvQbllg== dependencies: - uglify-js "~1.2.5" + ast-module-types "^2.4.0" + node-source-walk "^4.0.0" -detective@^4.3.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" - integrity sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig== +detective-es6@^2.0.0, detective-es6@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detective-es6/-/detective-es6-2.1.0.tgz#7848feaec92279d82f7b3a98d8e1f5d93483a0f7" + integrity sha512-QSHqKGOp/YBIfmIqKXaXeq2rlL+bp3bcIQMfZ+0PvKzRlELSOSZxKRvpxVcxlLuocQv4QnOfuWGniGrmPbz8MQ== dependencies: - acorn "^5.2.1" - defined "^1.0.0" + node-source-walk "^4.0.0" + +detective-less@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/detective-less/-/detective-less-1.0.2.tgz#a68af9ca5f69d74b7d0aa190218b211d83b4f7e3" + integrity sha512-Rps1xDkEEBSq3kLdsdnHZL1x2S4NGDcbrjmd4q+PykK5aJwDdP5MBgrJw1Xo+kyUHuv3JEzPqxr+Dj9ryeDRTA== + dependencies: + debug "^4.0.0" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-postcss@^3.0.0, detective-postcss@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detective-postcss/-/detective-postcss-3.0.1.tgz#511921951f66135e17d0ece2e7604c6e4966c9c6" + integrity sha512-tfTS2GdpUal5NY0aCqI4dpEy8Xfr88AehYKB0iBIZvo8y2g3UsrcDnrp9PR2FbzoW7xD5Rip3NJW7eCSvtqdUw== + dependencies: + debug "^4.1.1" + is-url "^1.2.4" + postcss "^7.0.2" + postcss-values-parser "^1.5.0" + +detective-sass@^3.0.0, detective-sass@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detective-sass/-/detective-sass-3.0.1.tgz#496b819efd1f5c4dd3f0e19b43a8634bdd6927c4" + integrity sha512-oSbrBozRjJ+QFF4WJFbjPQKeakoaY1GiR380NPqwdbWYd5wfl5cLWv0l6LsJVqrgWfFN1bjFqSeo32Nxza8Lbw== + dependencies: + debug "^4.1.1" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-scss@^2.0.0, detective-scss@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/detective-scss/-/detective-scss-2.0.1.tgz#06f8c21ae6dedad1fccc26d544892d968083eaf8" + integrity sha512-VveyXW4WQE04s05KlJ8K0bG34jtHQVgTc9InspqoQxvnelj/rdgSAy7i2DXAazyQNFKlWSWbS+Ro2DWKFOKTPQ== + dependencies: + debug "^4.1.1" + gonzales-pe "^4.2.3" + node-source-walk "^4.0.0" + +detective-stylus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detective-stylus/-/detective-stylus-1.0.0.tgz#50aee7db8babb990381f010c63fabba5b58e54cd" + integrity sha1-UK7n24uruZA4HwEMY/q7pbWOVM0= + +detective-typescript@^5.1.1, detective-typescript@^5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/detective-typescript/-/detective-typescript-5.7.0.tgz#513a000e08bcfa0b5656fc7e499a554659b9dda8" + integrity sha512-4SQeACXWAjIOsd2kJykPL8gWC9nVA+z8w7KtAdtd/7BCpDfrpI2ZA7pdhsmHv/zxf3ofeqpYi72vCkZ65bAjtA== + dependencies: + "@typescript-eslint/typescript-estree" "^2.4.0" + ast-module-types "^2.5.0" + node-source-walk "^4.2.0" + typescript "^3.6.4" dezalgo@^1.0.0: version "1.0.3" @@ -4764,16 +5063,42 @@ dom-serialize@^2.2.0: extend "^3.0.0" void-elements "^2.0.0" +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^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== +domelementtype@1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" + integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== + domino@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.2.tgz#70e8367839ee8ad8bde3aeb4857cf3d93bd98b85" integrity sha512-nzg76s4Smji9teyLwOnqqUCdFVOho+OQFqUwp+42Wo+SEZ1FGw7uhemv6OKk2qp8YIgnGB3jVt0sJWU96wbPgA== +domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + dot-prop@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" @@ -4781,7 +5106,7 @@ dot-prop@^3.0.0: dependencies: is-obj "^1.0.0" -dot-prop@^4.1.0: +dot-prop@^4.1.0, dot-prop@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== @@ -4874,11 +5199,21 @@ 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.295, electron-to-chromium@^1.3.306: +electron-to-chromium@^1.3.306: version "1.3.311" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.311.tgz#73baa361e2b1f44b7b4f1a443aaa1372f8074ebb" integrity sha512-7GH6RKCzziLzJ9ejmbiBEdzHZsc6C3eRpav14dmRfTWMpNgMqpP1ukw/FU/Le2fR+ep642naq7a23xNdmh2s+A== +electron-to-chromium@^1.3.322: + version "1.3.334" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.334.tgz#0588359f4ac5c4185ebacdf5fc7e1937e2c99872" + integrity sha512-RcjJhpsVaX0X6ntu/WSBlW9HE9pnCgXS9B8mTUObl1aDxaiOa0Lu+NMveIS5IDC+VELzhM32rFJDCC+AApVwcA== + +electron-to-chromium@^1.3.338: + version "1.3.340" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz#5d4fe78e984d4211194cf5a52e08069543da146f" + integrity sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww== + elliptic@^6.0.0: version "6.5.2" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" @@ -4999,6 +5334,11 @@ entities@1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= +entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" + integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== + err-code@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" @@ -5018,6 +5358,23 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: + version "1.17.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" + integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + es-abstract@^1.5.1: version "1.15.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.15.0.tgz#8884928ec7e40a79e3c9bc812d37d10c8b24cc57" @@ -5043,6 +5400,15 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + es5-ext@^0.10.12, es5-ext@^0.10.30: version "0.10.45" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" @@ -5127,6 +5493,18 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^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.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.13.0.tgz#c7adf9bd3f3cc675bb752f202f79a720189cab29" + integrity sha512-eYk2dCkxR07DsHA/X2hRBj0CFAZeri/LyDMc0C8JT1Hqi6JnVpMhJ7XFITbb0+yZS3lVkaPL2oCkZ3AVmeVbMw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -5135,26 +5513,16 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -esprima-fb@8001.1001.0-dev-harmony-fb: - version "8001.1001.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-8001.1001.0-dev-harmony-fb.tgz#c3190b05341d45643e093af70485ab4988e34d5e" - integrity sha1-wxkLBTQdRWQ+CTr3BIWrSYjjTV4= +eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -esprima@^4.0.0, esprima@~4.0.0: +esprima@4.0.1, esprima@^4.0.0, esprima@^4.0.1, 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== -esprima@~1.2.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" - integrity sha1-CZNQL+r2aBODJXVvMPmlH+7sEek= - -esprima@~3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= - esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" @@ -5162,7 +5530,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -5467,6 +5835,11 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + fast-text-encoding@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz#3e5ce8293409cfaa7177a71b9ca84e1b1e6f25ef" @@ -5512,6 +5885,11 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" +file-exists-dazinatorfork@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/file-exists-dazinatorfork/-/file-exists-dazinatorfork-1.0.2.tgz#cd8d0d85f63e39dc81eceb0b687c44a2cca95c47" + integrity sha512-r70c72ln2YHzQINNfxDp02hAhbGkt1HffZ+Du8oetWDLjDtFja/Lm10lUaSh9e+wD+7VDvPee0b0C9SAy8pWZg== + file-loader@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.2.0.tgz#5fb124d2369d7075d70a9a5abecd12e60a95215e" @@ -5530,6 +5908,25 @@ filesize@^3.1.3: resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== +filing-cabinet@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/filing-cabinet/-/filing-cabinet-2.5.1.tgz#f920976d46310710595ed995f033a301570ef6ab" + integrity sha512-GWOdObzou2L0HrJUk8MpJa01q0ZOwuTwTssM2+P+ABJWEGlVWd6ueEatANFdin94/3rdkVSdqpH14VqCNqp3RA== + dependencies: + app-module-path "^2.2.0" + commander "^2.13.0" + debug "^4.1.1" + decomment "^0.9.2" + enhanced-resolve "^4.1.0" + is-relative-path "^1.0.2" + module-definition "^3.0.0" + module-lookup-amd "^6.1.0" + resolve "^1.11.1" + resolve-dependency-path "^2.0.0" + sass-lookup "^3.0.0" + stylus-lookup "^3.0.1" + typescript "^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" @@ -5602,10 +5999,10 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-cache-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.1.0.tgz#9935894999debef4cf9f677fdf646d002c4cdecb" - integrity sha512-zw+EFiNBNPgI2NTrKkDd1xd7q0cs6wr/iWnr/oUkI0yF9K9GqQ+riIt4aiyFaaqpaWbxPrJXHI+QvmNUQbX+0Q== +find-cache-dir@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.2.0.tgz#e7fe44c1abc1299f516146e563108fd1006c1874" + integrity sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg== dependencies: commondir "^1.0.1" make-dir "^3.0.0" @@ -5646,6 +6043,13 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" +find@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/find/-/find-0.3.0.tgz#4082e8fc8d8320f1a382b5e4f521b9bc50775cb8" + integrity sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw== + dependencies: + traverse-chain "~0.1.0" + findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" @@ -5790,6 +6194,11 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + 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" @@ -6097,6 +6506,19 @@ genfun@^5.0.0: resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-amd-module-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-amd-module-type/-/get-amd-module-type-3.0.0.tgz#bb334662fa04427018c937774570de495845c288" + integrity sha512-99Q7COuACPfVt18zH9N4VAMyb81S6TUgJm2NgV6ERtkh9VIkAaByZkW530wl3lLN5KTtSrK9jVLxYsoP5hQKsw== + dependencies: + ast-module-types "^2.3.2" + node-source-walk "^4.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" @@ -6112,6 +6534,11 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + get-pkg-repo@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d" @@ -6256,7 +6683,7 @@ glob2base@^0.0.12: dependencies: find-index "^0.1.1" -glob@5.x.x, glob@^5.0.15, glob@~5.0.0: +glob@5.x.x, glob@~5.0.0: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= @@ -6301,7 +6728,7 @@ glob@^4.3.1: minimatch "^2.0.1" once "^1.3.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.2, glob@^7.1.3, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -6366,11 +6793,6 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -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" @@ -6422,6 +6844,13 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" +gonzales-pe@^4.2.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.4.tgz#356ae36a312c46fe0f1026dd6cb539039f8500d2" + integrity sha512-v0Ts/8IsSbh9n1OJRnSfa7Nlxi4AkXIsWB6vPept8FDbL4bXn3FNuxjYtO/nmBGu7GDkL9MFeGebeSu6l55EPQ== + dependencies: + minimist "1.1.x" + google-auth-library@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" @@ -6518,10 +6947,10 @@ graceful-fs@4.2.2, graceful-fs@^3.0.0, graceful-fs@^4.1.0, graceful-fs@^4.1.11, resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= -graphviz@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/graphviz/-/graphviz-0.0.7.tgz#e5ae4b5429353a099609c9d4a4b518b95516efee" - integrity sha1-5a5LVCk1OgmWCcnUpLUYuVUW7+4= +graphviz@0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/graphviz/-/graphviz-0.0.9.tgz#0bbf1df588c6a92259282da35323622528c4bbc4" + integrity sha512-SmoY2pOtcikmMCqCSy2NO1YsRfu9OO0wpTlOYW++giGjfX1a6gax/m1Fo8IdUd0/3H15cTOfR1SMKwohj4LKsg== dependencies: temp "~0.4.0" @@ -6750,6 +7179,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + has-gulplog@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" @@ -6762,6 +7196,11 @@ has-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= +has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -6798,7 +7237,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1, has@^1.0.3: +has@^1.0.0, has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -6843,6 +7282,11 @@ he@^1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -6896,6 +7340,21 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-comment-regex@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" + integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== + html-entities@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" @@ -7062,7 +7521,7 @@ husky@^0.14.3: normalize-path "^1.0.0" strip-indent "^2.0.0" -iconv-lite@0.4.23, iconv-lite@^0.4.5: +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== @@ -7170,6 +7629,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" @@ -7301,6 +7765,11 @@ ipaddr.js@^1.9.0: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + is-absolute-url@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" @@ -7345,6 +7814,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + 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" @@ -7376,6 +7850,11 @@ is-callable@^1.1.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + is-ci@^1.0.10: version "1.2.1" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" @@ -7383,6 +7862,18 @@ is-ci@^1.0.10: dependencies: ci-info "^1.5.0" +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^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" @@ -7574,7 +8065,7 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.0: +is-obj@^1.0.0, is-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= @@ -7668,6 +8159,23 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" +is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== + dependencies: + has "^1.0.3" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-relative-path@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-relative-path/-/is-relative-path-1.0.2.tgz#091b46a0d67c1ed0fe85f1f8cfdde006bb251d46" + integrity sha1-CRtGoNZ8HtD+hfH4z93gBrslHUY= + is-relative@^0.1.0: version "0.1.3" resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.1.3.tgz#905fee8ae86f45b3ec614bc3c15c869df0876e82" @@ -7680,6 +8188,11 @@ is-relative@^1.0.0: dependencies: is-unc-path "^1.0.0" +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + is-retry-allowed@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" @@ -7705,6 +8218,13 @@ is-subset@^0.1.1: resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" integrity sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY= +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== + dependencies: + html-comment-regex "^1.1.0" + is-symbol@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" @@ -7731,7 +8251,7 @@ is-unc-path@^1.0.0: dependencies: unc-path-regex "^0.1.2" -is-url@^1.2.2: +is-url@^1.2.2, is-url@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== @@ -7817,33 +8337,28 @@ isstream@0.1.x, isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -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.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-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== +istanbul-lib-coverage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-instrument@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz#53321a7970f076262fd3292c8f9b2e4ac544aae1" + integrity sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ== 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" + "@babel/core" "^7.7.5" + "@babel/parser" "^7.7.5" + "@babel/template" "^7.7.4" + "@babel/traverse" "^7.7.4" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" istanbul-lib-report@^1.1.3: version "1.1.5" @@ -7917,7 +8432,7 @@ jasminewd2@^2.1.0: resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= -jest-worker@24.9.0, jest-worker@^24.9.0: +jest-worker@24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== @@ -7933,6 +8448,14 @@ jest-worker@^24.0.0: merge-stream "^1.0.1" supports-color "^6.1.0" +jest-worker@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.1.0.tgz#75d038bad6fdf58eba0d2ec1835856c497e3907a" + integrity sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg== + dependencies: + merge-stream "^2.0.0" + supports-color "^7.0.0" + jetpack-id@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/jetpack-id/-/jetpack-id-0.0.4.tgz#6fc35a394a4aea190820a2ce7f23d2bb53512a9b" @@ -8046,11 +8569,6 @@ jsbn@~0.1.0: 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" @@ -8195,15 +8713,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jstransform@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/jstransform/-/jstransform-8.2.0.tgz#e43f697f7cc01a1e7c827dd9df5a79d29d0c50bb" - integrity sha1-5D9pf3zAGh58gn3Z31p50p0MULs= - dependencies: - base62 "0.1.1" - esprima-fb "8001.1001.0-dev-harmony-fb" - source-map "0.1.31" - jszip@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jszip/-/jszip-2.4.0.tgz#487a93b76c3bffa6cb085cd61eb934eabe2d294f" @@ -8466,6 +8975,14 @@ less@3.10.3: 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.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.1.3.tgz#656fa6a8b2e711ee35c27ac8e1659a87240ef7f3" @@ -8747,6 +9264,11 @@ lodash.keys@~2.4.1: lodash._shimkeys "~2.4.1" lodash.isobject "~2.4.1" +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + lodash.noop@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" @@ -8815,6 +9337,11 @@ lodash.union@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + lodash.values@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.4.1.tgz#abf514436b3cb705001627978cbcf30b1280eea4" @@ -8947,23 +9474,32 @@ lru-queue@0.1: dependencies: es5-ext "~0.10.2" -madge@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/madge/-/madge-0.5.0.tgz#4da1ba55ccde09bd7642a8e721fe6cbcea32c60f" - integrity sha1-TaG6VczeCb12QqjnIf5svOoyxg8= +madge@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/madge/-/madge-3.6.0.tgz#f69e7c3e15a18a195e6bcd7942cc36efabcd9b9a" + integrity sha512-r4pCwKmihtzemQq8Y7edfkAKVKFqWU/AXTnDckwf1D4HOnX/uLAyWHQ+NgEo+FqBappi8wBzWJV5sFyQO2m6FQ== dependencies: - amdetective "0.0.2" - coffee-script "1.3.3" - colors "0.6.0-1" - commander "1.0.0" - commondir "0.0.1" - detective "0.1.1" - detective-es6 "1.1.0" - graphviz "0.0.7" - react-tools "0.12.1" - resolve "0.2.3" - uglify-js "1.2.6" - walkdir "0.0.5" + chalk "^3.0.0" + commander "^4.0.1" + commondir "^1.0.1" + debug "^4.0.1" + dependency-tree "^7.0.2" + detective-amd "^3.0.0" + detective-cjs "^3.1.1" + detective-es6 "^2.1.0" + detective-less "^1.0.2" + detective-postcss "^3.0.1" + detective-sass "^3.0.1" + detective-scss "^2.0.1" + detective-stylus "^1.0.0" + detective-typescript "^5.7.0" + graphviz "0.0.9" + ora "^4.0.2" + pify "^4.0.0" + pluralize "^8.0.0" + pretty-ms "^5.0.0" + rc "^1.2.7" + walkdir "^0.4.1" magic-string@0.25.4, magic-string@^0.25.2: version "0.25.4" @@ -8986,7 +9522,7 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" -make-dir@^2.0.0: +make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -9113,6 +9649,11 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -9222,6 +9763,13 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= +merge-source-map@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" + integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== + dependencies: + source-map "^0.6.1" + merge-stream@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" @@ -9408,6 +9956,11 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +minimist@1.1.x: + version "1.1.3" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" + integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= + minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -9493,7 +10046,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.x: +mkdirp@0.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1, mkdirp@~0.5.x: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -9517,6 +10070,26 @@ modify-values@^1.0.0: resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== +module-definition@^3.0.0, module-definition@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/module-definition/-/module-definition-3.3.0.tgz#aae06d68c99c5f93841e59b8a4469b974956d4d4" + integrity sha512-HTplA9xwDzH67XJFC1YvZMUElWJD28DV0dUq7lhTs+JKJamUOWA/CcYWSlhW5amJO66uWtY7XdltT+LfX0wIVg== + dependencies: + ast-module-types "^2.6.0" + node-source-walk "^4.0.0" + +module-lookup-amd@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/module-lookup-amd/-/module-lookup-amd-6.2.0.tgz#70600008b3f26630fde9ef9ae6165ac69de6ecbb" + integrity sha512-uxHCj5Pw9psZiC1znjU2qPsubt6haCSsN9m7xmIdoTciEgfxUkE1vhtDvjHPuOXEZrVJhjKgkmkP+w73rRuelQ== + dependencies: + commander "^2.8.1" + debug "^4.1.0" + file-exists-dazinatorfork "^1.0.2" + find "^0.3.0" + requirejs "^2.3.5" + requirejs-config-file "^3.1.1" + moment@2.x.x: version "2.22.2" resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" @@ -9776,19 +10349,33 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.38, node-releases@^1.1.40: +node-releases@^1.1.40: version "1.1.41" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.41.tgz#57674a82a37f812d18e3b26118aefaf53a00afed" integrity sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg== dependencies: semver "^6.3.0" -node-source-walk@~1.4.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-1.4.2.tgz#311ee1e18d8795874bc2229426d572cf0c356256" - integrity sha1-MR7h4Y2HlYdLwiKUJtVyzww1YlY= +node-releases@^1.1.44: + version "1.1.45" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.45.tgz#4cf7e9175d71b1317f15ffd68ce63bce1d53e9f2" + integrity sha512-cXvGSfhITKI8qsV116u2FTzH5EWZJfgG7d4cpqwF8I8+1tWpD6AsvvGRKq2onR0DNj1jfqsjkXZsm14JMS7Cyg== dependencies: - acorn "^1.0.3" + semver "^6.3.0" + +node-releases@^1.1.46: + version "1.1.47" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4" + integrity sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA== + dependencies: + semver "^6.3.0" + +node-source-walk@^4.0.0, node-source-walk@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/node-source-walk/-/node-source-walk-4.2.0.tgz#c2efe731ea8ba9c03c562aa0a9d984e54f27bc2c" + integrity sha512-hPs/QMe6zS94f5+jG3kk9E7TNm4P2SulrKiLWMzKszBfNZvL/V6wseHlTd7IvfW0NZWqPtK3+9yYNr+3USGteA== + dependencies: + "@babel/parser" "^7.0.0" node-uuid@1.4.8, node-uuid@~1.4.7: version "1.4.8" @@ -9879,6 +10466,11 @@ normalize-url@1.9.1: query-string "^4.1.0" sort-keys "^1.0.0" +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + npm-bundled@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" @@ -9969,6 +10561,13 @@ npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" +nth-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.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" @@ -10028,6 +10627,11 @@ object-inspect@^1.6.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== + object-is@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" @@ -10073,6 +10677,14 @@ object.getownpropertydescriptors@^2.0.3: define-properties "^1.1.2" es-abstract "^1.5.1" +object.getownpropertydescriptors@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + object.map@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37" @@ -10096,6 +10708,16 @@ object.pick@^1.2.0, object.pick@^1.3.0: dependencies: isobject "^3.0.1" +object.values@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -10180,6 +10802,18 @@ optimist@0.6.x, optimist@^0.6.1, optimist@~0.6.0: minimist "~0.0.1" wordwrap "~0.0.2" +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + ora@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/ora/-/ora-4.0.2.tgz#0e1e68fd45b135d28648b27cf08081fa6e8a297d" @@ -10205,6 +10839,20 @@ ora@^3.4.0: strip-ansi "^5.2.0" wcwidth "^1.0.1" +ora@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/ora/-/ora-4.0.3.tgz#752a1b7b4be4825546a7a3d59256fa523b6b6d05" + integrity sha512-fnDebVFyz309A73cqCipVL1fBZewq4vwgSHfxh43vVy31mbyoQ8sCH3Oeaog/owYOs/lLlGVPCISQonTneg6Pg== + dependencies: + chalk "^3.0.0" + cli-cursor "^3.1.0" + cli-spinners "^2.2.0" + is-interactive "^1.0.0" + log-symbols "^3.0.0" + mute-stream "0.0.8" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + orchestrator@^0.3.0: version "0.3.8" resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e" @@ -10318,6 +10966,13 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^2.2.1, p-limit@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" + integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== + 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" @@ -10488,6 +11143,11 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-ms@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" + integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -10672,7 +11332,7 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= -pify@^4.0.1: +pify@^4.0.0, pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== @@ -10738,6 +11398,11 @@ plugin-error@^1.0.1: arr-union "^3.1.0" extend-shallow "^3.0.2" +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + portfinder@^1.0.13, portfinder@^1.0.23, portfinder@^1.0.25: version "1.0.25" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" @@ -10752,6 +11417,63 @@ 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= +postcss-calc@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.1.tgz#36d77bab023b0ecbb9789d84dcb23c4941145436" + integrity sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ== + dependencies: + css-unit-converter "^1.1.1" + postcss "^7.0.5" + postcss-selector-parser "^5.0.0-rc.4" + postcss-value-parser "^3.3.1" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + postcss-import@12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-12.0.1.tgz#cf8c7ab0b5ccab5649024536e565f841928b7153" @@ -10780,7 +11502,216 @@ postcss-loader@3.0.0: postcss-load-config "^2.0.0" schema-utils "^1.0.0" -postcss-value-parser@^3.2.3: +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + alphanum-sort "^1.0.0" + browserslist "^4.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-selector-parser@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" + integrity sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU= + dependencies: + dot-prop "^4.1.1" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" + integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== + dependencies: + is-svg "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.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== @@ -10790,6 +11721,15 @@ postcss-value-parser@^4.0.2: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9" integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ== +postcss-values-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-1.5.0.tgz#5d9fa63e2bcb0179ce48f3235303765eb89f3047" + integrity sha512-3M3p+2gMp0AH3da530TlX8kiO1nxdTnc3C6vr8dMxRLIlh8UYkz0/wcwptSXjhtx2Fr0TySI7a+BHDQ8NL7LaQ== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + postcss@7.0.21: version "7.0.21" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" @@ -10808,6 +11748,39 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.21: source-map "^0.6.1" supports-color "^6.1.0" +postcss@^7.0.2, postcss@^7.0.5: + version "7.0.26" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" + integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +precinct@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/precinct/-/precinct-6.2.0.tgz#1755c369316d58ffeed2332a31442d5498f3cc33" + integrity sha512-BCAmnOxZzobF3H1/h/gq70pEyvX/BVLWCrzi8beFD22dqu5Z14qOghNUsI24Wg8oaTsGFcIjOGtFX5L9ttmjVg== + dependencies: + commander "^2.19.0" + debug "^4.1.1" + detective-amd "^3.0.0" + detective-cjs "^3.1.1" + detective-es6 "^2.0.0" + detective-less "^1.0.2" + detective-postcss "^3.0.0" + detective-sass "^3.0.0" + detective-scss "^2.0.0" + detective-stylus "^1.0.0" + detective-typescript "^5.1.1" + module-definition "^3.3.0" + node-source-walk "^4.2.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= + prepend-http@^1.0.0, prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -10823,7 +11796,14 @@ pretty-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -private@^0.1.6, private@~0.1.5: +pretty-ms@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-5.1.0.tgz#b906bdd1ec9e9799995c372e2b1c34f073f95384" + integrity sha512-4gaK1skD2gwscCfkswYQRmddUb2GJZtzDGRjHWadVHtK/DIKFufa12MvES6/xu1tVbUYeia5bmLcwJtZJQUqnw== + dependencies: + parse-ms "^2.1.0" + +private@^0.1.6: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== @@ -10912,9 +11892,9 @@ protoduck@^5.0.1: genfun "^5.0.0" protractor@^5.4.2: - version "5.4.2" - resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.4.2.tgz#329efe37f48b2141ab9467799be2d4d12eb48c13" - integrity sha512-zlIj64Cr6IOWP7RwxVeD8O4UskLYPoyIcg0HboWJL9T79F1F0VWtKkGTr/9GN6BKL+/Q/GmM7C9kFVCfDbP5sA== + version "5.4.3" + resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.4.3.tgz#35f050741e404a45868618ea648745d89af31683" + integrity sha512-7pMAolv8Ah1yJIqaorDTzACtn3gk7BamVKPTeO5lqIGOrfosjPgXFx/z1dqSI+m5EeZc2GMJHPr5DYlodujDNA== dependencies: "@types/q" "^0.0.32" "@types/selenium-webdriver" "^3.0.0" @@ -11162,14 +12142,6 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-tools@0.12.1: - version "0.12.1" - resolved "https://registry.yarnpkg.com/react-tools/-/react-tools-0.12.1.tgz#cd016e2f1b80d35a6006100305c068925e25e3d2" - integrity sha1-zQFuLxuA01pgBhADBcBokl4l49I= - dependencies: - commoner "^0.10.0" - jstransform "^8.2.0" - read-cache@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" @@ -11347,16 +12319,6 @@ readdirp@~3.3.0: dependencies: picomatch "^2.0.7" -recast@^0.11.17: - version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" - integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM= - dependencies: - ast-types "0.9.6" - esprima "~3.1.0" - private "~0.1.5" - source-map "~0.5.0" - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -11625,7 +12587,16 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -requirejs@^2.3.6: +requirejs-config-file@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/requirejs-config-file/-/requirejs-config-file-3.1.2.tgz#de8c0b3eebdf243511c994a8a24b006f8b825997" + integrity sha512-sdLWywcDuNz7EIOhenSbRfT4YF84nItDv90coN2htbokjmU2QeyQuSBZILQUKNksepl8UPVU+hgYySFaDxbJPQ== + dependencies: + esprima "^4.0.0" + make-dir "^2.1.0" + stringify-object "^3.2.1" + +requirejs@^2.3.5, requirejs@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== @@ -11642,6 +12613,11 @@ resolve-cwd@^2.0.0: dependencies: resolve-from "^3.0.0" +resolve-dependency-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-dependency-path/-/resolve-dependency-path-2.0.0.tgz#11700e340717b865d216c66cabeb4a2a3c696736" + integrity sha512-DIgu+0Dv+6v2XwRaNWnumKu7GPufBBOr5I1gRPJHkvghrfCGOooJODFvgFimX/KRxk9j0whD2MnKHzM1jYvk9w== + resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" @@ -11660,11 +12636,6 @@ 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@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.2.3.tgz#f1eb7fb76436f91d87fd19c5f973fe7d506f6571" - integrity sha1-8et/t2Q2+R2H/RnF+XP+fVBvZXE= - resolve@1.8.1, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" @@ -11748,7 +12719,17 @@ rfdc@^1.1.4: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.4.tgz#ba72cc1367a0ccd9cf81a870b3b58bd3ad07f8c2" integrity sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug== -rimraf@2, rimraf@^2.5.2, rimraf@^2.6.0: +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@2, rimraf@^2.6.0: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== @@ -11762,7 +12743,7 @@ rimraf@3.0.0: dependencies: glob "^7.1.3" -rimraf@^2.2.8, rimraf@^2.6.3, rimraf@^2.7.1: +rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -11946,6 +12927,13 @@ sass-loader@8.0.0: schema-utils "^2.1.0" semver "^6.3.0" +sass-lookup@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/sass-lookup/-/sass-lookup-3.0.0.tgz#3b395fa40569738ce857bc258e04df2617c48cac" + integrity sha512-TTsus8CfFRn1N44bvdEai1no6PqdmDiQUiqW5DlpmtT+tYnIt1tXtDIph5KA1efC+LmioJXSnCtUVpcK9gaKIg== + dependencies: + commander "^2.16.0" + sass@1.23.3: version "1.23.3" resolved "https://registry.yarnpkg.com/sass/-/sass-1.23.3.tgz#f07503b9e8d2bcf06ef69e8beea5d085589b1620" @@ -11980,13 +12968,6 @@ sax@>=0.6.0, sax@^1.2.4, sax@~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@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -11996,7 +12977,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.5.0: +schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0: version "2.5.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f" integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ== @@ -12004,6 +12985,14 @@ schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.5 ajv "^6.10.2" ajv-keywords "^3.4.1" +schema-utils@^2.6.1, schema-utils@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" + integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -12075,6 +13064,11 @@ semver@6.3.0, semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + semver@^4.1.0: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" @@ -12137,10 +13131,10 @@ serialize-javascript@^1.7.0: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== -serialize-javascript@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.0.tgz#9310276819efd0eb128258bb341957f6eb2fc570" - integrity sha512-a/mxFfU00QT88umAJQsNWOnUKckhNCqOl028N48e7wFmo2/EHpTo9Wso+iJJCMrQnmFvcjto5RJdAHEvVhcyUQ== +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== serve-index@^1.9.1: version "1.9.1" @@ -12277,6 +13271,13 @@ 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= +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -12492,13 +13493,6 @@ 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.1.31: - version "0.1.31" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.31.tgz#9f704d0d69d9e138a81badf6ebb4fde33d151c61" - integrity sha1-n3BNDWnZ4TioG63267T94z0VHGE= - 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" @@ -12509,7 +13503,7 @@ source-map@0.7.3, source-map@^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.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -12673,6 +13667,11 @@ ssri@^7.0.0: figgy-pudding "^3.5.1" minipass "^3.1.1" +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" @@ -12842,6 +13841,14 @@ string.prototype.trimleft@^2.1.0: define-properties "^1.1.3" function-bind "^1.1.1" +string.prototype.trimleft@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" + integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + string.prototype.trimright@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" @@ -12850,6 +13857,14 @@ string.prototype.trimright@^2.1.0: define-properties "^1.1.3" function-bind "^1.1.1" +string.prototype.trimright@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" + integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -12869,6 +13884,15 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +stringify-object@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + stringstream@~0.0.4: version "0.0.6" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" @@ -12895,6 +13919,13 @@ strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + strip-bom-buf@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572" @@ -12960,6 +13991,15 @@ style-loader@1.0.0: loader-utils "^1.2.3" schema-utils "^2.0.1" +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.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" @@ -12969,6 +14009,14 @@ stylus-loader@3.0.2: lodash.clonedeep "^4.5.0" when "~3.6.x" +stylus-lookup@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/stylus-lookup/-/stylus-lookup-3.0.2.tgz#c9eca3ff799691020f30b382260a67355fefdddd" + integrity sha512-oEQGHSjg/AMaWlKe7gqsnYzan8DLcGIHe0dUaFkucZZ14z4zjENRlQMCHT4FNsiWnJf17YN9OvrCfCoi7VvOyg== + dependencies: + commander "^2.8.1" + debug "^4.1.0" + stylus@0.54.7: version "0.54.7" resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.7.tgz#c6ce4793965ee538bcebe50f31537bfc04d88cd2" @@ -13045,6 +14093,13 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + supports-hyperlinks@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz#71daedf36cc1060ac5100c351bb3da48c29c0ef7" @@ -13053,6 +14108,25 @@ supports-hyperlinks@^1.0.1: has-flag "^2.0.0" supports-color "^5.0.0" +svgo@^1.0.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.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" @@ -13141,18 +14215,19 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -terser-webpack-plugin@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.2.1.tgz#5569e6c7d8be79e5e43d6da23acc3b6ba77d22bd" - integrity sha512-jwdauV5Al7zopR6OAYvIIRcxXCSvLjZjr7uZE8l2tIWb/ryrGN48sJftqGf5k9z09tWhajx53ldp0XPI080YnA== +terser-webpack-plugin@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.3.tgz#b89043168bd414153bab86f4362ac23d537b78b0" + integrity sha512-gWHkaGzGYjmDoYxksFZynWTzvXOAjQ5dd7xuTMYlv4zpWlLSb6v0QLSZjELzP5dMs1ox30O1BIPs9dgqlMHuLQ== dependencies: cacache "^13.0.1" - find-cache-dir "^3.0.0" - jest-worker "^24.9.0" - schema-utils "^2.5.0" - serialize-javascript "^2.1.0" + find-cache-dir "^3.2.0" + jest-worker "^25.1.0" + p-limit "^2.2.2" + schema-utils "^2.6.4" + serialize-javascript "^2.1.2" source-map "^0.6.1" - terser "^4.3.9" + terser "^4.4.3" webpack-sources "^1.4.3" terser-webpack-plugin@^1.4.1: @@ -13170,10 +14245,10 @@ terser-webpack-plugin@^1.4.1: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser@4.4.0, terser@^4.1.2, terser@^4.3.9, terser@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.0.tgz#22c46b4817cf4c9565434bfe6ad47336af259ac3" - integrity sha512-oDG16n2WKm27JO8h4y/w3iqBGAOSCtq7k8dRmrn4Wf9NouL0b2WpMHGChFGZq4nFAQy1FsNJrVQHfurXOSTmOA== +terser@4.5.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.5.1.tgz#63b52d6b6ce344aa6fedcd0ee06a695799eb50bd" + integrity sha512-lH9zLIbX8PRBEFCTvfHGCy0s9HEKnNso1Dx9swSopF3VUnFLB8DpQ61tHxoofovNC/sG0spajJM3EIIRSTByiQ== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -13188,6 +14263,24 @@ terser@^3.14.1: source-map "~0.6.1" source-map-support "~0.5.10" +terser@^4.1.2, terser@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.0.tgz#22c46b4817cf4c9565434bfe6ad47336af259ac3" + integrity sha512-oDG16n2WKm27JO8h4y/w3iqBGAOSCtq7k8dRmrn4Wf9NouL0b2WpMHGChFGZq4nFAQy1FsNJrVQHfurXOSTmOA== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +terser@^4.4.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" + integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + test-exclude@^5.2.2: version "5.2.3" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" @@ -13311,6 +14404,11 @@ timers-ext@^0.1.5: es5-ext "~0.10.46" next-tick "1" +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" @@ -13354,11 +14452,6 @@ to-buffer@^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-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" @@ -13437,6 +14530,11 @@ toxic@^1.0.0: dependencies: lodash "^4.17.10" +traverse-chain@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1" + integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE= + traverse@>=0.2.4: version "0.6.6" resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" @@ -13447,10 +14545,10 @@ traverse@>=0.2.4: resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= -tree-kill@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" - integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q== +tree-kill@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== trim-newlines@^1.0.0: version "1.0.0" @@ -13467,20 +14565,15 @@ trim-off-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= -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= - try-require@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/try-require/-/try-require-1.2.1.tgz#34489a2cac0c09c1cc10ed91ba011594d4333be2" integrity sha1-NEiaLKwMCcHMEO2RugEVlNQzO+I= -tsickle@0.37.1: - version "0.37.1" - resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.37.1.tgz#2f8a87c1b15766e866457bd06fb6c0e0d84eed09" - integrity sha512-0GwgOJEnsmRsrONXCvcbAWY0CvdqF3UugPVoupUpA8Ul0qCPTuqqq0ou/hLqtKZOyyulzCP6MYRjb9/J1g9bJg== +tsickle@0.38.0: + version "0.38.0" + resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.38.0.tgz#89f5952c9bb3ba0b36dc384975e23cf90e584822" + integrity sha512-k7kI6afBuLd2jIrj9JR8lKhEkp99sFVRKQbHeaHQkdvDaH5AvzwqA/qX+aNj28OfuAsWryOKAZoXm24l7JelEw== tslib@1.10.0, tslib@^1.10.0, tslib@^1.9.0: version "1.10.0" @@ -13549,6 +14642,13 @@ tsutils@^1.4.0: resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" integrity sha1-ufmrROVa+WgYMdXyjQrur1x1DLA= +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + 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" @@ -13571,6 +14671,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: 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-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -13609,20 +14716,25 @@ typescript@3.2.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d" integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== -typescript@3.6.4, typescript@~3.6.4: +typescript@3.6.4: version "3.6.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== +typescript@^3.0.3, typescript@^3.6.4: + version "3.7.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" + integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== + typescript@~3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== -uglify-js@1.2.6, uglify-js@~1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-1.2.6.tgz#d354b2d3c1cf10ebc18fa78c11a28bdd9ce1580d" - integrity sha1-01Sy08HPEOvBj6eMEaKL3ZzhWA0= +typescript@~3.7.4: + version "3.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19" + integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw== uglify-js@^1.3.3: version "1.3.5" @@ -13697,6 +14809,16 @@ union@~0.4.3: dependencies: qs "~2.3.3" +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -13752,6 +14874,11 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -13793,11 +14920,6 @@ unzipper@^0.10.5: readable-stream "~2.3.6" setimmediate "~1.0.4" -upath@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" - integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== - upath@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" @@ -13894,6 +15016,16 @@ util-promisify@^2.1.0: dependencies: object.getownpropertydescriptors "^2.0.3" +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" @@ -13984,6 +15116,11 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +vendors@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -14058,17 +15195,12 @@ vrsource-tslint-rules@5.1.1: dependencies: tslint "~5.1.0" -walkdir@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.5.tgz#8b36be89c4f189249fd2d931cf133ba0c1c6fde8" - integrity sha1-iza+icTxiSSf0tkxzxM7oMHG/eg= - walkdir@^0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532" integrity sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI= -walkdir@^0.4.0: +walkdir@^0.4.0, walkdir@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39" integrity sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ== @@ -14324,6 +15456,11 @@ winston@^1.0.1: pkginfo "0.3.x" stack-trace "0.0.x" +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"