diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bc99a10472..9090d4c99d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,8 +3,17 @@ name: TestCI on: [push] jobs: + CancelPrevious: + runs-on: ubuntu-latest + + steps: + - name: Cancel Old Pipeline + uses: rokroskar/workflow-run-cleanup-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + Quality: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 @@ -23,6 +32,11 @@ jobs: - name: Install root dependencies uses: bahmutov/npm-install@v1 + - name: Install e2e dependencies + uses: bahmutov/npm-install@v1 + with: + working-directory: e2e + - name: Code Quality run: | npm run format @@ -32,9 +46,14 @@ jobs: run: | npm run ng -- build --aot npx tsc -p tsconfig.spec.json + (cd e2e && npx tsc -p cypress/tsconfig.json) (cd schematics && npm run build && bash ../scripts/ci-test-no-changes.sh 'you probably committed unformatted code') (cd tslint-rules && npm run build && bash ../scripts/ci-test-no-changes.sh 'you probably committed unformatted code') + - name: Escalate TSLint Rules + run: | + node scripts/tslint-hard + - name: Lint by action uses: mooyoul/tslint-actions@v1.1.1 with: @@ -42,7 +61,7 @@ jobs: project: 'tsconfig.json' Jest: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 @@ -59,7 +78,7 @@ jobs: npm test Build: - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 @@ -97,7 +116,7 @@ jobs: Schematics: needs: [Build, Quality, Jest] - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 @@ -112,14 +131,16 @@ jobs: - name: Test Schematics run: | bash e2e/test-schematics.sh - sh scripts/ci-check-no-additional-warnings.sh + node scripts/tslint-hard + npm run lint Cypress: needs: Build - runs-on: ubuntu-16.04 + runs-on: ubuntu-latest strategy: - fail-fast: false + fail-fast: true + max-parallel: 2 matrix: test: [ @@ -128,6 +149,8 @@ jobs: 'account/*b2c*', 'checkout/*b2c*', 'shopping/*b2c*', + 'system/*b2c*', + 'extras/*b2c*', # TODO: include remaining in a general way # '!(shopping|account|checkout)*/*b2c*' # '@(cms|contact)*/*b2c*' @@ -147,10 +170,19 @@ jobs: with: name: dist + - name: Start SSR + if: matrix.test != '*mock*' + run: | + npm run serve & + + - name: Start Dev-Server + if: matrix.test == '*mock*' + run: | + npm run ng -- serve & + - name: Cypress - uses: cypress-io/github-action@master + uses: cypress-io/github-action@v1.22.0 with: - start: ${{ matrix.test == '*mock*' && 'npm run ng -- serve' || 'npm run serve > /dev/null 2>&1' }} wait-on: 'http://localhost:4200' wait-on-timeout: 180 working-directory: e2e diff --git a/.gitlab-ci-get-publish.sh b/.gitlab-ci-get-publish.sh index 293a617d11..b3499d87d7 100644 --- a/.gitlab-ci-get-publish.sh +++ b/.gitlab-ci-get-publish.sh @@ -3,7 +3,7 @@ [ -z "$1" ] && echo "instance name required" && exit 1 internalPort="${2:-4200}" -currentPort="$(docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}}{{(index $conf 0).HostPort}}{{end}}' "$1")" +currentPort="$(docker inspect --format='{{(index (index .NetworkSettings.Ports "$internalPort/tcp") 0).HostPort}}' "$1")" if [ -z "$currentPort" ] then diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0866188e83..1765e8e385 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -61,7 +61,7 @@ migration: - merge_requests except: refs: - - develop + - github-develop - master tags: - docker-executor @@ -379,6 +379,7 @@ deploy_demo_b2b: --name ${SERVICE} --env ICM_BASE_URL=$ICM_BASE_URL --env LOGGING=true + --env THEME="blue|688dc3" --env FEATURES=quoting,compare,recently,businessCustomerRegistration,advancedVariationHandling,sentry --env ICM_CHANNEL=inSPIRED-inTRONICS_Business-Site --env SENTRY_DSN=${SENTRY_DSN} @@ -410,7 +411,6 @@ deploy_demo_nginx: --detach --publish 4326:80 --name "${SERVICE}" - -e UPSTREAM_ICM=${ICM_BASE_URL} -e UPSTREAM_PWA=http://$DEMO_SERVER_NAME:4321 -e PWA_1_SUBDOMAIN=b2c -e PWA_1_CHANNEL=inSPIRED-inTRONICS-Site @@ -535,7 +535,7 @@ deploy_review_b2c: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}-${CI_BUILD_REF} - PUBLISH_NGINX=$(sh .gitlab-ci-get-publish.sh "${CI_COMMIT_REF_SLUG}-nginx" 80) - docker rm -f "${CI_COMMIT_REF_SLUG}-nginx" || true - - docker pull ${CI_REGISTRY_IMAGE}:nginx-${CI_COMMIT_REF_SLUG} || (docker pull ${CI_REGISTRY_IMAGE}:nginx-develop && docker tag ${CI_REGISTRY_IMAGE}:nginx-develop ${CI_REGISTRY_IMAGE}:nginx-${CI_COMMIT_REF_SLUG}) + - docker pull ${CI_REGISTRY_IMAGE}:nginx-${CI_COMMIT_REF_SLUG} || (docker pull ${CI_REGISTRY_IMAGE}:nginx-github-develop && docker tag ${CI_REGISTRY_IMAGE}:nginx-github-develop ${CI_REGISTRY_IMAGE}:nginx-${CI_COMMIT_REF_SLUG}) - docker run --detach $PUBLISH_NGINX @@ -547,7 +547,7 @@ deploy_review_b2c: -e PWA_2_SUBDOMAIN=b2b -e PWA_2_CHANNEL=inSPIRED-inTRONICS_Business-Site -e PWA_2_FEATURES=quoting,recently,compare,businessCustomerRegistration,advancedVariationHandling,sentry - -e PWA_2_THEME=blue + -e PWA_2_THEME="blue|688dc3" -e PWA_3_SUBDOMAIN=de -e PWA_3_CHANNEL=inSPIRED-inTRONICS-Site -e PWA_3_LANG=de_DE @@ -556,7 +556,7 @@ deploy_review_b2c: -e PWA_4_CHANNEL=inSPIRED-inTRONICS-Site -e PWA_4_APPLICATION=smb-responsive -e PWA_4_FEATURES=quoting - -e PWA_4_THEME=blue + -e PWA_4_THEME="blue|688dc3" ${CI_REGISTRY_IMAGE}:nginx-${CI_COMMIT_REF_SLUG} - sleep 10 - docker run --rm --add-host $DEMO_SERVER_NAME:$DEMO_SERVER_IP mwendler/wget --wait 10 --tries 10 --retry-connrefused "http://$DEMO_SERVER_NAME:3000/${CI_COMMIT_REF_SLUG}-pwa-b2c" @@ -614,7 +614,7 @@ deploy_review_b2b: -e LOGGING=true -e SENTRY_DSN=${SENTRY_DSN} -e ICM_BASE_URL=${ICM_BASE_URL} - -e THEME=blue + -e THEME="blue|688dc3" -e ICM_CHANNEL=inSPIRED-inTRONICS_Business-Site -e FEATURES=quoting,recently,compare,businessCustomerRegistration,advancedVariationHandling,sentry --add-host $ICM_HOST:$ICM_IP @@ -717,7 +717,8 @@ schematics: script: - npm install - bash e2e/test-schematics.sh - - sh scripts/ci-check-no-additional-warnings.sh + - node scripts/tslint-hard + - npm run lint - echo "schematics complete" .universal_template: &universal_definition @@ -779,7 +780,7 @@ universal_b2b: cypress_remote: <<: *cypress_definition - parallel: 7 + parallel: 9 only: - merge_requests - triggers @@ -831,7 +832,8 @@ check_tslint_no_warnings: - performance script: - npm ci - - sh scripts/ci-check-no-additional-warnings.sh + - node scripts/tslint-hard + - npm run lint - echo "check complete" housekeeping_images: diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 7fa8169913..6f67400834 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -15,17 +15,14 @@ "angular.ng-template", "mikael.angular-beastcode", "formulahendry.auto-rename-tag", - "stringham.move-ts", // code style + formatting "editorconfig.editorconfig", "esbenp.prettier-vscode", "hex-ci.stylelint-plus", "ms-vscode.vscode-typescript-tslint-plugin", // testing - "orta.vscode-jest", - "andys8.jest-snippets", - "asvetliakov.snapshot-tools" + "andys8.jest-snippets" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. - "unwantedRecommendations": [] + "unwantedRecommendations": ["eg2.tslint"] } diff --git a/3rd-party-licenses.txt b/3rd-party-licenses.txt index dcb268003e..cd96648bec 100644 --- a/3rd-party-licenses.txt +++ b/3rd-party-licenses.txt @@ -1,71 +1,56 @@ "module name","licenses","copyright","repository" -"@angular-devkit/architect@0.803.18","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@angular-devkit/architect@0.803.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@angular-devkit/build-angular@0.803.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@angular-devkit/build-optimizer@0.803.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@angular-devkit/build-webpack@0.803.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular-devkit/core@8.3.18","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@angular-devkit/core@8.3.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular-devkit/schematics@8.3.18","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular/animations@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/cli@8.3.18","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular/common@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/compiler-cli@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/compiler@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/core@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/forms@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/language-service@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/platform-browser-dynamic@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/platform-browser@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/platform-server@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/pwa@0.803.18","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@angular/router@8.2.13","MIT","","https://github.com/angular/angular" -"@angular/service-worker@8.2.13","MIT","","https://github.com/angular/angular" +"@angular-devkit/schematics@8.3.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular/animations@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/cli@8.3.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular/common@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/compiler-cli@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/compiler@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/core@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/forms@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/language-service@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/platform-browser-dynamic@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/platform-browser@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/platform-server@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/pwa@0.803.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@angular/router@8.2.14","MIT","","https://github.com/angular/angular" +"@angular/service-worker@8.2.14","MIT","","https://github.com/angular/angular" "@babel/code-frame@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-code-frame" "@babel/code-frame@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-code-frame" +"@babel/compat-data@7.8.1","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-compat-data" "@babel/core@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-core" "@babel/core@7.7.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-core" "@babel/core@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-core" "@babel/generator@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-generator" "@babel/generator@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-generator" -"@babel/helper-annotate-as-pure@7.0.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie ","https://github.com/babel/babel/tree/master/packages/babel-helper-annotate-as-pure" "@babel/helper-annotate-as-pure@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-annotate-as-pure" -"@babel/helper-builder-binary-assignment-operator-visitor@7.1.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-builder-binary-assignment-operator-visitor" "@babel/helper-builder-binary-assignment-operator-visitor@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-builder-binary-assignment-operator-visitor" -"@babel/helper-call-delegate@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-call-delegate" "@babel/helper-call-delegate@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-call-delegate" +"@babel/helper-compilation-targets@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-compilation-targets" "@babel/helper-create-regexp-features-plugin@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel" -"@babel/helper-define-map@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-define-map" "@babel/helper-define-map@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-define-map" -"@babel/helper-explode-assignable-expression@7.1.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-explode-assignable-expression" "@babel/helper-explode-assignable-expression@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-explode-assignable-expression" "@babel/helper-function-name@7.1.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-function-name" "@babel/helper-function-name@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-function-name" "@babel/helper-get-function-arity@7.0.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie ","https://github.com/babel/babel/tree/master/packages/babel-helper-get-function-arity" "@babel/helper-get-function-arity@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-get-function-arity" -"@babel/helper-hoist-variables@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-hoist-variables" "@babel/helper-hoist-variables@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-hoist-variables" -"@babel/helper-member-expression-to-functions@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-member-expression-to-functions" "@babel/helper-member-expression-to-functions@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-member-expression-to-functions" -"@babel/helper-module-imports@7.0.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie ","https://github.com/babel/babel/tree/master/packages/babel-helper-module-imports" "@babel/helper-module-imports@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-module-imports" -"@babel/helper-module-transforms@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-module-transforms" "@babel/helper-module-transforms@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-module-transforms" -"@babel/helper-optimise-call-expression@7.0.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie ","https://github.com/babel/babel/tree/master/packages/babel-helper-optimise-call-expression" "@babel/helper-optimise-call-expression@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-optimise-call-expression" "@babel/helper-plugin-utils@7.0.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie ","https://github.com/babel/babel/tree/master/packages/babel-helper-plugin-utils" "@babel/helper-plugin-utils@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-plugin-utils" -"@babel/helper-regex@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-regex" "@babel/helper-regex@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-regex" -"@babel/helper-remap-async-to-generator@7.1.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-remap-async-to-generator" "@babel/helper-remap-async-to-generator@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-remap-async-to-generator" -"@babel/helper-replace-supers@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-replace-supers" "@babel/helper-replace-supers@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-replace-supers" -"@babel/helper-simple-access@7.1.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-simple-access" "@babel/helper-simple-access@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-simple-access" "@babel/helper-split-export-declaration@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-split-export-declaration" "@babel/helper-split-export-declaration@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-split-export-declaration" -"@babel/helper-wrap-function@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-wrap-function" "@babel/helper-wrap-function@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helper-wrap-function" "@babel/helpers@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helpers" "@babel/helpers@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-helpers" @@ -73,93 +58,56 @@ "@babel/highlight@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-highlight" "@babel/parser@7.6.0","MIT","Copyright (C) 2012-2014 by various contributors (see AUTHORS)","https://github.com/babel/babel/tree/master/packages/babel-parser" "@babel/parser@7.8.3","MIT","Copyright (C) 2012-2014 by various contributors (see AUTHORS)","https://github.com/babel/babel/tree/master/packages/babel-parser" -"@babel/plugin-proposal-async-generator-functions@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-async-generator-functions" "@babel/plugin-proposal-async-generator-functions@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-async-generator-functions" -"@babel/plugin-proposal-dynamic-import@7.5.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-dynamic-import" "@babel/plugin-proposal-dynamic-import@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-dynamic-import" -"@babel/plugin-proposal-json-strings@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-json-strings" "@babel/plugin-proposal-json-strings@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-json-strings" -"@babel/plugin-proposal-object-rest-spread@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-object-rest-spread" +"@babel/plugin-proposal-nullish-coalescing-operator@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-nullish-coalescing-operator" "@babel/plugin-proposal-object-rest-spread@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-object-rest-spread" -"@babel/plugin-proposal-optional-catch-binding@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-optional-catch-binding" "@babel/plugin-proposal-optional-catch-binding@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-optional-catch-binding" -"@babel/plugin-proposal-unicode-property-regex@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-unicode-property-regex" +"@babel/plugin-proposal-optional-chaining@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-optional-chaining" "@babel/plugin-proposal-unicode-property-regex@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-unicode-property-regex" -"@babel/plugin-syntax-async-generators@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-async-generators" "@babel/plugin-syntax-async-generators@7.8.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-async-generators" -"@babel/plugin-syntax-dynamic-import@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-dynamic-import" "@babel/plugin-syntax-dynamic-import@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-dynamic-import" -"@babel/plugin-syntax-json-strings@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-json-strings" "@babel/plugin-syntax-json-strings@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-json-strings" +"@babel/plugin-syntax-nullish-coalescing-operator@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-nullish-coalescing-operator" "@babel/plugin-syntax-object-rest-spread@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-object-rest-spread" "@babel/plugin-syntax-object-rest-spread@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-object-rest-spread" -"@babel/plugin-syntax-optional-catch-binding@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-catch-binding" "@babel/plugin-syntax-optional-catch-binding@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-catch-binding" +"@babel/plugin-syntax-optional-chaining@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-optional-chaining" "@babel/plugin-syntax-top-level-await@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-top-level-await" -"@babel/plugin-transform-arrow-functions@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-arrow-functions" "@babel/plugin-transform-arrow-functions@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-arrow-functions" -"@babel/plugin-transform-async-to-generator@7.5.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-async-to-generator" "@babel/plugin-transform-async-to-generator@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-async-to-generator" -"@babel/plugin-transform-block-scoped-functions@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-block-scoped-functions" "@babel/plugin-transform-block-scoped-functions@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-block-scoped-functions" -"@babel/plugin-transform-block-scoping@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-block-scoping" "@babel/plugin-transform-block-scoping@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-block-scoping" -"@babel/plugin-transform-classes@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-classes" "@babel/plugin-transform-classes@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-classes" -"@babel/plugin-transform-computed-properties@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-computed-properties" "@babel/plugin-transform-computed-properties@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-computed-properties" -"@babel/plugin-transform-destructuring@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-destructuring" "@babel/plugin-transform-destructuring@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-destructuring" -"@babel/plugin-transform-dotall-regex@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-dotall-regex" "@babel/plugin-transform-dotall-regex@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-dotall-regex" -"@babel/plugin-transform-duplicate-keys@7.5.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-duplicate-keys" "@babel/plugin-transform-duplicate-keys@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-duplicate-keys" -"@babel/plugin-transform-exponentiation-operator@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-exponentiation-operator" "@babel/plugin-transform-exponentiation-operator@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-exponentiation-operator" -"@babel/plugin-transform-for-of@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-for-of" "@babel/plugin-transform-for-of@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-for-of" -"@babel/plugin-transform-function-name@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-function-name" "@babel/plugin-transform-function-name@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-function-name" -"@babel/plugin-transform-literals@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-literals" "@babel/plugin-transform-literals@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-literals" -"@babel/plugin-transform-member-expression-literals@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-member-expression-literals" "@babel/plugin-transform-member-expression-literals@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-member-expression-literals" -"@babel/plugin-transform-modules-amd@7.5.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-amd" "@babel/plugin-transform-modules-amd@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-amd" -"@babel/plugin-transform-modules-commonjs@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-commonjs" "@babel/plugin-transform-modules-commonjs@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-commonjs" -"@babel/plugin-transform-modules-systemjs@7.5.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-systemjs" "@babel/plugin-transform-modules-systemjs@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-systemjs" -"@babel/plugin-transform-modules-umd@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-umd" "@babel/plugin-transform-modules-umd@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-modules-umd" -"@babel/plugin-transform-named-capturing-groups-regex@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-named-capturing-groups-regex" "@babel/plugin-transform-named-capturing-groups-regex@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel" -"@babel/plugin-transform-new-target@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-new-target" "@babel/plugin-transform-new-target@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-new-target" -"@babel/plugin-transform-object-super@7.5.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-object-super" "@babel/plugin-transform-object-super@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-object-super" -"@babel/plugin-transform-parameters@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-parameters" "@babel/plugin-transform-parameters@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-parameters" -"@babel/plugin-transform-property-literals@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-property-literals" "@babel/plugin-transform-property-literals@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-property-literals" -"@babel/plugin-transform-regenerator@7.4.5","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-regenerator" "@babel/plugin-transform-regenerator@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-regenerator" -"@babel/plugin-transform-reserved-words@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-reserved-words" "@babel/plugin-transform-reserved-words@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-reserved-words" -"@babel/plugin-transform-shorthand-properties@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-shorthand-properties" "@babel/plugin-transform-shorthand-properties@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-shorthand-properties" -"@babel/plugin-transform-spread@7.2.2","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-spread" "@babel/plugin-transform-spread@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-spread" -"@babel/plugin-transform-sticky-regex@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-sticky-regex" "@babel/plugin-transform-sticky-regex@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-sticky-regex" -"@babel/plugin-transform-template-literals@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-template-literals" "@babel/plugin-transform-template-literals@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-template-literals" -"@babel/plugin-transform-typeof-symbol@7.2.0","MIT","Copyright (c) 2014-2018 Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-typeof-symbol" "@babel/plugin-transform-typeof-symbol@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-typeof-symbol" -"@babel/plugin-transform-unicode-regex@7.4.4","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-unicode-regex" "@babel/plugin-transform-unicode-regex@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-unicode-regex" -"@babel/preset-env@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-preset-env" "@babel/preset-env@7.7.6","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-preset-env" +"@babel/preset-env@7.8.3","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-preset-env" "@babel/runtime-corejs2@7.7.2","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-runtime-corejs2" "@babel/runtime@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-runtime" "@babel/template@7.6.0","MIT","Copyright (c) 2014-present Sebastian McKenzie and other contributors","https://github.com/babel/babel/tree/master/packages/babel-template" @@ -189,10 +137,10 @@ "@jest/types@24.9.0","MIT","Copyright (c) Facebook, Inc. and its affiliates.","https://github.com/facebook/jest" "@mrmlnc/readdir-enhanced@2.2.1","MIT","Copyright (c) 2016 James Messinger","https://github.com/bigstickcarpet/readdir-enhanced" "@ng-bootstrap/ng-bootstrap@5.1.4","MIT","Copyright (c) 2015-2018 Angular ng-bootstrap team","https://github.com/ng-bootstrap/ng-bootstrap" -"@ngrx/effects@8.5.0","MIT","","https://github.com/ngrx/platform" -"@ngrx/entity@8.5.0","MIT","","https://github.com/ngrx/platform" -"@ngrx/store-devtools@8.5.0","MIT","","https://github.com/ngrx/platform" -"@ngrx/store@8.5.0","MIT","","https://github.com/ngrx/platform" +"@ngrx/effects@8.6.0","MIT","","https://github.com/ngrx/platform" +"@ngrx/entity@8.6.0","MIT","","https://github.com/ngrx/platform" +"@ngrx/store-devtools@8.6.0","MIT","","https://github.com/ngrx/platform" +"@ngrx/store@8.6.0","MIT","","https://github.com/ngrx/platform" "@ngtools/webpack@8.3.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@nguniversal/express-engine@8.1.1","MIT","","https://github.com/angular/universal" "@nguniversal/module-map-ngfactory-loader@8.1.1","MIT","","https://github.com/angular/universal" @@ -208,8 +156,8 @@ "@phenomnomnominal/tsquery@3.0.0","MIT","Copyright (c) 2018 Craig Spence","https://github.com/phenomnomnominal/tsquery" "@phenomnomnominal/tsquery@4.0.0","MIT","Copyright (c) 2018 Craig Spence","https://github.com/phenomnomnominal/tsquery" "@samverschueren/stream-to-observable@0.3.0","MIT","Copyright (c) James Talmage (github.com/jamestalmage), Sam Verschueren (github.com/SamVerschueren)","https://github.com/SamVerschueren/stream-to-observable" -"@schematics/angular@8.3.18","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" -"@schematics/update@0.803.18","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@schematics/angular@8.3.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" +"@schematics/update@0.803.23","MIT","Copyright (c) 2017 Google, Inc.","https://github.com/angular/angular-cli" "@sentry/browser@5.8.0","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" "@sentry/core@5.8.0","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" "@sentry/hub@5.8.0","BSD-3-Clause","Copyright (c) 2019, Sentry. All rights reserved.","https://github.com/getsentry/sentry-javascript" @@ -222,7 +170,11 @@ "@types/babel__generator@7.0.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/babel__template@7.0.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/babel__traverse@7.0.7","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/body-parser@1.19.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/connect@3.4.33","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/events@3.0.0","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/express-serve-static-core@4.17.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/express@4.17.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/glob@7.1.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/grecaptcha@2.0.36","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/istanbul-lib-coverage@2.0.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" @@ -233,8 +185,11 @@ "@types/jest@24.0.18","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/lodash-es@4.17.3","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/lodash@4.14.138","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/mime@2.0.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/minimatch@3.0.3","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/node@12.12.11","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/range-parser@1.2.3","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" +"@types/serve-static@1.13.3","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/source-list-map@0.1.2","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/stack-utils@1.0.1","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" "@types/unist@2.0.3","MIT","","https://github.com/DefinitelyTyped/DefinitelyTyped" @@ -288,7 +243,7 @@ "ansi-colors@3.2.4","MIT","Copyright (c) 2015-present, Brian Woodward.","https://github.com/doowb/ansi-colors" "ansi-colors@4.1.1","MIT","Copyright (c) 2015-present, Brian Woodward.","https://github.com/doowb/ansi-colors" "ansi-escapes@3.2.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/ansi-escapes" -"ansi-escapes@4.2.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/ansi-escapes" +"ansi-escapes@4.3.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/ansi-escapes" "ansi-html@0.0.7","Apache-2.0","","https://github.com/Tjatse/ansi-html" "ansi-regex@2.1.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/chalk/ansi-regex" "ansi-regex@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/chalk/ansi-regex" @@ -348,6 +303,7 @@ "balanced-match@1.0.0","MIT","Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>","https://github.com/juliangruber/balanced-match" "base64-js@1.3.1","MIT","Copyright (c) 2014 Jameson Little","https://github.com/beatgammit/base64-js" "base@0.11.2","MIT","Copyright (c) 2015-2017, Jon Schlinkert.","https://github.com/node-base/base" +"basic-auth@2.0.1","MIT","Copyright (c) 2013 TJ Holowaychuk. Copyright (c) 2014 Jonathan Ong . Copyright (c) 2015-2016 Douglas Christopher Wilson ","https://github.com/jshttp/basic-auth" "batch@0.6.1","MIT","Copyright (c) 2013 TJ Holowaychuk ","https://github.com/visionmedia/batch" "bcrypt-pbkdf@1.0.2","BSD-3-Clause","Copyright (c) 2013 Ted Unangst *","https://github.com/joyent/node-bcrypt-pbkdf" "big.js@5.2.2","MIT","Copyright (c) 2018 Michael Mclaughlin","https://github.com/MikeMcl/big.js" @@ -372,6 +328,7 @@ "browserify-zlib@0.2.0","MIT","Copyright (c) 2014-2015 Devon Govett ","https://github.com/devongovett/browserify-zlib" "browserslist@4.6.6","MIT","Copyright 2014 Andrey Sitnik ","https://github.com/browserslist/browserslist" "browserslist@4.8.3","MIT","Copyright 2014 Andrey Sitnik ","https://github.com/browserslist/browserslist" +"browserslist@4.8.5","MIT","Copyright 2014 Andrey Sitnik ","https://github.com/browserslist/browserslist" "bser@2.1.0","Apache-2.0","","https://github.com/facebook/watchman" "buffer-from@1.1.1","MIT","Copyright (c) 2016, 2018 Linus Unnebäck","https://github.com/LinusU/buffer-from" "buffer-indexof@1.1.1","MIT","Copyright (c) 2013 Ryan Day","https://github.com/soldair/node-buffer-indexof" @@ -397,6 +354,7 @@ "camelcase@5.3.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/camelcase" "caniuse-lite@1.0.30000989","CC-BY-4.0","","https://github.com/ben-eb/caniuse-lite" "caniuse-lite@1.0.30001019","CC-BY-4.0","","https://github.com/ben-eb/caniuse-lite" +"caniuse-lite@1.0.30001023","CC-BY-4.0","","https://github.com/ben-eb/caniuse-lite" "canonical-path@1.0.0","MIT","Copyright (c) 2017 Pete Bacon Darwin","https://github.com/petebacondarwin/node-canonical-path" "capture-exit@2.0.0","ISC","","https://github.com/stefanpenner/capture-exit" "caseless@0.12.0","Apache-2.0","","https://github.com/mikeal/caseless" @@ -477,7 +435,6 @@ "copy-concurrently@1.0.5","ISC","Copyright (c) 2017, Rebecca Turner ","https://github.com/npm/copy-concurrently" "copy-descriptor@0.1.1","MIT","Copyright (c) 2015-2016, Jon Schlinkert","https://github.com/jonschlinkert/copy-descriptor" "copy-webpack-plugin@5.1.1","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack-contrib/copy-webpack-plugin" -"core-js-compat@3.2.1","MIT","Copyright (c) 2014-2019 Denis Pushkarev","https://github.com/zloirock/core-js" "core-js-compat@3.6.4","MIT","Copyright (c) 2014-2020 Denis Pushkarev","https://github.com/zloirock/core-js" "core-js@2.6.9","MIT","Copyright (c) 2014-2019 Denis Pushkarev","https://github.com/zloirock/core-js" "core-js@3.2.1","MIT","Copyright (c) 2014-2019 Denis Pushkarev","https://github.com/zloirock/core-js" @@ -556,7 +513,7 @@ "domelementtype@2.0.1","BSD-2-Clause","Copyright (c) Felix Böhm. All rights reserved.","https://github.com/fb55/domelementtype" "domexception@1.0.1","MIT","Copyright © 2017 Domenic Denicola","https://github.com/jsdom/domexception" "domhandler@2.4.2","BSD-2-Clause","Copyright (c) Felix Böhm. All rights reserved.","https://github.com/fb55/DomHandler" -"domino@2.1.3","BSD-2-Clause","Copyright (c) 2011 The Mozilla Foundation.. All rights reserved.","https://github.com/fgnass/domino" +"domino@2.1.4","BSD-2-Clause","Copyright (c) 2011 The Mozilla Foundation.. All rights reserved.","https://github.com/fgnass/domino" "domutils@1.7.0","BSD-2-Clause","Copyright (c) Felix Böhm. All rights reserved.","https://github.com/FB55/domutils" "dot-prop@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/dot-prop" "dot-prop@4.2.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/dot-prop" @@ -607,6 +564,7 @@ "expand-brackets@2.1.4","MIT","Copyright (c) 2015-2016, Jon Schlinkert","https://github.com/jonschlinkert/expand-brackets" "expand-tilde@2.0.2","MIT","Copyright (c) 2015-2016, Jon Schlinkert.","https://github.com/jonschlinkert/expand-tilde" "expect@24.9.0","MIT","Copyright (c) Facebook, Inc. and its affiliates.","https://github.com/facebook/jest" +"express-http-proxy@1.6.0","MIT","Copyright (c) 2013 villadora , contributors. http://kael.me/","https://github.com/villadora/express-http-proxy" "express-robots-txt@0.4.1","MIT","","https://github.com/modosc/express-robots-txt" "express@4.17.1","MIT","Copyright (c) 2009-2014 TJ Holowaychuk . Copyright (c) 2013-2014 Roman Shtylman . Copyright (c) 2014-2015 Douglas Christopher Wilson ","https://github.com/expressjs/express" "extend-shallow@2.0.1","MIT","Copyright (c) 2014-2015, Jon Schlinkert.","https://github.com/jonschlinkert/extend-shallow" @@ -764,7 +722,7 @@ "inquirer@6.5.1","MIT","Copyright (c) 2012 Simon Boudrias","https://github.com/SBoudrias/Inquirer.js" "internal-ip@4.3.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/internal-ip" "interpret@1.2.0","MIT","Copyright (c) 2014-2018 Tyler Kellen , Blaine Bublitz , and Eric Schoffstall ","https://github.com/gulpjs/interpret" -"intershop-pwa@0.17.0","UNLICENSED","Copyright (c) 2019 Intershop Communications AG, http://www.intershop.de","" +"intershop-pwa@0.18.0","UNLICENSED","Copyright (c) 2020 Intershop Communications AG, http://www.intershop.de","" "intershop-schematics@0.0.1","UNLICENSED","","" "intershop-tslint-rules@0.0.1","UNLICENSED","","" "invariant@2.2.4","MIT","Copyright (c) 2013-present, Facebook, Inc.","https://github.com/zertosh/invariant" @@ -918,6 +876,7 @@ "less-loader@5.0.0","MIT","Copyright JS Foundation and other contributors","https://github.com/webpack-contrib/less-loader" "less@3.9.0","Apache-2.0","","https://github.com/less/less.js" "leven@3.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/leven" +"levenary@1.1.1","MIT","Copyright (c) 2019 Tan Li Hau","https://github.com/tanhauhau/levenary" "levn@0.3.0","MIT","Copyright (c) George Zahariev","https://github.com/gkz/levn" "libphonenumber-js@0.4.52","MIT","Copyright (c) 2016 @catamphetamine ","https://github.com/catamphetamine/libphonenumber-js" "license-webpack-plugin@2.1.2","ISC","Copyright (c) 2016, S K (xz64)","https://github.com/xz64/license-webpack-plugin" @@ -955,7 +914,7 @@ "make-dir@2.1.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/make-dir" "make-dir@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/make-dir" "make-error@1.3.5","ISC","Copyright 2014 Julien Fontanet","https://github.com/JsCommunity/make-error" -"make-fetch-happen@5.0.1","ISC","Copyright (c) npm, Inc.","https://github.com/zkat/make-fetch-happen" +"make-fetch-happen@5.0.2","ISC","Copyright (c) npm, Inc.","https://github.com/zkat/make-fetch-happen" "makeerror@1.0.11","BSD-3-Clause","Copyright (c) 2014, Naitik Shah. All rights reserved.","https://github.com/daaku/nodejs-makeerror" "mamacro@0.0.3","MIT","","" "map-age-cleaner@0.1.3","MIT","Copyright (c) Sam Verschueren (github.com/SamVerschueren)","https://github.com/SamVerschueren/map-age-cleaner" @@ -1007,6 +966,7 @@ "mixin-deep@1.3.2","MIT","Copyright (c) 2014-2015, 2017, Jon Schlinkert.","https://github.com/jonschlinkert/mixin-deep" "mkdirp@0.5.1","MIT","Copyright 2010 James Halliday (mail@substack.net)","https://github.com/substack/node-mkdirp" "modify-values@1.0.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/modify-values" +"morgan@1.9.1","MIT","Copyright (c) 2014 Jonathan Ong . Copyright (c) 2014-2017 Douglas Christopher Wilson ","https://github.com/expressjs/morgan" "move-concurrently@1.0.1","ISC","Copyright (c) 2017, Rebecca Turner ","https://github.com/npm/move-concurrently" "ms@2.0.0","MIT","Copyright (c) 2016 Zeit, Inc.","https://github.com/zeit/ms" "ms@2.1.1","MIT","Copyright (c) 2016 Zeit, Inc.","https://github.com/zeit/ms" @@ -1047,9 +1007,11 @@ "normalize-selector@0.2.0","MIT","","https://github.com/getify/normalize-selector" "normalize-url@1.9.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/normalize-url" "npm-bundled@1.0.6","ISC","Copyright (c) npm, Inc. and Contributors","https://github.com/npm/npm-bundled" +"npm-bundled@1.1.1","ISC","Copyright (c) npm, Inc. and Contributors","https://github.com/npm/npm-bundled" +"npm-normalize-package-bin@1.0.1","ISC","Copyright (c) npm, Inc.","https://github.com/npm/npm-normalize-package-bin" "npm-package-arg@6.1.0","ISC","Copyright (c) Isaac Z. Schlueter","https://github.com/npm/npm-package-arg" "npm-packlist@1.4.1","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/npm-packlist" -"npm-packlist@1.4.6","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/npm-packlist" +"npm-packlist@1.4.8","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/npm-packlist" "npm-path@2.0.4","MIT","Copyright (c) 2014 Tim Oxley","https://github.com/timoxley/npm-path" "npm-pick-manifest@2.2.3","ISC","Copyright (c) npm, Inc.","https://github.com/zkat/npm-pick-manifest" "npm-pick-manifest@3.0.2","ISC","Copyright (c) npm, Inc.","https://github.com/npm/npm-pick-manifest" @@ -1207,7 +1169,7 @@ "rc@1.2.8","(BSD-2-Clause OR MIT OR Apache-2.0)","Copyright (c) 2011 Dominic Tarr","https://github.com/dominictarr/rc" "react-is@16.9.0","MIT","Copyright (c) Facebook, Inc. and its affiliates.","https://github.com/facebook/react" "read-cache@1.0.0","MIT","Copyright 2016 Bogdan Chadkin ","https://github.com/TrySound/read-cache" -"read-package-json@2.1.0","ISC","Copyright (c) Isaac Z. Schlueter","https://github.com/npm/read-package-json" +"read-package-json@2.1.1","ISC","Copyright (c) Isaac Z. Schlueter","https://github.com/npm/read-package-json" "read-package-tree@5.3.1","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/read-package-tree" "read-pkg-up@1.0.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/read-pkg-up" "read-pkg-up@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/read-pkg-up" @@ -1216,6 +1178,7 @@ "read-pkg@3.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/read-pkg" "read-pkg@4.0.1","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/read-pkg" "readable-stream@2.3.6","MIT","","https://github.com/nodejs/readable-stream" +"readable-stream@2.3.7","MIT","","https://github.com/nodejs/readable-stream" "readable-stream@3.4.0","MIT","","https://github.com/nodejs/readable-stream" "readdir-scoped-modules@1.1.0","ISC","Copyright (c) Isaac Z. Schlueter and Contributors","https://github.com/npm/readdir-scoped-modules" "readdirp@2.2.1","MIT","Copyright (c) 2012-2015 Thorsten Lorenz","https://github.com/paulmillr/readdirp" @@ -1230,7 +1193,6 @@ "regenerator-runtime@0.13.3","MIT","Copyright (c) 2014-present, Facebook, Inc.","https://github.com/facebook/regenerator/tree/master/packages/regenerator-runtime" "regenerator-transform@0.14.1","MIT","Copyright (c) 2014-present, Facebook, Inc.","https://github.com/facebook/regenerator/tree/master/packages/regenerator-transform" "regex-not@1.0.2","MIT","Copyright (c) 2016, 2018, Jon Schlinkert.","https://github.com/jonschlinkert/regex-not" -"regexp-tree@0.1.13","MIT","Copyright (c) 2017 Dmitry Soshnikov","https://github.com/DmitrySoshnikov/regexp-tree" "regexp.prototype.flags@1.2.0","MIT","Copyright (C) 2014 Jordan Harband","https://github.com/es-shims/RegExp.prototype.flags" "regexpu-core@1.0.0","MIT","Copyright Mathias Bynens ","https://github.com/mathiasbynens/regexpu-core" "regexpu-core@4.6.0","MIT","Copyright Mathias Bynens ","https://github.com/mathiasbynens/regexpu-core" @@ -1474,7 +1436,7 @@ "tunnel-agent@0.6.0","Apache-2.0","","https://github.com/mikeal/tunnel-agent" "tweetnacl@0.14.5","Unlicense","","https://github.com/dchest/tweetnacl-js" "type-check@0.3.2","MIT","Copyright (c) George Zahariev","https://github.com/gkz/type-check" -"type-fest@0.5.2","(MIT OR CC0-1.0)","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/type-fest" +"type-fest@0.8.1","(MIT OR CC0-1.0)","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/type-fest" "type-is@1.6.18","MIT","Copyright (c) 2014 Jonathan Ong . Copyright (c) 2014-2015 Douglas Christopher Wilson ","https://github.com/jshttp/type-is" "typedarray@0.0.6","MIT","","https://github.com/substack/typedarray" "typeface-roboto-condensed@0.0.75","MIT","","https://github.com/KyleAMathews/typefaces/tree/master/packages/roboto-condensed" @@ -1518,6 +1480,7 @@ "utils-merge@1.0.1","MIT","Copyright (c) 2013-2017 Jared Hanson","https://github.com/jaredhanson/utils-merge" "uuid@2.0.3","MIT","Copyright (c) 2010-2012 Robert Kieffer. MIT License - http://opensource.org/licenses/mit-license.php.","https://github.com/defunctzombie/node-uuid" "uuid@3.3.3","MIT","Copyright (c) 2010-2016 Robert Kieffer and other contributors","https://github.com/kelektiv/node-uuid" +"uuid@3.4.0","MIT","Copyright (c) 2010-2016 Robert Kieffer and other contributors","https://github.com/uuidjs/uuid" "v8-compile-cache@2.0.3","MIT","Copyright (c) 2019 Andres Suarez","https://github.com/zertosh/v8-compile-cache" "validate-npm-package-license@3.0.4","Apache-2.0","","https://github.com/kemitchell/validate-npm-package-license.js" "validate-npm-package-name@3.0.0","ISC","Copyright (c) 2015, npm, Inc","https://github.com/npm/validate-npm-package-name" @@ -1584,4 +1547,4 @@ "yargs@13.3.0","MIT","Copyright 2010 James Halliday (mail@substack.net). Modified work Copyright 2014 Contributors (ben@npmjs.com)","https://github.com/yargs/yargs" "yn@2.0.0","MIT","Copyright (c) Sindre Sorhus (sindresorhus.com)","https://github.com/sindresorhus/yn" "yup@0.27.0","MIT","Copyright (c) 2014 Jason Quense","https://github.com/jquense/yup" -"zone.js@0.9.1","MIT","Copyright (c) 2016-2018 Google, Inc.","https://github.com/angular/zone.js" +"zone.js@0.9.1","MIT","Copyright (c) 2016-2018 Google, Inc.","https://github.com/angular/zone.js" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 928f5e16a5..6b68846dd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +# [0.18.0](https://github.com/intershop/intershop-pwa/releases/tag/0.18.0) (2020-03-09) + +**required Intershop Commerce Management version: 7.10.16.6** + +### Features + +- manage multiple personal wishlists (#34, #129) ([199f25b](https://github.com/intershop/intershop-pwa/commit/199f25b)) +- SEO friendly localized URLs for category and product list pages (#110) ([4e3169e](https://github.com/intershop/intershop-pwa/commit/4e3169e)) +- SEO friendly localized URLs for product detail pages (#110) ([91767f3](https://github.com/intershop/intershop-pwa/commit/91767f3)) +- support running ICM and PWA in hybrid mode (#99) ([d95b36e](https://github.com/intershop/intershop-pwa/commit/d95b36e)) +- HTTPS deployment for universal server (#99) ([90e6440](https://github.com/intershop/intershop-pwa/commit/90e6440)) +- proxy ICM through express server (#99) ([f39bd83](https://github.com/intershop/intershop-pwa/commit/f39bd83)) +- use nginx with https upstream (#99) ([d0fdd75](https://github.com/intershop/intershop-pwa/commit/d0fdd75)) +- add support for CMS Landing Page components (#108) ([da50347](https://github.com/intershop/intershop-pwa/commit/da50347)) +- use morgan for logging in expressjs server ([ea4c800](https://github.com/intershop/intershop-pwa/commit/ea4c800)) +- add url property to RouteNavigation ([ca946f2](https://github.com/intershop/intershop-pwa/commit/ca946f2)) +- extend ishServerHtml directive to apply default handling to 'javascript:' links and allow a callback function in combination with further link handling ([8716834](https://github.com/intershop/intershop-pwa/commit/8716834)) +- use ishServerHtml for header error-keys in error-message component ([2e87448](https://github.com/intershop/intershop-pwa/commit/2e87448)) +- error-message component uses header error-key as fallback ([b4f7ae9](https://github.com/intershop/intershop-pwa/commit/b4f7ae9)) +- dynamic breadcrumb for quote-edit and quote-request-edit ([5769cba](https://github.com/intershop/intershop-pwa/commit/5769cba)) +- provide preview image for social media sharing - add og:image to meta tags (#126) ([52a1907](https://github.com/intershop/intershop-pwa/commit/52a1907)) +- display product labels in product lists (#73, #131) ([7314bf0](https://github.com/intershop/intershop-pwa/commit/7314bf0)) +- extended multiple theme support to control system icons (e.g. favicon), manifest.webmanifest and theme-color as well (#88, #100) ([46e84ba](https://github.com/intershop/intershop-pwa/commit/46e84ba)) +- **schematics:** create facade skeleton when creating an extension ([c02d4d2](https://github.com/intershop/intershop-pwa/commit/c02d4d2)) + +### Bug Fixes + +- quotes routerActiveLink on account menu ([c95c31f](https://github.com/intershop/intershop-pwa/commit/c95c31f), [5bf460c](https://github.com/intershop/intershop-pwa/commit/5bf460c)) +- 'submit quote request' and 'copy submitted quote request' from modal dialog should not navigate to my account (#112) ([8039fe5](https://github.com/intershop/intershop-pwa/commit/8039fe5)) +- "Add Quote to Cart" behaviour changed to only route on success and hide the button on error (#51) ([a70da64](https://github.com/intershop/intershop-pwa/commit/a70da64)) +- show quote item availability on quote detail page (#51) ([788b6dd](https://github.com/intershop/intershop-pwa/commit/788b6dd)) +- save quote request from modal dialog navigates to my account (#56) ([e26d4e1](https://github.com/intershop/intershop-pwa/commit/e26d4e1)) +- missing product names in quote items listing (#111) ([af71f23](https://github.com/intershop/intershop-pwa/commit/af71f23)) +- breadcrumb quote detail page ([d9ddcfe](https://github.com/intershop/intershop-pwa/commit/d9ddcfe)) +- display user friendly error messages for quoting (#51) ([0c9a943](https://github.com/intershop/intershop-pwa/commit/0c9a943)) +- add user friendly error message for "Forbidden (QuoteRequest is not editable)" with reload link (ISREST-943) ([671aad3](https://github.com/intershop/intershop-pwa/commit/671aad3)) +- correct "Thank you for your quote" page heading to "Thank you for your quote request" (ISREST-945) ([5067f93](https://github.com/intershop/intershop-pwa/commit/5067f93)) +- remove duplicated content on "Thank you for your quote request" page (ISREST-944) ([5efa993](https://github.com/intershop/intershop-pwa/commit/5efa993), [d506c8e](https://github.com/intershop/intershop-pwa/commit/d506c8e)) +- set correct URL for sharing product page via email (#128, #138) ([a338c22](https://github.com/intershop/intershop-pwa/commit/a338c22)) +- respect selected category when switching variations on product detail page ([3a806f3](https://github.com/intershop/intershop-pwa/commit/3a806f3)) +- display localized product attribute names (#91, #107) ([3205ba5](https://github.com/intershop/intershop-pwa/commit/3205ba5)) +- display product labels on search result pages (#134) ([0062272](https://github.com/intershop/intershop-pwa/commit/0062272)) +- remove preferred language management in user profile (#120) ([9f44cff](https://github.com/intershop/intershop-pwa/commit/9f44cff)) +- correctly propagate queryParams to login route ([95bf324](https://github.com/intershop/intershop-pwa/commit/95bf324)) +- timeout in auth guard only on first routing ([d7a310c](https://github.com/intershop/intershop-pwa/commit/d7a310c)) +- change password redirects to login page on success instead of displaying the login dialog (#130) ([ebf8379](https://github.com/intershop/intershop-pwa/commit/ebf8379)) +- **schematics:** prevent using same name for store and store-group ([09d66f4](https://github.com/intershop/intershop-pwa/commit/09d66f4)) +- **schematics:** make store location selection more robust ([c0ab56c](https://github.com/intershop/intershop-pwa/commit/c0ab56c)) + # [0.17.0](https://github.com/intershop/intershop-pwa/releases/tag/0.17.0) (2020-01-24) **required Intershop Commerce Management version: 7.10.15.2** @@ -14,7 +63,7 @@ - add counter input component (#61) ([a7f5aee](https://github.com/intershop/intershop-pwa/commit/a7f5aee)) - serve robots.txt from universal server (#66) ([34bbd04](https://github.com/intershop/intershop-pwa/commit/34bbd04)) - seo canonical link support (#45) ([7e19179](https://github.com/intershop/intershop-pwa/commit/7e19179)) -- remove promotion from basket (#71) ([16c6f1f](https://github.com/intershop/intershop-pwa/commit/16c6f1f)) +- remove promotion code from basket (#71) ([16c6f1f](https://github.com/intershop/intershop-pwa/commit/16c6f1f)) - migration script for removing container-component-pattern ([c7a1c9e](https://github.com/intershop/intershop-pwa/commit/c7a1c9e)) - add move-component schematic ([6b1523b](https://github.com/intershop/intershop-pwa/commit/6b1523b)) - basket validation with adjustments on checkout shipping, review & payment page ([b04fadf](https://github.com/intershop/intershop-pwa/commit/b04fadf)) diff --git a/Dockerfile_reports b/Dockerfile_reports index fb7255cf0d..e19e1001ef 100644 --- a/Dockerfile_reports +++ b/Dockerfile_reports @@ -1,5 +1,5 @@ -FROM node:12-alpine as reporting -COPY package.json package-lock.json /workspace/ +FROM node:12-stretch as reporting +COPY package.json package-lock.json tsconfig.json /workspace/ COPY tslint-rules /workspace/tslint-rules/ WORKDIR /workspace ENV CI=true @@ -10,8 +10,9 @@ RUN npx license-checker --csv --out reports/licenses/licenses.csv --customPath t RUN npm run docs RUN npm i --no-save tslint-html-report && node reports/tslint-report RUN npm i --no-save jscpd-html-reporter && node reports/jscpd-report -RUN rm -Rf dist && npx ng build --progress false --aot --stats-json && npx webpack-bundle-analyzer dist/browser/stats-es2015.json dist/browser -r reports/bundle_aot/index.html -m static -RUN rm -Rf dist && npx ng build --progress false --prod --stats-json && npx webpack-bundle-analyzer dist/browser/stats-es2015.json dist/browser -r reports/bundle_prod/index.html -m static +RUN npm i -g webpack-bundle-analyzer +RUN rm -Rf dist && npx ng build --progress false --aot --stats-json && webpack-bundle-analyzer dist/browser/stats-es2015.json dist/browser -r reports/bundle_aot/index.html -m static +RUN rm -Rf dist && npx ng build --progress false --prod --stats-json && webpack-bundle-analyzer dist/browser/stats-es2015.json dist/browser -r reports/bundle_prod/index.html -m static FROM danjellz/http-server COPY --from=reporting /workspace/reports /public diff --git a/LICENSE b/LICENSE index 0756af1abc..15ff966aa5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Intershop Communications AG, http://www.intershop.de +Copyright (c) 2020 Intershop Communications AG, http://www.intershop.de Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/angular.json b/angular.json index 27b165ffd4..35d5480c00 100644 --- a/angular.json +++ b/angular.json @@ -27,11 +27,7 @@ "tsConfig": "tsconfig.app.json", "aot": true, "extractCss": true, - "assets": [ - "src/favicon.ico", - "src/assets", - "src/manifest.webmanifest" - ], + "assets": ["src/assets"], "styles": [ { "input": "src/styles/themes/default/style.scss", diff --git a/dist/.gitignore b/dist/.gitignore index 7fd7aa6c38..9b877d90bd 100644 --- a/dist/.gitignore +++ b/dist/.gitignore @@ -3,3 +3,5 @@ !/*.sh !/healthcheck.js !/robots.txt +!/server.crt +!/server.key diff --git a/dist/server.crt b/dist/server.crt new file mode 100644 index 0000000000..3c16edbe0e --- /dev/null +++ b/dist/server.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDxDCCAqygAwIBAgIJAJYvMbbAjzehMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD +VQQGEwJERTELMAkGA1UECAwCVEgxDTALBgNVBAcMBEplbmExEjAQBgNVBAoMCUlu +dGVyc2hvcDEUMBIGA1UECwwLRW5naW5lZXJpbmcxJDAiBgkqhkiG9w0BCQEWFXN1 +cHBvcnRAaW50ZXJzaG9wLmNvbTESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDEx +NDA4NDExOVoXDTIxMDExMzA4NDExOVowgY0xCzAJBgNVBAYTAkRFMQswCQYDVQQI +DAJUSDENMAsGA1UEBwwESmVuYTESMBAGA1UECgwJSW50ZXJzaG9wMRQwEgYDVQQL +DAtFbmdpbmVlcmluZzEkMCIGCSqGSIb3DQEJARYVc3VwcG9ydEBpbnRlcnNob3Au +Y29tMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDRXcHHCh2XNXdsH3zy8OQK+T6H6K29HoRus0wzv8Hp8jSbdOrF2RuH +9EeEbdrZe+EXhiuLGg76xvxD1dLwANA5fgVIo0/nrIR7Hj1m3fAFiKGBPNSCF0UX +P9ljWPH0U6WhHVcb+EinQdISQHObT0/OLefPZDQg5ymlZV/+fvlBV0hFkBvpSO30 +541EjUm3BubwvyciREOo1PKxnhAyUAZd7SjdM5+ORjfCX3GutTLIv7+XKUABHJ9f +AzJ8uig60hpcsx2cceNlTQ92uEReT5qAadDwLDwVNl5DZ2jhUvjhVlZZWHtW045D +YxCbxCjnanbn+0cydsgSxv9zvMxwB+x1AgMBAAGjJTAjMCEGA1UdEQQaMBiCCyou +bG9jYWxob3N0gglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggEBAA55lAtHrxzS +095HRl/5PQ/M1zUjgOUvLlR5WKKxdzU/nbc/n8wuZqfPL4CHD7s8EJ442yvw+WgP +mqaiXlPBqDCQkrDgHwWnjyT7ndrl7N52bKue14i32nTlsLn/pf+FOMoDnimghQeL +DqFzcLkHacgaxIHt5A0xy3cU/64gMeiL52V+PrgQCD4heeimIjtxGAB4c97GB7TR +FIkk2a4iUzHs5NEv60hKm+Ksgw48wI/jHrCfcxvXJ07f5Qt57IjZkoNmCEq6NX0V +5vvneRQjdFiprE/uiFusdSYGV1Hz2E9HrY0x/LLseS+CGWTBUlWZkOZTpdsnaqDh +DTNpH0moNzI= +-----END CERTIFICATE----- diff --git a/dist/server.key b/dist/server.key new file mode 100644 index 0000000000..5261b2d0c6 --- /dev/null +++ b/dist/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDRXcHHCh2XNXds +H3zy8OQK+T6H6K29HoRus0wzv8Hp8jSbdOrF2RuH9EeEbdrZe+EXhiuLGg76xvxD +1dLwANA5fgVIo0/nrIR7Hj1m3fAFiKGBPNSCF0UXP9ljWPH0U6WhHVcb+EinQdIS +QHObT0/OLefPZDQg5ymlZV/+fvlBV0hFkBvpSO30541EjUm3BubwvyciREOo1PKx +nhAyUAZd7SjdM5+ORjfCX3GutTLIv7+XKUABHJ9fAzJ8uig60hpcsx2cceNlTQ92 +uEReT5qAadDwLDwVNl5DZ2jhUvjhVlZZWHtW045DYxCbxCjnanbn+0cydsgSxv9z +vMxwB+x1AgMBAAECggEAWZmFR3g1x7NzA0vKfnHHNkcKksFqMShxRqrm7rKe+07T +YsA7hSZv2NQbEzqsUSzp3NZnpiUlyf8EkMdeeaXvdttOyZJSrPQw0jvTzUUn5kZd +z+BHldD9mYCSuSiki4qMtJHI6Mht116c14DLuOjNX5BXx3K7uGUVdpoW5eRTKbm5 +X4UIfa8eBtfZA063mc00/RC5s1AM4rBCr+p4xsQLOL1G4YBQk9Tdjme2VNjML37N +HYPLTjE5tALvyDYSscAW4hXCdzzJh8JErOWw+E8W5OkkCc8eUsfw1vAovbOaJw9Y +400Xd8ABXpJwYyg2WADwN3NGyoCFzJHj7J15nFlFQQKBgQDz8+8oIRhhlD8BNrgD +xc0xExGcXZ5GhVQ14Xp4YBxpnXWiE5mlORJczfBfk8vwWtH5qdC7JkZsTEy/vJvu +HglORDxYKNaHVnJNrVvhnjPICudOvaI8yLDlz5d7++3ddV/K6Hv4blXN10BYJS0B +OjGTzUtiYZ6PtwK6PwgEXrkEBQKBgQDbtJOd6aeepGLHCzv1dcb6rQo0+mTC+vwC +uB9/Ym/DTKSeuNBsQuqDEosMjOwLCB7RpzOU2wOxLU3y76yCBVHHC+O0EqI1FmxP +UQ5+GLWJflX3d+zWkEp5PQwIexMD8I3hNNbBBcJHtJnTflo+C9hFKGa5rAVxwGaN +rIUK3VGhsQKBgQClSb3cvq+6TatysxRy2e5xNa5U98lplqS77Q4ByXz2wk0Vh5ou +rECYyJ/44jbnn2Fte3WFmCVW80t9DdnIuGktsmYAhYr1H8lKgA8lCv+ipmCapTnr +XT8eNk05IDTGO+Svol18saVJVnKuRmH71uYIcqyE+Adq8GDUuChCbbuF0QKBgQCi +ilyvdh55InqlcS1BsomsCPrFKP4EtjRdOqSq1EOFBB3CA07G2Vav87cFaPh0TOSo +DH//v2xi1vaVJTXF13Ohw60JGsQAbH9iyr/jEBq2Bs5Iz+Na9dLzEPPnDk6KGpyM +oU/D66PI8tbe/dp7jr3IpFQjRx2cA1CbvaeL2yK6cQKBgQCiuWwjsi0NhmWDPEIe +09PWiJ8ZsZpvAqRs32qM3erskcRwzvxmegbtTByvP59kTmwiGHkquotmN5ifqJHe +2let3V6NCMEZ0qU6LKG6GTBaBZhHuHzuyPBhDW/6i1qZZxRNV73HteluQgXWkmVQ +UZoOi8uheodOmR4V9Mf9MREUmg== +-----END PRIVATE KEY----- diff --git a/e2e/Dockerfile b/e2e/Dockerfile index 4b4ea2d6d0..716300b1a3 100644 --- a/e2e/Dockerfile +++ b/e2e/Dockerfile @@ -1,4 +1,4 @@ -FROM cypress/browsers:chrome69 +FROM cypress/browsers:node12.16.1-chrome80-ff73 RUN apt-get update || true RUN apt-get -y install dnsutils jq COPY package.json package-lock.json /tmp/ diff --git a/e2e/cypress/integration/framework/index.ts b/e2e/cypress/integration/framework/index.ts index 1a22009dc6..71ffccfff3 100644 --- a/e2e/cypress/integration/framework/index.ts +++ b/e2e/cypress/integration/framework/index.ts @@ -16,7 +16,7 @@ function onPage(page: new () => T) { } export function at(type: new () => T, callback?: (page: T) => void) { - onPage(type).should('be.hidden'); + onPage(type).should('exist'); waitLoadingEnd(); if (callback) { callback(currentPage as T); diff --git a/e2e/cypress/integration/pages/account/add-to-wishlist.module.ts b/e2e/cypress/integration/pages/account/add-to-wishlist.module.ts new file mode 100644 index 0000000000..8fc69c0519 --- /dev/null +++ b/e2e/cypress/integration/pages/account/add-to-wishlist.module.ts @@ -0,0 +1,34 @@ +export class AddToWishlistModule { + constructor(private contextSelector: string = 'ish-product-listing') {} + + addProductToWishlistFromPage(title: string = '', modal: boolean = false) { + if (modal) { + cy.get(`[data-testing-id="${title}"]`).click(); + cy.get('[class="modal-footer"] button.btn-primary').click(); + } + this.closeAddProductToWishlistModal('link'); + } + + addProductToWishlistFromList(product: string, title: string, modal: boolean = true) { + if (modal) { + cy.get(this.contextSelector) + .find(`ish-product-item div[data-testing-sku="${product}"] button.add-to-wishlist`) + .click(); + cy.get(`[data-testing-id="${title}"]`).click(); + cy.get('[class="modal-footer"] button.btn-primary').click(); + this.closeAddProductToWishlistModal('link'); + } else { + cy.get(this.contextSelector) + .find(`ish-product-item div[data-testing-sku="${product}"] button.add-to-wishlist`) + .click(); + this.closeAddProductToWishlistModal('link'); + } + } + + private closeAddProductToWishlistModal(mode: 'link' | 'x') { + cy.wait(500); + mode === 'link' + ? cy.get('[data-testing-id="wishlist-success-link"] a').click() + : cy.get('[class="modal-header"] button').click(); + } +} diff --git a/e2e/cypress/integration/pages/account/login.page.ts b/e2e/cypress/integration/pages/account/login.page.ts index ef367c6719..7eab2e153d 100644 --- a/e2e/cypress/integration/pages/account/login.page.ts +++ b/e2e/cypress/integration/pages/account/login.page.ts @@ -28,13 +28,13 @@ export class LoginPage { submit() { cy.server() - .route('GET', '**/customers/**') - .as('customers'); + .route('GET', /.*\/customers\/-.*/) + .as('currentCustomer'); cy.wait(500); cy.get('button[name="login"]').click(); - return cy.wait('@customers'); + return cy.wait('@currentCustomer'); } get errorText() { diff --git a/e2e/cypress/integration/pages/account/my-account.page.ts b/e2e/cypress/integration/pages/account/my-account.page.ts index 7088e07d62..b1361a91d9 100644 --- a/e2e/cypress/integration/pages/account/my-account.page.ts +++ b/e2e/cypress/integration/pages/account/my-account.page.ts @@ -32,4 +32,8 @@ export class MyAccountPage { navigateToAddresses() { cy.get('a[data-testing-id="addresses-link"]').click(); } + + navigateToWishlists() { + cy.get('a[data-testing-id="wishlists-link"]').click(); + } } diff --git a/e2e/cypress/integration/pages/account/profile-edit-details.page.ts b/e2e/cypress/integration/pages/account/profile-edit-details.page.ts index 2b511a2840..d25b22045a 100644 --- a/e2e/cypress/integration/pages/account/profile-edit-details.page.ts +++ b/e2e/cypress/integration/pages/account/profile-edit-details.page.ts @@ -2,9 +2,7 @@ import { fillFormField } from '../../framework'; import { Registration } from './registration.page'; -export type ProfileEditDetailsTypes = Partial< - Pick ->; +export type ProfileEditDetailsTypes = Partial>; export class ProfileEditDetailsPage { readonly tag = 'ish-account-profile-user'; diff --git a/e2e/cypress/integration/pages/account/profile-edit-password.page.ts b/e2e/cypress/integration/pages/account/profile-edit-password.page.ts index 79f019fa20..3edeae659e 100644 --- a/e2e/cypress/integration/pages/account/profile-edit-password.page.ts +++ b/e2e/cypress/integration/pages/account/profile-edit-password.page.ts @@ -12,14 +12,14 @@ export class ProfileEditPasswordPage { submit() { cy.server() - .route('PUT', '**/customers/**') - .as('customers'); + .route('PUT', '**/password') + .as('passwordChange'); cy.wait(500); cy.get(this.tag) .find('button[type="submit"]') .click(); - return cy.wait('@customers'); + return cy.wait('@passwordChange'); } } diff --git a/e2e/cypress/integration/pages/account/profile.page.ts b/e2e/cypress/integration/pages/account/profile.page.ts index 2d4bfea449..f0ffc01446 100644 --- a/e2e/cypress/integration/pages/account/profile.page.ts +++ b/e2e/cypress/integration/pages/account/profile.page.ts @@ -33,10 +33,6 @@ export class ProfilePage { return cy.get(this.tag).find('[data-testing-id="phone-field"]'); } - get preferredLanguage() { - return cy.get(this.tag).find('[data-testing-id="preferred-language-field"]'); - } - get companyName() { return cy.get(this.tag).find('[data-testing-id="company-field"]'); } diff --git a/e2e/cypress/integration/pages/account/quote-list.page.ts b/e2e/cypress/integration/pages/account/quote-list.page.ts index 17f7edb210..4f979a2663 100644 --- a/e2e/cypress/integration/pages/account/quote-list.page.ts +++ b/e2e/cypress/integration/pages/account/quote-list.page.ts @@ -6,11 +6,11 @@ export class QuoteListPage { readonly header = new HeaderModule(); static navigateTo() { - cy.visit('/account/quote-list'); + cy.visit('/account/quotes'); } goToQuoteDetailLink(id: string) { - cy.get(`a[href="/account/quote/${id}"]`) + cy.get(`a[href="/account/quotes/request/${id}"], a[href="/account/quotes/${id}"]`) .first() .click(); } diff --git a/e2e/cypress/integration/pages/account/wishlists-details.page.ts b/e2e/cypress/integration/pages/account/wishlists-details.page.ts new file mode 100644 index 0000000000..4811f06a4d --- /dev/null +++ b/e2e/cypress/integration/pages/account/wishlists-details.page.ts @@ -0,0 +1,80 @@ +import { HeaderModule } from '../header.module'; + +export class WishlistsDetailsPage { + readonly tag = 'ish-account-wishlist-detail-page'; + + readonly header = new HeaderModule(); + + static navigateToOverviewPage() { + cy.get('[href="/account/wishlists"]') + .first() + .click(); + } + + get listItem() { + return cy.get('ish-account-wishlist-detail-line-item'); + } + + get listItemLink() { + return cy.get('ish-account-wishlist-detail-line-item').find('a[data-testing-id="wishlist-product-link"]'); + } + + get wishlistTitle() { + return cy + .get('ish-account-wishlist-detail-page') + .find('h1') + .invoke('text'); + } + + get wishlistPreferredTextElement() { + return cy.get('[data-testing-id="preferred-wishlist-text"]'); + } + + getWishlistItemById(id: string) { + return cy + .get('span') + .contains(id) + .closest('ish-account-wishlist-detail-line-item') + .parent(); + } + + editWishlistDetails(name: string, preferred: boolean) { + cy.get('[data-testing-id="wishlist-details-edit"]').click(); + cy.get('ngb-modal-window') + .find('[data-testing-id="title"]') + .clear() + .type(name); + cy.get('[data-testing-id="preferred"]').uncheck(); + if (preferred) { + cy.get('[data-testing-id="preferred"]').check(); + } + cy.get('[data-testing-id="wishlist-dialog-submit"]').click(); + } + + deleteWishlist(id: string) { + this.getWishlistItemById(id) + .find('[data-testing-id="delete-wishlist"]') + .click(); + } + + moveProductToWishlist(productId: string, listName: string) { + this.getWishlistItemById(productId) + .find('[data-testing-id="move-wishlist"]') + .click(); + cy.get(`[data-testing-id="${listName}"]`).check(); + cy.get('ngb-modal-window') + .find('button[class="btn btn-primary"]') + .click(); + cy.get('[data-testing-id="wishlist-success-link"] a').click(); + } + + addProductToBasket(productId: string, quantity: number) { + this.getWishlistItemById(productId) + .find('[data-testing-id="quantity"]') + .clear() + .type(quantity.toString()); + this.getWishlistItemById(productId) + .find('[data-testing-id="addToCartButton"]') + .click(); + } +} diff --git a/e2e/cypress/integration/pages/account/wishlists-overview.page.ts b/e2e/cypress/integration/pages/account/wishlists-overview.page.ts new file mode 100644 index 0000000000..8867ebf552 --- /dev/null +++ b/e2e/cypress/integration/pages/account/wishlists-overview.page.ts @@ -0,0 +1,49 @@ +import { HeaderModule } from '../header.module'; + +export class WishlistsOverviewPage { + readonly tag = 'ish-account-wishlist-page'; + + readonly header = new HeaderModule(); + + static navigateTo() { + cy.visit('/account/wishlists'); + } + + addWishlist(name: string, preferred: boolean) { + cy.get('a[data-testing-id="add-wishlist"').click(); + cy.get('[data-testing-id="wishlist-dialog-name"]') + .find('[data-testing-id="title"]') + .clear() + .type(name); + if (preferred) { + cy.get('[data-testing-id="wishlist-dialog-preferred"]') + .find('[data-testing-id="preferred"]') + .check(); + } + cy.get('[data-testing-id="wishlist-dialog-submit"]').click(); + } + + deleteWishlistById(id: string) { + this.wishlistsArray + .find('a') + .contains(id) + .closest('[data-testing-id="wishlist-list-item-container"]') + .find('[data-testing-id="delete-wishlist"]') + .click(); + cy.get('[data-testing-id="confirm"]').click(); + } + + goToWishlistDetailLink(name: string) { + cy.get('a') + .contains(name) + .click(); + } + + get wishlistsArray() { + return cy.get('[data-testing-id="wishlist-list-item"]'); + } + + get wishlistsTitlesArray() { + return this.wishlistsArray.find('[data-testing-id="wishlist-list-title"]').invoke('text'); + } +} diff --git a/e2e/cypress/integration/pages/checkout/cart.page.ts b/e2e/cypress/integration/pages/checkout/cart.page.ts index f39a12d780..f713fc549b 100644 --- a/e2e/cypress/integration/pages/checkout/cart.page.ts +++ b/e2e/cypress/integration/pages/checkout/cart.page.ts @@ -1,9 +1,11 @@ +import { AddToWishlistModule } from '../account/add-to-wishlist.module'; import { HeaderModule } from '../header.module'; export class CartPage { readonly tag = 'ish-shopping-basket'; readonly header = new HeaderModule(); + readonly addToWishlist = new AddToWishlistModule(); private saveQuoteRequestButton = () => cy.get('[id="createQuote"]'); @@ -19,10 +21,16 @@ export class CartPage { this.saveQuoteRequestButton().click(); } + private addToWishlistButton = () => cy.get('ish-shopping-basket').find('[data-testing-id="addToWishlistButton"]'); + get lineItems() { return cy.get(this.tag).find('div.pli-description'); } + addProductToWishlist() { + this.addToWishlistButton().click(); + } + lineItem(idx: number) { return { quantity: { diff --git a/e2e/cypress/integration/pages/header.module.ts b/e2e/cypress/integration/pages/header.module.ts index b1712d30a9..a4830674be 100644 --- a/e2e/cypress/integration/pages/header.module.ts +++ b/e2e/cypress/integration/pages/header.module.ts @@ -36,7 +36,7 @@ export class HeaderModule { } get myAccountLink() { - return cy.get('[data-testing-id="user-status-desktop"] [data-testing-id="link-myaccount"]'); + return cy.get('[data-testing-id="link-myaccount"]:visible'); } goToMyAccount() { diff --git a/e2e/cypress/integration/pages/shopping/family.page.ts b/e2e/cypress/integration/pages/shopping/family.page.ts index 8a50568668..18a5ad8475 100644 --- a/e2e/cypress/integration/pages/shopping/family.page.ts +++ b/e2e/cypress/integration/pages/shopping/family.page.ts @@ -10,6 +10,6 @@ export class FamilyPage { readonly productList = new ProductListModule('ish-product-listing'); static navigateTo(categoryUniqueId: string, page?: number) { - cy.visit(`/category/${categoryUniqueId}${page ? `?page=${page}` : ''}`); + cy.visit(`/cat${categoryUniqueId}${page ? `?page=${page}` : ''}`); } } diff --git a/e2e/cypress/integration/pages/shopping/product-detail.page.ts b/e2e/cypress/integration/pages/shopping/product-detail.page.ts index 5df9f279bc..b750975b14 100644 --- a/e2e/cypress/integration/pages/shopping/product-detail.page.ts +++ b/e2e/cypress/integration/pages/shopping/product-detail.page.ts @@ -1,3 +1,4 @@ +import { AddToWishlistModule } from '../account/add-to-wishlist.module'; import { BreadcrumbModule } from '../breadcrumb.module'; import { HeaderModule } from '../header.module'; @@ -13,18 +14,24 @@ export class ProductDetailPage { readonly retailSetParts = new ProductListModule('ish-retail-set-parts'); readonly variations = new ProductListModule('ish-product-master-variations'); + readonly addToWishlist = new AddToWishlistModule(); + static navigateTo(sku: string, categoryUniqueId?: string) { if (categoryUniqueId) { - cy.visit(`/category/${categoryUniqueId}/product/${sku}`); + cy.visit(`/sku${sku}-cat${categoryUniqueId}`); } else { - cy.visit(`/product/${sku}`); + cy.visit(`/sku${sku}`); } } private addToCartButton = () => cy.get('ish-product-detail').find('[data-testing-id="addToCartButton"]'); private addToCompareButton() { - return cy.get('ish-product-detail').find('ish-product-detail-actions [data-testing-id*="compare"]'); + return cy.get('ish-product-detail').find('ish-product-detail-actions [data-testing-id*="compare"] .share-label'); + } + private addToWishlistButton() { + return cy.get('ish-product-detail').find('ish-product-detail-actions [data-testing-id*="wishlist"] .share-label'); } + private addToQuoteRequestButton = () => cy.get('ish-product-detail').find('[data-testing-id="addToQuoteButton"]'); private quantityInput = () => cy.get('ish-product-detail').find('[data-testing-id="quantity"]'); @@ -44,19 +51,32 @@ export class ProductDetailPage { this.addToCompareButton().click(); } - addProductToCart() { + addProductToCart(): Cypress.Chainable { cy.wait(1000); cy.server() .route('POST', '**/baskets/*/items') .as('basket'); + cy.server() + .route('GET', '**/baskets/current*') + .as('basketCurrent'); this.addToCartButton().click(); - return cy.wait('@basket'); + + return ( + cy + .wait('@basket') + // tslint:disable-next-line: no-any + .then(result => (result.status >= 400 ? result : cy.wait('@basketCurrent').then(() => result))) as any + ); } addProductToQuoteRequest() { this.addToQuoteRequestButton().click(); } + addProductToWishlist() { + this.addToWishlistButton().click(); + } + setQuantity(quantity: number) { this.quantityInput().clear(); this.quantityInput().type(quantity.toString()); diff --git a/e2e/cypress/integration/pages/shopping/product-list.module.ts b/e2e/cypress/integration/pages/shopping/product-list.module.ts index 41248a17a4..c571b7ffcd 100644 --- a/e2e/cypress/integration/pages/shopping/product-list.module.ts +++ b/e2e/cypress/integration/pages/shopping/product-list.module.ts @@ -1,6 +1,8 @@ import { waitLoadingEnd } from '../../framework'; +import { AddToWishlistModule } from '../account/add-to-wishlist.module'; export class ProductListModule { + readonly addToWishlist = new AddToWishlistModule(); constructor(private contextSelector: string) {} get visibleProducts() { diff --git a/e2e/cypress/integration/pages/shopping/quote-request.dialog.ts b/e2e/cypress/integration/pages/shopping/quote-request.dialog.ts index e1933f3c28..23bba9b3ec 100644 --- a/e2e/cypress/integration/pages/shopping/quote-request.dialog.ts +++ b/e2e/cypress/integration/pages/shopping/quote-request.dialog.ts @@ -1,8 +1,11 @@ +import { waitLoadingEnd } from '../../framework'; + export class QuoteRequestDialog { readonly tag = 'ish-product-add-to-quote-dialog'; private saveQuoteRequestButton = () => cy.get('[data-testing-id="saveQuoteRequest"]'); private submitQuoteRequestButton = () => cy.get('[data-testing-id="submitQuoteRequest"]'); + private hideButton = () => cy.get('.close'); private quantityInput = () => cy.get('[data-testing-id="quantity"]'); saveQuoteRequest() { @@ -11,9 +14,42 @@ export class QuoteRequestDialog { submitQuoteRequest() { this.submitQuoteRequestButton().click(); + waitLoadingEnd(1000); + return this.quoteId; } setQuantity(quantity: number) { this.quantityInput().type(quantity.toString()); } + + hide() { + this.hideButton().click(); + } + + get productId() { + return cy.get('[itemprop="sku"]'); + } + + get quoteState() { + return cy.get('ish-quote-state'); + } + + get quoteId(): Cypress.Chainable { + return cy + .get('[data-testing-id="quoteId"]') + .invoke('attr', 'data-quote-id') + .then(s => (s as unknown) as string); + } + + get totalPrice() { + return cy.get('[data-testing-id="total-price"]'); + } + + deleteItemFromQuoteRequest() { + cy.get(`a[title="Remove"]`).click(); + } + + assertClosed() { + return cy.get(this.tag).should('not.exist'); + } } diff --git a/e2e/cypress/integration/specs/account/edit-user-preferred-language.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/account/edit-user-preferred-language.b2c.e2e-spec.ts deleted file mode 100644 index 38fb7c872a..0000000000 --- a/e2e/cypress/integration/specs/account/edit-user-preferred-language.b2c.e2e-spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { at } from '../../framework'; -import { createUserViaREST } from '../../framework/users'; -import { LoginPage } from '../../pages/account/login.page'; -import { ProfileEditDetailsPage } from '../../pages/account/profile-edit-details.page'; -import { ProfilePage } from '../../pages/account/profile.page'; -import { SupportedLanguage, sensibleDefaults } from '../../pages/account/registration.page'; - -const _ = { - user: { login: `testuser${new Date().getTime()}@test.intershop.de`, ...sensibleDefaults }, - catalog: { - id: 'Cameras-Camcorders', - englishName: 'Cameras', - germanName: 'Kameras', - }, - lang: { - en: { - displayName: 'English (United States)', - }, - de: { - selector: 'de_DE' as SupportedLanguage, - displayName: 'German (Germany)', - }, - }, - pageTitle: { - englishName: 'Profile Settings', - germanName: 'Profileinstellungen', - }, -}; - -describe('Changing User', () => { - before(() => { - createUserViaREST(_.user); - - LoginPage.navigateTo('/account/profile'); - at(LoginPage, page => - page - .fillForm(_.user.login, _.user.password) - .submit() - .its('status') - .should('equal', 200) - ); - }); - - it('should be able to edit preferred language', () => { - at(ProfilePage, page => { - page.title.should('have.text', _.pageTitle.englishName); - page.header.topLevelCategoryLink(_.catalog.id).should('contain', _.catalog.englishName); - page.preferredLanguage.should('have.text', _.lang.en.displayName); - page.editDetails(); - }); - - at(ProfileEditDetailsPage, page => - page - .fillForm({ preferredLanguage: _.lang.de.selector }) - .submit() - .its('status') - .should('equal', 200) - ); - at(ProfilePage, page => page.preferredLanguage.should('have.text', _.lang.de.displayName)); - }); - - xit('should change the language of the page', () => { - at(ProfilePage, page => { - page.title.should('have.text', _.pageTitle.germanName); - page.header.topLevelCategoryLink(_.catalog.id).should('contain', _.catalog.germanName); - }); - }); -}); diff --git a/e2e/cypress/integration/specs/checkout/cart-variation-handling.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/checkout/cart-variation-handling.b2c.e2e-spec.ts index 4c3e457c17..b625e6afec 100644 --- a/e2e/cypress/integration/specs/checkout/cart-variation-handling.b2c.e2e-spec.ts +++ b/e2e/cypress/integration/specs/checkout/cart-variation-handling.b2c.e2e-spec.ts @@ -8,7 +8,7 @@ const _ = { productSkuTarget: '201807231-02', selections: [ { - attr: '[data-testing-id="Attr_harddrivesize"]', + attr: '[data-testing-id="Hard_disk_drive_capacity"]', value: '512GB', }, ], diff --git a/e2e/cypress/integration/specs/shopping/compare-products.mock.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/extras/compare-products.mock.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/shopping/compare-products.mock.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/extras/compare-products.mock.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/extras/wishlists-management.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/extras/wishlists-management.b2c.e2e-spec.ts new file mode 100644 index 0000000000..c701b37b1b --- /dev/null +++ b/e2e/cypress/integration/specs/extras/wishlists-management.b2c.e2e-spec.ts @@ -0,0 +1,135 @@ +import { at } from '../../framework'; +import { createUserViaREST } from '../../framework/users'; +import { LoginPage } from '../../pages/account/login.page'; +import { sensibleDefaults } from '../../pages/account/registration.page'; +import { WishlistsDetailsPage } from '../../pages/account/wishlists-details.page'; +import { WishlistsOverviewPage } from '../../pages/account/wishlists-overview.page'; +import { CategoryPage } from '../../pages/shopping/category.page'; +import { FamilyPage } from '../../pages/shopping/family.page'; +import { ProductDetailPage } from '../../pages/shopping/product-detail.page'; + +const _ = { + user: { + login: `test${new Date().getTime()}@testcity.de`, + ...sensibleDefaults, + }, + category: 'Home-Entertainment', + subcategory: 'Home-Entertainment.SmartHome', + product1: '201807171', + product2: '201807194', + product3: '201807191', +}; + +describe('Wishlist MyAccount Functionality', () => { + const preferredWishlist = 'preferred wishlist'; + const unpreferredWishlist = 'unpreferred wishlist'; + const editedWishlist = 'edited wishlist'; + const anotherWishlist = 'another wishlist'; + + before(() => { + createUserViaREST(_.user); + LoginPage.navigateTo(); + at(LoginPage, page => { + page.fillForm(_.user.login, _.user.password); + page + .submit() + .its('status') + .should('equal', 200); + }); + WishlistsOverviewPage.navigateTo(); + }); + + it('user creates an unpreferred wishlist', () => { + at(WishlistsOverviewPage, page => { + page.addWishlist(unpreferredWishlist, false); + page.wishlistsArray.should('have.length', 1); + page.wishlistsTitlesArray.should('contain', unpreferredWishlist); + }); + }); + + it('user creates a preferred wishlist', () => { + at(WishlistsOverviewPage, page => { + page.addWishlist(preferredWishlist, true); + page.wishlistsArray.should('have.length', 2); + page.wishlistsTitlesArray.should('contain', preferredWishlist); + }); + }); + + it('user deletes first wishlist', () => { + at(WishlistsOverviewPage, page => { + page.wishlistsArray.then($listItems => { + const initLen = $listItems.length; + const firstItem = $listItems.first(); + + page.deleteWishlistById('unpreferred wishlist'); + page.wishlistsArray.should('have.length', initLen - 1); + page.wishlistsArray.should('not.include', firstItem); + }); + }); + }); + + it('user adds 2 products from the product detail page to wishlist (using preferred wishlist)', () => { + at(WishlistsOverviewPage, page => { + page.addWishlist(anotherWishlist, false); + page.header.gotoCategoryPage(_.category); + }); + + at(CategoryPage, page => page.gotoSubCategory(_.subcategory)); + at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product2)); + at(ProductDetailPage, page => { + page.addProductToWishlist(); + page.addToWishlist.addProductToWishlistFromPage(); + }); + at(WishlistsDetailsPage, page => { + page.listItemLink.invoke('attr', 'href').should('contain', _.product2); + page.header.gotoCategoryPage(_.category); + }); + + at(CategoryPage, page => page.gotoSubCategory(_.subcategory)); + at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product1)); + at(ProductDetailPage, page => { + page.addProductToWishlist(); + page.addToWishlist.addProductToWishlistFromPage(); + }); + at(WishlistsDetailsPage, page => { + page.listItemLink.should('have.length', 2); + }); + }); + + it('user renames a wishlist and sets it to unpreferred', () => { + at(WishlistsDetailsPage, page => { + page.editWishlistDetails(editedWishlist, false); + page.wishlistTitle.should('equal', editedWishlist); + page.wishlistPreferredTextElement.should('not.exist'); + }); + }); + + it('user deletes a product from wishlist', () => { + at(WishlistsDetailsPage, page => { + page.listItemLink.then($listItems => { + const initLength = $listItems.length; + page.deleteWishlist(_.product2); + cy.wait(500); + page.listItemLink.invoke('attr', 'href').should('not.contain', _.product2); + page.listItemLink.should('have.length', initLength - 1); + }); + }); + }); + + it('user moves a product to another wishlist', () => { + at(WishlistsDetailsPage, page => { + page.moveProductToWishlist(_.product1, anotherWishlist); + cy.wait(500); + page.wishlistTitle.should('equal', anotherWishlist); + page.getWishlistItemById(_.product1).should('exist'); + }); + WishlistsOverviewPage.navigateTo(); + at(WishlistsOverviewPage, page => { + page.goToWishlistDetailLink(editedWishlist); + }); + + at(WishlistsDetailsPage, page => { + page.listItem.should('not.exist'); + }); + }); +}); diff --git a/e2e/cypress/integration/specs/extras/wishlists-shopping.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/extras/wishlists-shopping.b2c.e2e-spec.ts new file mode 100644 index 0000000000..c9ddf0d5bf --- /dev/null +++ b/e2e/cypress/integration/specs/extras/wishlists-shopping.b2c.e2e-spec.ts @@ -0,0 +1,93 @@ +import { at } from '../../framework'; +import { createUserViaREST } from '../../framework/users'; +import { LoginPage } from '../../pages/account/login.page'; +import { sensibleDefaults } from '../../pages/account/registration.page'; +import { WishlistsDetailsPage } from '../../pages/account/wishlists-details.page'; +import { WishlistsOverviewPage } from '../../pages/account/wishlists-overview.page'; +import { CartPage } from '../../pages/checkout/cart.page'; +import { CategoryPage } from '../../pages/shopping/category.page'; +import { FamilyPage } from '../../pages/shopping/family.page'; + +const _ = { + user: { + login: `test${new Date().getTime()}@testcity.de`, + ...sensibleDefaults, + }, + category: 'Home-Entertainment', + subcategory: 'Home-Entertainment.SmartHome', + product1: '201807171', + product2: '201807194', + product3: '201807191', +}; + +describe('Wishlist Shopping Experience Functionality', () => { + const unpreferredWishlist = 'unpreferred wishlist'; + const shoppingUnpreferred = 'shopping wishlist'; + const shoppingPreferred = 'shopping wishlist preferred'; + before(() => { + createUserViaREST(_.user); + LoginPage.navigateTo(); + at(LoginPage, page => { + page.fillForm(_.user.login, _.user.password); + page + .submit() + .its('status') + .should('equal', 200); + }); + WishlistsOverviewPage.navigateTo(); + at(WishlistsOverviewPage, page => { + page.addWishlist(unpreferredWishlist, false); + page.addWishlist(shoppingUnpreferred, false); + }); + }); + + it('user adds a product from the product tile to wishlist (with selecting a wishlist)', () => { + at(WishlistsOverviewPage, page => { + page.header.gotoCategoryPage(_.category); + }); + + at(CategoryPage, page => page.gotoSubCategory(_.subcategory)); + at(FamilyPage, page => + page.productList.addToWishlist.addProductToWishlistFromList(_.product1, unpreferredWishlist) + ); + at(WishlistsDetailsPage, page => page.listItemLink.invoke('attr', 'href').should('contain', _.product1)); + }); + + it('user adds a wishlist product to cart', () => { + at(WishlistsDetailsPage, page => { + page.addProductToBasket(_.product1, 4); + page.header.miniCart.goToCart(); + }); + at(CartPage, page => { + page.lineItems.contains(_.product1).should('exist'); + page.lineItems + .contains(_.product1) + .closest('[data-testing-id="product-list-item"]') + .find('[data-testing-id="quantity"]') + .should('have.value', '4'); + }); + }); + + it('user adds a product to wishlist from shopping cart (with wishlist selection)', () => { + at(CartPage, page => { + page.addProductToWishlist(); + page.addToWishlist.addProductToWishlistFromPage(shoppingUnpreferred, true); + }); + at(WishlistsDetailsPage, page => { + page.listItemLink.invoke('attr', 'href').should('contain', _.product1); + }); + }); + + it('user adds a product to wishlist from shopping cart (to a preferred wishlist without selection)', () => { + WishlistsOverviewPage.navigateTo(); + at(WishlistsOverviewPage, page => { + page.addWishlist(shoppingPreferred, true); + page.header.miniCart.goToCart(); + }); + at(CartPage, page => { + page.addProductToWishlist(); + page.addToWishlist.addProductToWishlistFromPage(shoppingPreferred, false); + }); + at(WishlistsDetailsPage, page => page.listItemLink.invoke('attr', 'href').should('contain', _.product1)); + }); +}); diff --git a/e2e/cypress/integration/specs/quoting/quote-display.b2b.e2e-spec.ts b/e2e/cypress/integration/specs/quoting/quote-display.b2b.e2e-spec.ts new file mode 100644 index 0000000000..5819dc1e97 --- /dev/null +++ b/e2e/cypress/integration/specs/quoting/quote-display.b2b.e2e-spec.ts @@ -0,0 +1,95 @@ +import { at } from '../../framework'; +import { createB2BUserViaREST } from '../../framework/b2b-user'; +import { mockQuotes } from '../../framework/quote-mock'; +import { LoginPage } from '../../pages/account/login.page'; +import { MyAccountPage } from '../../pages/account/my-account.page'; +import { QuoteDetailPage } from '../../pages/account/quote-detail.page'; +import { QuoteListPage } from '../../pages/account/quote-list.page'; +import { sensibleDefaults } from '../../pages/account/registration.page'; + +const _ = { + user: { + login: `test${new Date().getTime()}@testcity.de`, + ...sensibleDefaults, + }, +}; + +describe('Quote MyAccount Display', () => { + before(() => { + createB2BUserViaREST(_.user); + LoginPage.navigateTo(); + at(LoginPage, page => { + page.fillForm(_.user.login, _.user.password); + page + .submit() + .its('status') + .should('equal', 200); + }); + }); + beforeEach(() => { + mockQuotes(); + }); + + it('check counter for newQuotes in my quotes table ', () => { + at(MyAccountPage, page => { + page.newQuoteLabel.should('have.text', '1'); + }); + }); + + it('check counter for submittedQuotes in my quotes table ', () => { + at(MyAccountPage, page => { + page.submittedQuoteLabel.should('have.text', '1'); + }); + }); + + it('check counter for acceptedQuotes in my quotes table ', () => { + at(MyAccountPage, page => { + page.acceptedQuoteLabel.should('have.text', '2'); + }); + }); + + it('check counter for rejectedQuotes in my quotes table ', () => { + at(MyAccountPage, page => { + page.rejectedQuoteLabel.should('have.text', '1'); + }); + }); + + it('check quote detail page properties for responded quote', () => { + at(MyAccountPage, page => { + page.navigateToQuoting(); + }); + at(QuoteListPage, page => { + page.goToQuoteDetailLink('quoteResponded'); + }); + at(QuoteDetailPage, page => { + page.quoteState.should('contain', 'Responded'); + page.header.goToMyAccount(); + }); + }); + + it('check quote detail page properties for expired quote', () => { + at(MyAccountPage, page => { + page.navigateToQuoting(); + }); + at(QuoteListPage, page => { + page.goToQuoteDetailLink('quoteExpired'); + }); + at(QuoteDetailPage, page => { + page.quoteState.should('contain', 'Expired'); + page.header.goToMyAccount(); + }); + }); + + it('check quote detail page properties for Rejected quote and logs out', () => { + at(MyAccountPage, page => { + page.navigateToQuoting(); + }); + at(QuoteListPage, page => { + page.goToQuoteDetailLink('quoteRejected'); + }); + at(QuoteDetailPage, page => { + page.quoteState.should('contain', 'Rejected'); + page.header.logout(); + }); + }); +}); diff --git a/e2e/cypress/integration/specs/quoting/quote-handling-anonymous.b2b.e2e-spec.ts b/e2e/cypress/integration/specs/quoting/quote-handling-anonymous.b2b.e2e-spec.ts index f065b82993..8afd9bc41f 100644 --- a/e2e/cypress/integration/specs/quoting/quote-handling-anonymous.b2b.e2e-spec.ts +++ b/e2e/cypress/integration/specs/quoting/quote-handling-anonymous.b2b.e2e-spec.ts @@ -44,15 +44,16 @@ describe('Quote Handling as Anonymous User', () => { it('user should be able to submit quote request', () => { at(ProductDetailPage, page => page.addProductToQuoteRequest()); - at(QuoteRequestDialog, dialog => dialog.submitQuoteRequest()); - at(QuoteDetailPage, page => { - page.productId.eq(0).should('contain', _.product.sku); - page.quoteState.should('have.text', 'Submitted'); + at(QuoteRequestDialog, dialog => { + dialog.submitQuoteRequest(); + dialog.productId.eq(0).should('contain', _.product.sku); + dialog.quoteState.should('have.text', 'Submitted'); + dialog.hide(); }); }); it('user should log out', () => { - at(QuoteDetailPage, page => page.header.logout()); + at(ProductDetailPage, page => page.header.logout()); at(HomePage); }); }); diff --git a/e2e/cypress/integration/specs/quoting/quote-handling.b2b.e2e-spec.ts b/e2e/cypress/integration/specs/quoting/quote-handling.b2b.e2e-spec.ts index 354e90d724..eec10f6d01 100644 --- a/e2e/cypress/integration/specs/quoting/quote-handling.b2b.e2e-spec.ts +++ b/e2e/cypress/integration/specs/quoting/quote-handling.b2b.e2e-spec.ts @@ -1,6 +1,5 @@ import { at } from '../../framework'; import { createB2BUserViaREST } from '../../framework/b2b-user'; -import { mockQuotes } from '../../framework/quote-mock'; import { LoginPage } from '../../pages/account/login.page'; import { MyAccountPage } from '../../pages/account/my-account.page'; import { QuoteDetailPage } from '../../pages/account/quote-detail.page'; @@ -25,8 +24,6 @@ const _ = { }, }; -const quantity = 2; - describe('Quote Handling', () => { before(() => { createB2BUserViaREST(_.user); @@ -41,6 +38,7 @@ describe('Quote Handling', () => { }); it('user adds one product from product detail page to quote', () => { + const quantity = 2; at(MyAccountPage, page => page.header.gotoCategoryPage(_.catalog)); at(CategoryPage, page => page.gotoSubCategory(_.categoryId)); at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); @@ -49,30 +47,24 @@ describe('Quote Handling', () => { page.addProductToQuoteRequest(); }); at(QuoteRequestDialog, dialog => { - dialog.saveQuoteRequest(); - }); - at(QuoteDetailPage, page => { - page.totalPrice.should('contain', _.product.price * quantity); - page.deleteItemFromQuoteRequest(); + dialog.totalPrice.should('contain', _.product.price * quantity); + dialog.deleteItemFromQuoteRequest(); + dialog.assertClosed(); }); }); it('user adds one product from product list page to quote', () => { - at(MyAccountPage, page => page.header.gotoCategoryPage(_.catalog)); - at(CategoryPage, page => page.gotoSubCategory(_.categoryId)); + at(ProductDetailPage, page => page.breadcrumb.items.eq(2).click()); at(FamilyPage, page => page.productList.addProductToQuoteRequest(_.product.sku)); at(QuoteRequestDialog, dialog => { - dialog.saveQuoteRequest(); - }); - at(QuoteDetailPage, page => { - page.totalPrice.should('contain', _.product.price); - page.deleteItemFromQuoteRequest(); + dialog.totalPrice.should('contain', _.product.price); + dialog.deleteItemFromQuoteRequest(); + dialog.assertClosed(); }); }); it('user adds one product from basket to quote', () => { - at(MyAccountPage, page => page.header.gotoCategoryPage(_.catalog)); - at(CategoryPage, page => page.gotoSubCategory(_.categoryId)); + const quantity = 2; at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); at(ProductDetailPage, page => { page.setQuantity(quantity); @@ -96,7 +88,12 @@ describe('Quote Handling', () => { at(CategoryPage, page => page.gotoSubCategory(_.categoryId)); at(FamilyPage, page => page.productList.addProductToQuoteRequest(_.product.sku)); at(QuoteRequestDialog, dialog => { - dialog.submitQuoteRequest(); + dialog.submitQuoteRequest().then(quoteId => { + dialog.hide(); + at(FamilyPage, page => page.header.goToMyAccount()); + at(MyAccountPage, page => page.navigateToQuoting()); + at(QuoteListPage, page => page.goToQuoteDetailLink(quoteId)); + }); }); at(QuoteDetailPage, page => { page.quoteState.should('have.text', 'Submitted'); @@ -108,7 +105,12 @@ describe('Quote Handling', () => { at(CategoryPage, page => page.gotoSubCategory(_.categoryId)); at(FamilyPage, page => page.productList.addProductToQuoteRequest(_.product.sku)); at(QuoteRequestDialog, dialog => { - dialog.submitQuoteRequest(); + dialog.submitQuoteRequest().then(quoteId => { + dialog.hide(); + at(FamilyPage, page => page.header.goToMyAccount()); + at(MyAccountPage, page => page.navigateToQuoting()); + at(QuoteListPage, page => page.goToQuoteDetailLink(quoteId)); + }); }); at(QuoteDetailPage, page => { page.copyQuoteRequest(); @@ -116,82 +118,3 @@ describe('Quote Handling', () => { }); }); }); - -describe('check displayed data from Rest', () => { - before(() => { - LoginPage.navigateTo(); - at(LoginPage, page => { - page.fillForm(_.user.login, _.user.password); - page - .submit() - .its('status') - .should('equal', 200); - }); - }); - beforeEach(() => { - mockQuotes(); - }); - - it('check counter for newQuotes in my quotes table ', () => { - at(MyAccountPage, page => { - page.newQuoteLabel.should('have.text', '1'); - }); - }); - - it('check counter for submittedQuotes in my quotes table ', () => { - at(MyAccountPage, page => { - page.submittedQuoteLabel.should('have.text', '1'); - }); - }); - - it('check counter for acceptedQuotes in my quotes table ', () => { - at(MyAccountPage, page => { - page.acceptedQuoteLabel.should('have.text', '2'); - }); - }); - - it('check counter for rejectedQuotes in my quotes table ', () => { - at(MyAccountPage, page => { - page.rejectedQuoteLabel.should('have.text', '1'); - }); - }); - - it('check quote detail page properties for responded quote', () => { - at(MyAccountPage, page => { - page.navigateToQuoting(); - }); - at(QuoteListPage, page => { - page.goToQuoteDetailLink('quoteResponded'); - }); - at(QuoteDetailPage, page => { - page.quoteState.should('contain', 'Responded'); - page.header.goToMyAccount(); - }); - }); - - it('check quote detail page properties for expired quote', () => { - at(MyAccountPage, page => { - page.navigateToQuoting(); - }); - at(QuoteListPage, page => { - page.goToQuoteDetailLink('quoteExpired'); - }); - at(QuoteDetailPage, page => { - page.quoteState.should('contain', 'Expired'); - page.header.goToMyAccount(); - }); - }); - - it('check quote detail page properties for Rejected quote and logs out', () => { - at(MyAccountPage, page => { - page.navigateToQuoting(); - }); - at(QuoteListPage, page => { - page.goToQuoteDetailLink('quoteRejected'); - }); - at(QuoteDetailPage, page => { - page.quoteState.should('contain', 'Rejected'); - page.header.logout(); - }); - }); -}); diff --git a/e2e/cypress/integration/specs/shopping/product-category-context-bundle-category.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/shopping/product-category-context-bundle-category.b2c.e2e-spec.ts new file mode 100644 index 0000000000..50c43742cd --- /dev/null +++ b/e2e/cypress/integration/specs/shopping/product-category-context-bundle-category.b2c.e2e-spec.ts @@ -0,0 +1,35 @@ +import { at } from '../../framework'; +import { FamilyPage } from '../../pages/shopping/family.page'; +import { ProductDetailPage } from '../../pages/shopping/product-detail.page'; + +const _ = { + bundleCategory: { + categoryId: 'Specials.HotDeals', + catalog: 'Specials', + name: 'Hot Deals', + }, + product: { + sku: '872843', + name: 'Epson Multipack', + }, +}; + +describe('Product Category Context', () => { + describe('located under bundle category', () => { + before(() => FamilyPage.navigateTo(_.bundleCategory.categoryId)); + + it('should find the product on family page', () => { + at(FamilyPage, page => page.productList.productTile(_.product.sku).should('contain', _.product.name)); + }); + + it('should follow to product detail page and see the category context of the bundle category', () => { + at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); + at(ProductDetailPage, page => { + page.sku.should('contain', _.product.sku); + page.breadcrumb.items.should('have.length', 4); + page.breadcrumb.items.eq(2).should('contain', _.bundleCategory.name); + page.breadcrumb.items.eq(3).should('contain', _.product.name); + }); + }); + }); +}); diff --git a/e2e/cypress/integration/specs/shopping/product-category-context-default-category.b2c.e2e-spec copy.ts b/e2e/cypress/integration/specs/shopping/product-category-context-default-category.b2c.e2e-spec copy.ts new file mode 100644 index 0000000000..53af799b8e --- /dev/null +++ b/e2e/cypress/integration/specs/shopping/product-category-context-default-category.b2c.e2e-spec copy.ts @@ -0,0 +1,37 @@ +import { at } from '../../framework'; +import { FamilyPage } from '../../pages/shopping/family.page'; +import { ProductDetailPage } from '../../pages/shopping/product-detail.page'; + +const _ = { + product: { + sku: '872843', + name: 'Epson Multipack', + defaultCategory: { + categoryId: 'Computers.225.373.377', + name: 'Ink Cartridges', + }, + }, +}; + +describe('Product Category Context', () => { + describe('located under default category', () => { + before(() => FamilyPage.navigateTo(_.product.defaultCategory.categoryId)); + + it('should see the product on the family page', () => { + at(FamilyPage, page => { + page.productList.makeAllProductsVisible(); + page.productList.productTile(_.product.sku).should('contain', _.product.name); + }); + }); + + it('should follow to product detail page and see the category context of the default category', () => { + at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); + at(ProductDetailPage, page => { + page.sku.should('contain', _.product.sku); + page.breadcrumb.items.should('have.length', 6); + page.breadcrumb.items.eq(4).should('contain', _.product.defaultCategory.name); + page.breadcrumb.items.eq(5).should('contain', _.product.name); + }); + }); + }); +}); diff --git a/e2e/cypress/integration/specs/shopping/product-category-context-product-detail.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/shopping/product-category-context-product-detail.b2c.e2e-spec.ts new file mode 100644 index 0000000000..88f3201464 --- /dev/null +++ b/e2e/cypress/integration/specs/shopping/product-category-context-product-detail.b2c.e2e-spec.ts @@ -0,0 +1,53 @@ +import { at } from '../../framework'; +import { CategoryPage } from '../../pages/shopping/category.page'; +import { FamilyPage } from '../../pages/shopping/family.page'; +import { ProductDetailPage } from '../../pages/shopping/product-detail.page'; + +const _ = { + bundleCategory: { + categoryId: 'Specials.HotDeals', + catalog: 'Specials', + name: 'Hot Deals', + }, + product: { + sku: '872843', + name: 'Epson Multipack', + defaultCategory: { + categoryId: 'Computers.225.373.377', + name: 'Ink Cartridges', + }, + }, +}; + +describe('Product Category Context', () => { + describe('directly navigating to product detail page', () => { + before(() => ProductDetailPage.navigateTo(_.product.sku)); + + it('should see the category context of the default category', () => { + at(ProductDetailPage, page => { + page.sku.should('contain', _.product.sku); + page.breadcrumb.items.should('have.length', 6); + page.breadcrumb.items.eq(4).should('contain', _.product.defaultCategory.name); + page.breadcrumb.items.eq(5).should('contain', _.product.name); + }); + }); + + describe('and then finding it via bundle category', () => { + it('should go to bundle category', () => { + at(ProductDetailPage, page => page.header.gotoCategoryPage(_.bundleCategory.catalog)); + at(CategoryPage, page => page.gotoSubCategory(_.bundleCategory.categoryId)); + at(FamilyPage, page => page.productList.productTile(_.product.sku).should('contain', _.product.name)); + }); + + it('should follow to product detail page and see the category context of the bundle category', () => { + at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); + at(ProductDetailPage, page => { + page.sku.should('contain', _.product.sku); + page.breadcrumb.items.should('have.length', 4); + page.breadcrumb.items.eq(2).should('contain', _.bundleCategory.name); + page.breadcrumb.items.eq(3).should('contain', _.product.name); + }); + }); + }); + }); +}); diff --git a/e2e/cypress/integration/specs/shopping/product-category-context-search.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/shopping/product-category-context-search.b2c.e2e-spec.ts new file mode 100644 index 0000000000..7c08e5af4b --- /dev/null +++ b/e2e/cypress/integration/specs/shopping/product-category-context-search.b2c.e2e-spec.ts @@ -0,0 +1,39 @@ +import { at } from '../../framework'; +import { HomePage } from '../../pages/home.page'; +import { ProductDetailPage } from '../../pages/shopping/product-detail.page'; +import { SearchResultPage } from '../../pages/shopping/search-result.page'; + +const _ = { + product: { + sku: '872843', + name: 'Epson Multipack', + defaultCategory: { + categoryId: 'Computers.225.373.377', + name: 'Ink Cartridges', + }, + }, +}; + +describe('Product Category Context', () => { + describe('when searching for the product', () => { + before(() => HomePage.navigateTo()); + + it('should search for the product', () => { + at(HomePage, page => page.header.doProductSearch(_.product.name)); + }); + + it('should find the product on search result page', () => { + at(SearchResultPage, page => page.productList.productTile(_.product.sku).should('contain', _.product.name)); + }); + + it('should follow to product detail page and see the category context of the default category', () => { + at(SearchResultPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); + at(ProductDetailPage, page => { + page.sku.should('contain', _.product.sku); + page.breadcrumb.items.should('have.length', 6); + page.breadcrumb.items.eq(4).should('contain', _.product.defaultCategory.name); + page.breadcrumb.items.eq(5).should('contain', _.product.name); + }); + }); + }); +}); diff --git a/e2e/cypress/integration/specs/shopping/product-category-context.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/shopping/product-category-context.b2c.e2e-spec.ts deleted file mode 100644 index c653340509..0000000000 --- a/e2e/cypress/integration/specs/shopping/product-category-context.b2c.e2e-spec.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { at } from '../../framework'; -import { HomePage } from '../../pages/home.page'; -import { CategoryPage } from '../../pages/shopping/category.page'; -import { FamilyPage } from '../../pages/shopping/family.page'; -import { ProductDetailPage } from '../../pages/shopping/product-detail.page'; -import { SearchResultPage } from '../../pages/shopping/search-result.page'; - -const _ = { - bundleCategory: { - categoryId: 'Specials.HotDeals', - catalog: 'Specials', - name: 'Hot Deals', - }, - product: { - sku: '872843', - name: 'Epson Multipack', - defaultCategory: { - categoryId: 'Computers.225.373.377', - name: 'Ink Cartridges', - }, - }, -}; - -describe('Product Category Context', () => { - describe('located under default category', () => { - before(() => FamilyPage.navigateTo(_.product.defaultCategory.categoryId)); - - it('should see the product on the family page', () => { - at(FamilyPage, page => { - page.productList.makeAllProductsVisible(); - page.productList.productTile(_.product.sku).should('contain', _.product.name); - }); - }); - - it('should follow to product detail page and see the category context of the default category', () => { - at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); - at(ProductDetailPage, page => { - page.sku.should('contain', _.product.sku); - page.breadcrumb.items.should('have.length', 6); - page.breadcrumb.items.eq(4).should('contain', _.product.defaultCategory.name); - page.breadcrumb.items.eq(5).should('contain', _.product.name); - }); - }); - }); - - describe('located under bundle category', () => { - before(() => FamilyPage.navigateTo(_.bundleCategory.categoryId)); - - it('should find the product on family page', () => { - at(FamilyPage, page => page.productList.productTile(_.product.sku).should('contain', _.product.name)); - }); - - it('should follow to product detail page and see the category context of the bundle category', () => { - at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); - at(ProductDetailPage, page => { - page.sku.should('contain', _.product.sku); - page.breadcrumb.items.should('have.length', 4); - page.breadcrumb.items.eq(2).should('contain', _.bundleCategory.name); - page.breadcrumb.items.eq(3).should('contain', _.product.name); - }); - }); - }); - - describe('when searching for the product', () => { - before(() => HomePage.navigateTo()); - - it('should search for the product', () => { - at(HomePage, page => page.header.doProductSearch(_.product.name)); - }); - - it('should find the product on search result page', () => { - at(SearchResultPage, page => page.productList.productTile(_.product.sku).should('contain', _.product.name)); - }); - - it('should follow to product detail page and see the category context of the default category', () => { - at(SearchResultPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); - at(ProductDetailPage, page => { - page.sku.should('contain', _.product.sku); - page.breadcrumb.items.should('have.length', 6); - page.breadcrumb.items.eq(4).should('contain', _.product.defaultCategory.name); - page.breadcrumb.items.eq(5).should('contain', _.product.name); - }); - }); - }); - - describe('directly navigating to product detail page', () => { - before(() => ProductDetailPage.navigateTo(_.product.sku)); - - it('should see the category context of the default category', () => { - at(ProductDetailPage, page => { - page.sku.should('contain', _.product.sku); - page.breadcrumb.items.should('have.length', 6); - page.breadcrumb.items.eq(4).should('contain', _.product.defaultCategory.name); - page.breadcrumb.items.eq(5).should('contain', _.product.name); - }); - }); - - describe('and then finding it via bundle category', () => { - it('should go to bundle category', () => { - at(ProductDetailPage, page => page.header.gotoCategoryPage(_.bundleCategory.catalog)); - at(CategoryPage, page => page.gotoSubCategory(_.bundleCategory.categoryId)); - at(FamilyPage, page => page.productList.productTile(_.product.sku).should('contain', _.product.name)); - }); - - it('should follow to product detail page and see the category context of the bundle category', () => { - at(FamilyPage, page => page.productList.gotoProductDetailPageBySku(_.product.sku)); - at(ProductDetailPage, page => { - page.sku.should('contain', _.product.sku); - page.breadcrumb.items.should('have.length', 4); - page.breadcrumb.items.eq(2).should('contain', _.bundleCategory.name); - page.breadcrumb.items.eq(3).should('contain', _.product.name); - }); - }); - }); - }); -}); diff --git a/e2e/cypress/integration/specs/shopping/search-products.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/shopping/search-products.b2c.e2e-spec.ts index ad730cf02c..1d82404131 100644 --- a/e2e/cypress/integration/specs/shopping/search-products.b2c.e2e-spec.ts +++ b/e2e/cypress/integration/specs/shopping/search-products.b2c.e2e-spec.ts @@ -5,7 +5,7 @@ import { SearchResultPage } from '../../pages/shopping/search-result.page'; const _ = { suggestTerm: 'k', - searchTerm: 'kodak', + searchTerm: 'kodak M552', suggestItemText: 'Kodak', product: '7912057', }; diff --git a/e2e/cypress/integration/specs/shopping/variation-handling.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/shopping/variation-handling.b2c.e2e-spec.ts index e13b78305a..3221fae11a 100644 --- a/e2e/cypress/integration/specs/shopping/variation-handling.b2c.e2e-spec.ts +++ b/e2e/cypress/integration/specs/shopping/variation-handling.b2c.e2e-spec.ts @@ -25,7 +25,7 @@ describe('Variation Handling B2C', () => { }); it('changing the variation should redirect to other variation', () => { - at(ProductDetailPage, page => page.changeVariationWithSelect('Attr_harddrivesize', '256GB')); + at(ProductDetailPage, page => page.changeVariationWithSelect('Hard_disk_drive_capacity', '256GB')); at(ProductDetailPage, page => page.sku.should('have.text', _.otherVariationSKU)); }); diff --git a/e2e/cypress/integration/specs/account/authentication-timeouts-anonymous.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/authentication-timeouts-anonymous.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/account/authentication-timeouts-anonymous.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/authentication-timeouts-anonymous.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/account/authentication-timeouts-loggedin.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/authentication-timeouts-loggedin.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/account/authentication-timeouts-loggedin.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/authentication-timeouts-loggedin.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/account/change-language-authentication.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/change-language-authentication.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/account/change-language-authentication.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/change-language-authentication.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/shopping/change-language-family-page.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/change-language-family-page.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/shopping/change-language-family-page.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/change-language-family-page.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/shopping/change-language-hompage.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/change-language-hompage.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/shopping/change-language-hompage.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/change-language-hompage.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/shopping/change-language-product-detail.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/change-language-product-detail.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/shopping/change-language-product-detail.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/change-language-product-detail.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/shopping/change-language-search-result.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/change-language-search-result.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/shopping/change-language-search-result.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/change-language-search-result.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/shopping/rest-error-handling.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/rest-error-handling.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/shopping/rest-error-handling.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/rest-error-handling.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/account/retain-authentication.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/retain-authentication.b2c.e2e-spec.ts similarity index 100% rename from e2e/cypress/integration/specs/account/retain-authentication.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/retain-authentication.b2c.e2e-spec.ts diff --git a/e2e/cypress/integration/specs/system/retain-basket-anonymous.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/retain-basket-anonymous.b2c.e2e-spec.ts new file mode 100644 index 0000000000..48f9016eb6 --- /dev/null +++ b/e2e/cypress/integration/specs/system/retain-basket-anonymous.b2c.e2e-spec.ts @@ -0,0 +1,31 @@ +import { at, waitLoadingEnd } from '../../framework'; +import { HomePage } from '../../pages/home.page'; +import { ProductDetailPage } from '../../pages/shopping/product-detail.page'; + +const _ = { + product: { + sku: '201807171', + price: 185.5, + }, +}; + +describe('Returning User with Basket', () => { + describe('anonymous user', () => { + it('should add product to basket', () => { + ProductDetailPage.navigateTo(_.product.sku); + at(ProductDetailPage, page => { + page + .addProductToCart() + .its('status') + .should('equal', 201); + page.header.miniCart.total.should('contain', _.product.price); + waitLoadingEnd(1000); + }); + }); + + it('should refresh page and still have basket', () => { + HomePage.navigateTo(); + at(HomePage, page => page.header.miniCart.total.should('contain', _.product.price)); + }); + }); +}); diff --git a/e2e/cypress/integration/specs/checkout/retain-basket.b2c.e2e-spec.ts b/e2e/cypress/integration/specs/system/retain-basket-authenticated.b2c.e2e-spec.ts similarity index 75% rename from e2e/cypress/integration/specs/checkout/retain-basket.b2c.e2e-spec.ts rename to e2e/cypress/integration/specs/system/retain-basket-authenticated.b2c.e2e-spec.ts index ce22041b77..379e323122 100644 --- a/e2e/cypress/integration/specs/checkout/retain-basket.b2c.e2e-spec.ts +++ b/e2e/cypress/integration/specs/system/retain-basket-authenticated.b2c.e2e-spec.ts @@ -1,4 +1,4 @@ -import { at, waitLoadingEnd } from '../../framework'; +import { at } from '../../framework'; import { createUserViaREST } from '../../framework/users'; import { LoginPage } from '../../pages/account/login.page'; import { MyAccountPage } from '../../pages/account/my-account.page'; @@ -25,25 +25,6 @@ const _ = { }; describe('Returning User with Basket', () => { - describe('anonymous user', () => { - it('should add product to basket', () => { - ProductDetailPage.navigateTo(_.product.sku); - at(ProductDetailPage, page => { - page - .addProductToCart() - .its('status') - .should('equal', 201); - page.header.miniCart.total.should('contain', _.product.price); - waitLoadingEnd(1000); - }); - }); - - it('should refresh page and still have basket', () => { - HomePage.navigateTo(); - at(HomePage, page => page.header.miniCart.total.should('contain', _.product.price)); - }); - }); - describe('authenticated user', () => { before(() => { createUserViaREST(_.user); diff --git a/e2e/cypress/tsconfig.json b/e2e/cypress/tsconfig.json index 29e09f63db..d2ade9b14e 100644 --- a/e2e/cypress/tsconfig.json +++ b/e2e/cypress/tsconfig.json @@ -11,7 +11,7 @@ "outDir": "../out-tsc", "module": "commonjs", "moduleResolution": "node", - "target": "es5", + "target": "es6", "types": ["node", "cypress"] } } diff --git a/e2e/package-lock.json b/e2e/package-lock.json index c77586909d..7b8f3c9e7f 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -834,6 +834,19 @@ "lodash.once": "^4.1.1" } }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "requires": { + "any-observable": "^0.3.0" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, "@types/node": { "version": "10.12.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", @@ -1044,9 +1057,9 @@ "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==" }, "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" }, "ansi-regex": { "version": "2.1.1", @@ -1061,6 +1074,11 @@ "color-convert": "^1.9.0" } }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==" + }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -1163,12 +1181,9 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async/-/async-3.1.1.tgz", + "integrity": "sha512-X5Dj8hK1pJNC2Wzo2Rcp9FBVdJMGRR/S7V+lH46s8GVFhtbo5O4Le5GECCF/8PISVdkUA6mMPvgz7qTTD1rf1g==" }, "async-each": { "version": "1.0.3", @@ -1501,12 +1516,9 @@ } }, "cachedir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-1.3.0.tgz", - "integrity": "sha512-O1ji32oyON9laVPJL1IZ5bmwd2cB46VfpxkDequezH+15FDzzVddEyrGEeX4WusDSqKxdyFdDQDEG1yo1GoWkg==", - "requires": { - "os-homedir": "^1.0.1" - } + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==" }, "caniuse-lite": { "version": "1.0.30000974", @@ -1567,9 +1579,9 @@ } }, "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, "cipher-base": { "version": "1.0.4", @@ -1609,11 +1621,6 @@ "restore-cursor": "^1.0.1" } }, - "cli-spinners": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", - "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=" - }, "cli-truncate": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", @@ -1659,9 +1666,9 @@ } }, "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.0.tgz", + "integrity": "sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw==" }, "common-tags": { "version": "1.8.0", @@ -1799,15 +1806,13 @@ } }, "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "crypto-browserify": { @@ -1834,52 +1839,101 @@ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" }, "cypress": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-3.8.2.tgz", - "integrity": "sha512-aTs0u3+dfEuLe0Ct0FVO5jD1ULqxbuqWUZwzBm0rxdLgLxIAOI/A9f/WkgY5Cfy1TEXe8pKC6Wal0ZpnkdGRSw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-4.0.2.tgz", + "integrity": "sha512-WRzxOoSd+TxyXKa7Zi9orz3ii5VW7yhhVYstCU+EpOKfPan9x5Ww2Clucmy4H/W0GHUYAo7GYFZRD33ZCSNBQA==", "requires": { "@cypress/listr-verbose-renderer": "0.4.1", "@cypress/xvfb": "1.2.4", "@types/sizzle": "2.3.2", "arch": "2.1.1", - "bluebird": "3.5.0", - "cachedir": "1.3.0", - "chalk": "2.4.2", + "bluebird": "3.7.2", + "cachedir": "2.3.0", + "chalk": "3.0.0", "check-more-types": "2.24.0", - "commander": "2.15.1", + "commander": "4.1.0", "common-tags": "1.8.0", - "debug": "3.2.6", + "debug": "4.1.1", "eventemitter2": "4.1.2", - "execa": "0.10.0", + "execa": "3.3.0", "executable": "4.1.1", "extract-zip": "1.6.7", - "fs-extra": "5.0.0", - "getos": "3.1.1", - "is-ci": "1.2.1", + "fs-extra": "8.1.0", + "getos": "3.1.4", + "is-ci": "2.0.0", "is-installed-globally": "0.1.0", "lazy-ass": "1.6.0", - "listr": "0.12.0", + "listr": "0.14.3", "lodash": "4.17.15", - "log-symbols": "2.2.0", + "log-symbols": "3.0.0", "minimist": "1.2.0", "moment": "2.24.0", - "ramda": "0.24.1", + "ramda": "0.26.1", "request": "2.88.0", "request-progress": "3.0.0", - "supports-color": "5.5.0", + "supports-color": "7.1.0", "tmp": "0.1.0", - "untildify": "3.0.3", + "untildify": "4.0.0", "url": "0.11.0", "yauzl": "2.10.0" }, "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { "ms": "^2.1.1" } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -2135,17 +2189,30 @@ } }, "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.3.0.tgz", + "integrity": "sha512-j5Vit5WZR/cbHlqU97+qcnw9WHRCIL4V1SVe75VcHcD1JRBdt8fv0zw89b7CQHQdUHTt2VjuhcF5ibAgVOxqpg==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + } } }, "executable": { @@ -2453,13 +2520,20 @@ } }, "fs-extra": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", - "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "requires": { - "graceful-fs": "^4.1.2", + "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" + } } }, "fs-write-stream-atomic": { @@ -2960,9 +3034,12 @@ } }, "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } }, "get-value": { "version": "2.0.6", @@ -2970,11 +3047,11 @@ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, "getos": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.1.1.tgz", - "integrity": "sha512-oUP1rnEhAr97rkitiszGP9EgDVYnmchgFzfqRzSkgtfv7ai6tEi7Ko8GgjNXts7VLWEqrTWyhsOKLe5C5b/Zkg==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.1.4.tgz", + "integrity": "sha512-UORPzguEB/7UG5hqiZai8f0vQ7hzynMQyJLxStoQ8dPGAcmgsfXOPA4iE/fGtweHYkK+z4zc9V0g+CIFRf5HYw==", "requires": { - "async": "2.6.1" + "async": "^3.1.0" } }, "getpass": { @@ -3135,6 +3212,11 @@ "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" + }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", @@ -3151,12 +3233,9 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "requires": { - "repeating": "^2.0.0" - } + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" }, "indexof": { "version": "0.0.1", @@ -3228,11 +3307,11 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "requires": { - "ci-info": "^1.5.0" + "ci-info": "^2.0.0" } }, "is-data-descriptor": { @@ -3280,14 +3359,6 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -3331,6 +3402,14 @@ } } }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "requires": { + "symbol-observable": "^1.1.0" + } + }, "is-path-inside": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", @@ -3353,9 +3432,9 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" }, "is-typedarray": { "version": "1.0.0", @@ -3474,57 +3553,25 @@ "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=" }, "listr": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", - "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", "requires": { - "chalk": "^1.1.3", - "cli-truncate": "^0.2.1", - "figures": "^1.7.0", - "indent-string": "^2.1.0", + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", "is-promise": "^2.1.0", "is-stream": "^1.1.0", "listr-silent-renderer": "^1.1.1", - "listr-update-renderer": "^0.2.0", - "listr-verbose-renderer": "^0.4.0", - "log-symbols": "^1.0.2", - "log-update": "^1.0.2", - "ora": "^0.2.3", - "p-map": "^1.1.1", - "rxjs": "^5.0.0-beta.11", - "stream-to-observable": "^0.1.0", - "strip-ansi": "^3.0.1" + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" }, "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "log-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", - "requires": { - "chalk": "^1.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" } } }, @@ -3534,9 +3581,9 @@ "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=" }, "listr-update-renderer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz", - "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", "requires": { "chalk": "^1.1.3", "cli-truncate": "^0.2.1", @@ -3544,7 +3591,7 @@ "figures": "^1.7.0", "indent-string": "^3.0.0", "log-symbols": "^1.0.2", - "log-update": "^1.0.2", + "log-update": "^2.3.0", "strip-ansi": "^3.0.1" }, "dependencies": { @@ -3565,11 +3612,6 @@ "supports-color": "^2.0.0" } }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=" - }, "log-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", @@ -3586,37 +3628,53 @@ } }, "listr-verbose-renderer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", - "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", "requires": { - "chalk": "^1.1.3", - "cli-cursor": "^1.0.2", + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", "date-fns": "^1.27.2", - "figures": "^1.7.0" + "figures": "^2.0.0" }, "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "escape-string-regexp": "^1.0.5" } }, - "supports-color": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } } } }, @@ -3665,20 +3723,53 @@ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "requires": { - "chalk": "^2.0.1" + "chalk": "^2.4.2" } }, "log-update": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", - "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", "requires": { - "ansi-escapes": "^1.0.0", - "cli-cursor": "^1.0.2" + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + } } }, "logdown": { @@ -3752,6 +3843,11 @@ "readable-stream": "^2.0.1" } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -3794,6 +3890,11 @@ "mime-db": "1.43.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -3920,11 +4021,6 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, "node-libs-browser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", @@ -3977,11 +4073,11 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "requires": { - "path-key": "^2.0.0" + "path-key": "^3.0.0" } }, "number-is-nan": { @@ -4056,55 +4152,15 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" }, - "ora": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", - "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "requires": { - "chalk": "^1.1.1", - "cli-cursor": "^1.0.2", - "cli-spinners": "^0.1.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", + "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==" }, "p-limit": { "version": "2.2.0", @@ -4123,9 +4179,9 @@ } }, "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" }, "p-try": { "version": "2.2.0", @@ -4191,9 +4247,9 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-parse": { "version": "1.0.6", @@ -4336,9 +4392,9 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "ramda": { - "version": "0.24.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz", - "integrity": "sha1-w7d1UZfzW43DUCIoJixMkd22uFc=" + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" }, "randombytes": { "version": "2.1.0", @@ -4472,14 +4528,6 @@ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -4569,11 +4617,11 @@ } }, "rxjs": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", - "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", "requires": { - "symbol-observable": "1.0.1" + "tslib": "^1.9.0" } }, "safe-buffer": { @@ -4650,17 +4698,17 @@ } }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "signal-exit": { "version": "3.0.2", @@ -4911,11 +4959,6 @@ "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, - "stream-to-observable": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.1.0.tgz", - "integrity": "sha1-Rb8dny19wJvtgfHDB8Qw5ouEz/4=" - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -4942,10 +4985,10 @@ "ansi-regex": "^2.0.0" } }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" }, "supports-color": { "version": "5.5.0", @@ -4956,9 +4999,9 @@ } }, "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, "tapable": { "version": "1.1.3", @@ -5262,9 +5305,9 @@ } }, "untildify": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", - "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==" }, "upath": { "version": "1.1.2", @@ -5399,9 +5442,9 @@ } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "requires": { "isexe": "^2.0.0" } @@ -5414,6 +5457,44 @@ "errno": "~0.1.7" } }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/e2e/package.json b/e2e/package.json index 4f7cf976a5..8fe5f772c9 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -10,7 +10,7 @@ "dependencies": { "@cypress/webpack-preprocessor": "^4.1.0", "@types/node": "^10.12.18", - "cypress": "^3.8.2", + "cypress": "^4.0.2", "cypress-failed-log": "^2.5.0", "ts-loader": "5.3.2", "typescript": "~3.2.2", diff --git a/e2e/test-e2e.sh b/e2e/test-e2e.sh index 352fa7b57a..715defb68a 100644 --- a/e2e/test-e2e.sh +++ b/e2e/test-e2e.sh @@ -15,5 +15,5 @@ wget --wait 10 --tries 10 --retry-connrefused $PWA_BASE_URL cd "$(dirname "$(readlink -f "$0")")" -TIMEOUT="20m" +TIMEOUT="10m" timeout $TIMEOUT node cypress-ci-e2e "$files" || ([ "$?" -eq "124" ] && timeout $TIMEOUT node cypress-ci-e2e "$files") || ([ "$?" -eq "124" ] && timeout $TIMEOUT node cypress-ci-e2e "$files") diff --git a/e2e/test-schematics.sh b/e2e/test-schematics.sh index e182172208..080698ed72 100644 --- a/e2e/test-schematics.sh +++ b/e2e/test-schematics.sh @@ -19,7 +19,7 @@ npx ng g store-group training stat src/app/core/store/training/training-store.ts grep "TrainingStoreModule" src/app/core/store/core-store.module.ts -npx ng g store core/store/training/warehouses --entity warehouse +npx ng g store training/warehouses --entity warehouse stat src/app/core/store/training/warehouses/warehouses.actions.ts stat src/app/core/store/training/warehouses/warehouses.effects.ts stat src/app/core/store/training/warehouses/warehouses.reducer.ts @@ -81,11 +81,6 @@ npx ng g customized-copy shell/footer/footer stat src/app/shell/footer/custom-footer/custom-footer.component.ts grep 'custom-footer' src/app/app.component.html - -git add -A -npx lint-staged -npx tsc --project tsconfig.spec.json - sed -i -e "s%icmBaseURL.*%icmBaseURL: 'http://localhost:4200',%g" src/environments/environment.prod.ts if grep mockServerAPI src/environments/environment.prod.ts @@ -95,6 +90,10 @@ else sed -i -e 's/^};$/mockServerAPI: true };/' src/environments/environment.prod.ts fi +git add -A +npx lint-staged +npx tsc --project tsconfig.spec.json + npm run build nohup bash -c "npm run serve &" diff --git a/e2e/test-universal.sh b/e2e/test-universal.sh index a254b84347..30c395eed4 100644 --- a/e2e/test-universal.sh +++ b/e2e/test-universal.sh @@ -15,12 +15,12 @@ universalTest() { } universalTest 1 "${PWA_BASE_URL}/" "router-outlet>Notebooks and PCs" -universalTest 6 "${PWA_BASE_URL}/category/Computers.1835" "

PCs

" -universalTest 7 "${PWA_BASE_URL}/category/Computers.1835.151" "add-to-compare" +universalTest 5 "${PWA_BASE_URL}/catComputers.1835" "

Notebooks and PCs

" +universalTest 6 "${PWA_BASE_URL}/catComputers.1835" "

PCs

" +universalTest 7 "${PWA_BASE_URL}/catComputers.1835.151" "add-to-compare" universalTest 8 "${PWA_BASE_URL}/home" "intershop-pwa-state" universalTest 9 "${PWA_BASE_URL}/home" "&q;baseURL&q;:" universalTest 10 "${PWA_BASE_URL}/home" " install.sh && \ - bash install.sh --nginx-version latest + bash install.sh --nginx-version latest --additional-nginx-configure-arguments '--with-http_ssl_module' FROM scratch as configstep COPY --from=nginx:mainline /etc/nginx /etc/nginx COPY nginx.conf perf.conf pagespeed.conf /etc/nginx/ -COPY icm.conf.tmpl channel.conf.tmpl /etc/nginx/conf.d/ +COPY channel.conf.tmpl /etc/nginx/conf.d/ COPY entrypoint.sh / COPY 50x.html /usr/share/nginx/html/ FROM ubuntu:latest RUN apt-get update && \ - apt-get install -y gettext-base && \ + apt-get install -y gettext-base libssl1.1 && \ apt-get -y autoremove && \ apt-get clean && \ rm -r /var/cache/apt /var/lib/apt/lists @@ -22,6 +22,6 @@ COPY --from=buildstep /usr/local/nginx /usr/local/nginx COPY --from=configstep / / ENV NPSC_ENABLE_FILTERS=in_place_optimize_for_browser,prioritize_critical_css,inline_preview_images,lazyload_images,rewrite_images,rewrite_css,remove_comments,local_storage_cache,move_css_to_head,move_css_above_scripts,collapse_whitespace,combine_javascript,extend_cache NPSC_JsPreserveURLs=off NPSC_ImagePreserveURLs=on NPSC_ForceCaching=off -EXPOSE 80 +EXPOSE 80 443 ENTRYPOINT [ "sh", "entrypoint.sh" ] diff --git a/nginx/README.md b/nginx/README.md index 2cee977770..9efda2a23e 100644 --- a/nginx/README.md +++ b/nginx/README.md @@ -21,6 +21,10 @@ Basic environment variables: If you want to use fully qualified names here, do not forget to also add host mappings to your orchestrator name resolution. For `docker run` this can be done with `--add-host`. +If you are using http, the server will run on default port 80. +If you use https as an upstream, it will run on default port 443. +In the latter case you will also have to supply the files `server.key` and `server.crt` in the folder `/etx/nginx` (either by volume mapping with `docker run` or in the image itself by `docker build`). + Setup at least one PWA channel configuration: - use mandatory `PWA_X_SUBDOMAIN` for the channel sub domain @@ -61,7 +65,3 @@ docker run -d --name "my-awesome-nginx" \ And then access the PWA with `http://b2b.:4199` If your DNS is not set up correctly, you have to use something like _dnsmasq_ (Linux) or _Acrylic DNS Proxy_ (Windows), or just ask your local network administrator. - -## Extras - -To fully release the potential of this nginx, also set `UPSTREAM_ICM` in the form of `http(s)://:` to tunnel all ICM traffic through this PageSpeed optimized nginx. This will automatically point the `ICM_BASE_URL` of the deployed PWA on a request basis to it. This however is still experimental. diff --git a/nginx/channel.conf.tmpl b/nginx/channel.conf.tmpl index 6ed1bbf783..775778fdd1 100644 --- a/nginx/channel.conf.tmpl +++ b/nginx/channel.conf.tmpl @@ -1,12 +1,38 @@ server { - listen 80; server_name ~^$SUBDOMAIN\..+$; + include /etc/nginx/conf.d/listen.conf; + # let ICM handle everything ICM related + location ~* ^/INTERSHOP.*$ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + add_header X-Cache-Status IGNORE; + + proxy_pass $UPSTREAM_PWA; + } + + # respect cache entries of static assets + location ~* ^/(assets|.*\.(js|css|ico|json|txt|webmanifest|woff|woff2))(.*)$ { + proxy_cache my_cache; + proxy_cache_use_stale error timeout http_404 http_500 http_502 http_503 http_504; + + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + add_header X-Cache-Status $upstream_cache_status; + + proxy_pass $UPSTREAM_PWA; + } + + # cache and rewriting for rendered pages location / { proxy_cache my_cache; proxy_cache_use_stale error timeout http_404 http_500 http_502 http_503 http_504; - proxy_set_header Host $host; + proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; @@ -24,15 +50,20 @@ server { rewrite ^/$ /home; if ($request_uri !~* ";lang=") { - rewrite ^(?!/INTERSHOP.*$)(?!/assets.*$)(?!.*\.js$)(?!.*\.css$)(?!.*\.ico$)(?!.*\.json$)(?!.*\.txt$)(?!.*\.webmanifest$)(.*)$ "$1;lang=$LANG"; + rewrite ^(.*)$ "$1;lang=$LANG"; } - if (-f /etc/nginx/conf.d/icm.conf) { - rewrite ^(?!/INTERSHOP.*$)(?!/assets.*$)(?!.*\.js$)(?!.*\.css$)(?!.*\.ico$)(?!.*\.json$)(?!.*\.txt$)(?!.*\.webmanifest$)(.*)$ "$1;icmScheme=$scheme;icmHost=$http_host"; + if ($request_uri !~* ";channel=") { + rewrite ^(.*)$ "$1;channel=$CHANNEL;application=$APPLICATION"; } - rewrite ^(?!/INTERSHOP.*$)(?!/assets.*$)(?!.*\.js$)(?!.*\.css$)(?!.*\.ico$)(?!.*\.json$)(?!.*\.txt$)(?!.*\.webmanifest$)(.*)$ "$1;channel=$CHANNEL;application=$APPLICATION;features=$FEATURES;theme=$THEME" break; + rewrite ^(.*)$ "$1;features=$FEATURES;theme=$THEME" break; proxy_pass $UPSTREAM_PWA; } - $ICM_INCLUDE + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } } diff --git a/nginx/entrypoint.sh b/nginx/entrypoint.sh index 6f10b5c2c3..45958ed8f8 100644 --- a/nginx/entrypoint.sh +++ b/nginx/entrypoint.sh @@ -5,14 +5,25 @@ set -e [ -z "$UPSTREAM_PWA" ] && echo "UPSTREAM_PWA is not set" && exit 1 -[ -f "/etc/nginx/conf.d/default.conf" ] && rm /etc/nginx/conf.d/default.conf - -if [ -n "$UPSTREAM_ICM" ] +if echo "$UPSTREAM_PWA" | grep -Eq '^https' then - envsubst \$UPSTREAM_ICM /etc/nginx/conf.d/icm.conf - export ICM_INCLUDE="include /etc/nginx/conf.d/icm.conf;" + cat >/etc/nginx/conf.d/listen.conf </etc/nginx/conf.d/listen.conf fi +[ -f "/etc/nginx/conf.d/default.conf" ] && rm /etc/nginx/conf.d/default.conf + i=1 while true do @@ -29,7 +40,7 @@ do echo "$i SUBDOMAIN=$SUBDOMAIN CHANNEL=$CHANNEL APPLICATION=$APPLICATION LANG=$LANG FEATURES=$FEATURES" - envsubst '$UPSTREAM_PWA,$SUBDOMAIN,$CHANNEL,$APPLICATION,$LANG,$FEATURES,$THEME,$ICM_INCLUDE' /etc/nginx/conf.d/channel$i.conf + envsubst '$UPSTREAM_PWA,$SUBDOMAIN,$CHANNEL,$APPLICATION,$LANG,$FEATURES,$THEME' /etc/nginx/conf.d/channel$i.conf i=$((i+1)) done diff --git a/nginx/icm.conf.tmpl b/nginx/icm.conf.tmpl deleted file mode 100644 index 52e61ba241..0000000000 --- a/nginx/icm.conf.tmpl +++ /dev/null @@ -1,36 +0,0 @@ -location /INTERSHOP { - proxy_cache my_cache; - proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; - - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - add_header X-Cache-Status $upstream_cache_status; - - proxy_pass $UPSTREAM_ICM; -} - -location /INTERSHOP/static { - proxy_cache my_cache; - proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; - - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - add_header X-Cache-Status $upstream_cache_status; - - add_header Cache-Control "public"; - proxy_pass $UPSTREAM_ICM; - - proxy_hide_header Cache-Control; - expires 1y; -} - -# redirect server error pages to the static page /50x.html -# -error_page 500 502 503 504 /50x.html; -location = /50x.html { - root /usr/share/nginx/html; -} diff --git a/package-lock.json b/package-lock.json index 3e95fa64b8..4e4f7e7c8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "intershop-pwa", - "version": "0.17.0", + "version": "0.18.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@angular-devkit/architect": { - "version": "0.803.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.18.tgz", - "integrity": "sha512-/oNutcuUduXH/4nxHSDRTYK3VGP0PkVUniPdo0yjpg8c2dbfoNkt1ILIV82LPaC8sDwjuXGLx0EH70ETtcnBwg==", + "version": "0.803.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.23.tgz", + "integrity": "sha512-BRDbnmdULrle2l7WFZHEW/OAwS8RRg08+jiNG3gEP0BxDN6QMNMKmWhxmX67pgq3e/xMvu2DH0z71mAPNtJDAw==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.18", + "@angular-devkit/core": "8.3.23", "rxjs": "6.4.0" }, "dependencies": { @@ -1727,9 +1727,9 @@ } }, "@angular-devkit/core": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.18.tgz", - "integrity": "sha512-SPlQmBlrcaKZeE9srvuFElcen9iOled4lkD3M4cGwe56u6YoJ71oTAtmGiw9nofTtW0PghGVq8WdDQG5BRqX8Q==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.23.tgz", + "integrity": "sha512-y++LN6R/fu+obPUKEMDSKZ5FzeWN5rV0Z8vrdC+uF02VJLv/5QI/dUx3ROKFzJO3m2LU6EAuo5b/TLAPq4ving==", "dev": true, "requires": { "ajv": "6.10.2", @@ -1751,12 +1751,12 @@ } }, "@angular-devkit/schematics": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.18.tgz", - "integrity": "sha512-J9sf/6cSUx2kdXppo/69uZ1gBeM5fcXfnP7MCJCVnsk09QCD9Kr+Xeh8h4WEmLtne7XzI9dcCttHQ5WDNuRulA==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.23.tgz", + "integrity": "sha512-O8i/vn6YfqbT0q7o4jsVOTnWE07T1tcvk2zJ4O/1ete2z+Z2aw1YtIddwXEGJNCDpeE0B7f2sUHoLOS4Jc4O9w==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.18", + "@angular-devkit/core": "8.3.23", "rxjs": "6.4.0" }, "dependencies": { @@ -1772,24 +1772,24 @@ } }, "@angular/animations": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.2.13.tgz", - "integrity": "sha512-ZE4UZsQ6HDW1ZIj9tL45PVosCcG4Ke7ihV7eWCE1VgLZKDDxTOPbLf1UeEiszUYptMLGH3eGMNBKo85mOlkH8w==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.2.14.tgz", + "integrity": "sha512-3Vc9TnNpKdtvKIXcWDFINSsnwgEMiDmLzjceWg1iYKwpeZGQahUXPoesLwQazBMmxJzQiA4HOMj0TTXKZ+Jzkg==", "requires": { "tslib": "^1.9.0" } }, "@angular/cli": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.18.tgz", - "integrity": "sha512-IWiGlAmVPkl/xWCrki3N45uqdYcjUvtWw9bRM53FF1EKLLbjue6DAVD1HktqgqjTyck0P7QkOXWRilT8rXKcEQ==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.23.tgz", + "integrity": "sha512-umr5puS6j8elTIhhsjyb/psTmwL00oeBbsnnz5K3fkbWB2wgdMsJvLi9aR/oAyh2NlSA2ZzgB62I38VjoDR0yQ==", "dev": true, "requires": { - "@angular-devkit/architect": "0.803.18", - "@angular-devkit/core": "8.3.18", - "@angular-devkit/schematics": "8.3.18", - "@schematics/angular": "8.3.18", - "@schematics/update": "0.803.18", + "@angular-devkit/architect": "0.803.23", + "@angular-devkit/core": "8.3.23", + "@angular-devkit/schematics": "8.3.23", + "@schematics/angular": "8.3.23", + "@schematics/update": "0.803.23", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.1", "debug": "^4.1.1", @@ -1838,33 +1838,33 @@ } }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true } } }, "@angular/common": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-8.2.13.tgz", - "integrity": "sha512-I9cTcjUi88L+Mb/a/ZzUrdDcn3YgFFK9LubxaPjAfr6+G7IZ//MY5HuvG8Y41yKprXVVvQCbQ1yQD+GGRSCkaA==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-8.2.14.tgz", + "integrity": "sha512-Qmt+aX2quUW54kaNT7QH7WGXnFxr/cC2C6sf5SW5SdkZfDQSiz8IaItvieZfXVQUbBOQKFRJ7TlSkt0jI/yjvw==", "requires": { "tslib": "^1.9.0" } }, "@angular/compiler": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-8.2.13.tgz", - "integrity": "sha512-u2NWCvEn4SjbMvn2PG6sYcf+rR5u3aYMv3/mNQ9k+2UmCIu3yJrcuCzebjo5SdlDVqKD2vzbyMZnr8VB9OcceQ==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-8.2.14.tgz", + "integrity": "sha512-ABZO4E7eeFA1QyJ2trDezxeQM5ZFa1dXw1Mpl/+1vuXDKNjJgNyWYwKp/NwRkLmrsuV0yv4UDCDe4kJOGbPKnw==", "requires": { "tslib": "^1.9.0" } }, "@angular/compiler-cli": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-8.2.13.tgz", - "integrity": "sha512-ryW2Kozx/oHJrtdeIhgZ24RIU7Za3YIOHS9EMCQ8xMo+ZlSI+t2zOlLAXzK4PVWEjuTtQlKbT0KqilgU0QsHJg==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-8.2.14.tgz", + "integrity": "sha512-XDrTyrlIZM+0NquVT+Kbg5bn48AaWFT+B3bAT288PENrTdkuxuF9AhjFRZj8jnMdmaE4O2rioEkXBtl6z3zptA==", "dev": true, "requires": { "canonical-path": "1.0.0", @@ -1948,14 +1948,15 @@ } }, "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", "dev": true, "optional": true, "requires": { + "bindings": "^1.5.0", "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" + "node-pre-gyp": "*" }, "dependencies": { "abbrev": { @@ -2003,7 +2004,7 @@ } }, "chownr": { - "version": "1.1.1", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true @@ -2033,7 +2034,7 @@ "optional": true }, "debug": { - "version": "4.1.1", + "version": "3.2.6", "bundled": true, "dev": true, "optional": true, @@ -2060,12 +2061,12 @@ "optional": true }, "fs-minipass": { - "version": "1.2.5", + "version": "1.2.7", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -2091,7 +2092,7 @@ } }, "glob": { - "version": "7.1.3", + "version": "7.1.6", "bundled": true, "dev": true, "optional": true, @@ -2120,7 +2121,7 @@ } }, "ignore-walk": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true, @@ -2139,7 +2140,7 @@ } }, "inherits": { - "version": "2.0.3", + "version": "2.0.4", "bundled": true, "dev": true, "optional": true @@ -2181,7 +2182,7 @@ "optional": true }, "minipass": { - "version": "2.3.5", + "version": "2.9.0", "bundled": true, "dev": true, "optional": true, @@ -2191,12 +2192,12 @@ } }, "minizlib": { - "version": "1.2.1", + "version": "1.3.3", "bundled": true, "dev": true, "optional": true, "requires": { - "minipass": "^2.2.1" + "minipass": "^2.9.0" } }, "mkdirp": { @@ -2209,24 +2210,24 @@ } }, "ms": { - "version": "2.1.1", + "version": "2.1.2", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.3.0", + "version": "2.4.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^4.1.0", + "debug": "^3.2.6", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.12.0", + "version": "0.14.0", "bundled": true, "dev": true, "optional": true, @@ -2240,7 +2241,7 @@ "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", - "tar": "^4" + "tar": "^4.4.2" } }, "nopt": { @@ -2254,13 +2255,22 @@ } }, "npm-bundled": { - "version": "1.0.6", + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.4.1", + "version": "1.4.7", "bundled": true, "dev": true, "optional": true, @@ -2331,7 +2341,7 @@ "optional": true }, "process-nextick-args": { - "version": "2.0.0", + "version": "2.0.1", "bundled": true, "dev": true, "optional": true @@ -2372,7 +2382,7 @@ } }, "rimraf": { - "version": "2.6.3", + "version": "2.7.1", "bundled": true, "dev": true, "optional": true, @@ -2399,7 +2409,7 @@ "optional": true }, "semver": { - "version": "5.7.0", + "version": "5.7.1", "bundled": true, "dev": true, "optional": true @@ -2452,18 +2462,18 @@ "optional": true }, "tar": { - "version": "4.4.8", + "version": "4.4.13", "bundled": true, "dev": true, "optional": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "yallist": "^3.0.3" } }, "util-deprecate": { @@ -2488,7 +2498,7 @@ "optional": true }, "yallist": { - "version": "3.0.3", + "version": "3.1.1", "bundled": true, "dev": true, "optional": true @@ -2527,9 +2537,9 @@ "dev": true }, "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -2551,9 +2561,9 @@ "dev": true }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -2655,47 +2665,47 @@ } }, "@angular/core": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-8.2.13.tgz", - "integrity": "sha512-W8HN0lUQV4Sq85l17nhRIXeIfcw1ZdpgGm6to98pl0y9l/1srfzWfTnofuwCJC7gedt5AMrYJGUaNiDbByosFw==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-8.2.14.tgz", + "integrity": "sha512-zeePkigi+hPh3rN7yoNENG/YUBUsIvUXdxx+AZq+QPaFeKEA2FBSrKn36ojHFrdJUjKzl0lPMEiGC2b6a6bo6g==", "requires": { "tslib": "^1.9.0" } }, "@angular/forms": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-8.2.13.tgz", - "integrity": "sha512-l7lHD4kbWK70KY0Xp4IpSa106ZzSgPMwRYMFKd9qhYaJ7v0Y7Shh7Z/ZDCOP730maj9WULnpy5X4eeozWXgvgg==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-8.2.14.tgz", + "integrity": "sha512-zhyKL3CFIqcyHJ/TQF/h1OZztK611a6rxuPHCrt/5Sn1SuBTJJQ1pPTkOYIDy6IrCrtyANc8qB6P17Mao71DNQ==", "requires": { "tslib": "^1.9.0" } }, "@angular/language-service": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-8.2.13.tgz", - "integrity": "sha512-uVkqC5oxul6Jqyxzy0o4DN1TpmcmUWIi7WnDBu+aJVQFp/kqxmkNuJQvugdouxlIYdHC/SwLeVnBIplRjGH5cw==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-8.2.14.tgz", + "integrity": "sha512-7EhN9JJbAJcH2xCa+rIOmekjiEuB0qwPdHuD5qn/wwMfRzMZo+Db4hHbR9KHrLH6H82PTwYKye/LLpDaZqoHOA==", "dev": true }, "@angular/platform-browser": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-8.2.13.tgz", - "integrity": "sha512-1lPbeLQIbbafjq9ul3IA8s2fMJ/EXeMJ74ouTolVXoPPur9ZPRLX9FqBAO1K4QzkAWhRlyf6qIC+mDZfJILwZw==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-8.2.14.tgz", + "integrity": "sha512-MtJptptyKzsE37JZ2VB/tI4cvMrdAH+cT9pMBYZd66YSZfKjIj5s+AZo7z8ncoskQSB1o3HMfDjSK7QXGx1mLQ==", "requires": { "tslib": "^1.9.0" } }, "@angular/platform-browser-dynamic": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.2.13.tgz", - "integrity": "sha512-KP5psUKujAO8jZKHi6LRC+N7hE/epiGOhYZxdher1sCi81sYoZmqrEWkVZ4VKhov/4aC409CocDXcF7nmHV8tg==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.2.14.tgz", + "integrity": "sha512-mO2JPR5kLU/A3AQngy9+R/Q5gaF9csMStBQjwsCRI0wNtlItOIGL6+wTYpiTuh/ux+WVN1F2sLcEYU4Zf1ud9A==", "requires": { "tslib": "^1.9.0" } }, "@angular/platform-server": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-8.2.13.tgz", - "integrity": "sha512-rRSqcUF0ExiE8mhX8Gwu4aDvrcyKi7VxLd2/wXXFQ3kuxwiWJ36RJ/ciJ8WrAjWjvvHHtJ8iEyF2BxJqGjqWlQ==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-8.2.14.tgz", + "integrity": "sha512-gGAgxMmac5CyLcwgB+qCD1o75An0NmpREh/lxPgz6n6Zs9JqdqpZROLSIHqGBaU6MWo1qiOfS6L08HwYPx7ipQ==", "requires": { "domino": "^2.1.2", "tslib": "^1.9.0", @@ -2703,20 +2713,20 @@ } }, "@angular/pwa": { - "version": "0.803.18", - "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-0.803.18.tgz", - "integrity": "sha512-KF40VDrjrl6iktU/7UBEAIOyEDmXm1sANdzLjynKwETpUExnoZ8k942KMChagVBtWJY8BrXo0EdWw1Kx6/4UmQ==", + "version": "0.803.23", + "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-0.803.23.tgz", + "integrity": "sha512-OxDLF5r3Gg3TvtdIkXsHaNJLJS+BVMUct0G6EfdvgxYxQ5pdRyhHDaEMl8WZaokPb8R+R1uwsV2gLW24dT1Iuw==", "requires": { - "@angular-devkit/core": "8.3.18", - "@angular-devkit/schematics": "8.3.18", - "@schematics/angular": "8.3.18", + "@angular-devkit/core": "8.3.23", + "@angular-devkit/schematics": "8.3.23", + "@schematics/angular": "8.3.23", "parse5-html-rewriting-stream": "5.1.0" }, "dependencies": { "@angular-devkit/core": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.18.tgz", - "integrity": "sha512-SPlQmBlrcaKZeE9srvuFElcen9iOled4lkD3M4cGwe56u6YoJ71oTAtmGiw9nofTtW0PghGVq8WdDQG5BRqX8Q==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.23.tgz", + "integrity": "sha512-y++LN6R/fu+obPUKEMDSKZ5FzeWN5rV0Z8vrdC+uF02VJLv/5QI/dUx3ROKFzJO3m2LU6EAuo5b/TLAPq4ving==", "requires": { "ajv": "6.10.2", "fast-json-stable-stringify": "2.0.0", @@ -2726,11 +2736,11 @@ } }, "@angular-devkit/schematics": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.18.tgz", - "integrity": "sha512-J9sf/6cSUx2kdXppo/69uZ1gBeM5fcXfnP7MCJCVnsk09QCD9Kr+Xeh8h4WEmLtne7XzI9dcCttHQ5WDNuRulA==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.23.tgz", + "integrity": "sha512-O8i/vn6YfqbT0q7o4jsVOTnWE07T1tcvk2zJ4O/1ete2z+Z2aw1YtIddwXEGJNCDpeE0B7f2sUHoLOS4Jc4O9w==", "requires": { - "@angular-devkit/core": "8.3.18", + "@angular-devkit/core": "8.3.23", "rxjs": "6.4.0" } }, @@ -2745,17 +2755,17 @@ } }, "@angular/router": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-8.2.13.tgz", - "integrity": "sha512-9CqnachtdASnEmRMtrG/R3c5nDCjjlCU4n0W/xt5+LlveyuUVvAT/CFUC38km4Df3lIvqap8mSpxzGaEzCL+wQ==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-8.2.14.tgz", + "integrity": "sha512-DHA2BhODqV7F0g6ZKgFaZgbsqzHHWRcfWchCOrOVKu2rYiKUTwwHVLBgZAhrpNeinq2pWanVYSIhMr7wy+LfEA==", "requires": { "tslib": "^1.9.0" } }, "@angular/service-worker": { - "version": "8.2.13", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-8.2.13.tgz", - "integrity": "sha512-9P0ode6zNbyiv76nG8D03SRbNR92/hWNLuCeXST53SvC2uvhp45/oVTVc0TCXNsodd0slOchQbq6RLN/LSAdHQ==", + "version": "8.2.14", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-8.2.14.tgz", + "integrity": "sha512-Xv1ES5bXDRxPJ5uyRqeKw6mGKaJVzKK0oFcR0mr4OSdyLXGZ+x6fC2S/QcLy4ugpb64fyEksrnHhHjeMVzGh2Q==", "requires": { "tslib": "^1.9.0" } @@ -2769,6 +2779,65 @@ "@babel/highlight": "^7.0.0" } }, + "@babel/compat-data": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.8.1.tgz", + "integrity": "sha512-Z+6ZOXvyOWYxJ50BwxzdhRnRsGST8Y3jaZgxYig575lTjVSs3KtJnmESwZegg6e2Dn0td1eDhoWlp1wI4BTCPw==", + "dev": true, + "requires": { + "browserslist": "^4.8.2", + "invariant": "^2.2.4", + "semver": "^5.5.0" + }, + "dependencies": { + "browserslist": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", + "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001022", + "electron-to-chromium": "^1.3.338", + "node-releases": "^1.1.46" + } + }, + "caniuse-lite": { + "version": "1.0.30001023", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", + "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", + "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==", + "dev": true + }, + "node-releases": { + "version": "1.1.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", + "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, "@babel/core": { "version": "7.5.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", @@ -2842,75 +2911,490 @@ } }, "@babel/helper-annotate-as-pure": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", - "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", + "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", - "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", + "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-explode-assignable-expression": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-call-delegate": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", - "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.4.4", - "@babel/traverse": "^7.4.4", - "@babel/types": "^7.4.4" - } - }, - "@babel/helper-create-regexp-features-plugin": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", - "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz", + "integrity": "sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==", "dev": true, "requires": { - "@babel/helper-regex": "^7.8.3", - "regexpu-core": "^4.6.0" + "@babel/helper-hoist-variables": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" }, "dependencies": { - "@babel/helper-regex": { + "@babel/code-frame": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", - "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", + "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", "dev": true, "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", + "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "dev": true, + "requires": { + "@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/helper-define-map": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", - "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/types": "^7.5.5", - "lodash": "^4.17.13" + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.3.tgz", + "integrity": "sha512-JLylPCsFjhLN+6uBSSh3iYdxKdeO9MNmoY96PE/99d8kyBFaXLORtAVhqN6iHa+wtPeqxKLghDOZry0+Aiw9Tw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.8.1", + "browserslist": "^4.8.2", + "invariant": "^2.2.4", + "levenary": "^1.1.0", + "semver": "^5.5.0" + }, + "dependencies": { + "browserslist": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", + "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001022", + "electron-to-chromium": "^1.3.338", + "node-releases": "^1.1.46" + } + }, + "caniuse-lite": { + "version": "1.0.30001023", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", + "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", + "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==", + "dev": true + }, + "node-releases": { + "version": "1.1.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", + "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", + "integrity": "sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==", + "dev": true, + "requires": { + "@babel/helper-regex": "^7.8.3", + "regexpu-core": "^4.6.0" + }, + "dependencies": { + "@babel/helper-regex": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", + "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + } + } + }, + "@babel/helper-define-map": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", + "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/types": "^7.8.3", + "lodash": "^4.17.13" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-explode-assignable-expression": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", - "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", + "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", + "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", + "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "dev": true, + "requires": { + "@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": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/helper-function-name": { @@ -2934,53 +3418,164 @@ } }, "@babel/helper-hoist-variables": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", - "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", + "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", "dev": true, "requires": { - "@babel/types": "^7.4.4" + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-member-expression-to-functions": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", - "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", "dev": true, "requires": { - "@babel/types": "^7.5.5" + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", + "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-module-transforms": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", - "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz", + "integrity": "sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.5.5", + "@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" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-optimise-call-expression": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", - "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-plugin-utils": { @@ -2990,47 +3585,355 @@ "dev": true }, "@babel/helper-regex": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", - "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", + "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", "dev": true, "requires": { "lodash": "^4.17.13" } }, "@babel/helper-remap-async-to-generator": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", - "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", + "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-wrap-function": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0" + "@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" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", + "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", + "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "dev": true, + "requires": { + "@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": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/helper-replace-supers": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", - "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", + "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.5.5", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/traverse": "^7.5.5", - "@babel/types": "^7.5.5" + "@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" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", + "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", + "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "dev": true, + "requires": { + "@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": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", + "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", "dev": true, "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-split-export-declaration": { @@ -3043,15 +3946,144 @@ } }, "@babel/helper-wrap-function": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", - "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", + "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.2.0" + "@babel/helper-function-name": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.3.tgz", + "integrity": "sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.3.tgz", + "integrity": "sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==", + "dev": true, + "requires": { + "@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": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/helpers": { @@ -3083,92 +4115,225 @@ "dev": true }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", - "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", + "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0", - "@babel/plugin-syntax-async-generators": "^7.2.0" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", - "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", + "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.2.0" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-proposal-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", - "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", + "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-json-strings": "^7.2.0" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz", - "integrity": "sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + } } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.8.3.tgz", + "integrity": "sha512-QIoIR9abkVn+seDE3OjA08jWcs3eZ9+wJCKSRgo3WdEU2csFYgdScb+8qHB3+WXsGJD55u+5hWCISI7ejXS+kg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", - "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz", + "integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-syntax-async-generators": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", - "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-syntax-dynamic-import": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", - "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, - "@babel/plugin-syntax-json-strings": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", - "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-syntax-object-rest-spread": { @@ -3181,12 +4346,37 @@ } }, "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", - "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-syntax-top-level-await": { @@ -3207,371 +4397,840 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", - "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", + "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", - "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", + "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-remap-async-to-generator": "^7.1.0" + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-remap-async-to-generator": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", - "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", + "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-block-scoping": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.0.tgz", - "integrity": "sha512-tIt4E23+kw6TgL/edACZwP1OUKrjOTyMrFMLoT5IOFrfMRabCgekjqFd5o6PaAMildBu46oFkekIdMuGkkPEpA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", + "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-plugin-utils": "^7.8.3", "lodash": "^4.17.13" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-classes": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", - "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz", + "integrity": "sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.5.5", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5", - "@babel/helper-split-export-declaration": "^7.4.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" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-computed-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", - "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", + "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-destructuring": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz", - "integrity": "sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz", + "integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", - "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", + "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", - "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", + "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", - "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", + "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-for-of": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", - "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz", + "integrity": "sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-function-name": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", - "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", + "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.3.tgz", + "integrity": "sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", - "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", + "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", - "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", + "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-modules-amd": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", - "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz", + "integrity": "sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@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" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", - "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz", + "integrity": "sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.4.4", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", + "@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" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", - "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz", + "integrity": "sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.4.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" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-modules-umd": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", - "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz", + "integrity": "sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.1.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-module-transforms": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.0.tgz", - "integrity": "sha512-jem7uytlmrRl3iCAuQyw8BpB4c4LWvSpvIeXKpMb+7j84lkx4m4mYr5ErAcmN5KM7B6BqrAvRGjBIbbzqCczew==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", + "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", "dev": true, "requires": { - "regexp-tree": "^0.1.13" + "@babel/helper-create-regexp-features-plugin": "^7.8.3" } }, "@babel/plugin-transform-new-target": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", - "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", + "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-object-super": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", - "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", + "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.5.5" + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-parameters": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", - "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz", + "integrity": "sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q==", "dev": true, "requires": { - "@babel/helper-call-delegate": "^7.4.4", - "@babel/helper-get-function-arity": "^7.0.0", - "@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" + }, + "dependencies": { + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/plugin-transform-property-literals": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", - "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", + "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-regenerator": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", - "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz", + "integrity": "sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==", "dev": true, "requires": { "regenerator-transform": "^0.14.0" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", - "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", + "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", - "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", + "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-spread": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", - "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", + "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", - "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", + "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", "dev": true, "requires": { - "@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" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-template-literals": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", - "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", + "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", - "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz", + "integrity": "sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", - "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", + "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-regex": "^7.4.4", - "regexpu-core": "^4.5.4" + "@babel/helper-create-regexp-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } } }, "@babel/preset-env": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.0.tgz", - "integrity": "sha512-1efzxFv/TcPsNXlRhMzRnkBFMeIqBBgzwmZwlFDw5Ubj0AGLeufxugirwZmkkX/ayi3owsSqoQ4fw8LkfK9SYg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.2.0", - "@babel/plugin-proposal-dynamic-import": "^7.5.0", - "@babel/plugin-proposal-json-strings": "^7.2.0", - "@babel/plugin-proposal-object-rest-spread": "^7.5.5", - "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@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-transform-arrow-functions": "^7.2.0", - "@babel/plugin-transform-async-to-generator": "^7.5.0", - "@babel/plugin-transform-block-scoped-functions": "^7.2.0", - "@babel/plugin-transform-block-scoping": "^7.6.0", - "@babel/plugin-transform-classes": "^7.5.5", - "@babel/plugin-transform-computed-properties": "^7.2.0", - "@babel/plugin-transform-destructuring": "^7.6.0", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@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.4.4", - "@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.6.0", - "@babel/plugin-transform-modules-systemjs": "^7.5.0", - "@babel/plugin-transform-modules-umd": "^7.2.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.6.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.4.5", - "@babel/plugin-transform-reserved-words": "^7.2.0", - "@babel/plugin-transform-shorthand-properties": "^7.2.0", - "@babel/plugin-transform-spread": "^7.2.0", - "@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.4.4", - "@babel/types": "^7.6.0", - "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.8.3.tgz", + "integrity": "sha512-Rs4RPL2KjSLSE2mWAx5/iCH+GC1ikKdxPrhnRS6PfFVaiZeom22VFKN4X8ZthyN61kAaR05tfXTbCvatl9WIQg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.8.0", + "@babel/helper-compilation-targets": "^7.8.3", + "@babel/helper-module-imports": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-proposal-async-generator-functions": "^7.8.3", + "@babel/plugin-proposal-dynamic-import": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-object-rest-spread": "^7.8.3", + "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.8.3", + "@babel/plugin-transform-async-to-generator": "^7.8.3", + "@babel/plugin-transform-block-scoped-functions": "^7.8.3", + "@babel/plugin-transform-block-scoping": "^7.8.3", + "@babel/plugin-transform-classes": "^7.8.3", + "@babel/plugin-transform-computed-properties": "^7.8.3", + "@babel/plugin-transform-destructuring": "^7.8.3", + "@babel/plugin-transform-dotall-regex": "^7.8.3", + "@babel/plugin-transform-duplicate-keys": "^7.8.3", + "@babel/plugin-transform-exponentiation-operator": "^7.8.3", + "@babel/plugin-transform-for-of": "^7.8.3", + "@babel/plugin-transform-function-name": "^7.8.3", + "@babel/plugin-transform-literals": "^7.8.3", + "@babel/plugin-transform-member-expression-literals": "^7.8.3", + "@babel/plugin-transform-modules-amd": "^7.8.3", + "@babel/plugin-transform-modules-commonjs": "^7.8.3", + "@babel/plugin-transform-modules-systemjs": "^7.8.3", + "@babel/plugin-transform-modules-umd": "^7.8.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", + "@babel/plugin-transform-new-target": "^7.8.3", + "@babel/plugin-transform-object-super": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.8.3", + "@babel/plugin-transform-property-literals": "^7.8.3", + "@babel/plugin-transform-regenerator": "^7.8.3", + "@babel/plugin-transform-reserved-words": "^7.8.3", + "@babel/plugin-transform-shorthand-properties": "^7.8.3", + "@babel/plugin-transform-spread": "^7.8.3", + "@babel/plugin-transform-sticky-regex": "^7.8.3", + "@babel/plugin-transform-template-literals": "^7.8.3", + "@babel/plugin-transform-typeof-symbol": "^7.8.3", + "@babel/plugin-transform-unicode-regex": "^7.8.3", + "@babel/types": "^7.8.3", + "browserslist": "^4.8.2", + "core-js-compat": "^3.6.2", "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", + "levenary": "^1.1.0", "semver": "^5.5.0" }, "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "browserslist": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", + "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001022", + "electron-to-chromium": "^1.3.338", + "node-releases": "^1.1.46" + } + }, + "caniuse-lite": { + "version": "1.0.30001023", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", + "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", + "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==", + "dev": true + }, + "node-releases": { + "version": "1.1.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", + "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -4014,24 +5673,24 @@ } }, "@ngrx/effects": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-8.5.0.tgz", - "integrity": "sha512-Ac60DGM2rV4Xd9DONFuhStGZJMffQF+uL69pd1a144WPtfSWWBWzo5sHeZOKs7O9YmfqXiihs1DfCKmGaJOciw==" + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-8.6.0.tgz", + "integrity": "sha512-JdyJLQbv/wnE0ZPY9DcDOtF9PzJuzsKWmIWgIGunHF18wdjk5O8Zpkcrxq18wDRL6geg5UTtNJRMvTQhpDbzow==" }, "@ngrx/entity": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-8.5.0.tgz", - "integrity": "sha512-3s/ULg43C8TPTTHPVwF2RS4/1xngZM9NbwfNARnS1jF/DN1EKh0R0z4OEq42016WsQm/qjGS7k4kq8OrJt6KIA==" + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-8.6.0.tgz", + "integrity": "sha512-Qq+ANgsHd2/i7gam1j05hxA8kPWQyf5ewtCLlbtMJI/qLmvA6ruSE8PYNNwrt90wm4BWdks2zKE5ERzvPzto0w==" }, "@ngrx/store": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-8.5.0.tgz", - "integrity": "sha512-PF+yi3CjRDkuJ7uPNW/2WAXSIs6iZHpC9RRnvbQ76D7c2qaq5AThnGGhPaB/tEuNZS0wv9z+0IoxeESJOe9jIg==" + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-8.6.0.tgz", + "integrity": "sha512-K4cvCEa+5hw9qrETQWO+Cha3YbVCAT8yaIKJr/N35KntTL9mQMjoL+51JWLZfBwPV0e19CFgJIyrBnVUTxwr2A==" }, "@ngrx/store-devtools": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-8.5.0.tgz", - "integrity": "sha512-v3LPXb9KzK+CDySYBUGl9jxTwQ/mRrgE8cF4e2Fsl72GiBDuSY0ZGapM612hB6w0QMxm+NI50D/jRNwOMqjM2Q==" + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-8.6.0.tgz", + "integrity": "sha512-PWZmiOZE0J56GFfZpuzKLb7w0K2c6OXZSp/eWDeAvtdHFD4/Nas1i4TXtiWWMWWnSZeNs0hNIg4nFJXi2EddJQ==" }, "@ngtools/webpack": { "version": "8.3.23", @@ -4177,18 +5836,18 @@ } }, "@schematics/angular": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.18.tgz", - "integrity": "sha512-3cQYcmzsWD/MnqauoSozIu1R7DJvty13BH6+XIorEfguWqOwOwgNIWLMsa0iIcy0+TV3vWFI0KZpCKup2u/I1Q==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.23.tgz", + "integrity": "sha512-yisP1iCLGC4VnZNC3kOnYyTS5cmfKEnLM9bMzhZGMWwov9RRfdxKKeSnG9FJNwHxI0WjQ0UWwfiz1dj0YacG3g==", "requires": { - "@angular-devkit/core": "8.3.18", - "@angular-devkit/schematics": "8.3.18" + "@angular-devkit/core": "8.3.23", + "@angular-devkit/schematics": "8.3.23" }, "dependencies": { "@angular-devkit/core": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.18.tgz", - "integrity": "sha512-SPlQmBlrcaKZeE9srvuFElcen9iOled4lkD3M4cGwe56u6YoJ71oTAtmGiw9nofTtW0PghGVq8WdDQG5BRqX8Q==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.23.tgz", + "integrity": "sha512-y++LN6R/fu+obPUKEMDSKZ5FzeWN5rV0Z8vrdC+uF02VJLv/5QI/dUx3ROKFzJO3m2LU6EAuo5b/TLAPq4ving==", "requires": { "ajv": "6.10.2", "fast-json-stable-stringify": "2.0.0", @@ -4198,11 +5857,11 @@ } }, "@angular-devkit/schematics": { - "version": "8.3.18", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.18.tgz", - "integrity": "sha512-J9sf/6cSUx2kdXppo/69uZ1gBeM5fcXfnP7MCJCVnsk09QCD9Kr+Xeh8h4WEmLtne7XzI9dcCttHQ5WDNuRulA==", + "version": "8.3.23", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.23.tgz", + "integrity": "sha512-O8i/vn6YfqbT0q7o4jsVOTnWE07T1tcvk2zJ4O/1ete2z+Z2aw1YtIddwXEGJNCDpeE0B7f2sUHoLOS4Jc4O9w==", "requires": { - "@angular-devkit/core": "8.3.18", + "@angular-devkit/core": "8.3.23", "rxjs": "6.4.0" } }, @@ -4217,13 +5876,13 @@ } }, "@schematics/update": { - "version": "0.803.18", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.18.tgz", - "integrity": "sha512-vJxyL1pbn2lcgSH6HUqgA373iJRXQWxdrxuUaQ56qyq1EoicG7EppKz7OlGyKs+nHR9HhtK0eJc35E7I0lEWgA==", + "version": "0.803.23", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.23.tgz", + "integrity": "sha512-pLd5PseFTYF3VZ+IgMeNEFATQY5A80ylot7Dcg9FDeihqr5R9Rd1maCWIR43oKXvtK5C5+ackwR0QaPBAZ9bdw==", "dev": true, "requires": { - "@angular-devkit/core": "8.3.18", - "@angular-devkit/schematics": "8.3.18", + "@angular-devkit/core": "8.3.23", + "@angular-devkit/schematics": "8.3.23", "@yarnpkg/lockfile": "1.1.0", "ini": "1.3.5", "pacote": "9.5.5", @@ -4450,12 +6109,52 @@ "@babel/types": "^7.3.0" } }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "dev": true }, + "@types/express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz", + "integrity": "sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz", + "integrity": "sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -4526,6 +6225,12 @@ "@types/lodash": "*" } }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -4538,6 +6243,22 @@ "integrity": "sha512-O+x6uIpa6oMNTkPuHDa9MhMMehlxLAd5QcOvKRjAFsBVpeFWTOPnXbDvILvFgFFZfQ1xh1EZi1FbXxUix+zpsQ==", "dev": true }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "@types/source-list-map": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", @@ -4944,12 +6665,12 @@ "dev": true }, "ansi-escapes": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", - "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", "dev": true, "requires": { - "type-fest": "^0.5.2" + "type-fest": "^0.8.1" } }, "ansi-html": { @@ -5454,6 +7175,21 @@ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", @@ -5481,6 +7217,16 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, "bluebird": { "version": "3.5.5", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", @@ -6734,13 +8480,61 @@ "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" }, "core-js-compat": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.2.1.tgz", - "integrity": "sha512-MwPZle5CF9dEaMYdDeWm73ao/IflDH+FjeJCWEADcEgFSE9TLimFKwJsfmkwzI8eC0Aj0mgvMDjeQjrElkz4/A==", + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.4.tgz", + "integrity": "sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA==", "dev": true, "requires": { - "browserslist": "^4.6.6", - "semver": "^6.3.0" + "browserslist": "^4.8.3", + "semver": "7.0.0" + }, + "dependencies": { + "browserslist": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.5.tgz", + "integrity": "sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001022", + "electron-to-chromium": "^1.3.338", + "node-releases": "^1.1.46" + } + }, + "caniuse-lite": { + "version": "1.0.30001023", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz", + "integrity": "sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.340", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz", + "integrity": "sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww==", + "dev": true + }, + "node-releases": { + "version": "1.1.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.47.tgz", + "integrity": "sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } } }, "core-util-is": { @@ -7492,9 +9286,9 @@ } }, "domino": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.3.tgz", - "integrity": "sha512-EwjTbUv1Q/RLQOdn9k7ClHutrQcWGsfXaRQNOnM/KgK4xDBoLFEcIRFuBSxAx13Vfa63X029gXYrNFrSy+DOSg==" + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.4.tgz", + "integrity": "sha512-l70mlQ7IjPKC8kT7GljQXJZmt5OqFL+RE91ik5y5WWQtsd9wP8R7gpFnNu96fK5MqAAZRXfLLsnzKtkty5fWGQ==" }, "domutils": { "version": "1.7.0", @@ -7705,8 +9499,7 @@ "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, "es6-promisify": { "version": "5.0.0", @@ -7988,6 +9781,31 @@ } } }, + "express-http-proxy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/express-http-proxy/-/express-http-proxy-1.6.0.tgz", + "integrity": "sha512-7Re6Lepg96NA2wiv7DC5csChAScn4K76/UgYnC71XiITCT1cgGTJUGK6GS0pIixudg3Fbx3Q6mmEW3mZv5tHFQ==", + "requires": { + "debug": "^3.0.1", + "es6-promise": "^4.1.1", + "raw-body": "^2.3.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "express-robots-txt": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/express-robots-txt/-/express-robots-txt-0.4.1.tgz", @@ -8217,6 +10035,13 @@ } } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, "fileset": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", @@ -12262,6 +14087,15 @@ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -12830,9 +14664,9 @@ "dev": true }, "make-fetch-happen": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.1.tgz", - "integrity": "sha512-b4dfaMvUDR67zxUq1+GN7Ke9rH5WvGRmoHuMH7l+gmUCR2tCXFP6mpeJ9Dp+jB6z8mShRopSf1vLRBhRs8Cu5w==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", "dev": true, "requires": { "agentkeepalive": "^3.4.1", @@ -13289,6 +15123,18 @@ "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==" }, + "morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "requires": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + } + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -13650,9 +15496,18 @@ } }, "npm-bundled": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", - "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", "dev": true }, "npm-package-arg": { @@ -13676,13 +15531,14 @@ } }, "npm-packlist": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", - "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "dev": true, "requires": { "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" } }, "npm-path": { @@ -13879,8 +15735,7 @@ "on-headers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" }, "once": { "version": "1.4.0", @@ -14978,24 +16833,16 @@ } }, "read-package-json": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.0.tgz", - "integrity": "sha512-KLhu8M1ZZNkMcrq1+0UJbR8Dii8KZUqB0Sha4mOx/bknfKI/fyrQVrG/YIt2UOtG667sD8+ee4EXMM91W9dC+A==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", + "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", "dev": true, "requires": { "glob": "^7.1.1", "graceful-fs": "^4.1.2", "json-parse-better-errors": "^1.0.1", "normalize-package-data": "^2.0.0", - "slash": "^1.0.0" - }, - "dependencies": { - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - } + "npm-normalize-package-bin": "^1.0.0" } }, "read-package-tree": { @@ -15122,12 +16969,6 @@ "safe-regex": "^1.1.0" } }, - "regexp-tree": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.13.tgz", - "integrity": "sha512-hwdV/GQY5F8ReLZWO+W1SRoN5YfpOKY6852+tBFcma72DKBIcHjPRIlIvQN35bCOljuAfP2G2iB0FC/w236mUw==", - "dev": true - }, "regexp.prototype.flags": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz", @@ -17847,9 +19688,9 @@ } }, "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, "type-is": { @@ -18078,9 +19919,9 @@ "dev": true }, "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true } } diff --git a/package.json b/package.json index e236d22411..33ee8e3a89 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "intershop-pwa", "description": "Intershop Progressive Web App", - "version": "0.17.0", + "version": "0.18.0", "license": "Intershop Standard Software End User License Agreement Intershop 7", "keywords": [ "intershop" @@ -34,25 +34,25 @@ "start": "npm run build && npm run serve" }, "dependencies": { - "@angular/animations": "~8.2.13", - "@angular/common": "~8.2.13", - "@angular/compiler": "~8.2.13", - "@angular/core": "~8.2.13", - "@angular/forms": "~8.2.13", - "@angular/platform-browser": "~8.2.13", - "@angular/platform-browser-dynamic": "~8.2.13", - "@angular/platform-server": "~8.2.13", - "@angular/pwa": "^0.803.18", - "@angular/router": "~8.2.13", - "@angular/service-worker": "~8.2.13", + "@angular/animations": "~8.2.14", + "@angular/common": "~8.2.14", + "@angular/compiler": "~8.2.14", + "@angular/core": "~8.2.14", + "@angular/forms": "~8.2.14", + "@angular/platform-browser": "~8.2.14", + "@angular/platform-browser-dynamic": "~8.2.14", + "@angular/platform-server": "~8.2.14", + "@angular/pwa": "^0.803.23", + "@angular/router": "~8.2.14", + "@angular/service-worker": "~8.2.14", "@fortawesome/angular-fontawesome": "^0.4.0", "@fortawesome/fontawesome-svg-core": "^1.2.21", "@fortawesome/free-solid-svg-icons": "^5.10.1", "@ng-bootstrap/ng-bootstrap": "^5.1.4", - "@ngrx/effects": "^8.5.0", - "@ngrx/entity": "^8.5.0", - "@ngrx/store": "^8.5.0", - "@ngrx/store-devtools": "^8.5.0", + "@ngrx/effects": "^8.6.0", + "@ngrx/entity": "^8.6.0", + "@ngrx/store": "^8.6.0", + "@ngrx/store-devtools": "^8.6.0", "@nguniversal/express-engine": "^8.1.1", "@nguniversal/module-map-ngfactory-loader": "8.1.1", "@ngx-formly/core": "^4.8.3", @@ -73,8 +73,10 @@ "conventional-changelog-cli": "^2.0.21", "core-js": "^2.6.9", "express": "^4.17.1", + "express-http-proxy": "^1.6.0", "express-robots-txt": "0.4.1", "lodash-es": "^4.17.15", + "morgan": "^1.9.1", "ng-recaptcha": "^5.0.0", "ng2-validation": "^4.2.0", "ngx-infinite-scroll": "^8.0.1", @@ -96,6 +98,7 @@ "@angular/language-service": "~8.2.13", "@babel/preset-env": "^7.5.5", "@schematics/angular": "^8.3.18", + "@types/express": "^4.17.2", "@types/jest": "^24.0.18", "@types/node": "^12.12.7", "codelyzer": "^5.1.0", diff --git a/schematics/src/extension/factory.js b/schematics/src/extension/factory.js index 9cbe5b083c..8675d730e6 100644 --- a/schematics/src/extension/factory.js +++ b/schematics/src/extension/factory.js @@ -34,7 +34,7 @@ function createExtension(options) { artifactName: core_1.strings.classify(options.name) + 'RoutingModule', moduleImportPath: `${projectRoot}/extensions/${core_1.strings.dasherize(options.name)}/pages/${core_1.strings.dasherize(options.name)}-routing.module`, }; - operations.push(registration_1.addImportToNgModuleBefore(appModuleOptions, 'AppNotFoundRoutingModule')); + operations.push(registration_1.addImportToNgModuleBefore(appModuleOptions, 'AppLastRoutingModule')); return schematics_1.chain(operations); }; } diff --git a/schematics/src/extension/factory.ts b/schematics/src/extension/factory.ts index c8b5cc2ea1..27bda401aa 100644 --- a/schematics/src/extension/factory.ts +++ b/schematics/src/extension/factory.ts @@ -58,7 +58,7 @@ export function createExtension(options: Options): Rule { options.name )}-routing.module`, }; - operations.push(addImportToNgModuleBefore(appModuleOptions, 'AppNotFoundRoutingModule')); + operations.push(addImportToNgModuleBefore(appModuleOptions, 'AppLastRoutingModule')); return chain(operations); }; diff --git a/schematics/src/extension/factory_spec.ts b/schematics/src/extension/factory_spec.ts index 7dd96ff1c0..4998bce0b3 100644 --- a/schematics/src/extension/factory_spec.ts +++ b/schematics/src/extension/factory_spec.ts @@ -2,7 +2,7 @@ import { UnitTestTree } from '@angular-devkit/schematics/testing'; import { noop } from 'rxjs'; import { - createAppNotFoundRoutingModule, + createAppLastRoutingModule, createApplication, createModule, createSchematicRunner, @@ -23,12 +23,12 @@ describe('Extension Schematic', () => { .pipe( createModule(schematicRunner, { name: 'shared' }), createModule(schematicRunner, { name: 'shell' }), - createAppNotFoundRoutingModule(schematicRunner) + createAppLastRoutingModule(schematicRunner) ) .toPromise(); }); - it('should create a page in root by default', async () => { + it('should create an extension', async () => { const options = { ...defaultOptions }; const tree = await schematicRunner.runSchematicAsync('extension', options, appTree).toPromise(); @@ -37,6 +37,7 @@ describe('Extension Schematic', () => { Array [ "/projects/bar/src/app/extensions/foo/foo.module.ts", "/projects/bar/src/app/extensions/foo/exports/foo-exports.module.ts", + "/projects/bar/src/app/extensions/foo/facades/foo.facade.ts", "/projects/bar/src/app/extensions/foo/pages/foo-routing.module.ts", "/projects/bar/src/app/extensions/foo/store/foo-store.ts", "/projects/bar/src/app/extensions/foo/store/foo-store.module.ts", @@ -55,7 +56,7 @@ describe('Extension Schematic', () => { import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; - import { AppNotFoundRoutingModule } from './pages/app-not-found-routing.module'; + import { AppLastRoutingModule } from './pages/app-last-routing.module'; import { FooRoutingModule } from './extensions/foo/pages/foo-routing.module'; @NgModule({ @@ -65,7 +66,7 @@ describe('Extension Schematic', () => { imports: [ BrowserModule, AppRoutingModule, - FooRoutingModule, AppNotFoundRoutingModule + FooRoutingModule, AppLastRoutingModule ], providers: [], bootstrap: [AppComponent] @@ -115,7 +116,7 @@ describe('Extension Schematic', () => { `); }); - it('should throw if app module does not contain AppNotFoundRoutingModule', done => { + it('should throw if app module does not contain AppLastRoutingModule', done => { appTree.overwrite( '/projects/bar/src/app/app.module.ts', `import { BrowserModule } from '@angular/platform-browser'; @@ -143,7 +144,7 @@ export class AppModule { } schematicRunner.runSchematicAsync('extension', options, appTree).subscribe(noop, err => { expect(err).toMatchInlineSnapshot( - `[Error: did not find 'AppNotFoundRoutingModule' in /projects/bar/src/app/app.module.ts]` + `[Error: did not find 'AppLastRoutingModule' in /projects/bar/src/app/app.module.ts]` ); done(); }); diff --git a/schematics/src/extension/files/__name@dasherize__/facades/__name@dasherize__.facade.__tsext__ b/schematics/src/extension/files/__name@dasherize__/facades/__name@dasherize__.facade.__tsext__ new file mode 100644 index 0000000000..1279a18035 --- /dev/null +++ b/schematics/src/extension/files/__name@dasherize__/facades/__name@dasherize__.facade.__tsext__ @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; +import { Store, select } from '@ngrx/store'; + +import { get<%= classify(name) %>State } from '../store/<%= dasherize(name) %>-store'; + +// tslint:disable:member-ordering +@Injectable({ providedIn: 'root' }) +export class <%= classify(name) %>Facade { + constructor(private store: Store<{}>) {} + + // example for debugging + <%= camelize(name) %>State$ = this.store.pipe(select(get<%= classify(name) %>State)); +} diff --git a/schematics/src/extension/files/__name@dasherize__/store/__name@dasherize__-store.__tsext__ b/schematics/src/extension/files/__name@dasherize__/store/__name@dasherize__-store.__tsext__ index df0d79cfee..22f5c79dac 100644 --- a/schematics/src/extension/files/__name@dasherize__/store/__name@dasherize__-store.__tsext__ +++ b/schematics/src/extension/files/__name@dasherize__/store/__name@dasherize__-store.__tsext__ @@ -1,5 +1,5 @@ -import { createFeatureSelector } from '@ngrx/store'; - export interface <%= classify(name) %>State {} -export const get<%= classify(name) %>State = createFeatureSelector<<%= classify(name) %>State>('<%= camelize(name) %>'); +// TODO: use createFeatureSelector after ivy dynamic loading +// tslint:disable-next-line: no-any +export const get<%= classify(name) %>State: (state: any) => <%= classify(name) %>State = state => state.<%= camelize(name) %>; diff --git a/schematics/src/kubernetes-deployment/files/charts/pwa-nginx/templates/deployment.yaml b/schematics/src/kubernetes-deployment/files/charts/pwa-nginx/templates/deployment.yaml index 40f1efdc8f..3a2265e6c1 100644 --- a/schematics/src/kubernetes-deployment/files/charts/pwa-nginx/templates/deployment.yaml +++ b/schematics/src/kubernetes-deployment/files/charts/pwa-nginx/templates/deployment.yaml @@ -24,8 +24,6 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} env: - - name: UPSTREAM_ICM - value: "{{ .Values.upstream.icm }}" - name: UPSTREAM_PWA value: "{{ .Values.upstream.pwa }}" - name: PWA_1_SUBDOMAIN diff --git a/schematics/src/page/factory.js b/schematics/src/page/factory.js index eb61d41a4f..60348621f9 100644 --- a/schematics/src/page/factory.js +++ b/schematics/src/page/factory.js @@ -11,9 +11,8 @@ function addRouteToArray(options, host, position, insertComma) { const dasherizedName = core_1.strings.dasherize(options.name); const loadChildren = `() => import('${options.child ? '..' : '.'}/${dasherizedName}/${dasherizedName}-page.module').then(m => m.${core_1.strings.classify(dasherizedName)}PageModule)`; const path = options.child ? options.child : dasherizedName; - const canActivate = options.routingModule === '/src/app/pages/app-routing.module.ts' ? 'canActivate: [MetaGuard],' : ''; const recorder = host.beginUpdate(options.routingModule); - recorder.insertRight(position, `${insertComma ? ', ' : ''}{ path: '${path}', loadChildren: ${loadChildren}, ${canActivate} }`); + recorder.insertRight(position, `${insertComma ? ', ' : ''}{ path: '${path}', loadChildren: ${loadChildren} }`); host.commitUpdate(recorder); } function determineRoutingModule(host, options) { diff --git a/schematics/src/page/factory.ts b/schematics/src/page/factory.ts index d329f82b97..6f3917f776 100644 --- a/schematics/src/page/factory.ts +++ b/schematics/src/page/factory.ts @@ -32,14 +32,9 @@ function addRouteToArray( options.child ? '..' : '.' }/${dasherizedName}/${dasherizedName}-page.module').then(m => m.${strings.classify(dasherizedName)}PageModule)`; const path = options.child ? options.child : dasherizedName; - const canActivate = - options.routingModule === '/src/app/pages/app-routing.module.ts' ? 'canActivate: [MetaGuard],' : ''; const recorder = host.beginUpdate(options.routingModule); - recorder.insertRight( - position, - `${insertComma ? ', ' : ''}{ path: '${path}', loadChildren: ${loadChildren}, ${canActivate} }` - ); + recorder.insertRight(position, `${insertComma ? ', ' : ''}{ path: '${path}', loadChildren: ${loadChildren} }`); host.commitUpdate(recorder); } diff --git a/schematics/src/service/factory_spec.ts b/schematics/src/service/factory_spec.ts index 8f1f81d77b..90ff6aed7c 100644 --- a/schematics/src/service/factory_spec.ts +++ b/schematics/src/service/factory_spec.ts @@ -24,7 +24,9 @@ describe('Service Schematic', () => { expect(files).toContain('/projects/bar/src/app/core/services/foo/foo.service.spec.ts'); expect(files).toContain('/projects/bar/src/app/core/services/foo/foo.service.ts'); - expect(tree.readContent('/projects/bar/src/app/core/services/foo/foo.service.ts')).toContain('../api/api.service'); + expect(tree.readContent('/projects/bar/src/app/core/services/foo/foo.service.ts')).toContain( + 'ish-core/services/api/api.service' + ); }); it('should ignore folders in name', async () => { diff --git a/schematics/src/service/files/__name@dasherize__/__name@dasherize__.service.__tsext__ b/schematics/src/service/files/__name@dasherize__/__name@dasherize__.service.__tsext__ index f91b029e85..223d1a3966 100644 --- a/schematics/src/service/files/__name@dasherize__/__name@dasherize__.service.__tsext__ +++ b/schematics/src/service/files/__name@dasherize__/__name@dasherize__.service.__tsext__ @@ -1,8 +1,12 @@ import { Injectable } from '@angular/core'; -import { ApiService } from '<% if(!extension) { %>..<% } else { %>ish-core/services<% } %>/api/api.service'; +import { ApiService } from 'ish-core/services/api/api.service'; @Injectable({ providedIn: 'root' }) export class <%= classify(name) %>Service { constructor(private apiService: ApiService) {} + + get<%= classify(name) %>() { + return this.apiService.get('<%= dasherize(name) %>'); + } } diff --git a/schematics/src/store/factory.js b/schematics/src/store/factory.js index 762efb1694..0c3c06a52e 100644 --- a/schematics/src/store/factory.js +++ b/schematics/src/store/factory.js @@ -17,10 +17,12 @@ function determineStoreLocation(host, options) { extension = requestDestination.match(regex)[1]; } let feature = options.feature; - const regex2 = /store\/([a-z][a-z0-9-]+)\//; - const requestDestination2 = core_1.normalize(`${options.path}/${options.name}`); - if (regex2.test(requestDestination2)) { - feature = requestDestination2.match(regex2)[1]; + if (!extension && !feature) { + const nameWOStore = options.name.replace(/.*store\//, ''); + if (nameWOStore.includes('/')) { + const pathFragments = nameWOStore.split('/'); + feature = pathFragments[pathFragments.length - 2]; + } } let parent; let path = options.path; @@ -39,7 +41,15 @@ function determineStoreLocation(host, options) { else { throw new Error('cannot add feature store in extension'); } - return Object.assign({}, options, { parentStorePath: `${path}${parent}`, extension, + const name = options.name.split('/').pop(); + if (name === feature) { + throw new Error('name of feature and store cannot be equal'); + } + if (name === extension) { + throw new Error('name of extension and store cannot be equal'); + } + return Object.assign({}, options, { parentStorePath: `${path}${parent}`, name, + extension, feature, path, parent }); diff --git a/schematics/src/store/factory.ts b/schematics/src/store/factory.ts index f8bb73ee9b..e8fa344c96 100644 --- a/schematics/src/store/factory.ts +++ b/schematics/src/store/factory.ts @@ -41,10 +41,12 @@ export function determineStoreLocation( } let feature = options.feature; - const regex2 = /store\/([a-z][a-z0-9-]+)\//; - const requestDestination2 = normalize(`${options.path}/${options.name}`); - if (regex2.test(requestDestination2)) { - feature = requestDestination2.match(regex2)[1]; + if (!extension && !feature) { + const nameWOStore = options.name.replace(/.*store\//, ''); + if (nameWOStore.includes('/')) { + const pathFragments = nameWOStore.split('/'); + feature = pathFragments[pathFragments.length - 2]; + } } let parent: string; @@ -62,10 +64,19 @@ export function determineStoreLocation( } else { throw new Error('cannot add feature store in extension'); } + const name = options.name.split('/').pop(); + + if (name === feature) { + throw new Error('name of feature and store cannot be equal'); + } + if (name === extension) { + throw new Error('name of extension and store cannot be equal'); + } return { ...options, parentStorePath: `${path}${parent}`, + name, extension, feature, path, diff --git a/schematics/src/store/factory_spec.ts b/schematics/src/store/factory_spec.ts index 3e91b2391e..4dad22dadc 100644 --- a/schematics/src/store/factory_spec.ts +++ b/schematics/src/store/factory_spec.ts @@ -2,12 +2,13 @@ import { UnitTestTree } from '@angular-devkit/schematics/testing'; import { mergeMap } from 'rxjs/operators'; import { - createAppNotFoundRoutingModule, + createAppLastRoutingModule, createApplication, createModule, createSchematicRunner, } from '../utils/testHelper'; +import { determineStoreLocation } from './factory'; import { PwaStoreOptionsSchema as Options } from './schema'; describe('Store Schematic', () => { @@ -23,7 +24,7 @@ describe('Store Schematic', () => { .pipe( createModule(schematicRunner, { name: 'shared' }), createModule(schematicRunner, { name: 'shell' }), - createAppNotFoundRoutingModule(schematicRunner), + createAppLastRoutingModule(schematicRunner), mergeMap(tree => schematicRunner.runSchematicAsync('extension', { name: 'feature', project: 'bar' }, tree)) ) .toPromise(); @@ -67,34 +68,9 @@ export interface CoreState { export const getCoreState: Selector = state => state; ` ); - appTree.create( - '/projects/bar/src/app/core/store/bar/bar-store.module.ts', - `import { NgModule } from '@angular/core'; -import { EffectsModule } from '@ngrx/effects'; -import { ActionReducerMap, StoreModule } from '@ngrx/store'; - -import { BarState } from './bar-store'; - -export const barReducers: ActionReducerMap = {}; - -export const barEffects = []; - -@NgModule({ - imports: [ - EffectsModule.forRoot(barEffects), - StoreModule.forRoot(barReducers), - ], -}) -export class BarStoreModule {} -` - ); - appTree.create( - '/projects/bar/src/app/core/store/bar/bar-store.ts', - `import { Selector } from '@ngrx/store'; - -export interface BarState {} -` - ); + appTree = await schematicRunner + .runSchematicAsync('store-group', { ...defaultOptions, name: 'bar' }, appTree) + .toPromise(); }); it('should create a store in core store by default', async () => { @@ -203,4 +179,64 @@ export interface BarState {} done(); }); }); + + describe('determineStoreLocation', () => { + it('should handle simple stores', () => { + const config = { + extension: undefined, + feature: undefined, + name: 'foobar', + parent: 'core', + parentStorePath: 'projects/bar/src/app/core/store/core', + path: 'projects/bar/src/app/core/store/', + project: 'bar', + }; + + expect(determineStoreLocation(appTree, { ...defaultOptions, name: 'foobar' })).toEqual(config); + expect(determineStoreLocation(appTree, { ...defaultOptions, name: 'core/store/foobar' })).toEqual(config); + }); + + it('should handle feature stores', () => { + const config = { + extension: undefined, + feature: 'bar', + name: 'foobar', + parent: 'bar', + parentStorePath: 'projects/bar/src/app/core/store/bar/bar', + path: 'projects/bar/src/app/core/store/bar/', + project: 'bar', + }; + + expect(determineStoreLocation(appTree, { ...defaultOptions, name: 'foobar', feature: 'bar' })).toEqual(config); + expect(determineStoreLocation(appTree, { ...defaultOptions, name: 'bar/foobar' })).toEqual(config); + expect(determineStoreLocation(appTree, { ...defaultOptions, name: 'core/store/bar/foobar' })).toEqual(config); + }); + + it('should handle extension stores', () => { + const config = { + extension: 'bar', + feature: undefined, + name: 'foobar', + parent: 'bar', + parentStorePath: 'projects/bar/src/app/extensions/bar/store/bar', + path: 'projects/bar/src/app/extensions/bar/store/', + project: 'bar', + }; + + expect(determineStoreLocation(appTree, { ...defaultOptions, name: 'foobar', extension: 'bar' })).toEqual(config); + expect(determineStoreLocation(appTree, { ...defaultOptions, name: 'extensions/bar/foobar' })).toEqual(config); + }); + + it('should throw if feature equals store name', () => { + expect(() => + determineStoreLocation(appTree, { ...defaultOptions, feature: defaultOptions.name }) + ).toThrowErrorMatchingInlineSnapshot(`"name of feature and store cannot be equal"`); + }); + + it('should throw if extension equals store name', () => { + expect(() => + determineStoreLocation(appTree, { ...defaultOptions, extension: defaultOptions.name }) + ).toThrowErrorMatchingInlineSnapshot(`"name of extension and store cannot be equal"`); + }); + }); }); diff --git a/schematics/src/utils/registration.js b/schematics/src/utils/registration.js index 1d60bb0334..cb9e2e41cd 100644 --- a/schematics/src/utils/registration.js +++ b/schematics/src/utils/registration.js @@ -87,12 +87,18 @@ function addProviderToNgModule(options) { } exports.addProviderToNgModule = addProviderToNgModule; function insertImport(source, recorder, artifactName, relativePath) { + const imp = `import { ${artifactName} } from '${relativePath}';`; // insert import statement to imports const lastImportEnd = tsutils_1.findImports(source, tsutils_1.ImportKind.All) .map(x => x.parent.end) .sort((x, y) => x - y) .pop(); - recorder.insertRight(lastImportEnd, `\nimport { ${artifactName} } from '${relativePath}';`); + if (lastImportEnd) { + recorder.insertRight(lastImportEnd, `\n${imp}`); + } + else { + recorder.insertLeft(0, `${imp}\n\n`); + } } exports.insertImport = insertImport; function addImportToNgModuleBefore(options, beforeToken) { diff --git a/schematics/src/utils/registration.ts b/schematics/src/utils/registration.ts index 8e86768b3b..473ffc6f6e 100644 --- a/schematics/src/utils/registration.ts +++ b/schematics/src/utils/registration.ts @@ -146,12 +146,18 @@ export function insertImport( artifactName: string, relativePath: string ) { + const imp = `import { ${artifactName} } from '${relativePath}';`; + // insert import statement to imports const lastImportEnd = findImports(source, ImportKind.All) .map(x => x.parent.end) .sort((x, y) => x - y) .pop(); - recorder.insertRight(lastImportEnd, `\nimport { ${artifactName} } from '${relativePath}';`); + if (lastImportEnd) { + recorder.insertRight(lastImportEnd, `\n${imp}`); + } else { + recorder.insertLeft(0, `${imp}\n\n`); + } } export function addImportToNgModuleBefore( diff --git a/schematics/src/utils/testHelper.js b/schematics/src/utils/testHelper.js index cac576bd52..7f3b7536bb 100644 --- a/schematics/src/utils/testHelper.js +++ b/schematics/src/utils/testHelper.js @@ -29,12 +29,12 @@ function createModule(schematicRunner, options) { return (source$) => source$.pipe(operators_1.switchMap(tree => schematicRunner.runSchematicAsync('module', Object.assign({}, options, { project: 'bar' }), tree))); } exports.createModule = createModule; -function createAppNotFoundRoutingModule(schematicRunner) { +function createAppLastRoutingModule(schematicRunner) { return (source$) => source$.pipe(operators_1.switchMap(tree => schematicRunner.runExternalSchematicAsync('@schematics/angular', 'module', { - name: 'pages/app-not-found-routing', + name: 'pages/app-last-routing', flat: true, module: 'app.module', project: 'bar', }, tree))); } -exports.createAppNotFoundRoutingModule = createAppNotFoundRoutingModule; +exports.createAppLastRoutingModule = createAppLastRoutingModule; diff --git a/schematics/src/utils/testHelper.ts b/schematics/src/utils/testHelper.ts index a7b79abdf8..de45108a88 100644 --- a/schematics/src/utils/testHelper.ts +++ b/schematics/src/utils/testHelper.ts @@ -43,7 +43,7 @@ export function createModule( source$.pipe(switchMap(tree => schematicRunner.runSchematicAsync('module', { ...options, project: 'bar' }, tree))); } -export function createAppNotFoundRoutingModule(schematicRunner: SchematicTestRunner) { +export function createAppLastRoutingModule(schematicRunner: SchematicTestRunner) { return (source$: Observable) => source$.pipe( switchMap(tree => @@ -51,7 +51,7 @@ export function createAppNotFoundRoutingModule(schematicRunner: SchematicTestRun '@schematics/angular', 'module', { - name: 'pages/app-not-found-routing', + name: 'pages/app-last-routing', flat: true, module: 'app.module', project: 'bar', diff --git a/scripts/ci-check-no-additional-warnings.sh b/scripts/ci-check-no-additional-warnings.sh deleted file mode 100644 index 3e78a99610..0000000000 --- a/scripts/ci-check-no-additional-warnings.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -set -e - -cat > tslint-hard.js < key !== 'no-disabled-tests').forEach(key => { - if (config.rules[key].severity && config.rules[key].severity.startsWith('warn')) { - config.rules[key].severity = 'error'; - } - }); - - fs.writeFileSync('tslint.hard.json', JSON.stringify(config)); -}); - -EOF - -cat tslint.json | grep -Ev '^\s*//' > tslint.hard.json - -node tslint-hard - -npx tslint --project tsconfig.spec.json -c tslint.hard.json -npx tslint --project e2e/cypress/tsconfig.json -c tslint.hard.json diff --git a/scripts/tslint-hard.js b/scripts/tslint-hard.js new file mode 100644 index 0000000000..8133fb0717 --- /dev/null +++ b/scripts/tslint-hard.js @@ -0,0 +1,20 @@ +const fs = require('fs'); +const { parse, stringify } = require('comment-json'); +const { execSync } = require('child_process'); + +const tslintJson = parse(fs.readFileSync('./tslint.json', { encoding: 'UTF-8' })); + +Object.keys(tslintJson.rules) + .filter(key => key !== 'no-disabled-tests') + .forEach(key => { + if ( + typeof tslintJson.rules[key] === 'object' && + tslintJson.rules[key].severity && + tslintJson.rules[key].severity.startsWith('warn') + ) { + tslintJson.rules[key].severity = 'error'; + } + }); + +fs.writeFileSync('./tslint.json', stringify(tslintJson, null, 2)); +execSync('npx prettier --write tslint.json'); diff --git a/server.ts b/server.ts index f27fe34f7f..a86b7098da 100644 --- a/server.ts +++ b/server.ts @@ -22,6 +22,19 @@ import * as express from 'express'; import { join } from 'path'; import * as robots from 'express-robots-txt'; import * as fs from 'fs'; +import * as proxy from 'express-http-proxy'; + +// * NOTE :: leave this as require() since this file is built Dynamically from webpack +const { AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap } = require('./dist/server/main'); + +// tslint:disable-next-line: ban-specific-imports +import { Environment } from 'src/environments/environment.model'; +const environment: Environment = require('./dist/server/main').environment; + +// tslint:disable-next-line: ban-specific-imports +import { HybridMappingEntry } from 'src/hybrid/default-url-mapping-table'; +const HYBRID_MAPPING_TABLE: HybridMappingEntry[] = require('./dist/server/main').HYBRID_MAPPING_TABLE; +const ICM_WEB_URL: string = require('./dist/server/main').ICM_WEB_URL; const logging = !!process.env.LOGGING; @@ -31,21 +44,40 @@ const app = express(); const PORT = process.env.PORT || 4200; const DIST_FOLDER = join(process.cwd(), 'dist'); -// * NOTE :: leave this as require() since this file is built Dynamically from webpack -const { AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap } = require('./dist/server/main'); +const ICM_BASE_URL = process.env.ICM_BASE_URL || environment.icmBaseURL; +if (!ICM_BASE_URL) { + console.error('ICM_BASE_URL not set'); + process.exit(1); +} + +if (process.env.TRUST_ICM) { + // trust https certificate if self-signed + // see also https://medium.com/nodejs-tips/ssl-certificate-explained-fc86f8aa43d4 + // and https://github.com/angular/universal/issues/856#issuecomment-436364729 + process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; + console.warn("ignoring all TLS verification as 'TRUST_ICM' variable is set - never use this in production!"); +} // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) app.engine( 'html', ngExpressEngine({ bootstrap: AppServerModuleNgFactory, - providers: [provideModuleMap(LAZY_MODULE_MAP)], + providers: [provideModuleMap(LAZY_MODULE_MAP), { provide: 'SSR_HYBRID', useValue: !!process.env.SSR_HYBRID }], }) ); app.set('view engine', 'html'); app.set('views', join(DIST_FOLDER, 'browser')); +if (logging) { + app.use( + require('morgan')('tiny', { + skip: req => req.originalUrl.startsWith('/INTERSHOP/static'), + }) + ); +} + // seo robots.txt const pathToRobotsTxt = join(DIST_FOLDER, 'robots.txt'); if (fs.existsSync(pathToRobotsTxt)) { @@ -87,10 +119,24 @@ app.get( }) ); -// All regular routes use the Universal engine -app.get('*', (req: express.Request, res: express.Response) => { +const icmProxy = proxy(ICM_BASE_URL, { + // preserve original path + proxyReqPathResolver: req => req.originalUrl, + proxyReqOptDecorator: options => { + if (process.env.TRUST_ICM) { + // https://github.com/villadora/express-http-proxy#q-how-to-ignore-self-signed-certificates- + options.rejectUnauthorized = false; + } + return options; + }, + // fool ICM so it thinks it's running here + // https://www.npmjs.com/package/express-http-proxy#preservehosthdr + preserveHostHdr: true, +}); + +const angularUniversal = (req: express.Request, res: express.Response) => { if (logging) { - console.log(`GET ${req.url}`); + console.log(`SSR ${req.originalUrl}`); } res.render( 'index', @@ -98,23 +144,106 @@ app.get('*', (req: express.Request, res: express.Response) => { req, res, }, - (err: Error, html: string) => { - res.status(html ? res.statusCode : 500).send(html || err.message); + (err, html) => { + if (html) { + let newHtml: string; + if (process.env.PROXY_ICM && req.get('host')) { + newHtml = html.replace(new RegExp(ICM_BASE_URL, 'g'), `${req.protocol}://${req.get('host')}`); + } + res.status(res.statusCode).send(newHtml || html); + } else { + res.status(500).send(err.message); + } if (logging) { - console.log(`RES ${res.statusCode} ${req.url}`); + console.log(`RES ${res.statusCode} ${req.originalUrl}`); if (err) { console.log(err); } } } ); -}); +}; -// Start up the Node server -app.listen(PORT, () => { - console.log(`Node Express server listening on http://localhost:${PORT}`); - const icmBaseUrl = process.env.ICM_BASE_URL; - if (icmBaseUrl) { - console.log('ICM_BASE_URL is', icmBaseUrl); +const hybridRedirect = (req: express.Request, res: express.Response, next: express.NextFunction) => { + const url = req.originalUrl; + let newUrl: string; + for (const entry of HYBRID_MAPPING_TABLE) { + const icmUrlRegex = new RegExp(entry.icm); + const pwaUrlRegex = new RegExp(entry.pwa); + if (icmUrlRegex.exec(url) && entry.handledBy === 'pwa') { + newUrl = url.replace(icmUrlRegex, '/' + entry.pwaBuild); + break; + } else if (pwaUrlRegex.exec(url) && entry.handledBy === 'icm') { + const config: { [is: string]: string } = {}; + let locale; + if (/;lang=[\w_]+/.test(url)) { + const [, lang] = /;lang=([\w_]+)/.exec(url); + if (lang !== 'default') { + locale = environment.locales.find(loc => loc.lang === lang); + } + } + if (!locale) { + locale = environment.locales[0]; + } + config.lang = locale.lang; + config.currency = locale.currency; + + if (/;channel=[^;]*/.test(url)) { + config.channel = /;channel=([^;]*)/.exec(url)[1]; + } else { + config.channel = environment.icmChannel; + } + + if (/;application=[^;]*/.test(url)) { + config.application = /;application=([^;]*)/.exec(url)[1]; + } else { + config.application = environment.icmApplication || '-'; + } + + const build = [ICM_WEB_URL, entry.icmBuild] + .join('/') + .replace(/\$<(\w+)>/g, (match, group) => config[group] || match); + newUrl = url.replace(pwaUrlRegex, build).replace(/;.*/g, ''); + break; + } } -}); + if (newUrl) { + if (logging) { + console.log('RED', newUrl); + } + res.redirect(301, newUrl); + } else { + next(); + } +}; + +if (process.env.SSR_HYBRID) { + app.use('*', hybridRedirect); +} + +if (process.env.PROXY_ICM || process.env.SSR_HYBRID) { + console.log("making ICM available for all requests to '/INTERSHOP'"); + app.use('/INTERSHOP', icmProxy); +} + +// All regular routes use the Universal engine +app.use('*', angularUniversal); + +if (process.env.SSL) { + const https = require('https'); + const privateKey = fs.readFileSync(join(DIST_FOLDER, 'server.key'), 'utf8'); + const certificate = fs.readFileSync(join(DIST_FOLDER, 'server.crt'), 'utf8'); + const credentials = { key: privateKey, cert: certificate }; + + https.createServer(credentials, app).listen(PORT); + + console.log(`Node Express server listening on https://${require('os').hostname()}:${PORT}`); +} else { + const http = require('http'); + + http.createServer(app).listen(PORT); + + console.log(`Node Express server listening on http://${require('os').hostname()}:${PORT}`); +} + +console.log('ICM_BASE_URL is', ICM_BASE_URL); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 51bbd18658..5b72e0ca76 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -5,8 +5,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CoreModule } from 'ish-core/core.module'; import { AppComponent } from './app.component'; -import { QuotingRoutingModule } from './extensions/quoting/pages/quoting-routing.module'; -import { AppNotFoundRoutingModule } from './pages/app-not-found-routing.module'; +import { AppLastRoutingModule } from './pages/app-last-routing.module'; import { AppRoutingModule } from './pages/app-routing.module'; import { ShellModule } from './shell/shell.module'; @@ -18,8 +17,7 @@ import { ShellModule } from './shell/shell.module'; CoreModule, ShellModule, AppRoutingModule, - QuotingRoutingModule, - AppNotFoundRoutingModule, + AppLastRoutingModule, ], bootstrap: [AppComponent], }) diff --git a/src/app/core/directives/server-html.directive.spec.ts b/src/app/core/directives/server-html.directive.spec.ts index a06640c0d8..82768acae8 100644 --- a/src/app/core/directives/server-html.directive.spec.ts +++ b/src/app/core/directives/server-html.directive.spec.ts @@ -38,7 +38,7 @@ describe('Server Html Directive', () => { it('should transform the given links to routing links', () => { expect(element).toMatchInlineSnapshot(` @@ -80,16 +80,16 @@ describe('Server Html Directive', () => { it('should transform the given media object source to the correct source', () => { expect(element).toMatchInlineSnapshot(` -
- -
- `); +
+ +
+ `); }); }); diff --git a/src/app/core/directives/server-html.directive.ts b/src/app/core/directives/server-html.directive.ts index 369457e3f0..f14b51d99c 100644 --- a/src/app/core/directives/server-html.directive.ts +++ b/src/app/core/directives/server-html.directive.ts @@ -93,22 +93,30 @@ export class ServerHtmlDirective implements AfterContentInit, AfterViewInit, OnD const href = el.getAttribute('href'); const cb = el.getAttribute('callback'); - // apply default link handling for empty href, external links & target _blank - if (!cb && (!href || href.startsWith('http') || el.getAttribute('target') === '_blank')) { + // handle links with callback functions, e.g. + if (cb && this.callbacks && typeof this.callbacks[cb] === 'function') { + this.callbacks[cb](); + } + + // apply default link handling for empty href, external links, javascript links & target _blank + if ( + !href || + href.startsWith('http') || + href.startsWith('javascript:') || + el.getAttribute('target') === '_blank' + ) { return; } - if (cb && this.callbacks && typeof this.callbacks[cb] === 'function') { - // handle links with callback functions, e.g. - this.callbacks[cb](); - } else if (href.startsWith('#')) { - // handle fragment links / anchor navigation + // handle fragment links / anchor navigation + if (href.startsWith('#')) { document.getElementById(href.replace('#', '')).scrollIntoView({ block: 'start', behavior: 'smooth' }); } else { // otherwise handle as routerLink this.router.navigateByUrl(href); } + // prevent default link handling event.preventDefault(); return false; } diff --git a/src/app/core/facades/app.facade.ts b/src/app/core/facades/app.facade.ts index 509850dfdd..22efdd8b55 100644 --- a/src/app/core/facades/app.facade.ts +++ b/src/app/core/facades/app.facade.ts @@ -1,10 +1,8 @@ -import { Location } from '@angular/common'; import { Injectable } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; -import { getICMBaseURL } from 'ish-core/store/configuration'; import { LoadCountries, getAllCountries, getCountriesLoading } from 'ish-core/store/countries'; import { getGeneralError, getGeneralErrorType } from 'ish-core/store/error'; import { getAvailableLocales, getCurrentLocale } from 'ish-core/store/locale'; @@ -19,12 +17,7 @@ import { @Injectable({ providedIn: 'root' }) export class AppFacade { - constructor(private store: Store<{}>, private location: Location) {} - - currentUrl$ = this.store.pipe( - select(getICMBaseURL), - map(baseUrl => baseUrl + this.location.path()) - ); + constructor(private store: Store<{}>) {} headerType$ = this.store.pipe(select(getHeaderType)); deviceType$ = this.store.pipe(select(getDeviceType)); diff --git a/src/app/core/facades/message.facade.ts b/src/app/core/facades/message.facade.ts new file mode 100644 index 0000000000..2cc86c4c23 --- /dev/null +++ b/src/app/core/facades/message.facade.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; + +import { + ErrorMessage, + InfoMessage, + MessagesPayloadType, + SuccessMessage, + WarningMessage, +} from 'ish-core/store/messages'; + +@Injectable({ providedIn: 'root' }) +export class MessageFacade { + constructor(private store: Store<{}>) {} + + info(data: MessagesPayloadType) { + this.store.dispatch(new InfoMessage(data)); + } + + error(data: MessagesPayloadType) { + this.store.dispatch(new ErrorMessage(data)); + } + + warn(data: MessagesPayloadType) { + this.store.dispatch(new WarningMessage(data)); + } + + success(data: MessagesPayloadType) { + this.store.dispatch(new SuccessMessage(data)); + } +} diff --git a/src/app/core/guards/auth.guard.ts b/src/app/core/guards/auth.guard.ts index 13dcddf069..f282ef3563 100644 --- a/src/app/core/guards/auth.guard.ts +++ b/src/app/core/guards/auth.guard.ts @@ -3,6 +3,7 @@ import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, + Params, Router, RouterStateSnapshot, UrlTree, @@ -21,15 +22,15 @@ import { whenTruthy } from 'ish-core/utils/operators'; export class AuthGuard implements CanActivate, CanActivateChild { constructor(private store: Store<{}>, private router: Router) {} - canActivate(_: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.guardAccess(state.url); + canActivate(snapshot: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.guardAccess({ ...snapshot.queryParams, returnUrl: state.url }); } - canActivateChild(_: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.guardAccess(state.url); + canActivateChild(snapshot: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.guardAccess({ ...snapshot.queryParams, returnUrl: state.url }); } - private guardAccess(url: string): Observable { + private guardAccess(queryParams: Params): Observable { return race( // wait till authorization can be aquired through cookie this.store.pipe( @@ -37,8 +38,8 @@ export class AuthGuard implements CanActivate, CanActivateChild { whenTruthy(), take(1) ), - // send to login after timeout - timer(4000).pipe(mapTo(this.router.createUrlTree(['/login'], { queryParams: { returnUrl: url } }))) + // send to login after timeout on first routing only + timer(this.router.navigated ? 0 : 4000).pipe(mapTo(this.router.createUrlTree(['/login'], { queryParams }))) ); } } diff --git a/src/app/core/guards/hybrid-redirect.guard.ts b/src/app/core/guards/hybrid-redirect.guard.ts new file mode 100644 index 0000000000..0b559dc33f --- /dev/null +++ b/src/app/core/guards/hybrid-redirect.guard.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@angular/core'; +import { CanActivate, CanActivateChild, RouterStateSnapshot } from '@angular/router'; +import { Store, select } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { getICMWebURL } from 'ish-core/store/hybrid'; + +import { HYBRID_MAPPING_TABLE } from '../../../hybrid/default-url-mapping-table'; + +@Injectable({ providedIn: 'root' }) +export class HybridRedirectGuard implements CanActivate, CanActivateChild { + constructor(private store$: Store<{}>) {} + + private checkRedirect(url: string): boolean | Observable { + return this.store$.pipe( + select(getICMWebURL), + map(icmWebUrl => { + for (const entry of HYBRID_MAPPING_TABLE) { + if (entry.handledBy === 'pwa') { + continue; + } + const regex = new RegExp(entry.pwa); + if (regex.exec(url)) { + const newUrl = url.replace(regex, `${icmWebUrl}/${entry.icmBuild}`); + location.assign(newUrl); + return false; + } + } + return true; + }) + ); + } + + canActivate(_, state: RouterStateSnapshot) { + return this.checkRedirect(state.url); + } + + canActivateChild(_, state: RouterStateSnapshot) { + return this.checkRedirect(state.url); + } +} diff --git a/src/app/core/guards/login.guard.ts b/src/app/core/guards/login.guard.ts index b2258c01e6..b69dd613f1 100644 --- a/src/app/core/guards/login.guard.ts +++ b/src/app/core/guards/login.guard.ts @@ -34,6 +34,11 @@ export class LoginGuard implements CanActivate { return true; } + // force page view by queryParam + if (route.queryParams.forcePageView) { + return true; + } + const returnUrl = route.queryParams.returnUrl || '/home'; this.currentDialog = this.modalService.open(LazyLoginModalComponent, { centered: true, size: 'sm' }); diff --git a/src/app/core/icon.module.ts b/src/app/core/icon.module.ts index a06b2e4eee..1de5ead2e8 100644 --- a/src/app/core/icon.module.ts +++ b/src/app/core/icon.module.ts @@ -6,11 +6,13 @@ import { faAngleDown, faAngleRight, faAngleUp, + faArrowsAlt, faBars, faCheck, faCog, faColumns, faGlobeAmericas, + faHeart, faHome, faInbox, faInfoCircle, @@ -48,6 +50,7 @@ export class IconModule { faAngleDown, faAngleRight, faAngleUp, + faArrowsAlt, faBars, faCheck, faCog, @@ -75,7 +78,8 @@ export class IconModule { faTrashAlt, faUser, faStar, - faStarHalf + faStarHalf, + faHeart ); } } diff --git a/src/app/core/interceptors/auth.interceptor.spec.ts b/src/app/core/interceptors/auth.interceptor.spec.ts index 481c68ebc9..101ca54e61 100644 --- a/src/app/core/interceptors/auth.interceptor.spec.ts +++ b/src/app/core/interceptors/auth.interceptor.spec.ts @@ -90,7 +90,7 @@ describe('Auth Interceptor', () => { const req2 = httpTestingController.expectOne('some/url'); expect(req2.request.headers.get(ApiService.TOKEN_HEADER_KEY)).toBeFalsy(); req2.flush('some data'); - }, 100); + }, 1000); }); it('should re-throw errors unrelated to tokens', done => { diff --git a/src/app/core/interceptors/auth.interceptor.ts b/src/app/core/interceptors/auth.interceptor.ts index 741abbc043..b4d55c7b53 100644 --- a/src/app/core/interceptors/auth.interceptor.ts +++ b/src/app/core/interceptors/auth.interceptor.ts @@ -50,7 +50,7 @@ export class AuthInterceptor implements HttpInterceptor { // retry request without auth token const retryRequest = req.clone({ headers: req.headers.delete(ApiService.TOKEN_HEADER_KEY) }); // timer introduced for testability - return timer(10).pipe(switchMapTo(next.handle(retryRequest))); + return timer(500).pipe(switchMapTo(next.handle(retryRequest))); } return throwError(err); }), diff --git a/src/app/core/models/basket-feedback/basket-feedback.model.ts b/src/app/core/models/basket-feedback/basket-feedback.model.ts index efbcbda7d5..bf033f375f 100644 --- a/src/app/core/models/basket-feedback/basket-feedback.model.ts +++ b/src/app/core/models/basket-feedback/basket-feedback.model.ts @@ -1,5 +1,5 @@ import { LineItem } from 'ish-core/models/line-item/line-item.model'; -import { Product } from 'ish-core/models/product/product.model'; +import { ProductView } from 'ish-core/models/product-view/product-view.model'; export interface BasketFeedback { code: string; @@ -13,6 +13,6 @@ export interface BasketFeedback { } export interface BasketFeedbackView extends BasketFeedback { - product?: Product; + product?: ProductView; lineItem?: LineItem; } diff --git a/src/app/core/models/basket/basket.model.ts b/src/app/core/models/basket/basket.model.ts index 790900611f..e83cb01837 100644 --- a/src/app/core/models/basket/basket.model.ts +++ b/src/app/core/models/basket/basket.model.ts @@ -7,6 +7,7 @@ import { BasketTotal } from 'ish-core/models/basket-total/basket-total.model'; import { BasketValidationResultType } from 'ish-core/models/basket-validation/basket-validation.model'; import { LineItem, LineItemView } from 'ish-core/models/line-item/line-item.model'; import { Payment } from 'ish-core/models/payment/payment.model'; +import { createProductView } from 'ish-core/models/product-view/product-view.model'; import { VariationProductMaster } from 'ish-core/models/product/product-variation-master.model'; import { VariationProduct } from 'ish-core/models/product/product-variation.model'; import { Product } from 'ish-core/models/product/product.model'; @@ -33,7 +34,7 @@ export interface Basket extends AbstractBasket {} export interface BasketView extends AbstractBasket {} export const createBasketView = memoize( - (basket, products, validationResults, basketInfo): BasketView => { + (basket, products, validationResults, basketInfo, categoryTree): BasketView => { if (!basket) { return; } @@ -43,7 +44,7 @@ export const createBasketView = memoize( lineItems: basket.lineItems ? basket.lineItems.map(li => ({ ...li, - product: products[li.productSKU], + product: createProductView(products[li.productSKU], categoryTree), name: products && products[li.productSKU] ? products[li.productSKU].name : undefined, inStock: products && products[li.productSKU] ? products[li.productSKU].inStock : undefined, availability: products && products[li.productSKU] ? products[li.productSKU].availability : undefined, diff --git a/src/app/core/models/content-view/content-view.helper.spec.ts b/src/app/core/models/content-view/content-view.helper.spec.ts index 8f7e43fda3..380dd7f5f5 100644 --- a/src/app/core/models/content-view/content-view.helper.spec.ts +++ b/src/app/core/models/content-view/content-view.helper.spec.ts @@ -9,7 +9,7 @@ describe('Content View Helper', () => { [ { input: 'route://category/Computers', expected: '/category/Computers' }, { input: 'route://category/Home-Entertainment.SmartHome', expected: '/category/Home-Entertainment.SmartHome' }, - { input: 'product://201807195@inSPIRED-inTRONICS', expected: '/product/201807195' }, + { input: 'product://201807195@inSPIRED-inTRONICS', expected: '/sku201807195' }, ], ({ input, expected }) => { it(`should transform ${input} to ${expected}`, () => { diff --git a/src/app/core/models/line-item/line-item.model.ts b/src/app/core/models/line-item/line-item.model.ts index 6347843072..297761c6ff 100644 --- a/src/app/core/models/line-item/line-item.model.ts +++ b/src/app/core/models/line-item/line-item.model.ts @@ -1,7 +1,7 @@ import { BasketFeedback } from 'ish-core/models/basket-feedback/basket-feedback.model'; import { BasketRebate } from 'ish-core/models/basket-rebate/basket-rebate.model'; import { Price } from 'ish-core/models/price/price.model'; -import { Product } from 'ish-core/models/product/product.model'; +import { ProductView } from 'ish-core/models/product-view/product-view.model'; export interface LineItem { id: string; @@ -45,7 +45,7 @@ export interface LineItem { } export interface LineItemView extends LineItem { - product: Product; + product: ProductView; validationError?: BasketFeedback; info?: BasketFeedback; } diff --git a/src/app/core/models/order/order.model.ts b/src/app/core/models/order/order.model.ts index c7e011d92b..0f4e7b302b 100644 --- a/src/app/core/models/order/order.model.ts +++ b/src/app/core/models/order/order.model.ts @@ -2,6 +2,7 @@ import { Dictionary } from '@ngrx/entity'; import { memoize } from 'lodash-es'; import { Basket, BasketView } from 'ish-core/models/basket/basket.model'; +import { createProductView } from 'ish-core/models/product-view/product-view.model'; import { VariationProductMaster } from 'ish-core/models/product/product-variation-master.model'; import { VariationProduct } from 'ish-core/models/product/product-variation.model'; import { Product } from 'ish-core/models/product/product.model'; @@ -26,7 +27,7 @@ export interface Order extends Basket, AbstractOrder {} export interface OrderView extends BasketView, AbstractOrder {} export const createOrderView = memoize( - (order, products): OrderView => { + (order, products, categoryTree): OrderView => { if (!order) { return; } @@ -36,7 +37,7 @@ export const createOrderView = memoize( lineItems: order.lineItems ? order.lineItems.map(li => ({ ...li, - product: products ? products[li.productSKU] : undefined, + product: products ? createProductView(products[li.productSKU], categoryTree) : undefined, })) : [], }; diff --git a/src/app/core/models/product-view/product-view.model.ts b/src/app/core/models/product-view/product-view.model.ts index 884519e758..e0eccf65b5 100644 --- a/src/app/core/models/product-view/product-view.model.ts +++ b/src/app/core/models/product-view/product-view.model.ts @@ -58,7 +58,7 @@ export function createVariationProductMasterView( : () => [], defaultVariation: product.defaultVariationSKU ? once(() => createVariationProductView(entities[product.defaultVariationSKU], entities, tree)) - : undefined, + : () => undefined, }; } diff --git a/src/app/core/models/product/__snapshots__/product.mapper.spec.ts.snap b/src/app/core/models/product/__snapshots__/product.mapper.spec.ts.snap index 9b2361eb5b..0e8ac2fa94 100644 --- a/src/app/core/models/product/__snapshots__/product.mapper.spec.ts.snap +++ b/src/app/core/models/product/__snapshots__/product.mapper.spec.ts.snap @@ -2,7 +2,17 @@ exports[`Product Mapper fromStubData should construct a stub when supplied with a complex API response 1`] = ` Object { - "attributeGroups": undefined, + "attributeGroups": Object { + "attrGroup": Object { + "attributes": Array [ + Object { + "name": "attrName", + "type": "Boolean", + "value": true, + }, + ], + }, + }, "availability": true, "completenessLevel": 2, "defaultCategoryId": undefined, diff --git a/src/app/core/models/product/product.interface.ts b/src/app/core/models/product/product.interface.ts index ec929ddecd..ead38ba19d 100644 --- a/src/app/core/models/product/product.interface.ts +++ b/src/app/core/models/product/product.interface.ts @@ -74,7 +74,7 @@ export interface ProductData { } export interface ProductDataStub { - attributeGroups?: { [id: string]: AttributeGroup }; + attributeGroup?: { name: string; attributes: Attribute[] }; attributes: Attribute[]; description: string; title: string; diff --git a/src/app/core/models/product/product.mapper.spec.ts b/src/app/core/models/product/product.mapper.spec.ts index 6cc4b16a52..43915a4cb6 100644 --- a/src/app/core/models/product/product.mapper.spec.ts +++ b/src/app/core/models/product/product.mapper.spec.ts @@ -114,6 +114,26 @@ describe('Product Mapper', () => { expect(product.type).toEqual('RetailSet'); expect(ProductHelper.isRetailSet(product)).toBeTrue(); }); + + it('should return attributes or detailed product attributes when PRODUCT_DETAIL_ATTRIBUTES enabled', () => { + const p1: Product = productMapper.fromData({ + sku: '1', + attributes: [{ name: 'Graphics', type: 'String', value: 'NVIDIA Quadro K2200' }], + } as ProductData); + const p2: Product = productMapper.fromData(({ + sku: '1', + attributes: [{ name: 'Graphics', type: 'String', value: 'NVIDIA Quadro K2200' }], + attributeGroups: { + PRODUCT_DETAIL_ATTRIBUTES: { + attributes: [{ name: 'Grafikkarte', type: 'String', value: 'NVIDIA Quadro K2200' }], + }, + }, + } as unknown) as ProductData); + expect(p1).toBeTruthy(); + expect(p1.attributes).toEqual([{ name: 'Graphics', type: 'String', value: 'NVIDIA Quadro K2200' }]); + expect(p2).toBeTruthy(); + expect(p2.attributes).toEqual([{ name: 'Grafikkarte', type: 'String', value: 'NVIDIA Quadro K2200' }]); + }); }); describe('fromStubData', () => { @@ -128,6 +148,16 @@ describe('Product Mapper', () => { attributes: [{ name: 'sku', value: 'productSKU', type: 'String' }], title: 'productName', description: 'productDescription', + attributeGroup: { + name: 'attrGroup', + attributes: [ + { + name: 'attrName', + type: 'Boolean', + value: true, + }, + ], + }, }); expect(stub).toBeTruthy(); expect(stub.name).toEqual('productName'); @@ -157,6 +187,16 @@ describe('Product Mapper', () => { ] as Attribute[], description: 'EasyShare M552, 14MP, 6.858 cm (2.7 ") LCD, 4x, 28mm, HD 720p, Black', title: 'Kodak M series EasyShare M552', + attributeGroup: { + name: 'attrGroup', + attributes: [ + { + name: 'attrName', + type: 'Boolean', + value: true, + }, + ], + }, }); expect(stub).toMatchSnapshot(); diff --git a/src/app/core/models/product/product.mapper.ts b/src/app/core/models/product/product.mapper.ts index e12cd64842..ec2d314ad8 100644 --- a/src/app/core/models/product/product.mapper.ts +++ b/src/app/core/models/product/product.mapper.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; +import { AttributeGroup } from 'ish-core/models/attribute-group/attribute-group.model'; import { AttributeHelper } from 'ish-core/models/attribute/attribute.helper'; import { CategoryData } from 'ish-core/models/category/category.interface'; import { CategoryMapper } from 'ish-core/models/category/category.mapper'; @@ -33,6 +34,13 @@ function mapPromotionIds(data: Link[]): string[] { return data ? data.map(promotionLink => promotionLink.itemId) : []; } +/** + * maps an attribute group and its attribute data to the same format as it is used in a single product call + */ +function mapAttributeGroups(data: ProductDataStub): { [id: string]: AttributeGroup } { + return { [data.attributeGroup.name]: { attributes: data.attributeGroup.attributes } }; +} + /** * Product Mapper maps data of HTTP requests to model instances and vice versa. */ @@ -142,7 +150,7 @@ export class ProductMapper { longDescription: undefined, minOrderQuantity, packingUnit: retrieveStubAttributeValue(data, 'packingUnit'), - attributeGroups: data.attributeGroups, + attributeGroups: data.attributeGroup && mapAttributeGroups(data), readyForShipmentMin: undefined, readyForShipmentMax: undefined, roundedAverageRating: +retrieveStubAttributeValue(data, 'roundedAverageRating') || 0, @@ -188,7 +196,11 @@ export class ProductMapper { minOrderQuantity: data.minOrderQuantity || 1, packingUnit: data.packingUnit, maxOrderQuantity: data.maxOrderQuantity || 100, - attributes: data.attributes, + attributes: + (data.attributeGroups && + data.attributeGroups.PRODUCT_DETAIL_ATTRIBUTES && + data.attributeGroups.PRODUCT_DETAIL_ATTRIBUTES.attributes) || + data.attributes, attributeGroups: data.attributeGroups, images: this.imageMapper.fromImages(data.images), listPrice: filterPrice(data.listPrice), diff --git a/src/app/core/models/seo-attribute/seo-attribute.model.ts b/src/app/core/models/seo-attribute/seo-attribute.model.ts index 3daf875304..28dbb429ba 100644 --- a/src/app/core/models/seo-attribute/seo-attribute.model.ts +++ b/src/app/core/models/seo-attribute/seo-attribute.model.ts @@ -3,4 +3,5 @@ export interface SeoAttributes { metaTitle?: string; robots?: string[]; canonical?: string; + 'og:image'?: string; } diff --git a/src/app/core/pipes.module.ts b/src/app/core/pipes.module.ts index 298c51d9c1..63ace0ee6c 100644 --- a/src/app/core/pipes.module.ts +++ b/src/app/core/pipes.module.ts @@ -2,13 +2,13 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; import { AttributeToStringPipe } from './models/attribute/attribute.pipe'; import { PricePipe } from './models/price/price.pipe'; -import { CategoryRoutePipe } from './pipes/category-route.pipe'; import { DatePipe } from './pipes/date.pipe'; import { HighlightPipe } from './pipes/highlight.pipe'; import { MakeHrefPipe } from './pipes/make-href.pipe'; -import { ProductRoutePipe } from './pipes/product-route.pipe'; import { SafeHtmlPipe } from './pipes/safe-html.pipe'; import { SanitizePipe } from './pipes/sanitize.pipe'; +import { CategoryRoutePipe } from './routing/category/category-route.pipe'; +import { ProductRoutePipe } from './routing/product/product-route.pipe'; const pipes = [ AttributeToStringPipe, diff --git a/src/app/core/pipes/category-route.pipe.spec.ts b/src/app/core/pipes/category-route.pipe.spec.ts deleted file mode 100644 index 8a37fe55c5..0000000000 --- a/src/app/core/pipes/category-route.pipe.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { Category } from 'ish-core/models/category/category.model'; - -import { CategoryRoutePipe } from './category-route.pipe'; - -describe('Category Route Pipe', () => { - let categoryRoutePipe: CategoryRoutePipe; - let cat: Category; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [CategoryRoutePipe], - }); - categoryRoutePipe = TestBed.get(CategoryRoutePipe); - cat = { uniqueId: 'cate' } as Category; - }); - - it('should be created', () => { - expect(categoryRoutePipe).toBeTruthy(); - }); - - it('should generate category route for category', () => { - expect(categoryRoutePipe.transform(cat)).toEqual('/category/cate'); - }); -}); diff --git a/src/app/core/pipes/category-route.pipe.ts b/src/app/core/pipes/category-route.pipe.ts deleted file mode 100644 index c6924a1991..0000000000 --- a/src/app/core/pipes/category-route.pipe.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { Category } from 'ish-core/models/category/category.model'; - -@Pipe({ name: 'ishCategoryRoute', pure: true }) -export class CategoryRoutePipe implements PipeTransform { - transform(category: Category): string { - return '/category/' + category.uniqueId; - } -} diff --git a/src/app/core/pipes/date.pipe.ts b/src/app/core/pipes/date.pipe.ts index c2e6a1a233..2f477684d8 100644 --- a/src/app/core/pipes/date.pipe.ts +++ b/src/app/core/pipes/date.pipe.ts @@ -22,6 +22,13 @@ export function formatISHDate( return formatDate(date, format, lang, timezone || '+0000'); } +/** + * The date pipe converts a number, string or date into a localized date format + * example values: + * as number: 1581690101334 + * as string: '01 Jan 1970 00:00:00 GMT' + * other parameters see also angular date pipe + */ @Pipe({ name: 'ishDate', pure: true }) export class DatePipe implements PipeTransform { constructor(private translateService: TranslateService) {} diff --git a/src/app/core/pipes/product-route.pipe.spec.ts b/src/app/core/pipes/product-route.pipe.spec.ts deleted file mode 100644 index 76e9896191..0000000000 --- a/src/app/core/pipes/product-route.pipe.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import * as using from 'jasmine-data-provider'; - -import { ProductRoutePipe } from './product-route.pipe'; - -describe('Product Route Pipe', () => { - let productRoutePipe: ProductRoutePipe; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ProductRoutePipe], - }); - productRoutePipe = TestBed.get(ProductRoutePipe); - }); - - it('should be created', () => { - expect(productRoutePipe).toBeTruthy(); - }); - - function dataProvider() { - return [ - { - product: { sku: 'SKU' }, - category: { uniqueId: 'CAT' }, - expected: '/category/CAT/product/SKU', - }, - { product: { sku: 'SKU' }, category: undefined, expected: '/product/SKU' }, - { product: {}, category: undefined, expected: '/' }, - { product: undefined, category: undefined, expected: '/' }, - { - product: { sku: 'SKU', name: 'name' }, - category: { uniqueId: 'CAT' }, - expected: '/category/CAT/product/SKU/name', - }, - { product: { sku: 'SKU', name: 'name' }, category: undefined, expected: '/product/SKU/name' }, - { product: { sku: 'A' }, expected: '/product/A' }, - { product: { sku: 'A', name: '' }, expected: '/product/A' }, - { product: { sku: 'A', name: 'some example name' }, expected: '/product/A/some-example-name' }, - { product: { sku: 'A', name: 'name & speci@l char$' }, expected: '/product/A/name-speci-l-char' }, - ]; - } - - using(dataProvider, dataSlice => { - it(`should return ${dataSlice.expected} when supplying product '${JSON.stringify( - dataSlice.product - )}' and category '${JSON.stringify(dataSlice.category)}'`, () => { - expect(productRoutePipe.transform(dataSlice.product, dataSlice.category)).toEqual(dataSlice.expected); - }); - }); -}); diff --git a/src/app/core/pipes/product-route.pipe.ts b/src/app/core/pipes/product-route.pipe.ts deleted file mode 100644 index ba21992846..0000000000 --- a/src/app/core/pipes/product-route.pipe.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -import { Category } from 'ish-core/models/category/category.model'; -import { Product } from 'ish-core/models/product/product.model'; - -function generateProductSlug(product: Product) { - return product && product.name ? product.name.replace(/[^a-zA-Z0-9-]+/g, '-').replace(/-+$/g, '') : undefined; -} - -/** - * Generate a product detail route with optional category context. - * @param product The Product to genereate the route for - * @param category The optional Category that should be used as context for the product route - * @returns Product route string - */ - -export function generateProductRoute(product: Product, category?: Category): string { - if (!(product && product.sku)) { - return '/'; - } - let productRoute = '/product/' + product.sku; - const productSlug = generateProductSlug(product); - if (productSlug) { - productRoute += '/' + productSlug; - } - - if (category) { - productRoute = `/category/${category.uniqueId}${productRoute}`; - } else { - // TODO: add defaultCategory to route once this information is available with the products REST call - } - return productRoute; -} - -@Pipe({ name: 'ishProductRoute', pure: true }) -export class ProductRoutePipe implements PipeTransform { - transform(product: Product, category?: Category): string { - return generateProductRoute(product, category); - } -} diff --git a/src/app/core/routing/category/category-route.pipe.ts b/src/app/core/routing/category/category-route.pipe.ts new file mode 100644 index 0000000000..43216b0fc8 --- /dev/null +++ b/src/app/core/routing/category/category-route.pipe.ts @@ -0,0 +1,12 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +import { CategoryView } from 'ish-core/models/category-view/category-view.model'; + +import { generateCategoryUrl } from './category.route'; + +@Pipe({ name: 'ishCategoryRoute', pure: true }) +export class CategoryRoutePipe implements PipeTransform { + transform(category: CategoryView): string { + return generateCategoryUrl(category); + } +} diff --git a/src/app/core/routing/category/category.route.spec.ts b/src/app/core/routing/category/category.route.spec.ts new file mode 100644 index 0000000000..6637cdc90c --- /dev/null +++ b/src/app/core/routing/category/category.route.spec.ts @@ -0,0 +1,176 @@ +import { TestBed } from '@angular/core/testing'; +import { Router, UrlMatchResult, UrlSegment } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { cold } from 'jest-marbles'; +import { RouteNavigation } from 'ngrx-router'; +import { of } from 'rxjs'; + +import { createCategoryView } from 'ish-core/models/category-view/category-view.model'; +import { Category } from 'ish-core/models/category/category.model'; +import { categoryTree } from 'ish-core/utils/dev/test-data-utils'; + +import { + generateCategoryUrl, + generateLocalizedCategorySlug, + matchCategoryRoute, + ofCategoryRoute, +} from './category.route'; + +describe('Category Route', () => { + const specials = { categoryPath: ['Specials'], uniqueId: 'Specials', name: 'Spezielles' } as Category; + const topSeller = { + categoryPath: ['Specials', 'Specials.TopSeller'], + uniqueId: 'Specials.TopSeller', + name: 'Angebote', + } as Category; + const limitedOffer = { + categoryPath: ['Specials', 'Specials.TopSeller', 'Specials.TopSeller.LimitedOffer'], + uniqueId: 'Specials.TopSeller.LimitedOffer', + name: 'Black Friday', + } as Category; + + expect.addSnapshotSerializer({ + test: val => val && val.consumed && val.posParams, + print: (val: UrlMatchResult, serialize) => + serialize( + Object.keys(val.posParams) + .map(key => ({ [key]: val.posParams[key].path })) + .reduce((acc, v) => ({ ...acc, ...v }), {}) + ), + }); + + let wrap: (url: string) => UrlSegment[]; + + beforeEach(() => { + TestBed.configureTestingModule({ imports: [RouterTestingModule] }); + const router: Router = TestBed.get(Router); + wrap = url => { + const primary = router.parseUrl(url).root.children.primary; + return primary ? primary.segments : []; + }; + }); + + describe('without anything', () => { + it('should be created', () => { + expect(generateCategoryUrl(undefined)).toMatchInlineSnapshot(`"/"`); + }); + + it('should not be a match for matcher', () => { + expect(matchCategoryRoute(wrap(generateCategoryUrl(undefined)))).toMatchInlineSnapshot(`undefined`); + }); + }); + + describe('with top level category without name', () => { + const category = createCategoryView(categoryTree([{ ...specials, name: undefined }]), specials.uniqueId); + + it('should be created', () => { + expect(generateCategoryUrl(category)).toMatchInlineSnapshot(`"/catSpecials"`); + }); + + it('should not be a match for matcher', () => { + expect(matchCategoryRoute(wrap(generateCategoryUrl(category)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials", + } + `); + }); + }); + + describe('with top level category', () => { + const category = createCategoryView(categoryTree([specials]), specials.uniqueId); + + it('should be created', () => { + expect(generateCategoryUrl(category)).toMatchInlineSnapshot(`"/Spezielles-catSpecials"`); + }); + + it('should not be a match for matcher', () => { + expect(matchCategoryRoute(wrap(generateCategoryUrl(category)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials", + } + `); + }); + }); + + describe('with deep category', () => { + const category = createCategoryView(categoryTree([specials, topSeller, limitedOffer]), limitedOffer.uniqueId); + + it('should be created', () => { + expect(generateCategoryUrl(category)).toMatchInlineSnapshot(`"/Black-Friday-catSpecials.TopSeller.LimitedOffer"`); + }); + + it('should not be a match for matcher', () => { + expect(matchCategoryRoute(wrap(generateCategoryUrl(category)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials.TopSeller.LimitedOffer", + } + `); + }); + }); + + describe('compatibility', () => { + it('should detect category route without product after it', () => { + expect(matchCategoryRoute(wrap('/category/123'))).toHaveProperty('consumed'); + }); + + it('should not detect category route with product after it', () => { + expect(matchCategoryRoute(wrap('/category/123/product/123'))).toBeUndefined(); + }); + }); + + describe('additional URL params', () => { + it('should ignore additional URL params when supplied', () => { + const category = createCategoryView(categoryTree([specials, topSeller, limitedOffer]), limitedOffer.uniqueId); + expect(matchCategoryRoute(wrap(generateCategoryUrl(category) + ';lang=de_DE;redirect=1'))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials.TopSeller.LimitedOffer", + } + `); + }); + }); + + describe('ofCategoryRoute', () => { + it('should detect category route when categoryUniqueId is a param', () => { + const stream$ = of(new RouteNavigation({ path: 'any', params: { categoryUniqueId: '123' } })); + expect(stream$.pipe(ofCategoryRoute())).toBeObservable( + cold('(a|)', { + a: new RouteNavigation({ + params: { + categoryUniqueId: '123', + }, + path: 'any', + url: '/any', + }), + }) + ); + }); + + it('should not detect category route when categoryUniqueId is missing', () => { + const stream$ = of(new RouteNavigation({ path: 'any' })); + + expect(stream$.pipe(ofCategoryRoute())).toBeObservable(cold('|')); + }); + + it('should not detect category route when categoryUniqueId and sku are params', () => { + const stream$ = of(new RouteNavigation({ path: 'any', params: { categoryUniqueId: '123', sku: '123' } })); + + expect(stream$.pipe(ofCategoryRoute())).toBeObservable(cold('|')); + }); + }); + + describe('generateLocalizedCategorySlug', () => { + it('should generate slug for top level category', () => { + const category = createCategoryView(categoryTree([specials]), specials.uniqueId); + expect(generateLocalizedCategorySlug(category)).toMatchInlineSnapshot(`"Spezielles"`); + }); + + it('should generate slug for deep category', () => { + const category = createCategoryView(categoryTree([specials, topSeller, limitedOffer]), limitedOffer.uniqueId); + expect(generateLocalizedCategorySlug(category)).toMatchInlineSnapshot(`"Black-Friday"`); + }); + + it('should return empty string when category is unavailable', () => { + expect(generateLocalizedCategorySlug(undefined)).toMatchInlineSnapshot(`""`); + }); + }); +}); diff --git a/src/app/core/routing/category/category.route.ts b/src/app/core/routing/category/category.route.ts new file mode 100644 index 0000000000..4729ce8b45 --- /dev/null +++ b/src/app/core/routing/category/category.route.ts @@ -0,0 +1,62 @@ +import { UrlMatchResult, UrlSegment } from '@angular/router'; +import { RouteNavigation, ofRoute } from 'ngrx-router'; +import { MonoTypeOperatorFunction } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { CategoryView } from 'ish-core/models/category-view/category-view.model'; + +export function generateLocalizedCategorySlug(category: CategoryView) { + if (!category || !category.categoryPath.length) { + return ''; + } + const lastCat = category.pathCategories()[category.categoryPath.length - 1].name; + return lastCat ? lastCat.replace(/ /g, '-') : ''; +} + +const categoryRouteFormat = new RegExp('^/(?!category/.*$)(.*)cat(.*)$'); + +export function matchCategoryRoute(segments: UrlSegment[]): UrlMatchResult { + // compatibility to old routes + if (segments && segments.length === 2 && segments[0].path === 'category') { + return { consumed: [] }; + } + + const url = '/' + segments.map(s => s.path).join('/'); + if (categoryRouteFormat.test(url)) { + const match = categoryRouteFormat.exec(url); + const posParams: { [id: string]: UrlSegment } = {}; + if (match[2]) { + posParams.categoryUniqueId = new UrlSegment(match[2], {}); + } + return { + consumed: [], + posParams, + }; + } + return; +} + +export function generateCategoryUrl(category: CategoryView): string { + if (!category) { + return '/'; + } + let route = '/'; + + route += generateLocalizedCategorySlug(category); + + if (route !== '/') { + route += '-'; + } + + route += `cat${category.uniqueId}`; + + return route; +} + +export function ofCategoryRoute(): MonoTypeOperatorFunction { + return source$ => + source$.pipe( + ofRoute(), + filter(action => action.payload.params && action.payload.params.categoryUniqueId && !action.payload.params.sku) + ); +} diff --git a/src/app/core/routing/product/product-route.pipe.ts b/src/app/core/routing/product/product-route.pipe.ts new file mode 100644 index 0000000000..b9ab7e5cc5 --- /dev/null +++ b/src/app/core/routing/product/product-route.pipe.ts @@ -0,0 +1,12 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +import { CategoryView } from 'ish-core/models/category-view/category-view.model'; +import { ProductView } from 'ish-core/models/product-view/product-view.model'; +import { generateProductUrl } from 'ish-core/routing/product/product.route'; + +@Pipe({ name: 'ishProductRoute', pure: true }) +export class ProductRoutePipe implements PipeTransform { + transform(product: ProductView, category?: CategoryView): string { + return generateProductUrl(product, category); + } +} diff --git a/src/app/core/routing/product/product.route.spec.ts b/src/app/core/routing/product/product.route.spec.ts new file mode 100644 index 0000000000..87512d7742 --- /dev/null +++ b/src/app/core/routing/product/product.route.spec.ts @@ -0,0 +1,342 @@ +import { TestBed } from '@angular/core/testing'; +import { Router, UrlMatchResult, UrlSegment } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { cold } from 'jest-marbles'; +import { RouteNavigation } from 'ngrx-router'; +import { of } from 'rxjs'; + +import { createCategoryView } from 'ish-core/models/category-view/category-view.model'; +import { Category } from 'ish-core/models/category/category.model'; +import { createProductView } from 'ish-core/models/product-view/product-view.model'; +import { VariationProduct } from 'ish-core/models/product/product-variation.model'; +import { Product } from 'ish-core/models/product/product.model'; +import { categoryTree } from 'ish-core/utils/dev/test-data-utils'; + +import { generateProductUrl, matchProductRoute, ofProductRoute } from './product.route'; + +describe('Product Route', () => { + const specials = { categoryPath: ['Specials'], uniqueId: 'Specials', name: 'Spezielles' } as Category; + const topSeller = { + categoryPath: ['Specials', 'Specials.TopSeller'], + uniqueId: 'Specials.TopSeller', + name: 'Angebote', + } as Category; + const limitedOffer = { + categoryPath: ['Specials', 'Specials.TopSeller', 'Specials.TopSeller.LimitedOffer'], + uniqueId: 'Specials.TopSeller.LimitedOffer', + name: 'Black Friday', + } as Category; + + expect.addSnapshotSerializer({ + test: val => val && val.consumed && val.posParams, + print: (val: UrlMatchResult, serialize) => + serialize( + Object.keys(val.posParams) + .map(key => ({ [key]: val.posParams[key].path })) + .reduce((acc, v) => ({ ...acc, ...v }), {}) + ), + }); + + let wrap: (url: string) => UrlSegment[]; + + beforeEach(() => { + TestBed.configureTestingModule({ imports: [RouterTestingModule] }); + const router: Router = TestBed.get(Router); + wrap = url => { + const primary = router.parseUrl(url).root.children.primary; + return primary ? primary.segments : []; + }; + }); + + describe('without anything', () => { + it('should be created', () => { + expect(generateProductUrl(undefined)).toMatchInlineSnapshot(`"/"`); + expect(generateProductUrl(undefined, undefined)).toMatchInlineSnapshot(`"/"`); + }); + + it('should not be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(undefined)))).toMatchInlineSnapshot(`undefined`); + }); + }); + + describe('without category', () => { + describe('without product name', () => { + const product = createProductView({ sku: 'A' } as Product, categoryTree()); + it('should create simple link when just sku is supplied', () => { + expect(generateProductUrl(product)).toMatchInlineSnapshot(`"/skuA"`); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product)))).toMatchInlineSnapshot(` + Object { + "sku": "A", + } + `); + }); + }); + + describe('with product name', () => { + const product = createProductView({ sku: 'A', name: 'some example name' } as Product, categoryTree()); + + it('should include slug when product has a name', () => { + expect(generateProductUrl(product)).toMatchInlineSnapshot(`"/some-example-name-skuA"`); + }); + + it('should include filtered slug when product has a name with special characters', () => { + const product2 = { ...product, name: 'name & speci@l char$' }; + expect(generateProductUrl(product2)).toMatchInlineSnapshot(`"/name-&-speci@l-char$-skuA"`); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product)))).toMatchInlineSnapshot(` + Object { + "sku": "A", + } + `); + }); + }); + + describe('variation product', () => { + const product = createProductView( + { + sku: 'A', + name: 'some example name', + type: 'VariationProduct', + variableVariationAttributes: [{ value: 'SSD' }, { value: 'Blue' }], + } as VariationProduct, + categoryTree() + ); + + it('should include attribute values in slug when product is a variation', () => { + expect(generateProductUrl(product)).toMatchInlineSnapshot(`"/some-example-name-SSD-Blue-skuA"`); + }); + }); + }); + + describe('with top level category', () => { + const categories = categoryTree([specials]); + const category = createCategoryView(categories, specials.uniqueId); + + describe('as context', () => { + describe('without product name', () => { + const product = createProductView({ sku: 'A' } as Product, categories); + + it('should be created', () => { + expect(generateProductUrl(product, category)).toMatchInlineSnapshot(`"/Spezielles/skuA-catSpecials"`); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product, category)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials", + "sku": "A", + } + `); + }); + }); + + describe('with product name', () => { + const product = createProductView({ sku: 'A', name: 'Das neue Surface Pro 7' } as Product, categories); + + it('should be created', () => { + expect(generateProductUrl(product, category)).toMatchInlineSnapshot( + `"/Spezielles/Das-neue-Surface-Pro-7-skuA-catSpecials"` + ); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product, category)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials", + "sku": "A", + } + `); + }); + }); + }); + + describe('as default category', () => { + describe('without product name', () => { + const product = createProductView({ sku: 'A', defaultCategoryId: specials.uniqueId } as Product, categories); + + it('should be created', () => { + expect(generateProductUrl(product)).toMatchInlineSnapshot(`"/Spezielles/skuA-catSpecials"`); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials", + "sku": "A", + } + `); + }); + }); + + describe('with product name', () => { + const product = createProductView( + { sku: 'A', name: 'Das neue Surface Pro 7', defaultCategoryId: specials.uniqueId } as Product, + categories + ); + + it('should be created', () => { + expect(generateProductUrl(product)).toMatchInlineSnapshot( + `"/Spezielles/Das-neue-Surface-Pro-7-skuA-catSpecials"` + ); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials", + "sku": "A", + } + `); + }); + }); + }); + }); + + describe('with deep category', () => { + const categories = categoryTree([specials, topSeller, limitedOffer]); + const category = createCategoryView(categories, limitedOffer.uniqueId); + + describe('as context', () => { + describe('without product name', () => { + const product = createProductView({ sku: 'A' } as Product, categories); + + it('should be created', () => { + expect(generateProductUrl(product, category)).toMatchInlineSnapshot( + `"/Black-Friday/skuA-catSpecials.TopSeller.LimitedOffer"` + ); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product, category)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials.TopSeller.LimitedOffer", + "sku": "A", + } + `); + }); + }); + + describe('with product name', () => { + const product = createProductView({ sku: 'A', name: 'Das neue Surface Pro 7' } as Product, categories); + + it('should be created', () => { + expect(generateProductUrl(product, category)).toMatchInlineSnapshot( + `"/Black-Friday/Das-neue-Surface-Pro-7-skuA-catSpecials.TopSeller.LimitedOffer"` + ); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product, category)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials.TopSeller.LimitedOffer", + "sku": "A", + } + `); + }); + }); + }); + + describe('as default category', () => { + describe('without product name', () => { + const product = createProductView( + { sku: 'A', defaultCategoryId: limitedOffer.uniqueId } as Product, + categories + ); + + it('should be created', () => { + expect(generateProductUrl(product)).toMatchInlineSnapshot( + `"/Black-Friday/skuA-catSpecials.TopSeller.LimitedOffer"` + ); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials.TopSeller.LimitedOffer", + "sku": "A", + } + `); + }); + }); + + describe('with product name', () => { + const product = createProductView( + { sku: 'A', name: 'Das neue Surface Pro 7', defaultCategoryId: limitedOffer.uniqueId } as Product, + categories + ); + + it('should be created', () => { + expect(generateProductUrl(product)).toMatchInlineSnapshot( + `"/Black-Friday/Das-neue-Surface-Pro-7-skuA-catSpecials.TopSeller.LimitedOffer"` + ); + }); + + it('should be a match for matcher', () => { + expect(matchProductRoute(wrap(generateProductUrl(product)))).toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials.TopSeller.LimitedOffer", + "sku": "A", + } + `); + }); + }); + }); + }); + + describe('compatibility', () => { + it.each(['/product/123', '/product/123/slug', '/category/123/product/123', '/category/123/product/123/slug'])( + 'should detect %p as route', + url => { + expect(matchProductRoute(wrap(url))).toHaveProperty('consumed'); + } + ); + + it('should not detect category route without product after it', () => { + expect(matchProductRoute(wrap('/category/123'))).toBeUndefined(); + }); + }); + + describe('additional URL params', () => { + it('should ignore additional URL params when supplied', () => { + const category = createCategoryView(categoryTree([specials, topSeller, limitedOffer]), limitedOffer.uniqueId); + const product = createProductView({ sku: 'A', name: 'Das neue Surface Pro 7' } as Product, categoryTree()); + + expect(matchProductRoute(wrap(generateProductUrl(product, category) + ';lang=de_DE;redirect=1'))) + .toMatchInlineSnapshot(` + Object { + "categoryUniqueId": "Specials.TopSeller.LimitedOffer", + "sku": "A", + } + `); + }); + }); + + describe('ofProductRoute', () => { + it('should detect product route when sku is a param', () => { + const stream$ = of(new RouteNavigation({ path: 'any', params: { sku: '123' } })); + + expect(stream$.pipe(ofProductRoute())).toBeObservable( + cold('(a|)', { + a: new RouteNavigation({ + params: { + sku: '123', + }, + path: 'any', + url: '/any', + }), + }) + ); + }); + + it('should not detect product route when sku is missing', () => { + const stream$ = of(new RouteNavigation({ path: 'any' })); + + expect(stream$.pipe(ofProductRoute())).toBeObservable(cold('|')); + }); + }); +}); diff --git a/src/app/core/routing/product/product.route.ts b/src/app/core/routing/product/product.route.ts new file mode 100644 index 0000000000..203f5c34ab --- /dev/null +++ b/src/app/core/routing/product/product.route.ts @@ -0,0 +1,91 @@ +import { UrlMatchResult, UrlSegment } from '@angular/router'; +import { RouteNavigation, ofRoute } from 'ngrx-router'; +import { MonoTypeOperatorFunction } from 'rxjs'; +import { filter } from 'rxjs/operators'; + +import { CategoryView } from 'ish-core/models/category-view/category-view.model'; +import { ProductView } from 'ish-core/models/product-view/product-view.model'; +import { ProductHelper } from 'ish-core/models/product/product.model'; +import { generateLocalizedCategorySlug } from 'ish-core/routing/category/category.route'; + +function generateProductSlug(product: ProductView) { + if (!product || !product.name) { + return; + } + + let slug = product.name.replace(/ /g, '-').replace(/-+$/g, ''); + + if (ProductHelper.isVariationProduct(product) && product.variableVariationAttributes) { + slug += '-'; + slug += product.variableVariationAttributes + .map(att => att.value) + .filter(val => typeof val === 'string' || typeof val === 'boolean' || typeof val === 'number') + .join('-'); + } + + return slug; +} + +const productRouteFormat = new RegExp('^/(.*)?sku(.*?)(-cat(.*))?$'); + +export function matchProductRoute(segments: UrlSegment[]): UrlMatchResult { + // compatibility to old routes + const isSimpleProduct = segments && segments.length > 0 && segments[0].path === 'product'; + const isContextProduct = + segments && segments.length > 2 && segments[0].path === 'category' && segments[2].path === 'product'; + if (isSimpleProduct || isContextProduct) { + return { consumed: [] }; + } + + const url = '/' + segments.map(s => s.path).join('/'); + if (productRouteFormat.test(url)) { + const match = productRouteFormat.exec(url); + const posParams: { [id: string]: UrlSegment } = {}; + if (match[4]) { + posParams.categoryUniqueId = new UrlSegment(match[4], {}); + } + if (match[2]) { + posParams.sku = new UrlSegment(match[2], {}); + } + return { + consumed: [], + posParams, + }; + } + return; +} + +export function generateProductUrl(product: ProductView, category?: CategoryView): string { + const contextCategory = category || (product && product.defaultCategory()); + + if (!(product && product.sku)) { + return '/'; + } + + let route = '/'; + + if (contextCategory) { + route += generateLocalizedCategorySlug(contextCategory); + route += '/'; + } + + if (product.name) { + route += `${generateProductSlug(product)}-`; + } + + route += `sku${product.sku}`; + + if (contextCategory) { + route += `-cat${contextCategory.uniqueId}`; + } + + return route; +} + +export function ofProductRoute(): MonoTypeOperatorFunction { + return source$ => + source$.pipe( + ofRoute(), + filter(action => action.payload.params && action.payload.params.sku) + ); +} diff --git a/src/app/core/services/products/products.service.spec.ts b/src/app/core/services/products/products.service.spec.ts index 8f3491679e..cdafdf57e4 100644 --- a/src/app/core/services/products/products.service.spec.ts +++ b/src/app/core/services/products/products.service.spec.ts @@ -30,12 +30,32 @@ describe('Products Service', () => { uri: '/categories/CategoryID/products/ProductA', title: 'Product A', attributes: [{ name: 'sku', type: 'String', value: 'ProductA' }], + attributeGroup: { + name: 'attrGroupA', + attributes: [ + { + name: 'attrNameA', + type: 'Boolean', + value: true, + }, + ], + }, }, { type: 'Link', uri: '/categories/CategoryID/products/ProductB', title: 'Product B', attributes: [{ name: 'sku', type: 'String', value: 'ProductB' }], + attributeGroup: { + name: 'attrGroupB', + attributes: [ + { + name: 'attrNameB', + type: 'Boolean', + value: true, + }, + ], + }, }, ], type: 'ResourceCollection', diff --git a/src/app/core/services/products/products.service.ts b/src/app/core/services/products/products.service.ts index fdb91b7072..d7bf8b7b04 100644 --- a/src/app/core/services/products/products.service.ts +++ b/src/app/core/services/products/products.service.ts @@ -70,7 +70,7 @@ export class ProductsService { let params = new HttpParams() .set('attrs', ProductsService.STUB_ATTRS) - .set('attrsGroups', AttributeGroupTypes.ProductLabelAttributes) // TODO: validate if this is working once ISREST-523 is implemented + .set('attributeGroup', AttributeGroupTypes.ProductLabelAttributes) .set('amount', this.itemsPerPage.toString()) .set('offset', ((page - 1) * this.itemsPerPage).toString()) .set('returnSortKeys', 'true') @@ -114,6 +114,7 @@ export class ProductsService { .set('amount', this.itemsPerPage.toString()) .set('offset', ((page - 1) * this.itemsPerPage).toString()) .set('attrs', ProductsService.STUB_ATTRS) + .set('attributeGroup', AttributeGroupTypes.ProductLabelAttributes) .set('returnSortKeys', 'true'); if (sortKey) { params = params.set('sortKey', sortKey); diff --git a/src/app/core/store/checkout/basket/basket.effects.spec.ts b/src/app/core/store/checkout/basket/basket.effects.spec.ts index 4d06554762..03beaaaf52 100644 --- a/src/app/core/store/checkout/basket/basket.effects.spec.ts +++ b/src/app/core/store/checkout/basket/basket.effects.spec.ts @@ -423,11 +423,7 @@ describe('Basket Effects', () => { describe('routeListenerForResettingBasketErrors$', () => { it('should fire ResetBasketErrors when route basket or checkout/* is navigated', () => { - const action = new RouteNavigation({ - path: 'checkout/payment', - params: {}, - queryParams: {}, - }); + const action = new RouteNavigation({ path: 'checkout/payment' }); const expected = new basketActions.ResetBasketErrors(); actions$ = hot('a', { a: action }); @@ -435,14 +431,14 @@ describe('Basket Effects', () => { }); it('should not fire ResetBasketErrors when route basket or checkout/* is navigated with query param error=true', () => { - const action = new RouteNavigation({ path: 'checkout/payment', params: {}, queryParams: { error: true } }); + const action = new RouteNavigation({ path: 'checkout/payment', queryParams: { error: true } }); actions$ = hot('a', { a: action }); expect(effects.routeListenerForResettingBasketErrors$).toBeObservable(cold('-')); }); it('should not fire ResetBasketErrors when route /something is navigated', () => { - const action = new RouteNavigation({ path: 'something', params: {}, queryParams: {} }); + const action = new RouteNavigation({ path: 'something' }); actions$ = hot('a', { a: action }); expect(effects.routeListenerForResettingBasketErrors$).toBeObservable(cold('-')); diff --git a/src/app/core/store/checkout/basket/basket.selectors.ts b/src/app/core/store/checkout/basket/basket.selectors.ts index 4e7ded8192..8dd3f48063 100644 --- a/src/app/core/store/checkout/basket/basket.selectors.ts +++ b/src/app/core/store/checkout/basket/basket.selectors.ts @@ -4,7 +4,9 @@ import { isEqual } from 'lodash-es'; import { AddressHelper } from 'ish-core/models/address/address.helper'; import { BasketValidationResultType } from 'ish-core/models/basket-validation/basket-validation.model'; import { BasketView, createBasketView } from 'ish-core/models/basket/basket.model'; +import { createProductView } from 'ish-core/models/product-view/product-view.model'; import { getCheckoutState } from 'ish-core/store/checkout/checkout-store'; +import { getCategoryTree } from 'ish-core/store/shopping/categories'; import { getProductEntities } from 'ish-core/store/shopping/products'; import { getLoggedInCustomer } from 'ish-core/store/user'; @@ -16,7 +18,8 @@ const getBasketState = createSelector( export const getBasketValidationResults = createSelector( getBasketState, getProductEntities, - (basket, products): BasketValidationResultType => { + getCategoryTree, + (basket, products, categoryTree): BasketValidationResultType => { if (!basket || !basket.validationResults) { return; } @@ -27,7 +30,7 @@ export const getBasketValidationResults = createSelector( infos: basketResults.infos ? basketResults.infos.map(info => ({ ...info, - product: info.parameters && products[info.parameters.productSku], + product: info.parameters && createProductView(products[info.parameters.productSku], categoryTree), })) : [], errors: basketResults.errors @@ -41,7 +44,10 @@ export const getBasketValidationResults = createSelector( error.parameters && error.parameters.lineItemId && basket.basket.lineItems.find(item => item.id === error.parameters.lineItemId) && - products[basket.basket.lineItems.find(item => item.id === error.parameters.lineItemId).productSKU], + createProductView( + products[basket.basket.lineItems.find(item => item.id === error.parameters.lineItemId).productSKU], + categoryTree + ), })) : [], }; @@ -61,8 +67,9 @@ export const getCurrentBasket = createSelector( getProductEntities, getBasketValidationResults, getBasketInfo, - (basket, products, validationResults, basketInfo): BasketView => - createBasketView(basket.basket, products, validationResults, basketInfo) + getCategoryTree, + (basket, products, validationResults, basketInfo, categoryTree): BasketView => + createBasketView(basket.basket, products, validationResults, basketInfo, categoryTree) ); export const getCurrentBasketId = createSelector( diff --git a/src/app/core/store/checkout/viewconf/viewconf.effects.ts b/src/app/core/store/checkout/viewconf/viewconf.effects.ts index e92a67a676..ef2af1ce12 100644 --- a/src/app/core/store/checkout/viewconf/viewconf.effects.ts +++ b/src/app/core/store/checkout/viewconf/viewconf.effects.ts @@ -1,6 +1,5 @@ import { Injectable } from '@angular/core'; import { Actions, Effect } from '@ngrx/effects'; -import { Store } from '@ngrx/store'; import { mapToData, ofRoute } from 'ngrx-router'; import { map } from 'rxjs/operators'; @@ -8,7 +7,7 @@ import { SetCheckoutStep } from './viewconf.actions'; @Injectable() export class ViewconfEffects { - constructor(private actions$: Actions, private store: Store<{}>) {} + constructor(private actions$: Actions) {} @Effect() retrieveCheckoutStepFromRouting$ = this.actions$.pipe( diff --git a/src/app/core/store/checkout/viewconf/viewconf.integration.spec.ts b/src/app/core/store/checkout/viewconf/viewconf.integration.spec.ts index e6ddfaf65b..59e522a0a3 100644 --- a/src/app/core/store/checkout/viewconf/viewconf.integration.spec.ts +++ b/src/app/core/store/checkout/viewconf/viewconf.integration.spec.ts @@ -30,7 +30,7 @@ describe('Viewconf Integration', () => { expect(getCheckoutStep(store$.state)).toBe(2); - store$.dispatch(new RouteNavigation({ path: 'checkout', data: {} })); + store$.dispatch(new RouteNavigation({ path: 'checkout' })); expect(getCheckoutStep(store$.state)).toBeUndefined(); }); diff --git a/src/app/core/store/configuration/configuration.selectors.ts b/src/app/core/store/configuration/configuration.selectors.ts index dca63d81bb..e155c99366 100644 --- a/src/app/core/store/configuration/configuration.selectors.ts +++ b/src/app/core/store/configuration/configuration.selectors.ts @@ -7,6 +7,11 @@ export const getConfigurationState = createSelector( state => state.configuration ); +export const getICMApplication = createSelector( + getConfigurationState, + state => state.application || '-' +); + export const getICMServerURL = createSelector( getConfigurationState, state => (state.baseURL && state.server ? `${state.baseURL}/${state.server}` : undefined) @@ -15,15 +20,17 @@ export const getICMServerURL = createSelector( export const getRestEndpoint = createSelector( getICMServerURL, getConfigurationState, - (serverUrl, state) => - serverUrl && state.channel ? `${serverUrl}/${state.channel}/${state.application || '-'}` : undefined + getICMApplication, + (serverUrl, state, application) => + serverUrl && state.channel ? `${serverUrl}/${state.channel}/${application}` : undefined ); export const getICMStaticURL = createSelector( getConfigurationState, - state => + getICMApplication, + (state, application) => state.baseURL && state.serverStatic && state.channel - ? `${state.baseURL}/${state.serverStatic}/${state.channel}/${state.application || '-'}` + ? `${state.baseURL}/${state.serverStatic}/${state.channel}/${application}` : undefined ); diff --git a/src/app/core/store/contact/contact/contact.effects.ts b/src/app/core/store/contact/contact/contact.effects.ts index 7b045d6236..c726bf296a 100644 --- a/src/app/core/store/contact/contact/contact.effects.ts +++ b/src/app/core/store/contact/contact/contact.effects.ts @@ -1,6 +1,5 @@ import { Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; -import { Store } from '@ngrx/store'; import { concatMap, map, mapTo } from 'rxjs/operators'; import { ContactService } from 'ish-core/services/contact/contact.service'; @@ -10,7 +9,7 @@ import * as ContactActions from './contact.actions'; @Injectable() export class ContactEffects { - constructor(private actions$: Actions, private store: Store<{}>, private contactService: ContactService) {} + constructor(private actions$: Actions, private contactService: ContactService) {} /** * Load the contact subjects, which the customer can select for his request diff --git a/src/app/core/store/core-store.module.ts b/src/app/core/store/core-store.module.ts index 7e0a58fe00..8b8646f682 100644 --- a/src/app/core/store/core-store.module.ts +++ b/src/app/core/store/core-store.module.ts @@ -18,6 +18,7 @@ import { CountriesEffects } from './countries/countries.effects'; import { countriesReducer } from './countries/countries.reducer'; import { ErrorEffects } from './error/error.effects'; import { errorReducer } from './error/error.reducer'; +import { HybridStoreModule } from './hybrid/hybrid-store.module'; import { LocaleEffects } from './locale/locale.effects'; import { localeReducer } from './locale/locale.reducer'; import { MessagesEffects } from './messages/messages.effects'; @@ -66,6 +67,7 @@ export const metaReducers: MetaReducer[] = [ngrxStateTransferMeta]; CheckoutStoreModule, ContentStoreModule, EffectsModule.forRoot(coreEffects), + HybridStoreModule, RestoreStoreModule, ShoppingStoreModule, StoreModule.forRoot(coreReducers, { diff --git a/src/app/core/store/error/error.reducer.spec.ts b/src/app/core/store/error/error.reducer.spec.ts index a0f336d273..db204380bb 100644 --- a/src/app/core/store/error/error.reducer.spec.ts +++ b/src/app/core/store/error/error.reducer.spec.ts @@ -46,7 +46,7 @@ describe('Error Reducer', () => { }, { state: { current: {}, type: ErrorActionTypes.TimeoutError }, - action: new RouteNavigation({ path: 'error', params: {}, queryParams: {} }), + action: new RouteNavigation({ path: 'error' }), expected: { current: {}, type: ErrorActionTypes.TimeoutError }, }, ]; diff --git a/src/app/core/store/hybrid/hybrid-store.module.ts b/src/app/core/store/hybrid/hybrid-store.module.ts new file mode 100644 index 0000000000..642c478405 --- /dev/null +++ b/src/app/core/store/hybrid/hybrid-store.module.ts @@ -0,0 +1,21 @@ +import { isPlatformBrowser } from '@angular/common'; +import { Inject, NgModule, PLATFORM_ID } from '@angular/core'; +import { TransferState } from '@angular/platform-browser'; +import { Router } from '@angular/router'; +import { EffectsModule } from '@ngrx/effects'; + +import { HybridRedirectGuard } from 'ish-core/guards/hybrid-redirect.guard'; +import { addGlobalGuard } from 'ish-core/utils/routing'; + +import { HybridEffects, SSR_HYBRID_STATE } from './hybrid.effects'; + +@NgModule({ + imports: [EffectsModule.forFeature([HybridEffects])], +}) +export class HybridStoreModule { + constructor(router: Router, transferState: TransferState, @Inject(PLATFORM_ID) platformId: string) { + if (isPlatformBrowser(platformId) && transferState.get(SSR_HYBRID_STATE, false)) { + addGlobalGuard(router, HybridRedirectGuard); + } + } +} diff --git a/src/app/core/store/hybrid/hybrid.effects.ts b/src/app/core/store/hybrid/hybrid.effects.ts new file mode 100644 index 0000000000..558a0944da --- /dev/null +++ b/src/app/core/store/hybrid/hybrid.effects.ts @@ -0,0 +1,24 @@ +import { isPlatformServer } from '@angular/common'; +import { Inject, Optional, PLATFORM_ID } from '@angular/core'; +import { TransferState, makeStateKey } from '@angular/platform-browser'; +import { Actions, Effect } from '@ngrx/effects'; +import { filter, take, tap } from 'rxjs/operators'; + +export const SSR_HYBRID_STATE = makeStateKey('ssrHybrid'); + +export class HybridEffects { + constructor( + private actions: Actions, + @Inject(PLATFORM_ID) private platformId: string, + private transferState: TransferState, + @Optional() @Inject('SSR_HYBRID') private ssrHybridState: boolean + ) {} + + @Effect({ dispatch: false }) + propagateSSRHybridPropToTransferState$ = this.actions.pipe( + take(1), + filter(() => isPlatformServer(this.platformId)), + filter(() => !!this.ssrHybridState), + tap(() => this.transferState.set(SSR_HYBRID_STATE, true)) + ); +} diff --git a/src/app/core/store/hybrid/hybrid.selectors.ts b/src/app/core/store/hybrid/hybrid.selectors.ts new file mode 100644 index 0000000000..27a64ce294 --- /dev/null +++ b/src/app/core/store/hybrid/hybrid.selectors.ts @@ -0,0 +1,17 @@ +import { createSelector } from '@ngrx/store'; + +import { getConfigurationState, getICMApplication } from 'ish-core/store/configuration'; +import { getCurrentLocale } from 'ish-core/store/locale'; + +import { ICM_WEB_URL } from '../../../../hybrid/default-url-mapping-table'; + +export const getICMWebURL = createSelector( + getConfigurationState, + getCurrentLocale, + getICMApplication, + (state, locale, application) => + ICM_WEB_URL.replace('$', state.channel) + .replace('$', locale.lang) + .replace('$', application) + .replace('$', locale.currency) +); diff --git a/src/app/core/store/hybrid/index.ts b/src/app/core/store/hybrid/index.ts new file mode 100644 index 0000000000..b409b1d147 --- /dev/null +++ b/src/app/core/store/hybrid/index.ts @@ -0,0 +1,3 @@ +// tslint:disable no-barrel-files +// API to access ngrx hybrid state +export * from './hybrid.selectors'; diff --git a/src/app/core/store/orders/orders.effects.spec.ts b/src/app/core/store/orders/orders.effects.spec.ts index ec600e6e08..12d7c7b043 100644 --- a/src/app/core/store/orders/orders.effects.spec.ts +++ b/src/app/core/store/orders/orders.effects.spec.ts @@ -290,7 +290,6 @@ describe('Orders Effects', () => { const action = new RouteNavigation({ path: 'account/orders/:orderId', params: { orderId }, - queryParams: {}, }); const expected = new orderActions.SelectOrder({ orderId }); @@ -299,7 +298,7 @@ describe('Orders Effects', () => { }); it('should not fire SelectOrder when route /something is navigated', () => { - const action = new RouteNavigation({ path: 'something', params: {}, queryParams: {} }); + const action = new RouteNavigation({ path: 'something' }); actions$ = hot('a', { a: action }); expect(effects.routeListenerForSelectingOrder$).toBeObservable(cold('-')); diff --git a/src/app/core/store/orders/orders.selectors.spec.ts b/src/app/core/store/orders/orders.selectors.spec.ts index 5c9950b9f4..5c6cb5630d 100644 --- a/src/app/core/store/orders/orders.selectors.spec.ts +++ b/src/app/core/store/orders/orders.selectors.spec.ts @@ -107,7 +107,7 @@ describe('Orders Selectors', () => { expect(loadedOrders[1].documentNo).toEqual(orders[1].documentNo); expect(loadedOrders[1].lineItems).toHaveLength(1); expect(loadedOrders[1].lineItems[0].id).toEqual('test2'); - expect(loadedOrders[1].lineItems[0].product).toEqual({ sku: 'sku' }); + expect(loadedOrders[1].lineItems[0].product).toHaveProperty('sku', 'sku'); }); }); @@ -146,7 +146,7 @@ describe('Orders Selectors', () => { expect(loadedOrder.documentNo).toEqual(orders[0].documentNo); expect(loadedOrder.lineItems).toHaveLength(1); expect(loadedOrder.lineItems[0].id).toEqual('test'); - expect(loadedOrder.lineItems[0].product).toEqual({ sku: 'sku' }); + expect(loadedOrder.lineItems[0].product).toHaveProperty('sku', 'sku'); }); }); diff --git a/src/app/core/store/orders/orders.selectors.ts b/src/app/core/store/orders/orders.selectors.ts index f9297fbf10..440fe3cbbc 100644 --- a/src/app/core/store/orders/orders.selectors.ts +++ b/src/app/core/store/orders/orders.selectors.ts @@ -2,6 +2,7 @@ import { createSelector } from '@ngrx/store'; import { OrderView, createOrderView } from 'ish-core/models/order/order.model'; import { getCoreState } from 'ish-core/store/core-store'; +import { getCategoryTree } from 'ish-core/store/shopping/categories'; import { getProductEntities } from 'ish-core/store/shopping/products'; import { orderAdapter } from './orders.reducer'; @@ -22,20 +23,25 @@ export const getSelectedOrder = createSelector( getOrderEntities, getSelectedOrderId, getProductEntities, - (entities, id, products): OrderView => (id && entities[id] ? createOrderView(entities[id], products) : undefined) + getCategoryTree, + (entities, id, products, categoryTree): OrderView => + id && entities[id] ? createOrderView(entities[id], products, categoryTree) : undefined ); export const getOrders = createSelector( getOrdersInternal, getProductEntities, - (orders, products): OrderView[] => (!orders ? [] : orders.map(e => createOrderView(e, products))) + getCategoryTree, + (orders, products, categoryTree): OrderView[] => + !orders ? [] : orders.map(e => createOrderView(e, products, categoryTree)) ); export const getOrder = createSelector( getOrdersInternal, getProductEntities, - (entities, products, props: { orderId: string }): OrderView => - createOrderView(entities.find(e => e.id === props.orderId), products) + getCategoryTree, + (entities, products, categoryTree, props: { orderId: string }): OrderView => + createOrderView(entities.find(e => e.id === props.orderId), products, categoryTree) ); export const getOrdersLoading = createSelector( diff --git a/src/app/core/store/shopping/categories/categories.effects.spec.ts b/src/app/core/store/shopping/categories/categories.effects.spec.ts index e905a6093a..d104329c6c 100644 --- a/src/app/core/store/shopping/categories/categories.effects.spec.ts +++ b/src/app/core/store/shopping/categories/categories.effects.spec.ts @@ -79,7 +79,6 @@ describe('Categories Effects', () => { const action = new RouteNavigation({ path: 'category/:categoryUniqueId', params: { categoryUniqueId: 'dummy' }, - queryParams: {}, }); const expected = new fromActions.SelectCategory({ categoryId: 'dummy' }); @@ -91,7 +90,6 @@ describe('Categories Effects', () => { const action = new RouteNavigation({ path: 'category/:categoryUniqueId/product/:sku', params: { categoryUniqueId: 'dummy', sku: 'foobar' }, - queryParams: {}, }); const expected = new fromActions.SelectCategory({ categoryId: 'dummy' }); @@ -100,11 +98,7 @@ describe('Categories Effects', () => { }); it('should not trigger SelectCategory when /something is visited', () => { - const action = new RouteNavigation({ - path: 'something', - params: {}, - queryParams: {}, - }); + const action = new RouteNavigation({ path: 'something' }); actions$ = hot('a', { a: action }); expect(effects.routeListenerForSelectingCategory$).toBeObservable(cold('-')); @@ -114,7 +108,6 @@ describe('Categories Effects', () => { const action = new RouteNavigation({ path: 'category/:categoryUniqueId', params: { categoryUniqueId: 'dummy' }, - queryParams: {}, }); const expected = new fromActions.SelectCategory({ categoryId: 'dummy' }); @@ -342,7 +335,6 @@ describe('Categories Effects', () => { a: new RouteNavigation({ path: 'category/:categoryUniqueId', params: { categoryUniqueId: category.uniqueId }, - queryParams: {}, }), }); @@ -359,7 +351,6 @@ describe('Categories Effects', () => { a: new RouteNavigation({ path: 'category/:categoryUniqueId/product/:sku', params: { categoryUniqueId: category.uniqueId, sku: 'dummy' }, - queryParams: {}, }), b: new fromActions.SelectedCategoryAvailable({ categoryId: category.uniqueId }), }); diff --git a/src/app/core/store/shopping/categories/categories.effects.ts b/src/app/core/store/shopping/categories/categories.effects.ts index 3bcff8979e..5210071e3f 100644 --- a/src/app/core/store/shopping/categories/categories.effects.ts +++ b/src/app/core/store/shopping/categories/categories.effects.ts @@ -17,6 +17,7 @@ import { import { MAIN_NAVIGATION_MAX_SUB_CATEGORIES_DEPTH } from 'ish-core/configurations/injection-keys'; import { CategoryHelper } from 'ish-core/models/category/category.model'; +import { ofCategoryRoute } from 'ish-core/routing/category/category.route'; import { CategoriesService } from 'ish-core/services/categories/categories.service'; import { LoadMoreProducts } from 'ish-core/store/shopping/product-listing'; import { HttpStatusCodeService } from 'ish-core/utils/http-status-code/http-status-code.service'; @@ -135,8 +136,9 @@ export class CategoriesEffects { @Effect() productOrCategoryChanged$ = this.actions$.pipe( - ofRoute('category/:categoryUniqueId'), - mapToParam('categoryUniqueId'), + ofCategoryRoute(), + mapToParam('sku'), + whenFalsy(), switchMap(() => this.store.pipe(select(selectors.getSelectedCategory))), whenTruthy(), filter(cat => cat.hasOnlineProducts), diff --git a/src/app/core/store/shopping/products/products.effects.spec.ts b/src/app/core/store/shopping/products/products.effects.spec.ts index e9100d8481..b55e7cbb20 100644 --- a/src/app/core/store/shopping/products/products.effects.spec.ts +++ b/src/app/core/store/shopping/products/products.effects.spec.ts @@ -307,7 +307,6 @@ describe('Products Effects', () => { const action = new RouteNavigation({ path: 'category/:categoryUniqueId/product/:sku', params: { categoryUniqueId: 'dummy', sku: 'foobar' }, - queryParams: {}, }); const expected = new fromActions.SelectProduct({ sku: 'foobar' }); @@ -319,7 +318,6 @@ describe('Products Effects', () => { const action = new RouteNavigation({ path: 'product/:sku', params: { sku: 'foobar' }, - queryParams: {}, }); const expected = new fromActions.SelectProduct({ sku: 'foobar' }); @@ -328,7 +326,7 @@ describe('Products Effects', () => { }); it('should not fire SelectProduct when route /something is navigated', () => { - const action = new RouteNavigation({ path: 'something', params: {}, queryParams: {} }); + const action = new RouteNavigation({ path: 'something' }); actions$ = hot('a', { a: action }); expect(effects.routeListenerForSelectingProducts$).toBeObservable(cold('-')); @@ -349,11 +347,13 @@ describe('Products Effects', () => { }); describe('redirectIfErrorInProducts$', () => { - it('should redirect if triggered on product detail page', fakeAsync(() => { - when(router.url).thenReturn('/category/A/product/SKU'); - - const action = new fromActions.LoadProductFail({ sku: 'SKU', error: { status: 404 } as HttpError }); + beforeEach(() => { + store$.dispatch(new fromActions.LoadProductFail({ sku: 'SKU', error: { status: 404 } as HttpError })); + store$.dispatch(new fromActions.SelectProduct({ sku: 'SKU' })); + }); + it('should redirect if triggered on product detail page', fakeAsync(() => { + const action = new RouteNavigation({ path: 'pr', params: { sku: 'SKU' } }); actions$ = of(action); effects.redirectIfErrorInProducts$.subscribe(noop, fail, noop); @@ -364,10 +364,7 @@ describe('Products Effects', () => { })); it('should not redirect if triggered on page other than product detail page', done => { - when(router.url).thenReturn('/search/term'); - - const action = new fromActions.LoadProductFail({ sku: 'SKU', error: { status: 404 } as HttpError }); - + const action = new RouteNavigation({ path: 'any' }); actions$ = of(action); effects.redirectIfErrorInProducts$.subscribe(fail, fail, done); diff --git a/src/app/core/store/shopping/products/products.effects.ts b/src/app/core/store/shopping/products/products.effects.ts index 2ff2c824d9..113dc6b650 100644 --- a/src/app/core/store/shopping/products/products.effects.ts +++ b/src/app/core/store/shopping/products/products.effects.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { Dictionary } from '@ngrx/entity'; import { Store, select } from '@ngrx/store'; @@ -8,11 +7,14 @@ import { concatMap, distinct, distinctUntilChanged, + distinctUntilKeyChanged, filter, groupBy, map, mergeMap, switchMap, + switchMapTo, + take, takeUntil, tap, throttleTime, @@ -23,6 +25,7 @@ import { ProductListingMapper } from 'ish-core/models/product-listing/product-li import { VariationProductMaster } from 'ish-core/models/product/product-variation-master.model'; import { VariationProduct } from 'ish-core/models/product/product-variation.model'; import { Product, ProductCompletenessLevel, ProductHelper } from 'ish-core/models/product/product.model'; +import { ofProductRoute } from 'ish-core/routing/product/product.route'; import { ProductsService } from 'ish-core/services/products/products.service'; import { LoadCategory } from 'ish-core/store/shopping/categories'; import { SetProductListingPages } from 'ish-core/store/shopping/product-listing'; @@ -32,6 +35,7 @@ import { mapToPayload, mapToPayloadProperty, mapToProperty, + whenFalsy, whenTruthy, } from 'ish-core/utils/operators'; @@ -44,7 +48,6 @@ export class ProductsEffects { private actions$: Actions, private store: Store<{}>, private productsService: ProductsService, - private router: Router, private httpStatusCodeService: HttpStatusCodeService, private productListingMapper: ProductListingMapper ) {} @@ -214,11 +217,14 @@ export class ProductsEffects { @Effect() loadDefaultCategoryContextForProduct$ = this.actions$.pipe( - ofRoute(/^product/), + ofProductRoute(), + mapToParam('categoryUniqueId'), + whenFalsy(), switchMap(() => this.store.pipe( select(productsSelectors.getSelectedProduct), whenTruthy(), + filter(p => !ProductHelper.isFailedLoading(p)), filter(product => !product.defaultCategory()), mapToProperty('defaultCategoryId'), whenTruthy(), @@ -264,8 +270,16 @@ export class ProductsEffects { @Effect({ dispatch: false }) redirectIfErrorInProducts$ = this.actions$.pipe( - ofType(productsActions.ProductsActionTypes.LoadProductFail), - filter(() => this.router.url.includes('/product/')), + ofProductRoute(), + switchMapTo( + this.store.pipe( + select(productsSelectors.getSelectedProduct), + whenTruthy(), + distinctUntilKeyChanged('sku'), + filter(ProductHelper.isFailedLoading), + take(1) + ) + ), tap(() => this.httpStatusCodeService.setStatusAndRedirect(404)) ); diff --git a/src/app/core/store/shopping/products/products.selectors.ts b/src/app/core/store/shopping/products/products.selectors.ts index 86acc52090..9ba4831b53 100644 --- a/src/app/core/store/shopping/products/products.selectors.ts +++ b/src/app/core/store/shopping/products/products.selectors.ts @@ -109,9 +109,7 @@ export const getProducts = createSelector( export const getSelectedProduct = createSelector( state => state, getSelectedProductId, - getFailed, - (state, sku, failed): ProductView | VariationProductView | VariationProductMasterView => - failed.includes(sku) ? undefined : getProduct(state, { sku }) + (state, sku): ProductView | VariationProductView | VariationProductMasterView => getProduct(state, { sku }) ); export const getProductVariationOptions = createSelector( diff --git a/src/app/core/store/shopping/recently/recently.effects.spec.ts b/src/app/core/store/shopping/recently/recently.effects.spec.ts index de040566fb..0d44242a99 100644 --- a/src/app/core/store/shopping/recently/recently.effects.spec.ts +++ b/src/app/core/store/shopping/recently/recently.effects.spec.ts @@ -5,10 +5,11 @@ import { cold, hot } from 'jest-marbles'; import { Observable } from 'rxjs'; import { FeatureToggleModule } from 'ish-core/feature-toggle.module'; +import { HttpError } from 'ish-core/models/http-error/http-error.model'; import { Product } from 'ish-core/models/product/product.model'; import { ApplyConfiguration } from 'ish-core/store/configuration'; import { configurationReducer } from 'ish-core/store/configuration/configuration.reducer'; -import { LoadProductSuccess, SelectProduct } from 'ish-core/store/shopping/products'; +import { LoadProductFail, LoadProductSuccess, SelectProduct } from 'ish-core/store/shopping/products'; import { shoppingReducers } from 'ish-core/store/shopping/shopping-store.module'; import { ngrxTesting } from 'ish-core/utils/dev/ngrx-testing'; @@ -54,6 +55,13 @@ describe('Recently Effects', () => { expect(effects.viewedProduct$).toBeObservable(cold('a', { a: new AddToRecently({ sku: 'A' }) })); }); + it('should not fire when product failed loading', () => { + store$.dispatch(new LoadProductFail({ error: {} as HttpError, sku: 'A' })); + store$.dispatch(new SelectProduct({ sku: 'A' })); + + expect(effects.viewedProduct$).toBeObservable(cold('------')); + }); + it('should not fire when product is deselected', () => { store$.dispatch(new SelectProduct({ sku: undefined })); diff --git a/src/app/core/store/shopping/recently/recently.effects.ts b/src/app/core/store/shopping/recently/recently.effects.ts index 4fcd8f412a..1385124cc5 100644 --- a/src/app/core/store/shopping/recently/recently.effects.ts +++ b/src/app/core/store/shopping/recently/recently.effects.ts @@ -18,6 +18,7 @@ export class RecentlyEffects { viewedProduct$ = this.store.pipe( select(getSelectedProduct), whenTruthy(), + filter(p => !ProductHelper.isFailedLoading(p)), distinctUntilKeyChanged('sku'), filter( product => diff --git a/src/app/core/store/shopping/search/search.effects.spec.ts b/src/app/core/store/shopping/search/search.effects.spec.ts index 606e90bc7e..77db119c34 100644 --- a/src/app/core/store/shopping/search/search.effects.spec.ts +++ b/src/app/core/store/shopping/search/search.effects.spec.ts @@ -93,7 +93,6 @@ describe('Search Effects', () => { const action = new RouteNavigation({ path: 'search/:searchTerm', params: { searchTerm: 'dummy' }, - queryParams: [], }); actions$ = hot('a-a-|', { a: action }); diff --git a/src/app/core/store/shopping/shopping-store.spec.ts b/src/app/core/store/shopping/shopping-store.spec.ts index 6395798ea5..2f568154bd 100644 --- a/src/app/core/store/shopping/shopping-store.spec.ts +++ b/src/app/core/store/shopping/shopping-store.spec.ts @@ -234,6 +234,7 @@ describe('Shopping Store', () => { params: {} queryParams: {} data: {} + url: "/home" path: "home" [Viewconf Internal] Set Device Type: deviceType: "pc" @@ -269,6 +270,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123"} queryParams: {} data: {} + url: "/category/A.123" path: "category/:categoryUniqueId" [Shopping] Select Category: categoryId: "A.123" @@ -321,6 +323,7 @@ describe('Shopping Store', () => { params: {"searchTerm":"something"} queryParams: {} data: {} + url: "/search/something" path: "search/:searchTerm" [Shopping] Set Search Term: searchTerm: "something" @@ -364,6 +367,7 @@ describe('Shopping Store', () => { params: {"sku":"P2"} queryParams: {} data: {} + url: "/product/P2" path: "product/:sku" [Shopping] Select Product: sku: "P2" @@ -398,6 +402,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123"} queryParams: {} data: {} + url: "/category/A.123" path: "category/:categoryUniqueId" [Viewconf Internal] Set Device Type: deviceType: "pc" @@ -441,6 +446,7 @@ describe('Shopping Store', () => { params: {} queryParams: {} data: {} + url: "/compare" path: "compare" [Shopping] Deselect Category `); @@ -471,6 +477,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.456"} queryParams: {} data: {} + url: "/category/A.123.456" path: "category/:categoryUniqueId" [Viewconf Internal] Set Device Type: deviceType: "pc" @@ -546,6 +553,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.456","sku":"P1"} queryParams: {} data: {} + url: "/category/A.123.456/product/P1" path: "category/:categoryUniqueId/product/:sku" [Shopping] Select Product: sku: "P1" @@ -576,6 +584,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.456"} queryParams: {} data: {} + url: "/category/A.123.456" path: "category/:categoryUniqueId" [ProductListing] Load More Products: id: {"type":"category","value":"A.123.456"} @@ -599,6 +608,7 @@ describe('Shopping Store', () => { params: {"searchTerm":"something"} queryParams: {} data: {} + url: "/search/something" path: "search/:searchTerm" [Shopping] Deselect Category [Shopping] Set Search Term: @@ -643,6 +653,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.456"} queryParams: {} data: {} + url: "/category/A.123.456" path: "category/:categoryUniqueId" [Shopping] Select Category: categoryId: "A.123.456" @@ -683,6 +694,7 @@ describe('Shopping Store', () => { params: {} queryParams: {} data: {} + url: "/compare" path: "compare" [Shopping] Deselect Category `); @@ -713,6 +725,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.456","sku":"P1"} queryParams: {} data: {} + url: "/category/A.123.456/product/P1" path: "category/:categoryUniqueId/product/:sku" [Viewconf Internal] Set Device Type: deviceType: "pc" @@ -773,6 +786,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.456"} queryParams: {} data: {} + url: "/category/A.123.456" path: "category/:categoryUniqueId" [ProductListing] Load More Products: id: {"type":"category","value":"A.123.456"} @@ -829,6 +843,7 @@ describe('Shopping Store', () => { params: {} queryParams: {} data: {} + url: "/compare" path: "compare" [Shopping] Deselect Category [Shopping] Select Product: @@ -861,6 +876,7 @@ describe('Shopping Store', () => { params: {"sku":"P1"} queryParams: {} data: {} + url: "/product/P1" path: "product/:sku" [Viewconf Internal] Set Device Type: deviceType: "pc" @@ -901,6 +917,7 @@ describe('Shopping Store', () => { params: {} queryParams: {} data: {} + url: "/compare" path: "compare" [Shopping] Select Product: sku: undefined @@ -932,6 +949,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.456","sku":"P3"} queryParams: {} data: {} + url: "/category/A.123.456/product/P3" path: "category/:categoryUniqueId/product/:sku" [Viewconf Internal] Set Device Type: deviceType: "pc" @@ -968,6 +986,7 @@ describe('Shopping Store', () => { params: {} queryParams: {} data: {} + url: "/error" path: "error" [Shopping] Deselect Category [Shopping] Select Product: @@ -1003,6 +1022,7 @@ describe('Shopping Store', () => { params: {"categoryUniqueId":"A.123.XXX"} queryParams: {} data: {} + url: "/category/A.123.XXX" path: "category/:categoryUniqueId" [Viewconf Internal] Set Device Type: deviceType: "pc" @@ -1022,6 +1042,7 @@ describe('Shopping Store', () => { params: {} queryParams: {} data: {} + url: "/error" path: "error" [Shopping] Deselect Category `); @@ -1049,6 +1070,7 @@ describe('Shopping Store', () => { params: {"searchTerm":"something"} queryParams: {} data: {} + url: "/search/something" path: "search/:searchTerm" [Viewconf Internal] Set Device Type: deviceType: "pc" diff --git a/src/app/core/store/user/user.effects.spec.ts b/src/app/core/store/user/user.effects.spec.ts index 34903afe58..26c024fbb8 100644 --- a/src/app/core/store/user/user.effects.spec.ts +++ b/src/app/core/store/user/user.effects.spec.ts @@ -218,7 +218,7 @@ describe('User Effects', () => { store$.dispatch(new ua.LoginUserSuccess(loginResponseData)); - actions$ = of(new RouteNavigation({ path: 'login', queryParams: {} })); + actions$ = of(new RouteNavigation({ path: 'login' })); effects.redirectAfterLogin$.subscribe(noop, fail, noop); @@ -234,7 +234,7 @@ describe('User Effects', () => { store$.dispatch(new ua.LoginUserSuccess(loginResponseData)); - actions$ = of(new RouteNavigation({ path: 'home', queryParams: {} })); + actions$ = of(new RouteNavigation({ path: 'home' })); effects.redirectAfterLogin$.subscribe(noop, fail, noop); @@ -493,7 +493,7 @@ describe('User Effects', () => { describe('resetUserError$', () => { it('should not dispatch UserErrorReset action on router navigation if error is not set', () => { - actions$ = hot('a', { a: new RouteNavigation({ path: 'any', params: {}, queryParams: {} }) }); + actions$ = hot('a', { a: new RouteNavigation({ path: 'any' }) }); expect(effects.resetUserError$).toBeObservable(cold('-')); }); @@ -501,7 +501,7 @@ describe('User Effects', () => { it('should dispatch UserErrorReset action on router navigation if error was set', () => { store$.dispatch(new ua.LoginUserFail({ error: { message: 'error' } as HttpError })); - actions$ = hot('a', { a: new RouteNavigation({ path: 'any', params: {}, queryParams: {} }) }); + actions$ = hot('a', { a: new RouteNavigation({ path: 'any' }) }); expect(effects.resetUserError$).toBeObservable(cold('a', { a: new ua.UserErrorReset() })); }); diff --git a/src/app/core/store/viewconf/viewconf.integration.spec.ts b/src/app/core/store/viewconf/viewconf.integration.spec.ts index c187fe34d9..f7f2cfb5ad 100644 --- a/src/app/core/store/viewconf/viewconf.integration.spec.ts +++ b/src/app/core/store/viewconf/viewconf.integration.spec.ts @@ -46,7 +46,7 @@ describe('Viewconf Integration', () => { expect(getWrapperClass(store$.state)).toEqual('something'); - store$.dispatch(new RouteNavigation({ path: 'any', data: {} })); + store$.dispatch(new RouteNavigation({ path: 'any' })); expect(getWrapperClass(store$.state)).toBeUndefined(); }); diff --git a/src/app/core/utils/link-parser.spec.ts b/src/app/core/utils/link-parser.spec.ts index 49c6c598e6..28f3ecc7e7 100644 --- a/src/app/core/utils/link-parser.spec.ts +++ b/src/app/core/utils/link-parser.spec.ts @@ -11,11 +11,11 @@ describe('Link Parser', () => { input: 'route://category/Home-Entertainment.SmartHome', output: '/category/Home-Entertainment.SmartHome', }, - { input: 'product://201807195@inSPIRED-inTRONICS', output: '/product/201807195' }, + { input: 'product://201807195@inSPIRED-inTRONICS', output: '/sku201807195' }, { input: 'http://google.de', output: 'http://google.de' }, { input: 'https://google.de', output: 'https://google.de' }, { input: 'page://mypage', output: '/page/mypage' }, - { input: 'category://Computers@inSPIRED-Computers', output: '/category/Computers' }, + { input: 'category://Computers@inSPIRED-Computers', output: '/catComputers' }, { input: '/product/ABC', output: '/product/ABC' }, { input: undefined, output: undefined }, ], diff --git a/src/app/core/utils/link-parser.ts b/src/app/core/utils/link-parser.ts index aad7840ba0..1663d6ca0b 100644 --- a/src/app/core/utils/link-parser.ts +++ b/src/app/core/utils/link-parser.ts @@ -9,11 +9,11 @@ export class LinkParser { case 'product': // TODO: for consistent product links it should have the default category in the route // TODO: use ProductRoutePipe - return `/product/${value}`; + return `/sku${value}`; case 'category': // TODO: the configuration parameter currently only works for first level categories // TODO: use CategoryRoutePipe - return `/category/${value}`; + return `/cat${value}`; case 'page': // CMS managed pages link return `/page/${value}`; diff --git a/src/app/core/utils/routing.ts b/src/app/core/utils/routing.ts new file mode 100644 index 0000000000..1f92d3ee03 --- /dev/null +++ b/src/app/core/utils/routing.ts @@ -0,0 +1,24 @@ +import { Router } from '@angular/router'; + +export function addGlobalGuard( + router: Router, + guard: unknown, + config: { canActivate: boolean; canActivateChild: boolean } = { canActivate: true, canActivateChild: true } +) { + router.config.forEach(route => { + if (config.canActivate) { + if (route.canActivate) { + route.canActivate.push(guard); + } else { + route.canActivate = [guard]; + } + } + if (config.canActivateChild) { + if (route.canActivateChild) { + route.canActivateChild.push(guard); + } else { + route.canActivateChild = [guard]; + } + } + }); +} diff --git a/src/app/core/utils/state-transfer/state-properties.service.ts b/src/app/core/utils/state-transfer/state-properties.service.ts index 7446ae997b..502aa7169b 100644 --- a/src/app/core/utils/state-transfer/state-properties.service.ts +++ b/src/app/core/utils/state-transfer/state-properties.service.ts @@ -8,6 +8,7 @@ import { getConfigurationState } from 'ish-core/store/configuration'; import { mapToProperty } from 'ish-core/utils/operators'; import { environment } from '../../../../environments/environment'; +import { Environment } from '../../../../environments/environment.model'; /** * Service for retrieving injection properties {@link ICM_BASE_URL} and {@link REST_ENDPOINT}. @@ -20,7 +21,7 @@ export class StatePropertiesService { /** * Retrieve property from first set property of server state, system environment or environment.ts */ - getStateOrEnvOrDefault(envKey: string, envPropKey: string): Observable { + getStateOrEnvOrDefault(envKey: string, envPropKey: keyof Environment): Observable { return this.store.pipe( select(getConfigurationState), // tslint:disable-next-line:no-any diff --git a/src/app/core/utils/theme/theme.service.ts b/src/app/core/utils/theme/theme.service.ts index c863739b80..21e599cd8d 100644 --- a/src/app/core/utils/theme/theme.service.ts +++ b/src/app/core/utils/theme/theme.service.ts @@ -17,15 +17,32 @@ export class ThemeService { private head: HTMLElement; private themeLinks: HTMLElement[] = []; + private iconLink: HTMLLinkElement; + private webmanifestLink: HTMLLinkElement; + private appleTouchIconLink: HTMLLinkElement; + private appleTouchIcon152x152Link: HTMLLinkElement; + private appleTouchIcon167x167Link: HTMLLinkElement; + private appleTouchIcon180x180Link: HTMLLinkElement; + private themeColor: HTMLMetaElement; + constructor( private rendererFactory: RendererFactory2, @Inject(DOCUMENT) private document: Document, private store: Store<{}> - ) {} - - init() { + ) { this.head = this.document.head; this.renderer = this.rendererFactory.createRenderer(undefined, undefined); + + this.iconLink = this.document.querySelector('link[rel="icon"]'); + this.webmanifestLink = this.document.querySelector('link[rel="manifest"]'); + this.appleTouchIconLink = this.document.querySelector('link[rel="apple-touch-icon"]:not([sizes])'); + this.appleTouchIcon152x152Link = this.document.querySelector('link[rel="apple-touch-icon"][sizes="152x152"]'); + this.appleTouchIcon167x167Link = this.document.querySelector('link[rel="apple-touch-icon"][sizes="167x167"]'); + this.appleTouchIcon180x180Link = this.document.querySelector('link[rel="apple-touch-icon"][sizes="180x180"]'); + this.themeColor = this.document.querySelector('meta[name="theme-color"]'); + } + + init() { this.store .pipe(select(getTheme)) .pipe( @@ -33,12 +50,22 @@ export class ThemeService { filter(x => !!x) ) .subscribe(async theme => { - await this.loadCss(`${theme}.css`); + const themeData = theme.split('|'); + const themeName = themeData[0]; + const themeColor = themeData[1]; + + this.iconLink.setAttribute('href', `assets/themes/${themeName}/img/favicon.ico`); + this.webmanifestLink.setAttribute('href', `assets/themes/${themeName}/manifest.webmanifest`); + this.appleTouchIconLink.setAttribute('href', `assets/themes/${themeName}/img/logo_apple_120x120.png`); + this.appleTouchIcon152x152Link.setAttribute('href', `assets/themes/${themeName}/img/logo_apple_152x152.png`); + this.appleTouchIcon167x167Link.setAttribute('href', `assets/themes/${themeName}/img/logo_apple_167x167.png`); + this.appleTouchIcon180x180Link.setAttribute('href', `assets/themes/${themeName}/img/logo_apple_180x180.png`); - // remove style of previous theme - if (this.themeLinks.length === 2) { - this.renderer.removeChild(this.head, this.themeLinks.shift()); + if (themeColor) { + this.themeColor.setAttribute('content', `#${themeColor}`); } + + await this.loadCss(`${themeName}.css`); }); } @@ -51,6 +78,11 @@ export class ThemeService { this.renderer.setProperty(linkEl, 'onload', resolve); this.renderer.appendChild(this.head, linkEl); this.themeLinks = [...this.themeLinks, linkEl]; + + // remove style of previous theme + if (this.themeLinks.length === 2) { + this.renderer.removeChild(this.head, this.themeLinks.shift()); + } }); } } diff --git a/src/app/extensions/quoting/facades/quoting.facade.ts b/src/app/extensions/quoting/facades/quoting.facade.ts index 16982dac0b..173c92c97a 100644 --- a/src/app/extensions/quoting/facades/quoting.facade.ts +++ b/src/app/extensions/quoting/facades/quoting.facade.ts @@ -13,6 +13,7 @@ import { DeleteQuote, LoadQuotes, RejectQuote, + ResetQuoteError, getCurrentQuotes, getQuoteError, getQuoteLoading, @@ -74,6 +75,10 @@ export class QuotingFacade { this.store.dispatch(new AddQuoteToBasket({ quoteId })); } + resetQuoteError() { + this.store.dispatch(new ResetQuoteError()); + } + // QUOTE REQUEST quoteRequest$ = this.store.pipe(select(getSelectedQuoteRequestWithProducts)); quoteRequestLoading$ = this.store.pipe(select(getQuoteRequestLoading)); @@ -109,8 +114,8 @@ export class QuotingFacade { this.store.dispatch(new UpdateSubmitQuoteRequest(payload)); } - copyQuoteRequest() { - this.store.dispatch(new CreateQuoteRequestFromQuoteRequest()); + copyQuoteRequest(preventRedirect?: boolean) { + this.store.dispatch(new CreateQuoteRequestFromQuoteRequest({ redirect: !preventRedirect })); } updateQuoteRequestItem(update: LineItemUpdate) { diff --git a/src/app/extensions/quoting/models/quote-request-item/quote-request-item.model.ts b/src/app/extensions/quoting/models/quote-request-item/quote-request-item.model.ts index 986ca150ea..857c1430ad 100644 --- a/src/app/extensions/quoting/models/quote-request-item/quote-request-item.model.ts +++ b/src/app/extensions/quoting/models/quote-request-item/quote-request-item.model.ts @@ -1,5 +1,5 @@ import { Price } from 'ish-core/models/price/price.model'; -import { Product } from 'ish-core/models/product/product.model'; +import { ProductView } from 'ish-core/models/product-view/product-view.model'; export interface QuoteRequestItem { id?: string; @@ -24,5 +24,5 @@ export interface QuoteRequestItem { } export interface QuoteRequestItemView extends QuoteRequestItem { - product: Product; + product: ProductView; } diff --git a/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.spec.ts b/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.spec.ts index 84b796750e..fed3d42af8 100644 --- a/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.spec.ts +++ b/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.spec.ts @@ -1,5 +1,5 @@ import { Location } from '@angular/common'; -import { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { Store, combineReducers } from '@ngrx/store'; import { TranslateModule } from '@ngx-translate/core'; @@ -20,7 +20,6 @@ describe('Quote Edit Page Component', () => { let fixture: ComponentFixture; let element: HTMLElement; let store$: Store<{}>; - let location: Location; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -58,10 +57,4 @@ describe('Quote Edit Page Component', () => { fixture.detectChanges(); expect(element.querySelector('ish-loading')).toBeTruthy(); }); - - it('should navigate to basket when addToBasket is clicked', fakeAsync(() => { - component.addQuoteToBasket(undefined); - tick(50); - expect(location.path()).toBe('/basket'); - })); }); diff --git a/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.ts b/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.ts index 0878d7780d..0db06a37db 100644 --- a/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.ts +++ b/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.component.ts @@ -1,5 +1,4 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { Router } from '@angular/router'; import { Observable } from 'rxjs'; import { AccountFacade } from 'ish-core/facades/account.facade'; @@ -20,7 +19,7 @@ export class QuoteEditPageComponent implements OnInit { quoteError$: Observable; user$: Observable; - constructor(private quotingFacade: QuotingFacade, private accountFacade: AccountFacade, private router: Router) {} + constructor(private quotingFacade: QuotingFacade, private accountFacade: AccountFacade) {} ngOnInit() { this.quote$ = this.quotingFacade.quote$; @@ -39,6 +38,5 @@ export class QuoteEditPageComponent implements OnInit { addQuoteToBasket(quoteId: string) { this.quotingFacade.addQuoteToBasket(quoteId); - this.router.navigate(['/basket']); } } diff --git a/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.module.ts b/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.module.ts index 296866c1f7..d0576c1b69 100644 --- a/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.module.ts +++ b/src/app/extensions/quoting/pages/quote-edit/quote-edit-page.module.ts @@ -5,7 +5,7 @@ import { QuotingModule } from '../../quoting.module'; import { QuoteEditPageComponent } from './quote-edit-page.component'; -const quoteEditPageRoutes: Routes = [{ path: ':quoteId', component: QuoteEditPageComponent }]; +const quoteEditPageRoutes: Routes = [{ path: '', component: QuoteEditPageComponent }]; @NgModule({ declarations: [QuoteEditPageComponent], diff --git a/src/app/extensions/quoting/pages/quote-list/quote-list/quote-list.component.ts b/src/app/extensions/quoting/pages/quote-list/quote-list/quote-list.component.ts index eeb4f966ed..29b336af9f 100644 --- a/src/app/extensions/quoting/pages/quote-list/quote-list/quote-list.component.ts +++ b/src/app/extensions/quoting/pages/quote-list/quote-list/quote-list.component.ts @@ -38,10 +38,10 @@ export class QuoteListComponent implements OnChanges { */ generateDetailRoute(item: Quote | QuoteRequest): string | void { if (item.type === 'Quote') { - return `/account/quote/${item.id}`; + return `/account/quotes/${item.id}`; } if (item.type === 'QuoteRequest') { - return `/account/quote-request/${item.id}`; + return `/account/quotes/request/${item.id}`; } } diff --git a/src/app/extensions/quoting/pages/quote-request-edit/quote-request-edit-page.module.ts b/src/app/extensions/quoting/pages/quote-request-edit/quote-request-edit-page.module.ts index 6eca07861a..96299bb4b5 100644 --- a/src/app/extensions/quoting/pages/quote-request-edit/quote-request-edit-page.module.ts +++ b/src/app/extensions/quoting/pages/quote-request-edit/quote-request-edit-page.module.ts @@ -5,7 +5,7 @@ import { QuotingModule } from '../../quoting.module'; import { QuoteRequestEditPageComponent } from './quote-request-edit-page.component'; -const quoteRequestEditPageRoutes: Routes = [{ path: ':quoteRequestId', component: QuoteRequestEditPageComponent }]; +const quoteRequestEditPageRoutes: Routes = [{ path: '', component: QuoteRequestEditPageComponent }]; @NgModule({ declarations: [QuoteRequestEditPageComponent], diff --git a/src/app/extensions/quoting/pages/quoting-routing.module.ts b/src/app/extensions/quoting/pages/quoting-routing.module.ts index 0f74402245..93e3a4dbcb 100644 --- a/src/app/extensions/quoting/pages/quoting-routing.module.ts +++ b/src/app/extensions/quoting/pages/quoting-routing.module.ts @@ -6,23 +6,32 @@ import { AuthGuard } from 'ish-core/guards/auth.guard'; const routes: Routes = [ { - path: 'quote-list', + path: '', loadChildren: () => import('./quote-list/quote-list-page.module').then(m => m.QuoteListPageModule), canActivate: [FeatureToggleGuard, AuthGuard], data: { feature: 'quoting' }, }, { - path: 'quote', + path: ':quoteId', loadChildren: () => import('./quote-edit/quote-edit-page.module').then(m => m.QuoteEditPageModule), canActivate: [FeatureToggleGuard, AuthGuard], - data: { feature: 'quoting' }, + data: { + feature: 'quoting', + breadcrumbData: [{ key: 'quote.quotes.link', link: '/account/quotes' }, { key: 'quote.quote_details.link' }], + }, }, { - path: 'quote-request', + path: 'request/:quoteRequestId', loadChildren: () => import('./quote-request-edit/quote-request-edit-page.module').then(m => m.QuoteRequestEditPageModule), canActivate: [FeatureToggleGuard, AuthGuard], - data: { feature: 'quoting' }, + data: { + feature: 'quoting', + breadcrumbData: [ + { key: 'quote.quotes.link', link: '/account/quotes' }, + { key: 'quote.edit.unsubmitted.quote_request_details.text' }, + ], + }, }, ]; diff --git a/src/app/extensions/quoting/shared/account/quote-widget/quote-widget.component.html b/src/app/extensions/quoting/shared/account/quote-widget/quote-widget.component.html index 578e80ca0c..dcf33a22df 100644 --- a/src/app/extensions/quoting/shared/account/quote-widget/quote-widget.component.html +++ b/src/app/extensions/quoting/shared/account/quote-widget/quote-widget.component.html @@ -16,7 +16,7 @@

{{ 'account.quotes.widget.my_quotes.heading' | translate }}

-
{{ + {{ 'account.quotes.widget.view_all_quotes.link' | translate }} diff --git a/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.html b/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.html index 1cf45e0bc9..4b18668b86 100644 --- a/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.html +++ b/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.html @@ -1,12 +1,12 @@ - + diff --git a/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.spec.ts b/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.spec.ts index dd0258d7e3..ea446751e0 100644 --- a/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.spec.ts +++ b/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.spec.ts @@ -3,10 +3,14 @@ import { ReactiveFormsModule } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { TranslateModule } from '@ngx-translate/core'; -import { MockComponent } from 'ng-mocks'; +import { MockComponent, MockDirective, MockPipe } from 'ng-mocks'; import { EMPTY, of } from 'rxjs'; import { anything, capture, instance, mock, verify, when } from 'ts-mockito'; +import { ServerHtmlDirective } from 'ish-core/directives/server-html.directive'; +import { AccountFacade } from 'ish-core/facades/account.facade'; +import { MessageFacade } from 'ish-core/facades/message.facade'; +import { DatePipe } from 'ish-core/pipes/date.pipe'; import { LineItemListComponent } from 'ish-shared/components/basket/line-item-list/line-item-list.component'; import { LoadingComponent } from 'ish-shared/components/common/loading/loading.component'; import { InputComponent } from 'ish-shared/forms/components/input/input.component'; @@ -21,9 +25,13 @@ describe('Product Add To Quote Dialog Component', () => { let fixture: ComponentFixture; let element: HTMLElement; let quotingFacade: QuotingFacade; + let messageFacade: MessageFacade; + let accountFacade: AccountFacade; beforeEach(async(() => { quotingFacade = mock(QuotingFacade); + messageFacade = mock(MessageFacade); + accountFacade = mock(AccountFacade); TestBed.configureTestingModule({ imports: [ReactiveFormsModule, RouterTestingModule, TranslateModule.forRoot()], @@ -32,9 +40,16 @@ describe('Product Add To Quote Dialog Component', () => { MockComponent(LineItemListComponent), MockComponent(LoadingComponent), MockComponent(QuoteStateComponent), + MockDirective(ServerHtmlDirective), + MockPipe(DatePipe), ProductAddToQuoteDialogComponent, ], - providers: [NgbActiveModal, { provide: QuotingFacade, useFactory: () => instance(quotingFacade) }], + providers: [ + NgbActiveModal, + { provide: QuotingFacade, useFactory: () => instance(quotingFacade) }, + { provide: MessageFacade, useFactory: () => instance(messageFacade) }, + { provide: AccountFacade, useFactory: () => instance(accountFacade) }, + ], }).compileComponents(); })); @@ -42,10 +57,11 @@ describe('Product Add To Quote Dialog Component', () => { fixture = TestBed.createComponent(ProductAddToQuoteDialogComponent); component = fixture.componentInstance; element = fixture.nativeElement; + when(quotingFacade.activeQuoteRequest$).thenReturn(EMPTY); }); it('should be created', () => { - when(quotingFacade.activeQuoteRequest$).thenReturn(EMPTY); + when(quotingFacade.quoteRequest$).thenReturn(EMPTY); expect(component).toBeTruthy(); expect(element).toBeTruthy(); @@ -54,7 +70,7 @@ describe('Product Add To Quote Dialog Component', () => { describe('Quote Request', () => { beforeEach(() => { - when(quotingFacade.activeQuoteRequest$).thenReturn( + when(quotingFacade.quoteRequest$).thenReturn( of({ id: 'ID', type: 'QuoteRequest', diff --git a/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.ts b/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.ts index 75d99db070..1eb48d0649 100644 --- a/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.ts +++ b/src/app/extensions/quoting/shared/product/product-add-to-quote-dialog/product-add-to-quote-dialog.component.ts @@ -2,9 +2,12 @@ import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/ import { FormControl, FormGroup, Validators } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Observable, Subject } from 'rxjs'; -import { distinctUntilKeyChanged, filter, take, takeUntil } from 'rxjs/operators'; +import { take, takeUntil } from 'rxjs/operators'; +import { AccountFacade } from 'ish-core/facades/account.facade'; +import { MessageFacade } from 'ish-core/facades/message.facade'; import { LineItemUpdate } from 'ish-core/models/line-item-update/line-item-update.model'; +import { User } from 'ish-core/models/user/user.model'; import { whenTruthy } from 'ish-core/utils/operators'; import { QuotingFacade } from '../../../facades/quoting.facade'; @@ -16,14 +19,20 @@ import { QuoteRequest } from '../../../models/quote-request/quote-request.model' changeDetection: ChangeDetectionStrategy.OnPush, }) export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { - activeQuoteRequest$: Observable; + selectedQuoteRequest$: Observable; quoteRequestLoading$: Observable; + user$: Observable; form: FormGroup; private destroy$ = new Subject(); - constructor(public ngbActiveModal: NgbActiveModal, private quotingFacade: QuotingFacade) { + constructor( + public ngbActiveModal: NgbActiveModal, + private quotingFacade: QuotingFacade, + private messageFacade: MessageFacade, + private accountFacade: AccountFacade + ) { this.form = new FormGroup({ displayName: new FormControl(undefined, [Validators.maxLength(255)]), description: new FormControl(undefined, []), @@ -31,10 +40,11 @@ export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { } ngOnInit() { - this.activeQuoteRequest$ = this.quotingFacade.activeQuoteRequest$; + this.user$ = this.accountFacade.user$; + this.selectedQuoteRequest$ = this.quotingFacade.quoteRequest$; this.quoteRequestLoading$ = this.quotingFacade.quoteRequestLoading$; - this.activeQuoteRequest$ + this.selectedQuoteRequest$ .pipe( whenTruthy(), takeUntil(this.destroy$) @@ -43,11 +53,11 @@ export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { this.patchForm(quote); }); - this.activeQuoteRequest$ + // make active quote request to selected + this.quotingFacade.activeQuoteRequest$ .pipe( - filter(quoteRequest => !!quoteRequest), - distinctUntilKeyChanged('id'), - takeUntil(this.destroy$) + whenTruthy(), + take(1) ) .subscribe(quoteRequest => this.quotingFacade.selectQuoteRequest(quoteRequest.id)); } @@ -71,7 +81,7 @@ export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { * @param item Item id and quantity pair that should be changed */ onUpdateItem(item: LineItemUpdate) { - this.activeQuoteRequest$ + this.selectedQuoteRequest$ .pipe( take(1), whenTruthy() @@ -91,7 +101,7 @@ export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { * Throws deleteQuoteRequest event when last item will be deleted. */ onDeleteItem(itemId: string) { - this.activeQuoteRequest$ + this.selectedQuoteRequest$ .pipe( take(1), whenTruthy() @@ -118,7 +128,6 @@ export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { } else { this.quotingFacade.submitQuoteRequest(); } - this.hide(); } /** @@ -133,7 +142,23 @@ export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { displayName: this.form.value.displayName, description: this.form.value.description, }); + + this.messageFacade.success({ + message: 'quote.edit.saved.your_quote_request_has_been_saved.text', + messageParams: { + 0: this.form.value.displayName, + }, + }); + this.hide(); + return false; + } + + /** + * Throws copyQuoteRequest event when copy button was clicked. + */ + copy() { + this.quotingFacade.copyQuoteRequest(true); } /** @@ -142,4 +167,13 @@ export class ProductAddToQuoteDialogComponent implements OnInit, OnDestroy { hide() { this.ngbActiveModal.close(); } + + /** + * Callback function to hide modal dialog (used with ishServerHtml). + */ + get callbackHideDialogModal() { + return () => { + this.hide(); + }; + } } diff --git a/src/app/extensions/quoting/shared/product/product-add-to-quote/product-add-to-quote.component.ts b/src/app/extensions/quoting/shared/product/product-add-to-quote/product-add-to-quote.component.ts index d080022495..f47d040187 100644 --- a/src/app/extensions/quoting/shared/product/product-add-to-quote/product-add-to-quote.component.ts +++ b/src/app/extensions/quoting/shared/product/product-add-to-quote/product-add-to-quote.component.ts @@ -21,7 +21,7 @@ import { ProductAddToQuoteDialogComponent } from '../product-add-to-quote-dialog export class ProductAddToQuoteComponent { @Input() product: Product; @Input() disabled?: boolean; - @Input() displayType?: string; + @Input() displayType?: 'icon' | 'link' = 'link'; @Input() class?: string; @Input() quantity?: number; diff --git a/src/app/extensions/quoting/shared/quote/quote-edit/quote-edit.component.html b/src/app/extensions/quoting/shared/quote/quote-edit/quote-edit.component.html index 7e82f601c0..6d9005fe1e 100644 --- a/src/app/extensions/quoting/shared/quote/quote-edit/quote-edit.component.html +++ b/src/app/extensions/quoting/shared/quote/quote-edit/quote-edit.component.html @@ -25,7 +25,7 @@

-
+
{{ 'quote.edit.submitted.your_quote_request_has_been_submitted.text' | translate: { '0': quote.creationDate | ishDate: 'shortDate' } @@ -33,27 +33,24 @@

- {{ 'quote.edit.saved.your_quote_request_has_been_saved.text' | translate }} + {{ 'quote.edit.saved.your_quote_request_has_been_saved.text' | translate: { '0': displayName } }}
- +

{{ 'quote.edit.submitted.your_quote_number.text' | translate }} - {{ quote.number }} -

-

- {{ 'quote.edit.submitted.your_quote_request.text' | translate }}
- + {{ quote.number }}

+

{{ 'quote.edit.submitted.we_will_email.text' | translate: { '0': user.email } }}

@@ -109,7 +106,7 @@

>
-